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