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++) 267e4b86885SCheng 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 636*3221df98SKrishna Elango 637*3221df98SKrishna Elango /* Setup the ESI port registers to enable SERR for southbridge */ 63820c794b3Sgavinm static void 63920c794b3Sgavinm nb_pex_init() 64020c794b3Sgavinm { 641*3221df98SKrishna Elango int i = 0; /* ESI port */ 6425f28a827Saf uint32_t mask; 643*3221df98SKrishna Elango uint16_t regw; 644*3221df98SKrishna Elango 645*3221df98SKrishna Elango emask_uncor_pex[i] = EMASK_UNCOR_PEX_RD(i); 646*3221df98SKrishna Elango emask_cor_pex[i] = EMASK_COR_PEX_RD(i); 647*3221df98SKrishna Elango emask_rp_pex[i] = EMASK_RP_PEX_RD(i); 648*3221df98SKrishna Elango docmd_pex[i] = PEX_ERR_DOCMD_RD(i); 649*3221df98SKrishna Elango uncerrsev[i] = UNCERRSEV_RD(i); 650*3221df98SKrishna Elango 651*3221df98SKrishna Elango if (nb5000_reset_uncor_pex) 652*3221df98SKrishna Elango EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex); 653*3221df98SKrishna Elango if (nb5000_reset_cor_pex) 654*3221df98SKrishna Elango EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex); 655*3221df98SKrishna Elango if (nb_set_docmd) { 656*3221df98SKrishna Elango if (nb_chipset == INTEL_NB_5400) { 657*3221df98SKrishna Elango /* disable masking of ERR pins used by DOCMD */ 658*3221df98SKrishna Elango PEX_ERR_PIN_MASK_WR(i, 0x10); 659*3221df98SKrishna Elango 660*3221df98SKrishna Elango mask = (docmd_pex[i] & nb5400_docmd_pex_mask) | 661*3221df98SKrishna Elango (nb5400_docmd_pex & ~nb5400_docmd_pex_mask); 662*3221df98SKrishna Elango } else { 663*3221df98SKrishna Elango mask = (docmd_pex[i] & nb5000_docmd_pex_mask) | 664*3221df98SKrishna Elango (nb5000_docmd_pex & ~nb5000_docmd_pex_mask); 6655f28a827Saf } 666*3221df98SKrishna Elango PEX_ERR_DOCMD_WR(i, mask); 667*3221df98SKrishna Elango } 6689a12e1bdSjveta 669*3221df98SKrishna Elango /* RP error message (CE/NFE/FE) detect mask */ 670*3221df98SKrishna Elango EMASK_RP_PEX_WR(i, nb5000_rp_pex); 6719a12e1bdSjveta 672*3221df98SKrishna Elango /* Command Register - Enable SERR */ 673*3221df98SKrishna Elango regw = nb_pci_getw(0, i, 0, PCI_CONF_COMM, 0); 674*3221df98SKrishna Elango nb_pci_putw(0, i, 0, PCI_CONF_COMM, 675*3221df98SKrishna Elango regw | PCI_COMM_SERR_ENABLE); 6769a12e1bdSjveta 677*3221df98SKrishna Elango /* Root Control Register - SERR on NFE/FE */ 678*3221df98SKrishna Elango PEXROOTCTL_WR(i, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | 679*3221df98SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_FE_EN); 6809a12e1bdSjveta 681*3221df98SKrishna Elango /* AER UE Mask - Mask UR */ 682*3221df98SKrishna Elango UNCERRMSK_WR(i, PCIE_AER_UCE_UR); 68320c794b3Sgavinm } 68420c794b3Sgavinm 68520c794b3Sgavinm static void 68620c794b3Sgavinm nb_pex_fini() 68720c794b3Sgavinm { 688*3221df98SKrishna Elango int i = 0; /* ESI port */ 68920c794b3Sgavinm 690*3221df98SKrishna Elango EMASK_UNCOR_PEX_WR(i, emask_uncor_pex[i]); 691*3221df98SKrishna Elango EMASK_COR_PEX_WR(i, emask_cor_pex[i]); 692*3221df98SKrishna Elango EMASK_RP_PEX_WR(i, emask_rp_pex[i]); 693*3221df98SKrishna Elango PEX_ERR_DOCMD_WR(i, docmd_pex[i]); 694*3221df98SKrishna Elango 695*3221df98SKrishna Elango if (nb5000_reset_uncor_pex) 696*3221df98SKrishna Elango EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex); 697*3221df98SKrishna Elango if (nb5000_reset_cor_pex) 698*3221df98SKrishna Elango EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex); 69920c794b3Sgavinm } 70020c794b3Sgavinm 70120c794b3Sgavinm void 70220c794b3Sgavinm nb_int_init() 70320c794b3Sgavinm { 70420c794b3Sgavinm uint8_t err0_int; 70520c794b3Sgavinm uint8_t err1_int; 70620c794b3Sgavinm uint8_t err2_int; 70720c794b3Sgavinm uint8_t mcerr_int; 7085f28a827Saf uint32_t emask_int; 70920c794b3Sgavinm uint16_t stepping; 71020c794b3Sgavinm 71120c794b3Sgavinm err0_int = ERR0_INT_RD(); 71220c794b3Sgavinm err1_int = ERR1_INT_RD(); 71320c794b3Sgavinm err2_int = ERR2_INT_RD(); 71420c794b3Sgavinm mcerr_int = MCERR_INT_RD(); 71520c794b3Sgavinm emask_int = EMASK_INT_RD(); 71620c794b3Sgavinm 71720c794b3Sgavinm nb_err0_int = err0_int; 71820c794b3Sgavinm nb_err1_int = err1_int; 71920c794b3Sgavinm nb_err2_int = err2_int; 72020c794b3Sgavinm nb_mcerr_int = mcerr_int; 72120c794b3Sgavinm nb_emask_int = emask_int; 72220c794b3Sgavinm 72320c794b3Sgavinm ERR0_INT_WR(0xff); 72420c794b3Sgavinm ERR1_INT_WR(0xff); 72520c794b3Sgavinm ERR2_INT_WR(0xff); 72620c794b3Sgavinm MCERR_INT_WR(0xff); 72720c794b3Sgavinm EMASK_INT_WR(0xff); 72820c794b3Sgavinm 72920c794b3Sgavinm mcerr_int &= ~nb5000_mask_bios_int; 73020c794b3Sgavinm mcerr_int |= nb5000_mask_bios_int & (~err0_int | ~err1_int | ~err2_int); 73120c794b3Sgavinm mcerr_int |= nb5000_mask_poll_int; 73220c794b3Sgavinm err0_int |= nb5000_mask_poll_int; 73320c794b3Sgavinm err1_int |= nb5000_mask_poll_int; 73420c794b3Sgavinm err2_int |= nb5000_mask_poll_int; 73520c794b3Sgavinm 73620c794b3Sgavinm l_mcerr_int = mcerr_int; 73720c794b3Sgavinm ERR0_INT_WR(err0_int); 73820c794b3Sgavinm ERR1_INT_WR(err1_int); 73920c794b3Sgavinm ERR2_INT_WR(err2_int); 74020c794b3Sgavinm MCERR_INT_WR(mcerr_int); 74120c794b3Sgavinm if (nb5000_reset_emask_int) { 74220c794b3Sgavinm if (nb_chipset == INTEL_NB_7300) { 74320c794b3Sgavinm stepping = NB5000_STEPPING(); 74420c794b3Sgavinm if (stepping == 0) 7455f28a827Saf EMASK_5000_INT_WR(nb7300_emask_int_step0); 74620c794b3Sgavinm else 7475f28a827Saf EMASK_5000_INT_WR(nb7300_emask_int); 7485f28a827Saf } else if (nb_chipset == INTEL_NB_5400) { 7495f28a827Saf EMASK_5400_INT_WR(nb5400_emask_int | 7505f28a827Saf (emask_int & EMASK_INT_RES)); 75120c794b3Sgavinm } else { 7525f28a827Saf EMASK_5000_INT_WR(nb5000_emask_int); 75320c794b3Sgavinm } 75420c794b3Sgavinm } else { 75520c794b3Sgavinm EMASK_INT_WR(nb_emask_int); 75620c794b3Sgavinm } 75720c794b3Sgavinm } 75820c794b3Sgavinm 75920c794b3Sgavinm void 76020c794b3Sgavinm nb_int_fini() 76120c794b3Sgavinm { 76220c794b3Sgavinm ERR0_INT_WR(0xff); 76320c794b3Sgavinm ERR1_INT_WR(0xff); 76420c794b3Sgavinm ERR2_INT_WR(0xff); 76520c794b3Sgavinm MCERR_INT_WR(0xff); 76620c794b3Sgavinm EMASK_INT_WR(0xff); 76720c794b3Sgavinm 76820c794b3Sgavinm ERR0_INT_WR(nb_err0_int); 76920c794b3Sgavinm ERR1_INT_WR(nb_err1_int); 77020c794b3Sgavinm ERR2_INT_WR(nb_err2_int); 77120c794b3Sgavinm MCERR_INT_WR(nb_mcerr_int); 77220c794b3Sgavinm EMASK_INT_WR(nb_emask_int); 77320c794b3Sgavinm } 77420c794b3Sgavinm 77520c794b3Sgavinm void 7765f28a827Saf nb_int_mask_mc(uint32_t mc_mask_int) 77720c794b3Sgavinm { 7785f28a827Saf uint32_t emask_int; 77920c794b3Sgavinm 78020c794b3Sgavinm emask_int = MCERR_INT_RD(); 78120c794b3Sgavinm if ((emask_int & mc_mask_int) != mc_mask_int) { 78220c794b3Sgavinm MCERR_INT_WR(emask_int|mc_mask_int); 78320c794b3Sgavinm nb_mask_mc_set = 1; 78420c794b3Sgavinm } 78520c794b3Sgavinm } 78620c794b3Sgavinm 78720c794b3Sgavinm void 78820c794b3Sgavinm nb_fbd_init() 78920c794b3Sgavinm { 79020c794b3Sgavinm uint32_t err0_fbd; 79120c794b3Sgavinm uint32_t err1_fbd; 79220c794b3Sgavinm uint32_t err2_fbd; 79320c794b3Sgavinm uint32_t mcerr_fbd; 79420c794b3Sgavinm uint32_t emask_fbd; 7955f28a827Saf uint32_t emask_bios_fbd; 7965f28a827Saf uint32_t emask_poll_fbd; 79720c794b3Sgavinm 79820c794b3Sgavinm err0_fbd = ERR0_FBD_RD(); 79920c794b3Sgavinm err1_fbd = ERR1_FBD_RD(); 80020c794b3Sgavinm err2_fbd = ERR2_FBD_RD(); 80120c794b3Sgavinm mcerr_fbd = MCERR_FBD_RD(); 80220c794b3Sgavinm emask_fbd = EMASK_FBD_RD(); 80320c794b3Sgavinm 80420c794b3Sgavinm nb_err0_fbd = err0_fbd; 80520c794b3Sgavinm nb_err1_fbd = err1_fbd; 80620c794b3Sgavinm nb_err2_fbd = err2_fbd; 80720c794b3Sgavinm nb_mcerr_fbd = mcerr_fbd; 80820c794b3Sgavinm nb_emask_fbd = emask_fbd; 80920c794b3Sgavinm 81020c794b3Sgavinm ERR0_FBD_WR(0xffffffff); 81120c794b3Sgavinm ERR1_FBD_WR(0xffffffff); 81220c794b3Sgavinm ERR2_FBD_WR(0xffffffff); 81320c794b3Sgavinm MCERR_FBD_WR(0xffffffff); 81420c794b3Sgavinm EMASK_FBD_WR(0xffffffff); 81520c794b3Sgavinm 81620c794b3Sgavinm if (nb_chipset == INTEL_NB_7300 && nb_mode == NB_MEMORY_MIRROR) { 81720c794b3Sgavinm /* MCH 7300 errata 34 */ 8185f28a827Saf emask_bios_fbd = nb5000_mask_bios_fbd & ~EMASK_FBD_M23; 8195f28a827Saf emask_poll_fbd = nb5000_mask_poll_fbd; 82020c794b3Sgavinm mcerr_fbd |= EMASK_FBD_M23; 8215f28a827Saf } else if (nb_chipset == INTEL_NB_5400) { 8225f28a827Saf emask_bios_fbd = nb5400_mask_bios_fbd; 8235f28a827Saf emask_poll_fbd = nb5400_mask_poll_fbd; 8245f28a827Saf } else { 8255f28a827Saf emask_bios_fbd = nb5000_mask_bios_fbd; 8265f28a827Saf emask_poll_fbd = nb5000_mask_poll_fbd; 82720c794b3Sgavinm } 8285f28a827Saf mcerr_fbd &= ~emask_bios_fbd; 8295f28a827Saf mcerr_fbd |= emask_bios_fbd & (~err0_fbd | ~err1_fbd | ~err2_fbd); 8305f28a827Saf mcerr_fbd |= emask_poll_fbd; 8315f28a827Saf err0_fbd |= emask_poll_fbd; 8325f28a827Saf err1_fbd |= emask_poll_fbd; 8335f28a827Saf err2_fbd |= emask_poll_fbd; 83420c794b3Sgavinm 83520c794b3Sgavinm l_mcerr_fbd = mcerr_fbd; 83620c794b3Sgavinm ERR0_FBD_WR(err0_fbd); 83720c794b3Sgavinm ERR1_FBD_WR(err1_fbd); 83820c794b3Sgavinm ERR2_FBD_WR(err2_fbd); 83920c794b3Sgavinm MCERR_FBD_WR(mcerr_fbd); 8405f28a827Saf if (nb5000_reset_emask_fbd) { 8415f28a827Saf if (nb_chipset == INTEL_NB_5400) 8425f28a827Saf EMASK_FBD_WR(nb5400_emask_fbd); 8435f28a827Saf else 8445f28a827Saf EMASK_FBD_WR(nb5000_emask_fbd); 8455f28a827Saf } else { 84620c794b3Sgavinm EMASK_FBD_WR(nb_emask_fbd); 8475f28a827Saf } 84820c794b3Sgavinm } 84920c794b3Sgavinm 85020c794b3Sgavinm void 85120c794b3Sgavinm nb_fbd_mask_mc(uint32_t mc_mask_fbd) 85220c794b3Sgavinm { 85320c794b3Sgavinm uint32_t emask_fbd; 85420c794b3Sgavinm 85520c794b3Sgavinm emask_fbd = MCERR_FBD_RD(); 85620c794b3Sgavinm if ((emask_fbd & mc_mask_fbd) != mc_mask_fbd) { 85720c794b3Sgavinm MCERR_FBD_WR(emask_fbd|mc_mask_fbd); 85820c794b3Sgavinm nb_mask_mc_set = 1; 85920c794b3Sgavinm } 86020c794b3Sgavinm } 86120c794b3Sgavinm 86220c794b3Sgavinm void 86320c794b3Sgavinm nb_fbd_fini() 86420c794b3Sgavinm { 86520c794b3Sgavinm ERR0_FBD_WR(0xffffffff); 86620c794b3Sgavinm ERR1_FBD_WR(0xffffffff); 86720c794b3Sgavinm ERR2_FBD_WR(0xffffffff); 86820c794b3Sgavinm MCERR_FBD_WR(0xffffffff); 86920c794b3Sgavinm EMASK_FBD_WR(0xffffffff); 87020c794b3Sgavinm 87120c794b3Sgavinm ERR0_FBD_WR(nb_err0_fbd); 87220c794b3Sgavinm ERR1_FBD_WR(nb_err1_fbd); 87320c794b3Sgavinm ERR2_FBD_WR(nb_err2_fbd); 87420c794b3Sgavinm MCERR_FBD_WR(nb_mcerr_fbd); 87520c794b3Sgavinm EMASK_FBD_WR(nb_emask_fbd); 87620c794b3Sgavinm } 87720c794b3Sgavinm 87820c794b3Sgavinm static void 87920c794b3Sgavinm nb_fsb_init() 88020c794b3Sgavinm { 88120c794b3Sgavinm uint16_t err0_fsb; 88220c794b3Sgavinm uint16_t err1_fsb; 88320c794b3Sgavinm uint16_t err2_fsb; 88420c794b3Sgavinm uint16_t mcerr_fsb; 88520c794b3Sgavinm uint16_t emask_fsb; 88620c794b3Sgavinm 88720c794b3Sgavinm err0_fsb = ERR0_FSB_RD(0); 88820c794b3Sgavinm err1_fsb = ERR1_FSB_RD(0); 88920c794b3Sgavinm err2_fsb = ERR2_FSB_RD(0); 89020c794b3Sgavinm mcerr_fsb = MCERR_FSB_RD(0); 89120c794b3Sgavinm emask_fsb = EMASK_FSB_RD(0); 89220c794b3Sgavinm 89320c794b3Sgavinm ERR0_FSB_WR(0, 0xffff); 89420c794b3Sgavinm ERR1_FSB_WR(0, 0xffff); 89520c794b3Sgavinm ERR2_FSB_WR(0, 0xffff); 89620c794b3Sgavinm MCERR_FSB_WR(0, 0xffff); 89720c794b3Sgavinm EMASK_FSB_WR(0, 0xffff); 89820c794b3Sgavinm 89920c794b3Sgavinm ERR0_FSB_WR(1, 0xffff); 90020c794b3Sgavinm ERR1_FSB_WR(1, 0xffff); 90120c794b3Sgavinm ERR2_FSB_WR(1, 0xffff); 90220c794b3Sgavinm MCERR_FSB_WR(1, 0xffff); 90320c794b3Sgavinm EMASK_FSB_WR(1, 0xffff); 90420c794b3Sgavinm 90520c794b3Sgavinm nb_err0_fsb = err0_fsb; 90620c794b3Sgavinm nb_err1_fsb = err1_fsb; 90720c794b3Sgavinm nb_err2_fsb = err2_fsb; 90820c794b3Sgavinm nb_mcerr_fsb = mcerr_fsb; 90920c794b3Sgavinm nb_emask_fsb = emask_fsb; 91020c794b3Sgavinm 91120c794b3Sgavinm mcerr_fsb &= ~nb5000_mask_bios_fsb; 91220c794b3Sgavinm mcerr_fsb |= nb5000_mask_bios_fsb & (~err2_fsb | ~err1_fsb | ~err0_fsb); 91320c794b3Sgavinm mcerr_fsb |= nb5000_mask_poll_fsb; 91420c794b3Sgavinm err0_fsb |= nb5000_mask_poll_fsb; 91520c794b3Sgavinm err1_fsb |= nb5000_mask_poll_fsb; 91620c794b3Sgavinm err2_fsb |= nb5000_mask_poll_fsb; 91720c794b3Sgavinm 91820c794b3Sgavinm l_mcerr_fsb = mcerr_fsb; 91920c794b3Sgavinm ERR0_FSB_WR(0, err0_fsb); 92020c794b3Sgavinm ERR1_FSB_WR(0, err1_fsb); 92120c794b3Sgavinm ERR2_FSB_WR(0, err2_fsb); 92220c794b3Sgavinm MCERR_FSB_WR(0, mcerr_fsb); 9235f28a827Saf if (nb5000_reset_emask_fsb) { 92420c794b3Sgavinm EMASK_FSB_WR(0, nb5000_emask_fsb); 9255f28a827Saf } else { 92620c794b3Sgavinm EMASK_FSB_WR(0, nb_emask_fsb); 9275f28a827Saf } 92820c794b3Sgavinm 92920c794b3Sgavinm ERR0_FSB_WR(1, err0_fsb); 93020c794b3Sgavinm ERR1_FSB_WR(1, err1_fsb); 93120c794b3Sgavinm ERR2_FSB_WR(1, err2_fsb); 93220c794b3Sgavinm MCERR_FSB_WR(1, mcerr_fsb); 9335f28a827Saf if (nb5000_reset_emask_fsb) { 93420c794b3Sgavinm EMASK_FSB_WR(1, nb5000_emask_fsb); 9355f28a827Saf } else { 93620c794b3Sgavinm EMASK_FSB_WR(1, nb_emask_fsb); 9375f28a827Saf } 93820c794b3Sgavinm 93920c794b3Sgavinm if (nb_chipset == INTEL_NB_7300) { 94020c794b3Sgavinm ERR0_FSB_WR(2, 0xffff); 94120c794b3Sgavinm ERR1_FSB_WR(2, 0xffff); 94220c794b3Sgavinm ERR2_FSB_WR(2, 0xffff); 94320c794b3Sgavinm MCERR_FSB_WR(2, 0xffff); 94420c794b3Sgavinm EMASK_FSB_WR(2, 0xffff); 94520c794b3Sgavinm 94620c794b3Sgavinm ERR0_FSB_WR(3, 0xffff); 94720c794b3Sgavinm ERR1_FSB_WR(3, 0xffff); 94820c794b3Sgavinm ERR2_FSB_WR(3, 0xffff); 94920c794b3Sgavinm MCERR_FSB_WR(3, 0xffff); 95020c794b3Sgavinm EMASK_FSB_WR(3, 0xffff); 95120c794b3Sgavinm 95220c794b3Sgavinm ERR0_FSB_WR(2, err0_fsb); 95320c794b3Sgavinm ERR1_FSB_WR(2, err1_fsb); 95420c794b3Sgavinm ERR2_FSB_WR(2, err2_fsb); 95520c794b3Sgavinm MCERR_FSB_WR(2, mcerr_fsb); 9565f28a827Saf if (nb5000_reset_emask_fsb) { 95720c794b3Sgavinm EMASK_FSB_WR(2, nb5000_emask_fsb); 9585f28a827Saf } else { 95920c794b3Sgavinm EMASK_FSB_WR(2, nb_emask_fsb); 9605f28a827Saf } 96120c794b3Sgavinm 96220c794b3Sgavinm ERR0_FSB_WR(3, err0_fsb); 96320c794b3Sgavinm ERR1_FSB_WR(3, err1_fsb); 96420c794b3Sgavinm ERR2_FSB_WR(3, err2_fsb); 96520c794b3Sgavinm MCERR_FSB_WR(3, mcerr_fsb); 9665f28a827Saf if (nb5000_reset_emask_fsb) { 96720c794b3Sgavinm EMASK_FSB_WR(3, nb5000_emask_fsb); 9685f28a827Saf } else { 96920c794b3Sgavinm EMASK_FSB_WR(3, nb_emask_fsb); 9705f28a827Saf } 97120c794b3Sgavinm } 97220c794b3Sgavinm } 97320c794b3Sgavinm 97420c794b3Sgavinm static void 97520c794b3Sgavinm nb_fsb_fini() { 97620c794b3Sgavinm ERR0_FSB_WR(0, 0xffff); 97720c794b3Sgavinm ERR1_FSB_WR(0, 0xffff); 97820c794b3Sgavinm ERR2_FSB_WR(0, 0xffff); 97920c794b3Sgavinm MCERR_FSB_WR(0, 0xffff); 98020c794b3Sgavinm EMASK_FSB_WR(0, 0xffff); 98120c794b3Sgavinm 98220c794b3Sgavinm ERR0_FSB_WR(0, nb_err0_fsb); 98320c794b3Sgavinm ERR1_FSB_WR(0, nb_err1_fsb); 98420c794b3Sgavinm ERR2_FSB_WR(0, nb_err2_fsb); 98520c794b3Sgavinm MCERR_FSB_WR(0, nb_mcerr_fsb); 98620c794b3Sgavinm EMASK_FSB_WR(0, nb_emask_fsb); 98720c794b3Sgavinm 98820c794b3Sgavinm ERR0_FSB_WR(1, 0xffff); 98920c794b3Sgavinm ERR1_FSB_WR(1, 0xffff); 99020c794b3Sgavinm ERR2_FSB_WR(1, 0xffff); 99120c794b3Sgavinm MCERR_FSB_WR(1, 0xffff); 99220c794b3Sgavinm EMASK_FSB_WR(1, 0xffff); 99320c794b3Sgavinm 99420c794b3Sgavinm ERR0_FSB_WR(1, nb_err0_fsb); 99520c794b3Sgavinm ERR1_FSB_WR(1, nb_err1_fsb); 99620c794b3Sgavinm ERR2_FSB_WR(1, nb_err2_fsb); 99720c794b3Sgavinm MCERR_FSB_WR(1, nb_mcerr_fsb); 99820c794b3Sgavinm EMASK_FSB_WR(1, nb_emask_fsb); 99920c794b3Sgavinm 100020c794b3Sgavinm if (nb_chipset == INTEL_NB_7300) { 100120c794b3Sgavinm ERR0_FSB_WR(2, 0xffff); 100220c794b3Sgavinm ERR1_FSB_WR(2, 0xffff); 100320c794b3Sgavinm ERR2_FSB_WR(2, 0xffff); 100420c794b3Sgavinm MCERR_FSB_WR(2, 0xffff); 100520c794b3Sgavinm EMASK_FSB_WR(2, 0xffff); 100620c794b3Sgavinm 100720c794b3Sgavinm ERR0_FSB_WR(2, nb_err0_fsb); 100820c794b3Sgavinm ERR1_FSB_WR(2, nb_err1_fsb); 100920c794b3Sgavinm ERR2_FSB_WR(2, nb_err2_fsb); 101020c794b3Sgavinm MCERR_FSB_WR(2, nb_mcerr_fsb); 101120c794b3Sgavinm EMASK_FSB_WR(2, nb_emask_fsb); 101220c794b3Sgavinm 101320c794b3Sgavinm ERR0_FSB_WR(3, 0xffff); 101420c794b3Sgavinm ERR1_FSB_WR(3, 0xffff); 101520c794b3Sgavinm ERR2_FSB_WR(3, 0xffff); 101620c794b3Sgavinm MCERR_FSB_WR(3, 0xffff); 101720c794b3Sgavinm EMASK_FSB_WR(3, 0xffff); 101820c794b3Sgavinm 101920c794b3Sgavinm ERR0_FSB_WR(3, nb_err0_fsb); 102020c794b3Sgavinm ERR1_FSB_WR(3, nb_err1_fsb); 102120c794b3Sgavinm ERR2_FSB_WR(3, nb_err2_fsb); 102220c794b3Sgavinm MCERR_FSB_WR(3, nb_mcerr_fsb); 102320c794b3Sgavinm EMASK_FSB_WR(3, nb_emask_fsb); 102420c794b3Sgavinm } 102520c794b3Sgavinm } 102620c794b3Sgavinm 102720c794b3Sgavinm void 102820c794b3Sgavinm nb_fsb_mask_mc(int fsb, uint16_t mc_mask_fsb) 102920c794b3Sgavinm { 103020c794b3Sgavinm uint16_t emask_fsb; 103120c794b3Sgavinm 103220c794b3Sgavinm emask_fsb = MCERR_FSB_RD(fsb); 103320c794b3Sgavinm if ((emask_fsb & mc_mask_fsb) != mc_mask_fsb) { 103420c794b3Sgavinm MCERR_FSB_WR(fsb, emask_fsb|mc_mask_fsb|EMASK_FBD_RES); 103520c794b3Sgavinm nb_mask_mc_set = 1; 103620c794b3Sgavinm } 103720c794b3Sgavinm } 103820c794b3Sgavinm 10395f28a827Saf static void 10405f28a827Saf nb_thr_init() 10415f28a827Saf { 10425f28a827Saf uint16_t err0_thr; 10435f28a827Saf uint16_t err1_thr; 10445f28a827Saf uint16_t err2_thr; 10455f28a827Saf uint16_t mcerr_thr; 10465f28a827Saf uint16_t emask_thr; 10475f28a827Saf 10485f28a827Saf if (nb_chipset == INTEL_NB_5400) { 10495f28a827Saf err0_thr = ERR0_THR_RD(0); 10505f28a827Saf err1_thr = ERR1_THR_RD(0); 10515f28a827Saf err2_thr = ERR2_THR_RD(0); 10525f28a827Saf mcerr_thr = MCERR_THR_RD(0); 10535f28a827Saf emask_thr = EMASK_THR_RD(0); 10545f28a827Saf 10555f28a827Saf ERR0_THR_WR(0xffff); 10565f28a827Saf ERR1_THR_WR(0xffff); 10575f28a827Saf ERR2_THR_WR(0xffff); 10585f28a827Saf MCERR_THR_WR(0xffff); 10595f28a827Saf EMASK_THR_WR(0xffff); 10605f28a827Saf 10615f28a827Saf nb_err0_thr = err0_thr; 10625f28a827Saf nb_err1_thr = err1_thr; 10635f28a827Saf nb_err2_thr = err2_thr; 10645f28a827Saf nb_mcerr_thr = mcerr_thr; 10655f28a827Saf nb_emask_thr = emask_thr; 10665f28a827Saf 10675f28a827Saf mcerr_thr &= ~nb_mask_bios_thr; 10685f28a827Saf mcerr_thr |= nb_mask_bios_thr & 10695f28a827Saf (~err2_thr | ~err1_thr | ~err0_thr); 10705f28a827Saf mcerr_thr |= nb_mask_poll_thr; 10715f28a827Saf err0_thr |= nb_mask_poll_thr; 10725f28a827Saf err1_thr |= nb_mask_poll_thr; 10735f28a827Saf err2_thr |= nb_mask_poll_thr; 10745f28a827Saf 10755f28a827Saf l_mcerr_thr = mcerr_thr; 10765f28a827Saf ERR0_THR_WR(err0_thr); 10775f28a827Saf ERR1_THR_WR(err1_thr); 10785f28a827Saf ERR2_THR_WR(err2_thr); 10795f28a827Saf MCERR_THR_WR(mcerr_thr); 10805f28a827Saf EMASK_THR_WR(nb_emask_thr); 10815f28a827Saf } 10825f28a827Saf } 10835f28a827Saf 10845f28a827Saf static void 10855f28a827Saf nb_thr_fini() 10865f28a827Saf { 10875f28a827Saf if (nb_chipset == INTEL_NB_5400) { 10885f28a827Saf ERR0_THR_WR(0xffff); 10895f28a827Saf ERR1_THR_WR(0xffff); 10905f28a827Saf ERR2_THR_WR(0xffff); 10915f28a827Saf MCERR_THR_WR(0xffff); 10925f28a827Saf EMASK_THR_WR(0xffff); 10935f28a827Saf 10945f28a827Saf ERR0_THR_WR(nb_err0_thr); 10955f28a827Saf ERR1_THR_WR(nb_err1_thr); 10965f28a827Saf ERR2_THR_WR(nb_err2_thr); 10975f28a827Saf MCERR_THR_WR(nb_mcerr_thr); 10985f28a827Saf EMASK_THR_WR(nb_emask_thr); 10995f28a827Saf } 11005f28a827Saf } 11015f28a827Saf 11025f28a827Saf void 11035f28a827Saf nb_thr_mask_mc(uint16_t mc_mask_thr) 11045f28a827Saf { 11055f28a827Saf uint16_t emask_thr; 11065f28a827Saf 11075f28a827Saf emask_thr = MCERR_THR_RD(0); 11085f28a827Saf if ((emask_thr & mc_mask_thr) != mc_mask_thr) { 11095f28a827Saf MCERR_THR_WR(emask_thr|mc_mask_thr); 11105f28a827Saf nb_mask_mc_set = 1; 11115f28a827Saf } 11125f28a827Saf } 11135f28a827Saf 111420c794b3Sgavinm void 111520c794b3Sgavinm nb_mask_mc_reset() 111620c794b3Sgavinm { 111720c794b3Sgavinm MCERR_FBD_WR(l_mcerr_fbd); 111820c794b3Sgavinm MCERR_INT_WR(l_mcerr_int); 111920c794b3Sgavinm MCERR_FSB_WR(0, l_mcerr_fsb); 112020c794b3Sgavinm MCERR_FSB_WR(1, l_mcerr_fsb); 112120c794b3Sgavinm if (nb_chipset == INTEL_NB_7300) { 112220c794b3Sgavinm MCERR_FSB_WR(2, l_mcerr_fsb); 112320c794b3Sgavinm MCERR_FSB_WR(3, l_mcerr_fsb); 112420c794b3Sgavinm } 11255f28a827Saf if (nb_chipset == INTEL_NB_5400) { 11265f28a827Saf MCERR_THR_WR(l_mcerr_thr); 11275f28a827Saf } 112820c794b3Sgavinm } 112920c794b3Sgavinm 113020c794b3Sgavinm int 113120c794b3Sgavinm nb_dev_init() 113220c794b3Sgavinm { 11339d6aa643Saf find_dimm_label_t *label_function_p; 11349d6aa643Saf 11359d6aa643Saf label_function_p = find_dimms_per_channel(); 113620c794b3Sgavinm mutex_init(&nb_mutex, NULL, MUTEX_DRIVER, NULL); 113720c794b3Sgavinm nb_queue = errorq_create("nb_queue", nb_drain, NULL, NB_MAX_ERRORS, 113820c794b3Sgavinm sizeof (nb_logout_t), 1, ERRORQ_VITAL); 113920c794b3Sgavinm if (nb_queue == NULL) { 114020c794b3Sgavinm mutex_destroy(&nb_mutex); 114120c794b3Sgavinm return (EAGAIN); 114220c794b3Sgavinm } 11439d6aa643Saf nb_int_init(); 11445f28a827Saf nb_thr_init(); 114520c794b3Sgavinm dimm_init(); 11469d6aa643Saf nb_dimms_init(label_function_p); 114720c794b3Sgavinm nb_mc_init(); 114820c794b3Sgavinm nb_pex_init(); 114920c794b3Sgavinm nb_fbd_init(); 115020c794b3Sgavinm nb_fsb_init(); 115120c794b3Sgavinm nb_scrubber_enable(); 115220c794b3Sgavinm return (0); 115320c794b3Sgavinm } 115420c794b3Sgavinm 115520c794b3Sgavinm int 115620c794b3Sgavinm nb_init() 115720c794b3Sgavinm { 1158e4b86885SCheng Sean Ye /* return ENOTSUP if there is no PCI config space support. */ 1159e4b86885SCheng Sean Ye if (pci_getl_func == NULL) 1160e4b86885SCheng Sean Ye return (ENOTSUP); 1161e4b86885SCheng Sean Ye 116220c794b3Sgavinm /* get vendor and device */ 116320c794b3Sgavinm nb_chipset = (*pci_getl_func)(0, 0, 0, PCI_CONF_VENID); 116420c794b3Sgavinm switch (nb_chipset) { 116520c794b3Sgavinm default: 116620c794b3Sgavinm if (nb_5000_memory_controller == 0) 116720c794b3Sgavinm return (ENOTSUP); 116820c794b3Sgavinm break; 116920c794b3Sgavinm case INTEL_NB_7300: 117020c794b3Sgavinm case INTEL_NB_5000P: 117120c794b3Sgavinm case INTEL_NB_5000X: 117220c794b3Sgavinm break; 117320c794b3Sgavinm case INTEL_NB_5000V: 117420c794b3Sgavinm case INTEL_NB_5000Z: 117520c794b3Sgavinm nb_number_memory_controllers = 1; 117620c794b3Sgavinm break; 11775f28a827Saf case INTEL_NB_5400: 11785f28a827Saf case INTEL_NB_5400A: 11795f28a827Saf case INTEL_NB_5400B: 11805f28a827Saf nb_chipset = INTEL_NB_5400; 11815f28a827Saf break; 118220c794b3Sgavinm } 118320c794b3Sgavinm return (0); 118420c794b3Sgavinm } 118520c794b3Sgavinm 118620c794b3Sgavinm void 118720c794b3Sgavinm nb_dev_reinit() 118820c794b3Sgavinm { 118920c794b3Sgavinm int i, j; 119020c794b3Sgavinm int nchannels = nb_number_memory_controllers * 2; 119120c794b3Sgavinm nb_dimm_t **dimmpp; 119220c794b3Sgavinm nb_dimm_t *dimmp; 119320c794b3Sgavinm nb_dimm_t **old_nb_dimms; 119420c794b3Sgavinm int old_nb_dimms_per_channel; 11959d6aa643Saf find_dimm_label_t *label_function_p; 119620c794b3Sgavinm 119720c794b3Sgavinm old_nb_dimms = nb_dimms; 119820c794b3Sgavinm old_nb_dimms_per_channel = nb_dimms_per_channel; 119920c794b3Sgavinm 120020c794b3Sgavinm dimm_fini(); 12019d6aa643Saf label_function_p = find_dimms_per_channel(); 120220c794b3Sgavinm dimm_init(); 12039d6aa643Saf nb_dimms_init(label_function_p); 120420c794b3Sgavinm nb_mc_init(); 120520c794b3Sgavinm nb_pex_init(); 120620c794b3Sgavinm nb_int_init(); 12075f28a827Saf nb_thr_init(); 120820c794b3Sgavinm nb_fbd_init(); 120920c794b3Sgavinm nb_fsb_init(); 121020c794b3Sgavinm nb_scrubber_enable(); 121120c794b3Sgavinm 121220c794b3Sgavinm dimmpp = old_nb_dimms; 121320c794b3Sgavinm for (i = 0; i < nchannels; i++) { 121420c794b3Sgavinm for (j = 0; j < old_nb_dimms_per_channel; j++) { 121520c794b3Sgavinm dimmp = *dimmpp; 121620c794b3Sgavinm if (dimmp) { 121720c794b3Sgavinm kmem_free(dimmp, sizeof (nb_dimm_t)); 121820c794b3Sgavinm *dimmpp = NULL; 121920c794b3Sgavinm } 122020c794b3Sgavinm dimmp++; 122120c794b3Sgavinm } 122220c794b3Sgavinm } 122320c794b3Sgavinm kmem_free(old_nb_dimms, sizeof (nb_dimm_t *) * 122420c794b3Sgavinm nb_number_memory_controllers * 2 * old_nb_dimms_per_channel); 122520c794b3Sgavinm } 122620c794b3Sgavinm 122720c794b3Sgavinm void 122820c794b3Sgavinm nb_dev_unload() 122920c794b3Sgavinm { 123020c794b3Sgavinm errorq_destroy(nb_queue); 123120c794b3Sgavinm nb_queue = NULL; 123220c794b3Sgavinm mutex_destroy(&nb_mutex); 123320c794b3Sgavinm nb_int_fini(); 12345f28a827Saf nb_thr_fini(); 123520c794b3Sgavinm nb_fbd_fini(); 123620c794b3Sgavinm nb_fsb_fini(); 123720c794b3Sgavinm nb_pex_fini(); 123820c794b3Sgavinm nb_fini(); 123920c794b3Sgavinm } 124020c794b3Sgavinm 124120c794b3Sgavinm void 124220c794b3Sgavinm nb_unload() 124320c794b3Sgavinm { 124420c794b3Sgavinm } 1245