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 /*
239ff4cbe7SAdrian Frost  * Copyright 2009 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;
5585738508SVuong Nguyen int nb_channels_per_branch = NB_MAX_CHANNELS_PER_BRANCH;
5620c794b3Sgavinm int nb_dimms_per_channel = 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 
6730cfc677SAdrian Frost extern int nb_no_smbios;
6830cfc677SAdrian Frost 
6920c794b3Sgavinm errorq_t *nb_queue;
7020c794b3Sgavinm kmutex_t nb_mutex;
7120c794b3Sgavinm 
7230cfc677SAdrian Frost static int nb_dimm_slots;
7330cfc677SAdrian Frost 
749ff4cbe7SAdrian Frost static uint32_t nb_err0_int;
759ff4cbe7SAdrian Frost static uint32_t nb_err1_int;
769ff4cbe7SAdrian Frost static uint32_t nb_err2_int;
779ff4cbe7SAdrian Frost static uint32_t nb_mcerr_int;
785f28a827Saf static uint32_t nb_emask_int;
7920c794b3Sgavinm 
8020c794b3Sgavinm static uint32_t nb_err0_fbd;
8120c794b3Sgavinm static uint32_t nb_err1_fbd;
8220c794b3Sgavinm static uint32_t nb_err2_fbd;
8320c794b3Sgavinm static uint32_t nb_mcerr_fbd;
8420c794b3Sgavinm static uint32_t nb_emask_fbd;
8520c794b3Sgavinm 
8685738508SVuong Nguyen static uint32_t nb_err0_mem;
8785738508SVuong Nguyen static uint32_t nb_err1_mem;
8885738508SVuong Nguyen static uint32_t nb_err2_mem;
8985738508SVuong Nguyen static uint32_t nb_mcerr_mem;
9085738508SVuong Nguyen static uint32_t nb_emask_mem;
9185738508SVuong Nguyen 
9220c794b3Sgavinm static uint16_t nb_err0_fsb;
9320c794b3Sgavinm static uint16_t nb_err1_fsb;
9420c794b3Sgavinm static uint16_t nb_err2_fsb;
9520c794b3Sgavinm static uint16_t nb_mcerr_fsb;
9620c794b3Sgavinm static uint16_t nb_emask_fsb;
9720c794b3Sgavinm 
985f28a827Saf static uint16_t nb_err0_thr;
995f28a827Saf static uint16_t nb_err1_thr;
1005f28a827Saf static uint16_t nb_err2_thr;
1015f28a827Saf static uint16_t nb_mcerr_thr;
1025f28a827Saf static uint16_t nb_emask_thr;
1035f28a827Saf 
10420c794b3Sgavinm static uint32_t	emask_uncor_pex[NB_PCI_DEV];
10520c794b3Sgavinm static uint32_t emask_cor_pex[NB_PCI_DEV];
10620c794b3Sgavinm static uint32_t emask_rp_pex[NB_PCI_DEV];
10720c794b3Sgavinm static uint32_t docmd_pex[NB_PCI_DEV];
10820c794b3Sgavinm static uint32_t uncerrsev[NB_PCI_DEV];
10920c794b3Sgavinm 
1109ff4cbe7SAdrian Frost static uint32_t l_mcerr_int;
11120c794b3Sgavinm static uint32_t l_mcerr_fbd;
11285738508SVuong Nguyen static uint32_t l_mcerr_mem;
11320c794b3Sgavinm static uint16_t l_mcerr_fsb;
1145f28a827Saf static uint16_t l_mcerr_thr;
11520c794b3Sgavinm 
1165f28a827Saf uint_t nb5000_emask_fbd = EMASK_5000_FBD_RES;
1175f28a827Saf uint_t nb5400_emask_fbd = 0;
11820c794b3Sgavinm int nb5000_reset_emask_fbd = 1;
11920c794b3Sgavinm uint_t nb5000_mask_poll_fbd = EMASK_FBD_NF;
12020c794b3Sgavinm uint_t nb5000_mask_bios_fbd = EMASK_FBD_FATAL;
1215f28a827Saf uint_t nb5400_mask_poll_fbd = EMASK_5400_FBD_NF;
1225f28a827Saf uint_t nb5400_mask_bios_fbd = EMASK_5400_FBD_FATAL;
123*f8e921e3SVuong Nguyen uint_t nb7300_mask_poll_fbd = EMASK_7300_FBD_NF;
124*f8e921e3SVuong Nguyen uint_t nb7300_mask_bios_fbd = EMASK_7300_FBD_FATAL;
12520c794b3Sgavinm 
12685738508SVuong Nguyen int nb5100_reset_emask_mem = 1;
12785738508SVuong Nguyen uint_t nb5100_mask_poll_mem = EMASK_MEM_NF;
12885738508SVuong Nguyen 
12920c794b3Sgavinm uint_t nb5000_emask_fsb = 0;
13020c794b3Sgavinm int nb5000_reset_emask_fsb = 1;
13120c794b3Sgavinm uint_t nb5000_mask_poll_fsb = EMASK_FSB_NF;
13220c794b3Sgavinm uint_t nb5000_mask_bios_fsb = EMASK_FSB_FATAL;
13320c794b3Sgavinm 
134*f8e921e3SVuong Nguyen uint_t nb5100_emask_int = EMASK_INT_5100;
1359ff4cbe7SAdrian Frost uint_t nb5400_emask_int = EMASK_INT_5400;
1365f28a827Saf 
13720c794b3Sgavinm uint_t nb7300_emask_int = EMASK_INT_7300;
13820c794b3Sgavinm uint_t nb7300_emask_int_step0 = EMASK_INT_7300_STEP_0;
13920c794b3Sgavinm uint_t nb5000_emask_int = EMASK_INT_5000;
14020c794b3Sgavinm int nb5000_reset_emask_int = 1;
14120c794b3Sgavinm uint_t nb5000_mask_poll_int = EMASK_INT_NF;
14220c794b3Sgavinm uint_t nb5000_mask_bios_int = EMASK_INT_FATAL;
143*f8e921e3SVuong Nguyen uint_t nb5100_mask_poll_int = EMASK_INT_5100_NF;
144*f8e921e3SVuong Nguyen uint_t nb5100_mask_bios_int = EMASK_INT_5100_FATAL;
14520c794b3Sgavinm 
1465f28a827Saf uint_t nb_mask_poll_thr = EMASK_THR_NF;
1475f28a827Saf uint_t nb_mask_bios_thr = EMASK_THR_FATAL;
1485f28a827Saf 
14920c794b3Sgavinm int nb5000_reset_uncor_pex = 0;
15020c794b3Sgavinm uint_t nb5000_mask_uncor_pex = 0;
1515f28a827Saf int nb5000_reset_cor_pex = 0;
15220c794b3Sgavinm uint_t nb5000_mask_cor_pex = 0xffffffff;
1539a12e1bdSjveta uint32_t nb5000_rp_pex = 0x1;
15420c794b3Sgavinm 
15520c794b3Sgavinm int nb_mask_mc_set;
15620c794b3Sgavinm 
1579d6aa643Saf typedef struct find_dimm_label {
1589d6aa643Saf 	void (*label_function)(int, char *, int);
1599d6aa643Saf } find_dimm_label_t;
1609d6aa643Saf 
1619d6aa643Saf static void x8450_dimm_label(int, char *, int);
16285738508SVuong Nguyen static void cp3250_dimm_label(int, char *, int);
1639d6aa643Saf 
1649d6aa643Saf static struct platform_label {
1659d6aa643Saf 	const char *sys_vendor;		/* SMB_TYPE_SYSTEM vendor prefix */
1669d6aa643Saf 	const char *sys_product;	/* SMB_TYPE_SYSTEM product prefix */
1679d6aa643Saf 	find_dimm_label_t dimm_label;
1689d6aa643Saf 	int dimms_per_channel;
1699d6aa643Saf } platform_label[] = {
1709d6aa643Saf 	{ "SUN MICROSYSTEMS", "SUN BLADE X8450 SERVER MODULE",
1719d6aa643Saf 	    x8450_dimm_label, 8 },
17285738508SVuong Nguyen 	{ "MiTAC,Shunde", "CP3250", cp3250_dimm_label, 0 },
1739d6aa643Saf 	{ NULL, NULL, NULL, 0 }
1749d6aa643Saf };
1759d6aa643Saf 
17620c794b3Sgavinm static unsigned short
17720c794b3Sgavinm read_spd(int bus)
17820c794b3Sgavinm {
17920c794b3Sgavinm 	unsigned short rt = 0;
18020c794b3Sgavinm 	int branch = bus >> 1;
18120c794b3Sgavinm 	int channel = bus & 1;
18220c794b3Sgavinm 
18320c794b3Sgavinm 	rt = SPD_RD(branch, channel);
18420c794b3Sgavinm 
18520c794b3Sgavinm 	return (rt);
18620c794b3Sgavinm }
18720c794b3Sgavinm 
18820c794b3Sgavinm static void
18920c794b3Sgavinm write_spdcmd(int bus, uint32_t val)
19020c794b3Sgavinm {
19120c794b3Sgavinm 	int branch = bus >> 1;
19220c794b3Sgavinm 	int channel = bus & 1;
19320c794b3Sgavinm 	SPDCMD_WR(branch, channel, val);
19420c794b3Sgavinm }
19520c794b3Sgavinm 
19620c794b3Sgavinm static int
19720c794b3Sgavinm read_spd_eeprom(int bus, int slave, int addr)
19820c794b3Sgavinm {
19920c794b3Sgavinm 	int retry = 4;
20020c794b3Sgavinm 	int wait;
20120c794b3Sgavinm 	int spd;
20220c794b3Sgavinm 	uint32_t cmd;
20320c794b3Sgavinm 
20420c794b3Sgavinm 	for (;;) {
20520c794b3Sgavinm 		wait = 1000;
20620c794b3Sgavinm 		for (;;) {
20720c794b3Sgavinm 			spd = read_spd(bus);
20820c794b3Sgavinm 			if ((spd & SPD_BUSY) == 0)
20920c794b3Sgavinm 				break;
21020c794b3Sgavinm 			if (--wait == 0)
21120c794b3Sgavinm 				return (-1);
21220c794b3Sgavinm 			drv_usecwait(10);
21320c794b3Sgavinm 		}
21420c794b3Sgavinm 		cmd = SPD_EEPROM_WRITE | SPD_ADDR(slave, addr);
21520c794b3Sgavinm 		write_spdcmd(bus, cmd);
21620c794b3Sgavinm 		wait = 1000;
21720c794b3Sgavinm 		for (;;) {
21820c794b3Sgavinm 			spd = read_spd(bus);
21920c794b3Sgavinm 			if ((spd & SPD_BUSY) == 0)
22020c794b3Sgavinm 				break;
22120c794b3Sgavinm 			if (--wait == 0) {
22220c794b3Sgavinm 				spd = SPD_BUS_ERROR;
22320c794b3Sgavinm 				break;
22420c794b3Sgavinm 			}
22520c794b3Sgavinm 			drv_usecwait(10);
22620c794b3Sgavinm 		}
22720c794b3Sgavinm 		while ((spd & SPD_BUS_ERROR) == 0 &&
22820c794b3Sgavinm 		    (spd & (SPD_READ_DATA_VALID|SPD_BUSY)) !=
22920c794b3Sgavinm 		    SPD_READ_DATA_VALID) {
23020c794b3Sgavinm 			spd = read_spd(bus);
23120c794b3Sgavinm 			if (--wait == 0)
23220c794b3Sgavinm 				return (-1);
23320c794b3Sgavinm 		}
23420c794b3Sgavinm 		if ((spd & SPD_BUS_ERROR) == 0)
23520c794b3Sgavinm 			break;
23620c794b3Sgavinm 		if (--retry == 0)
23720c794b3Sgavinm 			return (-1);
23820c794b3Sgavinm 	}
23920c794b3Sgavinm 	return (spd & 0xff);
24020c794b3Sgavinm }
24120c794b3Sgavinm 
24220c794b3Sgavinm static void
24320c794b3Sgavinm nb_fini()
24420c794b3Sgavinm {
24520c794b3Sgavinm 	int i, j;
24685738508SVuong Nguyen 	int nchannels = nb_number_memory_controllers * nb_channels_per_branch;
24720c794b3Sgavinm 	nb_dimm_t **dimmpp;
24820c794b3Sgavinm 	nb_dimm_t *dimmp;
24920c794b3Sgavinm 
25020c794b3Sgavinm 	dimmpp = nb_dimms;
25120c794b3Sgavinm 	for (i = 0; i < nchannels; i++) {
25220c794b3Sgavinm 		for (j = 0; j < nb_dimms_per_channel; j++) {
25320c794b3Sgavinm 			dimmp = *dimmpp;
25420c794b3Sgavinm 			if (dimmp) {
25520c794b3Sgavinm 				kmem_free(dimmp, sizeof (nb_dimm_t));
25620c794b3Sgavinm 				*dimmpp = NULL;
25720c794b3Sgavinm 			}
25820c794b3Sgavinm 			dimmp++;
25920c794b3Sgavinm 		}
26020c794b3Sgavinm 	}
26130cfc677SAdrian Frost 	kmem_free(nb_dimms, sizeof (nb_dimm_t *) * nb_dimm_slots);
26220c794b3Sgavinm 	nb_dimms = NULL;
26320c794b3Sgavinm 	dimm_fini();
26420c794b3Sgavinm }
26520c794b3Sgavinm 
26620c794b3Sgavinm void
26720c794b3Sgavinm nb_scrubber_enable()
26820c794b3Sgavinm {
26920c794b3Sgavinm 	uint32_t mc;
27020c794b3Sgavinm 
27120c794b3Sgavinm 	if (!nb_hw_memory_scrub_enable)
27220c794b3Sgavinm 		return;
27320c794b3Sgavinm 
27420c794b3Sgavinm 	mc = MC_RD();
27520c794b3Sgavinm 	if ((mc & MC_MIRROR) != 0) /* mirror mode */
27620c794b3Sgavinm 		mc |= MC_PATROL_SCRUB;
27720c794b3Sgavinm 	else
27820c794b3Sgavinm 		mc |= MC_PATROL_SCRUB|MC_DEMAND_SCRUB;
27920c794b3Sgavinm 	MC_WR(mc);
28020c794b3Sgavinm 
28120c794b3Sgavinm 	if (nb_sw_scrub_disabled++)
282e4b86885SCheng Sean Ye 		cmi_mc_sw_memscrub_disable();
28320c794b3Sgavinm }
28420c794b3Sgavinm 
28585738508SVuong Nguyen static void
28685738508SVuong Nguyen fbd_eeprom(int channel, int dimm, nb_dimm_t *dp)
28720c794b3Sgavinm {
28820c794b3Sgavinm 	int i, t;
28920c794b3Sgavinm 	int spd_sz;
29020c794b3Sgavinm 
29120c794b3Sgavinm 	t = read_spd_eeprom(channel, dimm, 0) & 0xf;
29220c794b3Sgavinm 	if (t == 1)
29320c794b3Sgavinm 		spd_sz = 128;
29420c794b3Sgavinm 	else if (t == 2)
29520c794b3Sgavinm 		spd_sz = 176;
29620c794b3Sgavinm 	else
29720c794b3Sgavinm 		spd_sz = 256;
29820c794b3Sgavinm 	dp->manufacture_id = read_spd_eeprom(channel, dimm, 117) |
29920c794b3Sgavinm 	    (read_spd_eeprom(channel, dimm, 118) << 8);
30020c794b3Sgavinm 	dp->manufacture_location = read_spd_eeprom(channel, dimm, 119);
30120c794b3Sgavinm 	dp->serial_number =
30220c794b3Sgavinm 	    (read_spd_eeprom(channel, dimm, 122) << 24) |
30320c794b3Sgavinm 	    (read_spd_eeprom(channel, dimm, 123) << 16) |
30420c794b3Sgavinm 	    (read_spd_eeprom(channel, dimm, 124) << 8) |
30520c794b3Sgavinm 	    read_spd_eeprom(channel, dimm, 125);
30620c794b3Sgavinm 	t = read_spd_eeprom(channel, dimm, 121);
30720c794b3Sgavinm 	dp->manufacture_week = (t >> 4) * 10 + (t & 0xf);
30820c794b3Sgavinm 	dp->manufacture_year = read_spd_eeprom(channel, dimm, 120);
30920c794b3Sgavinm 	if (spd_sz > 128) {
31020c794b3Sgavinm 		for (i = 0; i < sizeof (dp->part_number); i++) {
31120c794b3Sgavinm 			dp->part_number[i] =
31220c794b3Sgavinm 			    read_spd_eeprom(channel, dimm, 128 + i);
31320c794b3Sgavinm 		}
31420c794b3Sgavinm 		for (i = 0; i < sizeof (dp->revision); i++) {
31520c794b3Sgavinm 			dp->revision[i] =
31620c794b3Sgavinm 			    read_spd_eeprom(channel, dimm, 146 + i);
31720c794b3Sgavinm 		}
31820c794b3Sgavinm 	}
31985738508SVuong Nguyen }
32085738508SVuong Nguyen 
32185738508SVuong Nguyen /* read the manR of the DDR2 dimm */
32285738508SVuong Nguyen static void
32385738508SVuong Nguyen ddr2_eeprom(int channel, int dimm, nb_dimm_t *dp)
32485738508SVuong Nguyen {
32585738508SVuong Nguyen 	int i, t;
32685738508SVuong Nguyen 	int slave;
32785738508SVuong Nguyen 
32885738508SVuong Nguyen 	slave = channel & 0x1 ? dimm + 4 : dimm;
32985738508SVuong Nguyen 
33085738508SVuong Nguyen 	/* byte[3]: number of row addresses */
33185738508SVuong Nguyen 	dp->nrow = read_spd_eeprom(channel, slave, 3) & 0x1f;
33285738508SVuong Nguyen 
33385738508SVuong Nguyen 	/* byte[4]: number of column addresses */
33485738508SVuong Nguyen 	dp->ncolumn = read_spd_eeprom(channel, slave, 4) & 0xf;
33585738508SVuong Nguyen 
33685738508SVuong Nguyen 	/* byte[5]: numranks; 0 means one rank */
33785738508SVuong Nguyen 	dp->nranks = (read_spd_eeprom(channel, slave, 5) & 0x3) + 1;
33885738508SVuong Nguyen 
33985738508SVuong Nguyen 	/* byte[6]: data width */
34085738508SVuong Nguyen 	dp->width = (read_spd_eeprom(channel, slave, 6) >> 5) << 2;
34185738508SVuong Nguyen 
34285738508SVuong Nguyen 	/* byte[17]: number of banks */
34385738508SVuong Nguyen 	dp->nbanks = read_spd_eeprom(channel, slave, 17);
34485738508SVuong Nguyen 
34585738508SVuong Nguyen 	dp->dimm_size = DIMMSIZE(dp->nrow, dp->ncolumn, dp->nranks, dp->nbanks,
34685738508SVuong Nguyen 	    dp->width);
34785738508SVuong Nguyen 
34885738508SVuong Nguyen 	/* manufacture-id - byte[64-65] */
34985738508SVuong Nguyen 	dp->manufacture_id = read_spd_eeprom(channel, slave, 64) |
35085738508SVuong Nguyen 	    (read_spd_eeprom(channel, dimm, 65) << 8);
35185738508SVuong Nguyen 
35285738508SVuong Nguyen 	/* location - byte[72] */
35385738508SVuong Nguyen 	dp->manufacture_location = read_spd_eeprom(channel, slave, 72);
35485738508SVuong Nguyen 
35585738508SVuong Nguyen 	/* serial number - byte[95-98] */
35685738508SVuong Nguyen 	dp->serial_number =
35785738508SVuong Nguyen 	    (read_spd_eeprom(channel, slave, 98) << 24) |
35885738508SVuong Nguyen 	    (read_spd_eeprom(channel, slave, 97) << 16) |
35985738508SVuong Nguyen 	    (read_spd_eeprom(channel, slave, 96) << 8) |
36085738508SVuong Nguyen 	    read_spd_eeprom(channel, slave, 95);
36185738508SVuong Nguyen 
36285738508SVuong Nguyen 	/* week - byte[94] */
36385738508SVuong Nguyen 	t = read_spd_eeprom(channel, slave, 94);
36485738508SVuong Nguyen 	dp->manufacture_week = (t >> 4) * 10 + (t & 0xf);
36585738508SVuong Nguyen 	/* week - byte[93] */
36685738508SVuong Nguyen 	t = read_spd_eeprom(channel, slave, 93);
36785738508SVuong Nguyen 	dp->manufacture_year = (t >> 4) * 10 + (t & 0xf) + 2000;
36885738508SVuong Nguyen 
36985738508SVuong Nguyen 	/* part number - byte[73-81] */
37085738508SVuong Nguyen 	for (i = 0; i < 8; i++) {
37185738508SVuong Nguyen 		dp->part_number[i] = read_spd_eeprom(channel, slave, 73 + i);
37285738508SVuong Nguyen 	}
37385738508SVuong Nguyen 
37485738508SVuong Nguyen 	/* revision - byte[91-92] */
37585738508SVuong Nguyen 	for (i = 0; i < 2; i++) {
37685738508SVuong Nguyen 		dp->revision[i] = read_spd_eeprom(channel, slave, 91 + i);
37785738508SVuong Nguyen 	}
37885738508SVuong Nguyen }
37985738508SVuong Nguyen 
38085738508SVuong Nguyen static boolean_t
38185738508SVuong Nguyen nb_dimm_present(int channel, int dimm)
38285738508SVuong Nguyen {
38385738508SVuong Nguyen 	boolean_t rc = B_FALSE;
38485738508SVuong Nguyen 
38585738508SVuong Nguyen 	if (nb_chipset == INTEL_NB_5100) {
38685738508SVuong Nguyen 		int t, slave;
38785738508SVuong Nguyen 		slave = channel & 0x1 ? dimm + 4 : dimm;
38885738508SVuong Nguyen 		/* read the type field from the dimm and check for DDR2 type */
38985738508SVuong Nguyen 		if ((t = read_spd_eeprom(channel, slave, SPD_MEM_TYPE)) == -1)
39085738508SVuong Nguyen 			return (B_FALSE);
39185738508SVuong Nguyen 		rc = (t & 0xf) == SPD_DDR2;
39285738508SVuong Nguyen 	} else {
39385738508SVuong Nguyen 		rc = MTR_PRESENT(MTR_RD(channel, dimm)) != 0;
39485738508SVuong Nguyen 	}
39585738508SVuong Nguyen 
39685738508SVuong Nguyen 	return (rc);
39785738508SVuong Nguyen }
39885738508SVuong Nguyen 
39985738508SVuong Nguyen static nb_dimm_t *
40085738508SVuong Nguyen nb_ddr2_dimm_init(int channel, int dimm, int start_rank)
40185738508SVuong Nguyen {
40285738508SVuong Nguyen 	nb_dimm_t *dp;
40385738508SVuong Nguyen 
40485738508SVuong Nguyen 	if (nb_dimm_present(channel, dimm) == B_FALSE)
40585738508SVuong Nguyen 		return (NULL);
40685738508SVuong Nguyen 
40785738508SVuong Nguyen 	dp = kmem_zalloc(sizeof (nb_dimm_t), KM_SLEEP);
40885738508SVuong Nguyen 
40985738508SVuong Nguyen 	ddr2_eeprom(channel, dimm, dp);
41085738508SVuong Nguyen 
41185738508SVuong Nguyen 	/* The 1st rank of the dimm takes on this value */
41285738508SVuong Nguyen 	dp->start_rank = (uint8_t)start_rank;
41385738508SVuong Nguyen 
41485738508SVuong Nguyen 	dp->mtr_present = 1;
41585738508SVuong Nguyen 
41685738508SVuong Nguyen 	return (dp);
41785738508SVuong Nguyen }
41885738508SVuong Nguyen 
41985738508SVuong Nguyen static nb_dimm_t *
42085738508SVuong Nguyen nb_fbd_dimm_init(int channel, int dimm, uint16_t mtr)
42185738508SVuong Nguyen {
42285738508SVuong Nguyen 	nb_dimm_t *dp;
42385738508SVuong Nguyen 	int t;
42485738508SVuong Nguyen 
42585738508SVuong Nguyen 	if (MTR_PRESENT(mtr) == 0)
42685738508SVuong Nguyen 		return (NULL);
42785738508SVuong Nguyen 	t = read_spd_eeprom(channel, dimm, SPD_MEM_TYPE) & 0xf;
42885738508SVuong Nguyen 
42985738508SVuong Nguyen 	/* check for the dimm type */
43085738508SVuong Nguyen 	if (t != SPD_FBDIMM)
43185738508SVuong Nguyen 		return (NULL);
43285738508SVuong Nguyen 
43385738508SVuong Nguyen 	dp = kmem_zalloc(sizeof (nb_dimm_t), KM_SLEEP);
43485738508SVuong Nguyen 
43585738508SVuong Nguyen 	fbd_eeprom(channel, dimm, dp);
43685738508SVuong Nguyen 
4375de8e333Saf 	dp->mtr_present = MTR_PRESENT(mtr);
43885738508SVuong Nguyen 	dp->start_rank = dimm << 1;
43920c794b3Sgavinm 	dp->nranks = MTR_NUMRANK(mtr);
44020c794b3Sgavinm 	dp->nbanks = MTR_NUMBANK(mtr);
44120c794b3Sgavinm 	dp->ncolumn = MTR_NUMCOL(mtr);
44220c794b3Sgavinm 	dp->nrow = MTR_NUMROW(mtr);
44320c794b3Sgavinm 	dp->width = MTR_WIDTH(mtr);
44420c794b3Sgavinm 	dp->dimm_size = MTR_DIMMSIZE(mtr);
44520c794b3Sgavinm 
44620c794b3Sgavinm 	return (dp);
44720c794b3Sgavinm }
44820c794b3Sgavinm 
44920c794b3Sgavinm static uint64_t
45020c794b3Sgavinm mc_range(int controller, uint64_t base)
45120c794b3Sgavinm {
45220c794b3Sgavinm 	int i;
45320c794b3Sgavinm 	uint64_t limit = 0;
45420c794b3Sgavinm 
45520c794b3Sgavinm 	for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) {
45620c794b3Sgavinm 		if (nb_banks[i].way[controller] && base >= nb_banks[i].base &&
45720c794b3Sgavinm 		    base < nb_banks[i].limit) {
45820c794b3Sgavinm 			limit = nb_banks[i].limit;
45920c794b3Sgavinm 			if (base <= top_of_low_memory &&
46020c794b3Sgavinm 			    limit > top_of_low_memory) {
46120c794b3Sgavinm 				limit -= TLOW_MAX - top_of_low_memory;
46220c794b3Sgavinm 			}
46320c794b3Sgavinm 			if (nb_banks[i].way[0] && nb_banks[i].way[1] &&
46420c794b3Sgavinm 			    nb_mode != NB_MEMORY_MIRROR) {
46520c794b3Sgavinm 				limit = limit / 2;
46620c794b3Sgavinm 			}
46720c794b3Sgavinm 		}
46820c794b3Sgavinm 	}
46920c794b3Sgavinm 	return (limit);
47020c794b3Sgavinm }
47120c794b3Sgavinm 
47220c794b3Sgavinm void
47320c794b3Sgavinm nb_mc_init()
47420c794b3Sgavinm {
47520c794b3Sgavinm 	uint16_t tolm;
47620c794b3Sgavinm 	uint16_t mir;
47720c794b3Sgavinm 	uint32_t hole_base;
47820c794b3Sgavinm 	uint32_t hole_size;
47920c794b3Sgavinm 	uint32_t dmir;
48020c794b3Sgavinm 	uint64_t base;
48120c794b3Sgavinm 	uint64_t limit;
48220c794b3Sgavinm 	uint8_t way0, way1, rank0, rank1, rank2, rank3, branch_interleave;
48320c794b3Sgavinm 	int i, j, k;
48420c794b3Sgavinm 	uint8_t interleave;
48520c794b3Sgavinm 
48620c794b3Sgavinm 	base = 0;
48720c794b3Sgavinm 	tolm = TOLM_RD();
48820c794b3Sgavinm 	top_of_low_memory = ((uint32_t)(tolm >> 12) & 0xf) << 28;
48920c794b3Sgavinm 	for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) {
49020c794b3Sgavinm 		mir = MIR_RD(i);
49120c794b3Sgavinm 		limit = (uint64_t)(mir >> 4) << 28;
49220c794b3Sgavinm 		way0 = mir & 1;
49320c794b3Sgavinm 		way1 = (mir >> 1) & 1;
49420c794b3Sgavinm 		if (way0 == 0 && way1 == 0) {
49520c794b3Sgavinm 			way0 = 1;
49620c794b3Sgavinm 			way1 = 1;
49720c794b3Sgavinm 		}
49820c794b3Sgavinm 		if (limit > top_of_low_memory)
49920c794b3Sgavinm 			limit += TLOW_MAX - top_of_low_memory;
50020c794b3Sgavinm 		nb_banks[i].base = base;
50120c794b3Sgavinm 		nb_banks[i].limit = limit;
50220c794b3Sgavinm 		nb_banks[i].way[0] = way0;
50320c794b3Sgavinm 		nb_banks[i].way[1] = way1;
50420c794b3Sgavinm 		base = limit;
50520c794b3Sgavinm 	}
50620c794b3Sgavinm 	for (i = 0; i < nb_number_memory_controllers; i++) {
50720c794b3Sgavinm 		base = 0;
50820c794b3Sgavinm 
50920c794b3Sgavinm 		for (j = 0; j < NB_MEM_RANK_SELECT; j++) {
51020c794b3Sgavinm 			dmir = DMIR_RD(i, j);
51120c794b3Sgavinm 			limit = ((uint64_t)(dmir >> 16) & 0xff) << 28;
51220c794b3Sgavinm 			if (limit == 0) {
51320c794b3Sgavinm 				limit = mc_range(i, base);
51420c794b3Sgavinm 			}
51520c794b3Sgavinm 			branch_interleave = 0;
51620c794b3Sgavinm 			hole_base = 0;
51720c794b3Sgavinm 			hole_size = 0;
5189d6aa643Saf 			DMIR_RANKS(dmir, rank0, rank1, rank2, rank3);
51920c794b3Sgavinm 			if (rank0 == rank1)
52020c794b3Sgavinm 				interleave = 1;
52120c794b3Sgavinm 			else if (rank0 == rank2)
52220c794b3Sgavinm 				interleave = 2;
52320c794b3Sgavinm 			else
52420c794b3Sgavinm 				interleave = 4;
52520c794b3Sgavinm 			if (nb_mode != NB_MEMORY_MIRROR &&
52620c794b3Sgavinm 			    nb_mode != NB_MEMORY_SINGLE_CHANNEL) {
52720c794b3Sgavinm 				for (k = 0; k < NB_MEM_BRANCH_SELECT; k++) {
52820c794b3Sgavinm 					if (base >= nb_banks[k].base &&
52920c794b3Sgavinm 					    base < nb_banks[k].limit) {
53020c794b3Sgavinm 						if (nb_banks[i].way[0] &&
53120c794b3Sgavinm 						    nb_banks[i].way[1]) {
53220c794b3Sgavinm 							interleave *= 2;
53320c794b3Sgavinm 							limit *= 2;
53420c794b3Sgavinm 							branch_interleave = 1;
53520c794b3Sgavinm 						}
53620c794b3Sgavinm 						break;
53720c794b3Sgavinm 					}
53820c794b3Sgavinm 				}
53920c794b3Sgavinm 			}
54020c794b3Sgavinm 			if (base < top_of_low_memory &&
54120c794b3Sgavinm 			    limit > top_of_low_memory) {
54220c794b3Sgavinm 				hole_base = top_of_low_memory;
54320c794b3Sgavinm 				hole_size = TLOW_MAX - top_of_low_memory;
54420c794b3Sgavinm 				limit += hole_size;
54520c794b3Sgavinm 			} else if (base > top_of_low_memory) {
54620c794b3Sgavinm 				limit += TLOW_MAX - top_of_low_memory;
54720c794b3Sgavinm 			}
54820c794b3Sgavinm 			nb_ranks[i][j].base = base;
54920c794b3Sgavinm 			nb_ranks[i][j].limit = limit;
55020c794b3Sgavinm 			nb_ranks[i][j].rank[0] = rank0;
55120c794b3Sgavinm 			nb_ranks[i][j].rank[1] = rank1;
55220c794b3Sgavinm 			nb_ranks[i][j].rank[2] = rank2;
55320c794b3Sgavinm 			nb_ranks[i][j].rank[3] = rank3;
55420c794b3Sgavinm 			nb_ranks[i][j].interleave = interleave;
55520c794b3Sgavinm 			nb_ranks[i][j].branch_interleave = branch_interleave;
55620c794b3Sgavinm 			nb_ranks[i][j].hole_base = hole_base;
55720c794b3Sgavinm 			nb_ranks[i][j].hole_size = hole_size;
55820c794b3Sgavinm 			if (limit > base) {
55920c794b3Sgavinm 				if (rank0 != rank1) {
56020c794b3Sgavinm 					dimm_add_rank(i, rank1,
56120c794b3Sgavinm 					    branch_interleave, 1, base,
56220c794b3Sgavinm 					    hole_base, hole_size, interleave,
56320c794b3Sgavinm 					    limit);
56420c794b3Sgavinm 					if (rank0 != rank2) {
56520c794b3Sgavinm 						dimm_add_rank(i, rank2,
56620c794b3Sgavinm 						    branch_interleave, 2, base,
56720c794b3Sgavinm 						    hole_base, hole_size,
56820c794b3Sgavinm 						    interleave, limit);
56920c794b3Sgavinm 						dimm_add_rank(i, rank3,
57020c794b3Sgavinm 						    branch_interleave, 3, base,
57120c794b3Sgavinm 						    hole_base, hole_size,
57220c794b3Sgavinm 						    interleave, limit);
57320c794b3Sgavinm 					}
57420c794b3Sgavinm 				}
57520c794b3Sgavinm 			}
57620c794b3Sgavinm 			base = limit;
57720c794b3Sgavinm 		}
57820c794b3Sgavinm 	}
57920c794b3Sgavinm }
58020c794b3Sgavinm 
58120c794b3Sgavinm void
58220c794b3Sgavinm nb_used_spare_rank(int branch, int bad_rank)
58320c794b3Sgavinm {
58420c794b3Sgavinm 	int i;
58520c794b3Sgavinm 	int j;
58620c794b3Sgavinm 
58720c794b3Sgavinm 	for (i = 0; i < NB_MEM_RANK_SELECT; i++) {
58820c794b3Sgavinm 		for (j = 0; j < NB_RANKS_IN_SELECT; j++) {
58920c794b3Sgavinm 			if (nb_ranks[branch][i].rank[j] == bad_rank) {
59020c794b3Sgavinm 				nb_ranks[branch][i].rank[j] =
59120c794b3Sgavinm 				    spare_rank[branch];
59220c794b3Sgavinm 				i = NB_MEM_RANK_SELECT;
59320c794b3Sgavinm 				break;
59420c794b3Sgavinm 			}
59520c794b3Sgavinm 		}
59620c794b3Sgavinm 	}
59720c794b3Sgavinm }
59820c794b3Sgavinm 
5999d6aa643Saf find_dimm_label_t *
60020c794b3Sgavinm find_dimms_per_channel()
60120c794b3Sgavinm {
6029d6aa643Saf 	struct platform_label *pl;
6039d6aa643Saf 	smbios_info_t si;
6049d6aa643Saf 	smbios_system_t sy;
6059d6aa643Saf 	id_t id;
60630cfc677SAdrian Frost 	int i, j;
6079d6aa643Saf 	find_dimm_label_t *rt = NULL;
6089d6aa643Saf 
60930cfc677SAdrian Frost 	if (ksmbios != NULL && nb_no_smbios == 0) {
6109d6aa643Saf 		if ((id = smbios_info_system(ksmbios, &sy)) != SMB_ERR &&
6119d6aa643Saf 		    smbios_info_common(ksmbios, id, &si) != SMB_ERR) {
6129d6aa643Saf 			for (pl = platform_label; pl->sys_vendor; pl++) {
6139d6aa643Saf 				if (strncmp(pl->sys_vendor,
6149d6aa643Saf 				    si.smbi_manufacturer,
6159d6aa643Saf 				    strlen(pl->sys_vendor)) == 0 &&
6169d6aa643Saf 				    strncmp(pl->sys_product, si.smbi_product,
6179d6aa643Saf 				    strlen(pl->sys_product)) == 0) {
6189d6aa643Saf 					nb_dimms_per_channel =
6199d6aa643Saf 					    pl->dimms_per_channel;
6209d6aa643Saf 					rt = &pl->dimm_label;
6219d6aa643Saf 					break;
6229d6aa643Saf 				}
6239d6aa643Saf 			}
6249d6aa643Saf 		}
6259d6aa643Saf 	}
6269d6aa643Saf 	if (nb_dimms_per_channel == 0) {
62730cfc677SAdrian Frost 		/*
62830cfc677SAdrian Frost 		 * Scan all memory channels if we find a channel which has more
62930cfc677SAdrian Frost 		 * dimms then we have seen before set nb_dimms_per_channel to
63030cfc677SAdrian Frost 		 * the number of dimms on the channel
63130cfc677SAdrian Frost 		 */
63230cfc677SAdrian Frost 		for (i = 0; i < nb_number_memory_controllers; i++) {
63330cfc677SAdrian Frost 			for (j = nb_dimms_per_channel;
63430cfc677SAdrian Frost 			    j < NB_MAX_DIMMS_PER_CHANNEL; j++) {
63585738508SVuong Nguyen 				if (nb_dimm_present(i, j))
63630cfc677SAdrian Frost 					nb_dimms_per_channel = j + 1;
63730cfc677SAdrian Frost 			}
63820c794b3Sgavinm 		}
63920c794b3Sgavinm 	}
6409d6aa643Saf 	return (rt);
64120c794b3Sgavinm }
64220c794b3Sgavinm 
6439ff4cbe7SAdrian Frost struct smb_dimm_rec {
6449ff4cbe7SAdrian Frost 	int dimms;
6459ff4cbe7SAdrian Frost 	int slots;
6469ff4cbe7SAdrian Frost 	int populated;
6479ff4cbe7SAdrian Frost 	nb_dimm_t **dimmpp;
6489ff4cbe7SAdrian Frost };
6499ff4cbe7SAdrian Frost 
65020c794b3Sgavinm static int
65120c794b3Sgavinm dimm_label(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
65220c794b3Sgavinm {
6539ff4cbe7SAdrian Frost 	struct smb_dimm_rec *rp = (struct smb_dimm_rec *)arg;
6549ff4cbe7SAdrian Frost 	nb_dimm_t ***dimmpp;
65520c794b3Sgavinm 	nb_dimm_t *dimmp;
65620c794b3Sgavinm 	smbios_memdevice_t md;
65720c794b3Sgavinm 
6589ff4cbe7SAdrian Frost 	dimmpp = &rp->dimmpp;
65920c794b3Sgavinm 	if (sp->smbstr_type == SMB_TYPE_MEMDEVICE) {
66030cfc677SAdrian Frost 		if (*dimmpp >= &nb_dimms[nb_dimm_slots])
66130cfc677SAdrian Frost 			return (-1);
66220c794b3Sgavinm 		dimmp = **dimmpp;
66330cfc677SAdrian Frost 		if (smbios_info_memdevice(shp, sp->smbstr_id, &md) == 0 &&
66430cfc677SAdrian Frost 		    md.smbmd_dloc != NULL) {
66530cfc677SAdrian Frost 			if (md.smbmd_size) {
6669ff4cbe7SAdrian Frost 				if (dimmp == NULL &&
6679ff4cbe7SAdrian Frost 				    (rp->slots == nb_dimm_slots ||
6689ff4cbe7SAdrian Frost 				    rp->dimms < rp->populated)) {
6699ff4cbe7SAdrian Frost 					(*dimmpp)++;
6709ff4cbe7SAdrian Frost 					return (0);
6719ff4cbe7SAdrian Frost 				}
67230cfc677SAdrian Frost 				/*
67330cfc677SAdrian Frost 				 * if there is no physical dimm for this smbios
67430cfc677SAdrian Frost 				 * record it is because this system has less
67530cfc677SAdrian Frost 				 * physical slots than the controller supports
67630cfc677SAdrian Frost 				 * so skip empty slots to find the slot this
67730cfc677SAdrian Frost 				 * smbios record belongs too
67830cfc677SAdrian Frost 				 */
67930cfc677SAdrian Frost 				while (dimmp == NULL) {
6809ff4cbe7SAdrian Frost 					(*dimmpp)++;
68130cfc677SAdrian Frost 					if (*dimmpp >= &nb_dimms[nb_dimm_slots])
68230cfc677SAdrian Frost 						return (-1);
6839ff4cbe7SAdrian Frost 					dimmp = **dimmpp;
68430cfc677SAdrian Frost 				}
68530cfc677SAdrian Frost 				(void) snprintf(dimmp->label,
68630cfc677SAdrian Frost 				    sizeof (dimmp->label), "%s", md.smbmd_dloc);
68730cfc677SAdrian Frost 				(*dimmpp)++;
68830cfc677SAdrian Frost 			}
68920c794b3Sgavinm 		}
69020c794b3Sgavinm 	}
69120c794b3Sgavinm 	return (0);
69220c794b3Sgavinm }
69320c794b3Sgavinm 
6949ff4cbe7SAdrian Frost static int
6959ff4cbe7SAdrian Frost check_memdevice(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg)
6969ff4cbe7SAdrian Frost {
6979ff4cbe7SAdrian Frost 	struct smb_dimm_rec *rp = (struct smb_dimm_rec *)arg;
6989ff4cbe7SAdrian Frost 	smbios_memdevice_t md;
6999ff4cbe7SAdrian Frost 
7009ff4cbe7SAdrian Frost 	if (sp->smbstr_type == SMB_TYPE_MEMDEVICE) {
7019ff4cbe7SAdrian Frost 		if (smbios_info_memdevice(shp, sp->smbstr_id, &md) == 0) {
7029ff4cbe7SAdrian Frost 			rp->slots++;
7039ff4cbe7SAdrian Frost 			if (md.smbmd_size) {
7049ff4cbe7SAdrian Frost 				rp->populated++;
7059ff4cbe7SAdrian Frost 			}
7069ff4cbe7SAdrian Frost 		}
7079ff4cbe7SAdrian Frost 	}
7089ff4cbe7SAdrian Frost 	return (0);
7099ff4cbe7SAdrian Frost }
7109ff4cbe7SAdrian Frost 
71120c794b3Sgavinm void
71220c794b3Sgavinm nb_smbios()
71320c794b3Sgavinm {
7149ff4cbe7SAdrian Frost 	struct smb_dimm_rec r;
7159ff4cbe7SAdrian Frost 	int i;
71620c794b3Sgavinm 
71730cfc677SAdrian Frost 	if (ksmbios != NULL && nb_no_smbios == 0) {
7189ff4cbe7SAdrian Frost 		r.dimms = 0;
7199ff4cbe7SAdrian Frost 		r.slots = 0;
7209ff4cbe7SAdrian Frost 		r.populated = 0;
7219ff4cbe7SAdrian Frost 		r.dimmpp = nb_dimms;
7229ff4cbe7SAdrian Frost 		for (i = 0; i < nb_dimm_slots; i++) {
7239ff4cbe7SAdrian Frost 			if (nb_dimms[i] != NULL)
7249ff4cbe7SAdrian Frost 				r.dimms++;
7259ff4cbe7SAdrian Frost 		}
7269ff4cbe7SAdrian Frost 		(void) smbios_iter(ksmbios, check_memdevice, &r);
7279ff4cbe7SAdrian Frost 		(void) smbios_iter(ksmbios, dimm_label, &r);
72820c794b3Sgavinm 	}
72920c794b3Sgavinm }
73020c794b3Sgavinm 
73120c794b3Sgavinm static void
7329d6aa643Saf x8450_dimm_label(int dimm, char *label, int label_sz)
73320c794b3Sgavinm {
7349d6aa643Saf 	int channel = dimm >> 3;
7359d6aa643Saf 
7369d6aa643Saf 	dimm = dimm & 0x7;
7379d6aa643Saf 	(void) snprintf(label, label_sz, "D%d", (dimm * 4) + channel);
7389d6aa643Saf }
7399d6aa643Saf 
74085738508SVuong Nguyen /*
74185738508SVuong Nguyen  * CP3250 DIMM labels
74285738508SVuong Nguyen  * Channel   Dimm   Label
74385738508SVuong Nguyen  *       0      0      A0
74485738508SVuong Nguyen  *       1      0      B0
74585738508SVuong Nguyen  *       0      1      A1
74685738508SVuong Nguyen  *       1      1      B1
74785738508SVuong Nguyen  *       0      2      A2
74885738508SVuong Nguyen  *       1      2      B2
74985738508SVuong Nguyen  */
7509d6aa643Saf static void
75185738508SVuong Nguyen cp3250_dimm_label(int dimm, char *label, int label_sz)
75285738508SVuong Nguyen {
75385738508SVuong Nguyen 	int channel = dimm / nb_dimms_per_channel;
75485738508SVuong Nguyen 
75585738508SVuong Nguyen 	dimm = dimm % nb_dimms_per_channel;
75685738508SVuong Nguyen 	(void) snprintf(label, label_sz, "%c%d", channel == 0 ? 'A' : 'B',
75785738508SVuong Nguyen 	    dimm);
75885738508SVuong Nguyen }
75985738508SVuong Nguyen 
76085738508SVuong Nguyen /*
76185738508SVuong Nguyen  * Map the rank id to dimm id of a channel
76285738508SVuong Nguyen  * For the 5100 chipset, walk through the dimm list of channel the check if
76385738508SVuong Nguyen  * the given rank id is within the rank range assigned to the dimm.
76485738508SVuong Nguyen  * For other chipsets, the dimm is rank/2.
76585738508SVuong Nguyen  */
76685738508SVuong Nguyen int
76785738508SVuong Nguyen nb_rank2dimm(int channel, int rank)
76885738508SVuong Nguyen {
76985738508SVuong Nguyen 	int i;
77085738508SVuong Nguyen 	nb_dimm_t **dimmpp = nb_dimms;
77185738508SVuong Nguyen 
77285738508SVuong Nguyen 	if (nb_chipset != INTEL_NB_5100)
77385738508SVuong Nguyen 		return (rank >> 1);
77485738508SVuong Nguyen 
77585738508SVuong Nguyen 	dimmpp += channel * nb_dimms_per_channel;
77685738508SVuong Nguyen 	for (i = 0; i < nb_dimms_per_channel; i++) {
77785738508SVuong Nguyen 		if ((rank >= dimmpp[i]->start_rank) &&
77885738508SVuong Nguyen 		    (rank < dimmpp[i]->start_rank + dimmpp[i]->nranks)) {
77985738508SVuong Nguyen 			return (i);
78085738508SVuong Nguyen 		}
78185738508SVuong Nguyen 	}
78285738508SVuong Nguyen 	return (-1);
78385738508SVuong Nguyen }
78485738508SVuong Nguyen 
78585738508SVuong Nguyen static void
78685738508SVuong Nguyen nb_ddr2_dimms_init(find_dimm_label_t *label_function)
78785738508SVuong Nguyen {
78885738508SVuong Nguyen 	int i, j;
78985738508SVuong Nguyen 	int start_rank;
79085738508SVuong Nguyen 	uint32_t spcpc;
79185738508SVuong Nguyen 	uint8_t spcps;
79285738508SVuong Nguyen 	nb_dimm_t **dimmpp;
79385738508SVuong Nguyen 
79485738508SVuong Nguyen 	nb_dimm_slots = nb_number_memory_controllers * nb_channels_per_branch *
79585738508SVuong Nguyen 	    nb_dimms_per_channel;
79685738508SVuong Nguyen 	nb_dimms = (nb_dimm_t **)kmem_zalloc(sizeof (nb_dimm_t *) *
79785738508SVuong Nguyen 	    nb_dimm_slots, KM_SLEEP);
79885738508SVuong Nguyen 	dimmpp = nb_dimms;
79985738508SVuong Nguyen 	nb_mode = NB_MEMORY_NORMAL;
80085738508SVuong Nguyen 	for (i = 0; i < nb_number_memory_controllers; i++) {
80185738508SVuong Nguyen 		if (nb_mode == NB_MEMORY_NORMAL) {
80285738508SVuong Nguyen 			spcpc = SPCPC_RD(i);
80385738508SVuong Nguyen 			spcps = SPCPS_RD(i);
80485738508SVuong Nguyen 			if ((spcpc & SPCPC_SPARE_ENABLE) != 0 &&
80585738508SVuong Nguyen 			    (spcps & SPCPS_SPARE_DEPLOYED) != 0)
80685738508SVuong Nguyen 				nb_mode = NB_MEMORY_SPARE_RANK;
80785738508SVuong Nguyen 			spare_rank[i] = SPCPC_SPRANK(spcpc);
80885738508SVuong Nguyen 		}
80985738508SVuong Nguyen 
81085738508SVuong Nguyen 		/* The 1st dimm of a channel starts at rank 0 */
81185738508SVuong Nguyen 		start_rank = 0;
81285738508SVuong Nguyen 
81385738508SVuong Nguyen 		for (j = 0; j < nb_dimms_per_channel; j++) {
81485738508SVuong Nguyen 			dimmpp[j] = nb_ddr2_dimm_init(i, j, start_rank);
81585738508SVuong Nguyen 			if (dimmpp[j]) {
81685738508SVuong Nguyen 				nb_ndimm ++;
81785738508SVuong Nguyen 				if (label_function) {
81885738508SVuong Nguyen 					label_function->label_function(
81985738508SVuong Nguyen 					    (i * nb_dimms_per_channel) + j,
82085738508SVuong Nguyen 					    dimmpp[j]->label,
82185738508SVuong Nguyen 					    sizeof (dimmpp[j]->label));
82285738508SVuong Nguyen 				}
82385738508SVuong Nguyen 				start_rank += dimmpp[j]->nranks;
82485738508SVuong Nguyen 				/*
82585738508SVuong Nguyen 				 * add an extra rank because
82685738508SVuong Nguyen 				 * single-ranked dimm still takes on two ranks.
82785738508SVuong Nguyen 				 */
82885738508SVuong Nguyen 				if (dimmpp[j]->nranks & 0x1)
82985738508SVuong Nguyen 					start_rank++;
83085738508SVuong Nguyen 				}
83185738508SVuong Nguyen 		}
83285738508SVuong Nguyen 		dimmpp += nb_dimms_per_channel;
83385738508SVuong Nguyen 	}
83485738508SVuong Nguyen 
83585738508SVuong Nguyen 	/*
83685738508SVuong Nguyen 	 * single channel is supported.
83785738508SVuong Nguyen 	 */
83885738508SVuong Nguyen 	if (nb_ndimm > 0 && nb_ndimm <= nb_dimms_per_channel) {
83985738508SVuong Nguyen 		nb_mode = NB_MEMORY_SINGLE_CHANNEL;
84085738508SVuong Nguyen 	}
84185738508SVuong Nguyen }
84285738508SVuong Nguyen 
84385738508SVuong Nguyen static void
84485738508SVuong Nguyen nb_fbd_dimms_init(find_dimm_label_t *label_function)
8459d6aa643Saf {
8469d6aa643Saf 	int i, j, k, l;
84720c794b3Sgavinm 	uint16_t mtr;
84820c794b3Sgavinm 	uint32_t mc, mca;
84920c794b3Sgavinm 	uint32_t spcpc;
85020c794b3Sgavinm 	uint8_t spcps;
85120c794b3Sgavinm 	nb_dimm_t **dimmpp;
85220c794b3Sgavinm 
85320c794b3Sgavinm 	mca = MCA_RD();
85420c794b3Sgavinm 	mc = MC_RD();
85520c794b3Sgavinm 	if (mca & MCA_SCHDIMM)  /* single-channel mode */
85620c794b3Sgavinm 		nb_mode = NB_MEMORY_SINGLE_CHANNEL;
85720c794b3Sgavinm 	else if ((mc & MC_MIRROR) != 0) /* mirror mode */
85820c794b3Sgavinm 		nb_mode = NB_MEMORY_MIRROR;
85920c794b3Sgavinm 	else
86020c794b3Sgavinm 		nb_mode = NB_MEMORY_NORMAL;
86130cfc677SAdrian Frost 	nb_dimm_slots = nb_number_memory_controllers * 2 * nb_dimms_per_channel;
86220c794b3Sgavinm 	nb_dimms = (nb_dimm_t **)kmem_zalloc(sizeof (nb_dimm_t *) *
86330cfc677SAdrian Frost 	    nb_dimm_slots, KM_SLEEP);
86420c794b3Sgavinm 	dimmpp = nb_dimms;
86520c794b3Sgavinm 	for (i = 0; i < nb_number_memory_controllers; i++) {
86620c794b3Sgavinm 		if (nb_mode == NB_MEMORY_NORMAL) {
86720c794b3Sgavinm 			spcpc = SPCPC_RD(i);
86820c794b3Sgavinm 			spcps = SPCPS_RD(i);
86920c794b3Sgavinm 			if ((spcpc & SPCPC_SPARE_ENABLE) != 0 &&
87020c794b3Sgavinm 			    (spcps & SPCPS_SPARE_DEPLOYED) != 0)
87120c794b3Sgavinm 				nb_mode = NB_MEMORY_SPARE_RANK;
87220c794b3Sgavinm 			spare_rank[i] = SPCPC_SPRANK(spcpc);
87320c794b3Sgavinm 		}
87420c794b3Sgavinm 		for (j = 0; j < nb_dimms_per_channel; j++) {
87520c794b3Sgavinm 			mtr = MTR_RD(i, j);
87620c794b3Sgavinm 			k = i * 2;
87785738508SVuong Nguyen 			dimmpp[j] = nb_fbd_dimm_init(k, j, mtr);
87820c794b3Sgavinm 			if (dimmpp[j]) {
87920c794b3Sgavinm 				nb_ndimm ++;
8809d6aa643Saf 				if (label_function) {
8819d6aa643Saf 					label_function->label_function(
8829d6aa643Saf 					    (k * nb_dimms_per_channel) + j,
8839d6aa643Saf 					    dimmpp[j]->label,
8849d6aa643Saf 					    sizeof (dimmpp[j]->label));
8859d6aa643Saf 				}
88620c794b3Sgavinm 			}
88720c794b3Sgavinm 			dimmpp[j + nb_dimms_per_channel] =
88885738508SVuong Nguyen 			    nb_fbd_dimm_init(k + 1, j, mtr);
8899d6aa643Saf 			l = j + nb_dimms_per_channel;
8909d6aa643Saf 			if (dimmpp[l]) {
8919d6aa643Saf 				if (label_function) {
8929d6aa643Saf 					label_function->label_function(
8939d6aa643Saf 					    (k * nb_dimms_per_channel) + l,
8949d6aa643Saf 					    dimmpp[l]->label,
8959d6aa643Saf 					    sizeof (dimmpp[l]->label));
8969d6aa643Saf 				}
89720c794b3Sgavinm 				nb_ndimm ++;
8989d6aa643Saf 			}
89920c794b3Sgavinm 		}
90020c794b3Sgavinm 		dimmpp += nb_dimms_per_channel * 2;
90120c794b3Sgavinm 	}
90285738508SVuong Nguyen }
90385738508SVuong Nguyen 
90485738508SVuong Nguyen static void
90585738508SVuong Nguyen nb_dimms_init(find_dimm_label_t *label_function)
90685738508SVuong Nguyen {
90785738508SVuong Nguyen 	if (nb_chipset == INTEL_NB_5100)
90885738508SVuong Nguyen 		nb_ddr2_dimms_init(label_function);
90985738508SVuong Nguyen 	else
91085738508SVuong Nguyen 		nb_fbd_dimms_init(label_function);
91185738508SVuong Nguyen 
9129d6aa643Saf 	if (label_function == NULL)
9139d6aa643Saf 		nb_smbios();
91420c794b3Sgavinm }
91520c794b3Sgavinm 
9163221df98SKrishna Elango /* Setup the ESI port registers to enable SERR for southbridge */
91720c794b3Sgavinm static void
91820c794b3Sgavinm nb_pex_init()
91920c794b3Sgavinm {
9203221df98SKrishna Elango 	int i = 0; /* ESI port */
9213221df98SKrishna Elango 	uint16_t regw;
9223221df98SKrishna Elango 
9233221df98SKrishna Elango 	emask_uncor_pex[i] = EMASK_UNCOR_PEX_RD(i);
9243221df98SKrishna Elango 	emask_cor_pex[i] = EMASK_COR_PEX_RD(i);
9253221df98SKrishna Elango 	emask_rp_pex[i] = EMASK_RP_PEX_RD(i);
9263221df98SKrishna Elango 	docmd_pex[i] = PEX_ERR_DOCMD_RD(i);
9273221df98SKrishna Elango 	uncerrsev[i] = UNCERRSEV_RD(i);
9283221df98SKrishna Elango 
9293221df98SKrishna Elango 	if (nb5000_reset_uncor_pex)
9303221df98SKrishna Elango 		EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex);
9313221df98SKrishna Elango 	if (nb5000_reset_cor_pex)
9323221df98SKrishna Elango 		EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex);
9339ff4cbe7SAdrian Frost 	if (nb_chipset == INTEL_NB_5400) {
9349ff4cbe7SAdrian Frost 		/* disable masking of ERR pins used by DOCMD */
9359ff4cbe7SAdrian Frost 		PEX_ERR_PIN_MASK_WR(i, 0x10);
9363221df98SKrishna Elango 	}
9379a12e1bdSjveta 
9383221df98SKrishna Elango 	/* RP error message (CE/NFE/FE) detect mask */
9393221df98SKrishna Elango 	EMASK_RP_PEX_WR(i, nb5000_rp_pex);
9409a12e1bdSjveta 
9413221df98SKrishna Elango 	/* Command Register - Enable SERR */
9423221df98SKrishna Elango 	regw = nb_pci_getw(0, i, 0, PCI_CONF_COMM, 0);
9433221df98SKrishna Elango 	nb_pci_putw(0, i, 0, PCI_CONF_COMM,
9443221df98SKrishna Elango 	    regw | PCI_COMM_SERR_ENABLE);
9459a12e1bdSjveta 
9463221df98SKrishna Elango 	/* Root Control Register - SERR on NFE/FE */
9473221df98SKrishna Elango 	PEXROOTCTL_WR(i, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
9483221df98SKrishna Elango 	    PCIE_ROOTCTL_SYS_ERR_ON_FE_EN);
9499a12e1bdSjveta 
9503221df98SKrishna Elango 	/* AER UE Mask - Mask UR */
9513221df98SKrishna Elango 	UNCERRMSK_WR(i, PCIE_AER_UCE_UR);
95220c794b3Sgavinm }
95320c794b3Sgavinm 
95420c794b3Sgavinm static void
95520c794b3Sgavinm nb_pex_fini()
95620c794b3Sgavinm {
9573221df98SKrishna Elango 	int i = 0; /* ESI port */
95820c794b3Sgavinm 
9593221df98SKrishna Elango 	EMASK_UNCOR_PEX_WR(i, emask_uncor_pex[i]);
9603221df98SKrishna Elango 	EMASK_COR_PEX_WR(i, emask_cor_pex[i]);
9613221df98SKrishna Elango 	EMASK_RP_PEX_WR(i, emask_rp_pex[i]);
9623221df98SKrishna Elango 	PEX_ERR_DOCMD_WR(i, docmd_pex[i]);
9633221df98SKrishna Elango 
9643221df98SKrishna Elango 	if (nb5000_reset_uncor_pex)
9653221df98SKrishna Elango 		EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex);
9663221df98SKrishna Elango 	if (nb5000_reset_cor_pex)
9673221df98SKrishna Elango 		EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex);
96820c794b3Sgavinm }
96920c794b3Sgavinm 
97020c794b3Sgavinm void
97120c794b3Sgavinm nb_int_init()
97220c794b3Sgavinm {
9739ff4cbe7SAdrian Frost 	uint32_t err0_int;
9749ff4cbe7SAdrian Frost 	uint32_t err1_int;
9759ff4cbe7SAdrian Frost 	uint32_t err2_int;
9769ff4cbe7SAdrian Frost 	uint32_t mcerr_int;
9775f28a827Saf 	uint32_t emask_int;
978*f8e921e3SVuong Nguyen 	uint32_t nb_mask_bios_int;
979*f8e921e3SVuong Nguyen 	uint32_t nb_mask_poll_int;
98020c794b3Sgavinm 	uint16_t stepping;
98120c794b3Sgavinm 
982*f8e921e3SVuong Nguyen 	if (nb_chipset == INTEL_NB_5100) {
983*f8e921e3SVuong Nguyen 		nb_mask_bios_int = nb5100_mask_bios_int;
984*f8e921e3SVuong Nguyen 		nb_mask_poll_int = nb5100_mask_poll_int;
985*f8e921e3SVuong Nguyen 	} else {
986*f8e921e3SVuong Nguyen 		nb_mask_bios_int = nb5000_mask_bios_int;
987*f8e921e3SVuong Nguyen 		nb_mask_poll_int = nb5000_mask_poll_int;
988*f8e921e3SVuong Nguyen 	}
98920c794b3Sgavinm 	err0_int = ERR0_INT_RD();
99020c794b3Sgavinm 	err1_int = ERR1_INT_RD();
99120c794b3Sgavinm 	err2_int = ERR2_INT_RD();
99220c794b3Sgavinm 	mcerr_int = MCERR_INT_RD();
99320c794b3Sgavinm 	emask_int = EMASK_INT_RD();
99420c794b3Sgavinm 
99520c794b3Sgavinm 	nb_err0_int = err0_int;
99620c794b3Sgavinm 	nb_err1_int = err1_int;
99720c794b3Sgavinm 	nb_err2_int = err2_int;
99820c794b3Sgavinm 	nb_mcerr_int = mcerr_int;
99920c794b3Sgavinm 	nb_emask_int = emask_int;
100020c794b3Sgavinm 
10019ff4cbe7SAdrian Frost 	ERR0_INT_WR(ERR_INT_ALL);
10029ff4cbe7SAdrian Frost 	ERR1_INT_WR(ERR_INT_ALL);
10039ff4cbe7SAdrian Frost 	ERR2_INT_WR(ERR_INT_ALL);
10049ff4cbe7SAdrian Frost 	MCERR_INT_WR(ERR_INT_ALL);
10059ff4cbe7SAdrian Frost 	EMASK_INT_WR(ERR_INT_ALL);
100620c794b3Sgavinm 
1007*f8e921e3SVuong Nguyen 	mcerr_int &= ~nb_mask_bios_int;
1008*f8e921e3SVuong Nguyen 	mcerr_int |= nb_mask_bios_int & (~err0_int | ~err1_int | ~err2_int);
1009*f8e921e3SVuong Nguyen 	mcerr_int |= nb_mask_poll_int;
1010*f8e921e3SVuong Nguyen 	err0_int |= nb_mask_poll_int;
1011*f8e921e3SVuong Nguyen 	err1_int |= nb_mask_poll_int;
1012*f8e921e3SVuong Nguyen 	err2_int |= nb_mask_poll_int;
101320c794b3Sgavinm 
101420c794b3Sgavinm 	l_mcerr_int = mcerr_int;
101520c794b3Sgavinm 	ERR0_INT_WR(err0_int);
101620c794b3Sgavinm 	ERR1_INT_WR(err1_int);
101720c794b3Sgavinm 	ERR2_INT_WR(err2_int);
101820c794b3Sgavinm 	MCERR_INT_WR(mcerr_int);
101920c794b3Sgavinm 	if (nb5000_reset_emask_int) {
102020c794b3Sgavinm 		if (nb_chipset == INTEL_NB_7300) {
102120c794b3Sgavinm 			stepping = NB5000_STEPPING();
102220c794b3Sgavinm 			if (stepping == 0)
10235f28a827Saf 				EMASK_5000_INT_WR(nb7300_emask_int_step0);
102420c794b3Sgavinm 			else
10255f28a827Saf 				EMASK_5000_INT_WR(nb7300_emask_int);
10265f28a827Saf 		} else if (nb_chipset == INTEL_NB_5400) {
10275f28a827Saf 			EMASK_5400_INT_WR(nb5400_emask_int |
10285f28a827Saf 			    (emask_int & EMASK_INT_RES));
1029*f8e921e3SVuong Nguyen 		} else if (nb_chipset == INTEL_NB_5100) {
1030*f8e921e3SVuong Nguyen 			EMASK_5000_INT_WR(nb5100_emask_int);
103120c794b3Sgavinm 		} else {
10325f28a827Saf 			EMASK_5000_INT_WR(nb5000_emask_int);
103320c794b3Sgavinm 		}
103420c794b3Sgavinm 	} else {
103520c794b3Sgavinm 		EMASK_INT_WR(nb_emask_int);
103620c794b3Sgavinm 	}
103720c794b3Sgavinm }
103820c794b3Sgavinm 
103920c794b3Sgavinm void
104020c794b3Sgavinm nb_int_fini()
104120c794b3Sgavinm {
10429ff4cbe7SAdrian Frost 	ERR0_INT_WR(ERR_INT_ALL);
10439ff4cbe7SAdrian Frost 	ERR1_INT_WR(ERR_INT_ALL);
10449ff4cbe7SAdrian Frost 	ERR2_INT_WR(ERR_INT_ALL);
10459ff4cbe7SAdrian Frost 	MCERR_INT_WR(ERR_INT_ALL);
10469ff4cbe7SAdrian Frost 	EMASK_INT_WR(ERR_INT_ALL);
104720c794b3Sgavinm 
104820c794b3Sgavinm 	ERR0_INT_WR(nb_err0_int);
104920c794b3Sgavinm 	ERR1_INT_WR(nb_err1_int);
105020c794b3Sgavinm 	ERR2_INT_WR(nb_err2_int);
105120c794b3Sgavinm 	MCERR_INT_WR(nb_mcerr_int);
105220c794b3Sgavinm 	EMASK_INT_WR(nb_emask_int);
105320c794b3Sgavinm }
105420c794b3Sgavinm 
105520c794b3Sgavinm void
10565f28a827Saf nb_int_mask_mc(uint32_t mc_mask_int)
105720c794b3Sgavinm {
10585f28a827Saf 	uint32_t emask_int;
105920c794b3Sgavinm 
106020c794b3Sgavinm 	emask_int = MCERR_INT_RD();
106120c794b3Sgavinm 	if ((emask_int & mc_mask_int) != mc_mask_int) {
106220c794b3Sgavinm 		MCERR_INT_WR(emask_int|mc_mask_int);
106320c794b3Sgavinm 		nb_mask_mc_set = 1;
106420c794b3Sgavinm 	}
106520c794b3Sgavinm }
106620c794b3Sgavinm 
106785738508SVuong Nguyen static void
106820c794b3Sgavinm nb_fbd_init()
106920c794b3Sgavinm {
107020c794b3Sgavinm 	uint32_t err0_fbd;
107120c794b3Sgavinm 	uint32_t err1_fbd;
107220c794b3Sgavinm 	uint32_t err2_fbd;
107320c794b3Sgavinm 	uint32_t mcerr_fbd;
107420c794b3Sgavinm 	uint32_t emask_fbd;
10755f28a827Saf 	uint32_t emask_bios_fbd;
10765f28a827Saf 	uint32_t emask_poll_fbd;
107720c794b3Sgavinm 
107820c794b3Sgavinm 	err0_fbd = ERR0_FBD_RD();
107920c794b3Sgavinm 	err1_fbd = ERR1_FBD_RD();
108020c794b3Sgavinm 	err2_fbd = ERR2_FBD_RD();
108120c794b3Sgavinm 	mcerr_fbd = MCERR_FBD_RD();
108220c794b3Sgavinm 	emask_fbd = EMASK_FBD_RD();
108320c794b3Sgavinm 
108420c794b3Sgavinm 	nb_err0_fbd = err0_fbd;
108520c794b3Sgavinm 	nb_err1_fbd = err1_fbd;
108620c794b3Sgavinm 	nb_err2_fbd = err2_fbd;
108720c794b3Sgavinm 	nb_mcerr_fbd = mcerr_fbd;
108820c794b3Sgavinm 	nb_emask_fbd = emask_fbd;
108920c794b3Sgavinm 
109020c794b3Sgavinm 	ERR0_FBD_WR(0xffffffff);
109120c794b3Sgavinm 	ERR1_FBD_WR(0xffffffff);
109220c794b3Sgavinm 	ERR2_FBD_WR(0xffffffff);
109320c794b3Sgavinm 	MCERR_FBD_WR(0xffffffff);
109420c794b3Sgavinm 	EMASK_FBD_WR(0xffffffff);
109520c794b3Sgavinm 
1096*f8e921e3SVuong Nguyen 	if (nb_chipset == INTEL_NB_7300) {
1097*f8e921e3SVuong Nguyen 		if (nb_mode == NB_MEMORY_MIRROR) {
1098*f8e921e3SVuong Nguyen 			/* MCH 7300 errata 34 */
1099*f8e921e3SVuong Nguyen 			emask_bios_fbd = nb7300_mask_bios_fbd & ~EMASK_FBD_M23;
1100*f8e921e3SVuong Nguyen 			emask_poll_fbd = nb7300_mask_poll_fbd;
1101*f8e921e3SVuong Nguyen 			mcerr_fbd |= EMASK_FBD_M23;
1102*f8e921e3SVuong Nguyen 		} else {
1103*f8e921e3SVuong Nguyen 			emask_bios_fbd = nb7300_mask_bios_fbd;
1104*f8e921e3SVuong Nguyen 			emask_poll_fbd = nb7300_mask_poll_fbd;
1105*f8e921e3SVuong Nguyen 		}
11065f28a827Saf 	} else if (nb_chipset == INTEL_NB_5400) {
11075f28a827Saf 		emask_bios_fbd = nb5400_mask_bios_fbd;
11085f28a827Saf 		emask_poll_fbd = nb5400_mask_poll_fbd;
11095f28a827Saf 	} else {
11105f28a827Saf 		emask_bios_fbd = nb5000_mask_bios_fbd;
11115f28a827Saf 		emask_poll_fbd = nb5000_mask_poll_fbd;
111220c794b3Sgavinm 	}
11135f28a827Saf 	mcerr_fbd &= ~emask_bios_fbd;
11145f28a827Saf 	mcerr_fbd |= emask_bios_fbd & (~err0_fbd | ~err1_fbd | ~err2_fbd);
11155f28a827Saf 	mcerr_fbd |= emask_poll_fbd;
11165f28a827Saf 	err0_fbd |= emask_poll_fbd;
11175f28a827Saf 	err1_fbd |= emask_poll_fbd;
11185f28a827Saf 	err2_fbd |= emask_poll_fbd;
111920c794b3Sgavinm 
112020c794b3Sgavinm 	l_mcerr_fbd = mcerr_fbd;
112120c794b3Sgavinm 	ERR0_FBD_WR(err0_fbd);
112220c794b3Sgavinm 	ERR1_FBD_WR(err1_fbd);
112320c794b3Sgavinm 	ERR2_FBD_WR(err2_fbd);
112420c794b3Sgavinm 	MCERR_FBD_WR(mcerr_fbd);
11255f28a827Saf 	if (nb5000_reset_emask_fbd) {
11265f28a827Saf 		if (nb_chipset == INTEL_NB_5400)
11275f28a827Saf 			EMASK_FBD_WR(nb5400_emask_fbd);
11285f28a827Saf 		else
11295f28a827Saf 			EMASK_FBD_WR(nb5000_emask_fbd);
11305f28a827Saf 	} else {
113120c794b3Sgavinm 		EMASK_FBD_WR(nb_emask_fbd);
11325f28a827Saf 	}
113320c794b3Sgavinm }
113420c794b3Sgavinm 
113520c794b3Sgavinm void
113620c794b3Sgavinm nb_fbd_mask_mc(uint32_t mc_mask_fbd)
113720c794b3Sgavinm {
113820c794b3Sgavinm 	uint32_t emask_fbd;
113920c794b3Sgavinm 
114020c794b3Sgavinm 	emask_fbd = MCERR_FBD_RD();
114120c794b3Sgavinm 	if ((emask_fbd & mc_mask_fbd) != mc_mask_fbd) {
114220c794b3Sgavinm 		MCERR_FBD_WR(emask_fbd|mc_mask_fbd);
114320c794b3Sgavinm 		nb_mask_mc_set = 1;
114420c794b3Sgavinm 	}
114520c794b3Sgavinm }
114620c794b3Sgavinm 
114785738508SVuong Nguyen static void
114820c794b3Sgavinm nb_fbd_fini()
114920c794b3Sgavinm {
115020c794b3Sgavinm 	ERR0_FBD_WR(0xffffffff);
115120c794b3Sgavinm 	ERR1_FBD_WR(0xffffffff);
115220c794b3Sgavinm 	ERR2_FBD_WR(0xffffffff);
115320c794b3Sgavinm 	MCERR_FBD_WR(0xffffffff);
115420c794b3Sgavinm 	EMASK_FBD_WR(0xffffffff);
115520c794b3Sgavinm 
115620c794b3Sgavinm 	ERR0_FBD_WR(nb_err0_fbd);
115720c794b3Sgavinm 	ERR1_FBD_WR(nb_err1_fbd);
115820c794b3Sgavinm 	ERR2_FBD_WR(nb_err2_fbd);
115920c794b3Sgavinm 	MCERR_FBD_WR(nb_mcerr_fbd);
116020c794b3Sgavinm 	EMASK_FBD_WR(nb_emask_fbd);
116120c794b3Sgavinm }
116220c794b3Sgavinm 
116385738508SVuong Nguyen static void
116485738508SVuong Nguyen nb_mem_init()
116585738508SVuong Nguyen {
116685738508SVuong Nguyen 	uint32_t err0_mem;
116785738508SVuong Nguyen 	uint32_t err1_mem;
116885738508SVuong Nguyen 	uint32_t err2_mem;
116985738508SVuong Nguyen 	uint32_t mcerr_mem;
117085738508SVuong Nguyen 	uint32_t emask_mem;
117185738508SVuong Nguyen 	uint32_t emask_poll_mem;
117285738508SVuong Nguyen 
117385738508SVuong Nguyen 	err0_mem = ERR0_MEM_RD();
117485738508SVuong Nguyen 	err1_mem = ERR1_MEM_RD();
117585738508SVuong Nguyen 	err2_mem = ERR2_MEM_RD();
117685738508SVuong Nguyen 	mcerr_mem = MCERR_MEM_RD();
117785738508SVuong Nguyen 	emask_mem = EMASK_MEM_RD();
117885738508SVuong Nguyen 
117985738508SVuong Nguyen 	nb_err0_mem = err0_mem;
118085738508SVuong Nguyen 	nb_err1_mem = err1_mem;
118185738508SVuong Nguyen 	nb_err2_mem = err2_mem;
118285738508SVuong Nguyen 	nb_mcerr_mem = mcerr_mem;
118385738508SVuong Nguyen 	nb_emask_mem = emask_mem;
118485738508SVuong Nguyen 
118585738508SVuong Nguyen 	ERR0_MEM_WR(0xffffffff);
118685738508SVuong Nguyen 	ERR1_MEM_WR(0xffffffff);
118785738508SVuong Nguyen 	ERR2_MEM_WR(0xffffffff);
118885738508SVuong Nguyen 	MCERR_MEM_WR(0xffffffff);
118985738508SVuong Nguyen 	EMASK_MEM_WR(0xffffffff);
119085738508SVuong Nguyen 
119185738508SVuong Nguyen 	emask_poll_mem = nb5100_mask_poll_mem;
119285738508SVuong Nguyen 	mcerr_mem |= emask_poll_mem;
119385738508SVuong Nguyen 	err0_mem |= emask_poll_mem;
119485738508SVuong Nguyen 	err1_mem |= emask_poll_mem;
119585738508SVuong Nguyen 	err2_mem |= emask_poll_mem;
119685738508SVuong Nguyen 
119785738508SVuong Nguyen 	l_mcerr_mem = mcerr_mem;
119885738508SVuong Nguyen 	ERR0_MEM_WR(err0_mem);
119985738508SVuong Nguyen 	ERR1_MEM_WR(err1_mem);
120085738508SVuong Nguyen 	ERR2_MEM_WR(err2_mem);
120185738508SVuong Nguyen 	MCERR_MEM_WR(mcerr_mem);
120285738508SVuong Nguyen 	if (nb5100_reset_emask_mem) {
120385738508SVuong Nguyen 		EMASK_MEM_WR(~nb5100_mask_poll_mem);
120485738508SVuong Nguyen 	} else {
120585738508SVuong Nguyen 		EMASK_MEM_WR(nb_emask_mem);
120685738508SVuong Nguyen 	}
120785738508SVuong Nguyen }
120885738508SVuong Nguyen 
120985738508SVuong Nguyen void
121085738508SVuong Nguyen nb_mem_mask_mc(uint32_t mc_mask_mem)
121185738508SVuong Nguyen {
121285738508SVuong Nguyen 	uint32_t emask_mem;
121385738508SVuong Nguyen 
121485738508SVuong Nguyen 	emask_mem = MCERR_MEM_RD();
121585738508SVuong Nguyen 	if ((emask_mem & mc_mask_mem) != mc_mask_mem) {
121685738508SVuong Nguyen 		MCERR_MEM_WR(emask_mem|mc_mask_mem);
121785738508SVuong Nguyen 		nb_mask_mc_set = 1;
121885738508SVuong Nguyen 	}
121985738508SVuong Nguyen }
122085738508SVuong Nguyen 
122185738508SVuong Nguyen static void
122285738508SVuong Nguyen nb_mem_fini()
122385738508SVuong Nguyen {
122485738508SVuong Nguyen 	ERR0_MEM_WR(0xffffffff);
122585738508SVuong Nguyen 	ERR1_MEM_WR(0xffffffff);
122685738508SVuong Nguyen 	ERR2_MEM_WR(0xffffffff);
122785738508SVuong Nguyen 	MCERR_MEM_WR(0xffffffff);
122885738508SVuong Nguyen 	EMASK_MEM_WR(0xffffffff);
122985738508SVuong Nguyen 
123085738508SVuong Nguyen 	ERR0_MEM_WR(nb_err0_mem);
123185738508SVuong Nguyen 	ERR1_MEM_WR(nb_err1_mem);
123285738508SVuong Nguyen 	ERR2_MEM_WR(nb_err2_mem);
123385738508SVuong Nguyen 	MCERR_MEM_WR(nb_mcerr_mem);
123485738508SVuong Nguyen 	EMASK_MEM_WR(nb_emask_mem);
123585738508SVuong Nguyen }
123685738508SVuong Nguyen 
123720c794b3Sgavinm static void
123820c794b3Sgavinm nb_fsb_init()
123920c794b3Sgavinm {
124020c794b3Sgavinm 	uint16_t err0_fsb;
124120c794b3Sgavinm 	uint16_t err1_fsb;
124220c794b3Sgavinm 	uint16_t err2_fsb;
124320c794b3Sgavinm 	uint16_t mcerr_fsb;
124420c794b3Sgavinm 	uint16_t emask_fsb;
124520c794b3Sgavinm 
124620c794b3Sgavinm 	err0_fsb = ERR0_FSB_RD(0);
124720c794b3Sgavinm 	err1_fsb = ERR1_FSB_RD(0);
124820c794b3Sgavinm 	err2_fsb = ERR2_FSB_RD(0);
124920c794b3Sgavinm 	mcerr_fsb = MCERR_FSB_RD(0);
125020c794b3Sgavinm 	emask_fsb = EMASK_FSB_RD(0);
125120c794b3Sgavinm 
125220c794b3Sgavinm 	ERR0_FSB_WR(0, 0xffff);
125320c794b3Sgavinm 	ERR1_FSB_WR(0, 0xffff);
125420c794b3Sgavinm 	ERR2_FSB_WR(0, 0xffff);
125520c794b3Sgavinm 	MCERR_FSB_WR(0, 0xffff);
125620c794b3Sgavinm 	EMASK_FSB_WR(0, 0xffff);
125720c794b3Sgavinm 
125820c794b3Sgavinm 	ERR0_FSB_WR(1, 0xffff);
125920c794b3Sgavinm 	ERR1_FSB_WR(1, 0xffff);
126020c794b3Sgavinm 	ERR2_FSB_WR(1, 0xffff);
126120c794b3Sgavinm 	MCERR_FSB_WR(1, 0xffff);
126220c794b3Sgavinm 	EMASK_FSB_WR(1, 0xffff);
126320c794b3Sgavinm 
126420c794b3Sgavinm 	nb_err0_fsb = err0_fsb;
126520c794b3Sgavinm 	nb_err1_fsb = err1_fsb;
126620c794b3Sgavinm 	nb_err2_fsb = err2_fsb;
126720c794b3Sgavinm 	nb_mcerr_fsb = mcerr_fsb;
126820c794b3Sgavinm 	nb_emask_fsb = emask_fsb;
126920c794b3Sgavinm 
127020c794b3Sgavinm 	mcerr_fsb &= ~nb5000_mask_bios_fsb;
127120c794b3Sgavinm 	mcerr_fsb |= nb5000_mask_bios_fsb & (~err2_fsb | ~err1_fsb | ~err0_fsb);
127220c794b3Sgavinm 	mcerr_fsb |= nb5000_mask_poll_fsb;
127320c794b3Sgavinm 	err0_fsb |= nb5000_mask_poll_fsb;
127420c794b3Sgavinm 	err1_fsb |= nb5000_mask_poll_fsb;
127520c794b3Sgavinm 	err2_fsb |= nb5000_mask_poll_fsb;
127620c794b3Sgavinm 
127720c794b3Sgavinm 	l_mcerr_fsb = mcerr_fsb;
127820c794b3Sgavinm 	ERR0_FSB_WR(0, err0_fsb);
127920c794b3Sgavinm 	ERR1_FSB_WR(0, err1_fsb);
128020c794b3Sgavinm 	ERR2_FSB_WR(0, err2_fsb);
128120c794b3Sgavinm 	MCERR_FSB_WR(0, mcerr_fsb);
12825f28a827Saf 	if (nb5000_reset_emask_fsb) {
128320c794b3Sgavinm 		EMASK_FSB_WR(0, nb5000_emask_fsb);
12845f28a827Saf 	} else {
128520c794b3Sgavinm 		EMASK_FSB_WR(0, nb_emask_fsb);
12865f28a827Saf 	}
128720c794b3Sgavinm 
128820c794b3Sgavinm 	ERR0_FSB_WR(1, err0_fsb);
128920c794b3Sgavinm 	ERR1_FSB_WR(1, err1_fsb);
129020c794b3Sgavinm 	ERR2_FSB_WR(1, err2_fsb);
129120c794b3Sgavinm 	MCERR_FSB_WR(1, mcerr_fsb);
12925f28a827Saf 	if (nb5000_reset_emask_fsb) {
129320c794b3Sgavinm 		EMASK_FSB_WR(1, nb5000_emask_fsb);
12945f28a827Saf 	} else {
129520c794b3Sgavinm 		EMASK_FSB_WR(1, nb_emask_fsb);
12965f28a827Saf 	}
129720c794b3Sgavinm 
129820c794b3Sgavinm 	if (nb_chipset == INTEL_NB_7300) {
129920c794b3Sgavinm 		ERR0_FSB_WR(2, 0xffff);
130020c794b3Sgavinm 		ERR1_FSB_WR(2, 0xffff);
130120c794b3Sgavinm 		ERR2_FSB_WR(2, 0xffff);
130220c794b3Sgavinm 		MCERR_FSB_WR(2, 0xffff);
130320c794b3Sgavinm 		EMASK_FSB_WR(2, 0xffff);
130420c794b3Sgavinm 
130520c794b3Sgavinm 		ERR0_FSB_WR(3, 0xffff);
130620c794b3Sgavinm 		ERR1_FSB_WR(3, 0xffff);
130720c794b3Sgavinm 		ERR2_FSB_WR(3, 0xffff);
130820c794b3Sgavinm 		MCERR_FSB_WR(3, 0xffff);
130920c794b3Sgavinm 		EMASK_FSB_WR(3, 0xffff);
131020c794b3Sgavinm 
131120c794b3Sgavinm 		ERR0_FSB_WR(2, err0_fsb);
131220c794b3Sgavinm 		ERR1_FSB_WR(2, err1_fsb);
131320c794b3Sgavinm 		ERR2_FSB_WR(2, err2_fsb);
131420c794b3Sgavinm 		MCERR_FSB_WR(2, mcerr_fsb);
13155f28a827Saf 		if (nb5000_reset_emask_fsb) {
131620c794b3Sgavinm 			EMASK_FSB_WR(2, nb5000_emask_fsb);
13175f28a827Saf 		} else {
131820c794b3Sgavinm 			EMASK_FSB_WR(2, nb_emask_fsb);
13195f28a827Saf 		}
132020c794b3Sgavinm 
132120c794b3Sgavinm 		ERR0_FSB_WR(3, err0_fsb);
132220c794b3Sgavinm 		ERR1_FSB_WR(3, err1_fsb);
132320c794b3Sgavinm 		ERR2_FSB_WR(3, err2_fsb);
132420c794b3Sgavinm 		MCERR_FSB_WR(3, mcerr_fsb);
13255f28a827Saf 		if (nb5000_reset_emask_fsb) {
132620c794b3Sgavinm 			EMASK_FSB_WR(3, nb5000_emask_fsb);
13275f28a827Saf 		} else {
132820c794b3Sgavinm 			EMASK_FSB_WR(3, nb_emask_fsb);
13295f28a827Saf 		}
133020c794b3Sgavinm 	}
133120c794b3Sgavinm }
133220c794b3Sgavinm 
133320c794b3Sgavinm static void
133420c794b3Sgavinm nb_fsb_fini() {
133520c794b3Sgavinm 	ERR0_FSB_WR(0, 0xffff);
133620c794b3Sgavinm 	ERR1_FSB_WR(0, 0xffff);
133720c794b3Sgavinm 	ERR2_FSB_WR(0, 0xffff);
133820c794b3Sgavinm 	MCERR_FSB_WR(0, 0xffff);
133920c794b3Sgavinm 	EMASK_FSB_WR(0, 0xffff);
134020c794b3Sgavinm 
134120c794b3Sgavinm 	ERR0_FSB_WR(0, nb_err0_fsb);
134220c794b3Sgavinm 	ERR1_FSB_WR(0, nb_err1_fsb);
134320c794b3Sgavinm 	ERR2_FSB_WR(0, nb_err2_fsb);
134420c794b3Sgavinm 	MCERR_FSB_WR(0, nb_mcerr_fsb);
134520c794b3Sgavinm 	EMASK_FSB_WR(0, nb_emask_fsb);
134620c794b3Sgavinm 
134720c794b3Sgavinm 	ERR0_FSB_WR(1, 0xffff);
134820c794b3Sgavinm 	ERR1_FSB_WR(1, 0xffff);
134920c794b3Sgavinm 	ERR2_FSB_WR(1, 0xffff);
135020c794b3Sgavinm 	MCERR_FSB_WR(1, 0xffff);
135120c794b3Sgavinm 	EMASK_FSB_WR(1, 0xffff);
135220c794b3Sgavinm 
135320c794b3Sgavinm 	ERR0_FSB_WR(1, nb_err0_fsb);
135420c794b3Sgavinm 	ERR1_FSB_WR(1, nb_err1_fsb);
135520c794b3Sgavinm 	ERR2_FSB_WR(1, nb_err2_fsb);
135620c794b3Sgavinm 	MCERR_FSB_WR(1, nb_mcerr_fsb);
135720c794b3Sgavinm 	EMASK_FSB_WR(1, nb_emask_fsb);
135820c794b3Sgavinm 
135920c794b3Sgavinm 	if (nb_chipset == INTEL_NB_7300) {
136020c794b3Sgavinm 		ERR0_FSB_WR(2, 0xffff);
136120c794b3Sgavinm 		ERR1_FSB_WR(2, 0xffff);
136220c794b3Sgavinm 		ERR2_FSB_WR(2, 0xffff);
136320c794b3Sgavinm 		MCERR_FSB_WR(2, 0xffff);
136420c794b3Sgavinm 		EMASK_FSB_WR(2, 0xffff);
136520c794b3Sgavinm 
136620c794b3Sgavinm 		ERR0_FSB_WR(2, nb_err0_fsb);
136720c794b3Sgavinm 		ERR1_FSB_WR(2, nb_err1_fsb);
136820c794b3Sgavinm 		ERR2_FSB_WR(2, nb_err2_fsb);
136920c794b3Sgavinm 		MCERR_FSB_WR(2, nb_mcerr_fsb);
137020c794b3Sgavinm 		EMASK_FSB_WR(2, nb_emask_fsb);
137120c794b3Sgavinm 
137220c794b3Sgavinm 		ERR0_FSB_WR(3, 0xffff);
137320c794b3Sgavinm 		ERR1_FSB_WR(3, 0xffff);
137420c794b3Sgavinm 		ERR2_FSB_WR(3, 0xffff);
137520c794b3Sgavinm 		MCERR_FSB_WR(3, 0xffff);
137620c794b3Sgavinm 		EMASK_FSB_WR(3, 0xffff);
137720c794b3Sgavinm 
137820c794b3Sgavinm 		ERR0_FSB_WR(3, nb_err0_fsb);
137920c794b3Sgavinm 		ERR1_FSB_WR(3, nb_err1_fsb);
138020c794b3Sgavinm 		ERR2_FSB_WR(3, nb_err2_fsb);
138120c794b3Sgavinm 		MCERR_FSB_WR(3, nb_mcerr_fsb);
138220c794b3Sgavinm 		EMASK_FSB_WR(3, nb_emask_fsb);
138320c794b3Sgavinm 	}
138420c794b3Sgavinm }
138520c794b3Sgavinm 
138620c794b3Sgavinm void
138720c794b3Sgavinm nb_fsb_mask_mc(int fsb, uint16_t mc_mask_fsb)
138820c794b3Sgavinm {
138920c794b3Sgavinm 	uint16_t emask_fsb;
139020c794b3Sgavinm 
139120c794b3Sgavinm 	emask_fsb = MCERR_FSB_RD(fsb);
139220c794b3Sgavinm 	if ((emask_fsb & mc_mask_fsb) != mc_mask_fsb) {
139320c794b3Sgavinm 		MCERR_FSB_WR(fsb, emask_fsb|mc_mask_fsb|EMASK_FBD_RES);
139420c794b3Sgavinm 		nb_mask_mc_set = 1;
139520c794b3Sgavinm 	}
139620c794b3Sgavinm }
139720c794b3Sgavinm 
13985f28a827Saf static void
13995f28a827Saf nb_thr_init()
14005f28a827Saf {
14015f28a827Saf 	uint16_t err0_thr;
14025f28a827Saf 	uint16_t err1_thr;
14035f28a827Saf 	uint16_t err2_thr;
14045f28a827Saf 	uint16_t mcerr_thr;
14055f28a827Saf 	uint16_t emask_thr;
14065f28a827Saf 
14075f28a827Saf 	if (nb_chipset == INTEL_NB_5400) {
14085f28a827Saf 		err0_thr = ERR0_THR_RD(0);
14095f28a827Saf 		err1_thr = ERR1_THR_RD(0);
14105f28a827Saf 		err2_thr = ERR2_THR_RD(0);
14115f28a827Saf 		mcerr_thr = MCERR_THR_RD(0);
14125f28a827Saf 		emask_thr = EMASK_THR_RD(0);
14135f28a827Saf 
14145f28a827Saf 		ERR0_THR_WR(0xffff);
14155f28a827Saf 		ERR1_THR_WR(0xffff);
14165f28a827Saf 		ERR2_THR_WR(0xffff);
14175f28a827Saf 		MCERR_THR_WR(0xffff);
14185f28a827Saf 		EMASK_THR_WR(0xffff);
14195f28a827Saf 
14205f28a827Saf 		nb_err0_thr = err0_thr;
14215f28a827Saf 		nb_err1_thr = err1_thr;
14225f28a827Saf 		nb_err2_thr = err2_thr;
14235f28a827Saf 		nb_mcerr_thr = mcerr_thr;
14245f28a827Saf 		nb_emask_thr = emask_thr;
14255f28a827Saf 
14265f28a827Saf 		mcerr_thr &= ~nb_mask_bios_thr;
14275f28a827Saf 		mcerr_thr |= nb_mask_bios_thr &
14285f28a827Saf 		    (~err2_thr | ~err1_thr | ~err0_thr);
14295f28a827Saf 		mcerr_thr |= nb_mask_poll_thr;
14305f28a827Saf 		err0_thr |= nb_mask_poll_thr;
14315f28a827Saf 		err1_thr |= nb_mask_poll_thr;
14325f28a827Saf 		err2_thr |= nb_mask_poll_thr;
14335f28a827Saf 
14345f28a827Saf 		l_mcerr_thr = mcerr_thr;
14355f28a827Saf 		ERR0_THR_WR(err0_thr);
14365f28a827Saf 		ERR1_THR_WR(err1_thr);
14375f28a827Saf 		ERR2_THR_WR(err2_thr);
14385f28a827Saf 		MCERR_THR_WR(mcerr_thr);
14395f28a827Saf 		EMASK_THR_WR(nb_emask_thr);
14405f28a827Saf 	}
14415f28a827Saf }
14425f28a827Saf 
14435f28a827Saf static void
14445f28a827Saf nb_thr_fini()
14455f28a827Saf {
14465f28a827Saf 	if (nb_chipset == INTEL_NB_5400) {
14475f28a827Saf 		ERR0_THR_WR(0xffff);
14485f28a827Saf 		ERR1_THR_WR(0xffff);
14495f28a827Saf 		ERR2_THR_WR(0xffff);
14505f28a827Saf 		MCERR_THR_WR(0xffff);
14515f28a827Saf 		EMASK_THR_WR(0xffff);
14525f28a827Saf 
14535f28a827Saf 		ERR0_THR_WR(nb_err0_thr);
14545f28a827Saf 		ERR1_THR_WR(nb_err1_thr);
14555f28a827Saf 		ERR2_THR_WR(nb_err2_thr);
14565f28a827Saf 		MCERR_THR_WR(nb_mcerr_thr);
14575f28a827Saf 		EMASK_THR_WR(nb_emask_thr);
14585f28a827Saf 	}
14595f28a827Saf }
14605f28a827Saf 
14615f28a827Saf void
14625f28a827Saf nb_thr_mask_mc(uint16_t mc_mask_thr)
14635f28a827Saf {
14645f28a827Saf 	uint16_t emask_thr;
14655f28a827Saf 
14665f28a827Saf 	emask_thr = MCERR_THR_RD(0);
14675f28a827Saf 	if ((emask_thr & mc_mask_thr) != mc_mask_thr) {
14685f28a827Saf 		MCERR_THR_WR(emask_thr|mc_mask_thr);
14695f28a827Saf 		nb_mask_mc_set = 1;
14705f28a827Saf 	}
14715f28a827Saf }
14725f28a827Saf 
147320c794b3Sgavinm void
147420c794b3Sgavinm nb_mask_mc_reset()
147520c794b3Sgavinm {
147685738508SVuong Nguyen 	if (nb_chipset == INTEL_NB_5100)
147785738508SVuong Nguyen 		MCERR_MEM_WR(l_mcerr_mem);
147885738508SVuong Nguyen 	else
147985738508SVuong Nguyen 		MCERR_FBD_WR(l_mcerr_fbd);
148020c794b3Sgavinm 	MCERR_INT_WR(l_mcerr_int);
148120c794b3Sgavinm 	MCERR_FSB_WR(0, l_mcerr_fsb);
148220c794b3Sgavinm 	MCERR_FSB_WR(1, l_mcerr_fsb);
148320c794b3Sgavinm 	if (nb_chipset == INTEL_NB_7300) {
148420c794b3Sgavinm 		MCERR_FSB_WR(2, l_mcerr_fsb);
148520c794b3Sgavinm 		MCERR_FSB_WR(3, l_mcerr_fsb);
148620c794b3Sgavinm 	}
14875f28a827Saf 	if (nb_chipset == INTEL_NB_5400) {
14885f28a827Saf 		MCERR_THR_WR(l_mcerr_thr);
14895f28a827Saf 	}
149020c794b3Sgavinm }
149120c794b3Sgavinm 
149220c794b3Sgavinm int
149320c794b3Sgavinm nb_dev_init()
149420c794b3Sgavinm {
14959d6aa643Saf 	find_dimm_label_t *label_function_p;
14969d6aa643Saf 
14979d6aa643Saf 	label_function_p = find_dimms_per_channel();
149820c794b3Sgavinm 	mutex_init(&nb_mutex, NULL, MUTEX_DRIVER, NULL);
149920c794b3Sgavinm 	nb_queue = errorq_create("nb_queue", nb_drain, NULL, NB_MAX_ERRORS,
150020c794b3Sgavinm 	    sizeof (nb_logout_t), 1, ERRORQ_VITAL);
150120c794b3Sgavinm 	if (nb_queue == NULL) {
150220c794b3Sgavinm 		mutex_destroy(&nb_mutex);
150320c794b3Sgavinm 		return (EAGAIN);
150420c794b3Sgavinm 	}
15059d6aa643Saf 	nb_int_init();
15065f28a827Saf 	nb_thr_init();
150720c794b3Sgavinm 	dimm_init();
15089d6aa643Saf 	nb_dimms_init(label_function_p);
150920c794b3Sgavinm 	nb_mc_init();
151020c794b3Sgavinm 	nb_pex_init();
151185738508SVuong Nguyen 	if (nb_chipset == INTEL_NB_5100)
151285738508SVuong Nguyen 		nb_mem_init();
151385738508SVuong Nguyen 	else
151485738508SVuong Nguyen 		nb_fbd_init();
151520c794b3Sgavinm 	nb_fsb_init();
151620c794b3Sgavinm 	nb_scrubber_enable();
151720c794b3Sgavinm 	return (0);
151820c794b3Sgavinm }
151920c794b3Sgavinm 
152020c794b3Sgavinm int
152120c794b3Sgavinm nb_init()
152220c794b3Sgavinm {
1523e4b86885SCheng Sean Ye 	/* return ENOTSUP if there is no PCI config space support. */
1524e4b86885SCheng Sean Ye 	if (pci_getl_func == NULL)
1525e4b86885SCheng Sean Ye 		return (ENOTSUP);
1526e4b86885SCheng Sean Ye 
152720c794b3Sgavinm 	/* get vendor and device */
152820c794b3Sgavinm 	nb_chipset = (*pci_getl_func)(0, 0, 0, PCI_CONF_VENID);
152920c794b3Sgavinm 	switch (nb_chipset) {
153020c794b3Sgavinm 	default:
153120c794b3Sgavinm 		if (nb_5000_memory_controller == 0)
153220c794b3Sgavinm 			return (ENOTSUP);
153320c794b3Sgavinm 		break;
153420c794b3Sgavinm 	case INTEL_NB_7300:
153520c794b3Sgavinm 	case INTEL_NB_5000P:
153620c794b3Sgavinm 	case INTEL_NB_5000X:
153720c794b3Sgavinm 		break;
153820c794b3Sgavinm 	case INTEL_NB_5000V:
153920c794b3Sgavinm 	case INTEL_NB_5000Z:
154020c794b3Sgavinm 		nb_number_memory_controllers = 1;
154120c794b3Sgavinm 		break;
154285738508SVuong Nguyen 	case INTEL_NB_5100:
154385738508SVuong Nguyen 		nb_channels_per_branch = 1;
154485738508SVuong Nguyen 		break;
15455f28a827Saf 	case INTEL_NB_5400:
15465f28a827Saf 	case INTEL_NB_5400A:
15475f28a827Saf 	case INTEL_NB_5400B:
15485f28a827Saf 		nb_chipset = INTEL_NB_5400;
15495f28a827Saf 		break;
155020c794b3Sgavinm 	}
155120c794b3Sgavinm 	return (0);
155220c794b3Sgavinm }
155320c794b3Sgavinm 
155420c794b3Sgavinm void
155520c794b3Sgavinm nb_dev_reinit()
155620c794b3Sgavinm {
155720c794b3Sgavinm 	int i, j;
155820c794b3Sgavinm 	int nchannels = nb_number_memory_controllers * 2;
155920c794b3Sgavinm 	nb_dimm_t **dimmpp;
156020c794b3Sgavinm 	nb_dimm_t *dimmp;
156120c794b3Sgavinm 	nb_dimm_t **old_nb_dimms;
156220c794b3Sgavinm 	int old_nb_dimms_per_channel;
15639d6aa643Saf 	find_dimm_label_t *label_function_p;
156430cfc677SAdrian Frost 	int dimm_slot = nb_dimm_slots;
156520c794b3Sgavinm 
156620c794b3Sgavinm 	old_nb_dimms = nb_dimms;
156720c794b3Sgavinm 	old_nb_dimms_per_channel = nb_dimms_per_channel;
156820c794b3Sgavinm 
156920c794b3Sgavinm 	dimm_fini();
157030cfc677SAdrian Frost 	nb_dimms_per_channel = 0;
15719d6aa643Saf 	label_function_p = find_dimms_per_channel();
157220c794b3Sgavinm 	dimm_init();
15739d6aa643Saf 	nb_dimms_init(label_function_p);
157420c794b3Sgavinm 	nb_mc_init();
157520c794b3Sgavinm 	nb_pex_init();
157620c794b3Sgavinm 	nb_int_init();
15775f28a827Saf 	nb_thr_init();
157885738508SVuong Nguyen 	if (nb_chipset == INTEL_NB_5100)
157985738508SVuong Nguyen 		nb_mem_init();
158085738508SVuong Nguyen 	else
158185738508SVuong Nguyen 		nb_fbd_init();
158220c794b3Sgavinm 	nb_fsb_init();
158320c794b3Sgavinm 	nb_scrubber_enable();
158420c794b3Sgavinm 
158520c794b3Sgavinm 	dimmpp = old_nb_dimms;
158620c794b3Sgavinm 	for (i = 0; i < nchannels; i++) {
158720c794b3Sgavinm 		for (j = 0; j < old_nb_dimms_per_channel; j++) {
158820c794b3Sgavinm 			dimmp = *dimmpp;
158920c794b3Sgavinm 			if (dimmp) {
159020c794b3Sgavinm 				kmem_free(dimmp, sizeof (nb_dimm_t));
159120c794b3Sgavinm 				*dimmpp = NULL;
159220c794b3Sgavinm 			}
159320c794b3Sgavinm 			dimmp++;
159420c794b3Sgavinm 		}
159520c794b3Sgavinm 	}
159630cfc677SAdrian Frost 	kmem_free(old_nb_dimms, sizeof (nb_dimm_t *) * dimm_slot);
159720c794b3Sgavinm }
159820c794b3Sgavinm 
159920c794b3Sgavinm void
160020c794b3Sgavinm nb_dev_unload()
160120c794b3Sgavinm {
160220c794b3Sgavinm 	errorq_destroy(nb_queue);
160320c794b3Sgavinm 	nb_queue = NULL;
160420c794b3Sgavinm 	mutex_destroy(&nb_mutex);
160520c794b3Sgavinm 	nb_int_fini();
16065f28a827Saf 	nb_thr_fini();
160785738508SVuong Nguyen 	if (nb_chipset == INTEL_NB_5100)
160885738508SVuong Nguyen 		nb_mem_fini();
160985738508SVuong Nguyen 	else
161085738508SVuong Nguyen 		nb_fbd_fini();
161120c794b3Sgavinm 	nb_fsb_fini();
161220c794b3Sgavinm 	nb_pex_fini();
161320c794b3Sgavinm 	nb_fini();
161420c794b3Sgavinm }
161520c794b3Sgavinm 
161620c794b3Sgavinm void
161720c794b3Sgavinm nb_unload()
161820c794b3Sgavinm {
161920c794b3Sgavinm }
1620