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 /* 23*9ff4cbe7SAdrian Frost * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2420c794b3Sgavinm * Use is subject to license terms. 2520c794b3Sgavinm */ 2620c794b3Sgavinm 2720c794b3Sgavinm #include <sys/types.h> 2820c794b3Sgavinm #include <sys/cmn_err.h> 2920c794b3Sgavinm #include <sys/errno.h> 3020c794b3Sgavinm #include <sys/log.h> 3120c794b3Sgavinm #include <sys/systm.h> 3220c794b3Sgavinm #include <sys/modctl.h> 3320c794b3Sgavinm #include <sys/errorq.h> 3420c794b3Sgavinm #include <sys/controlregs.h> 3520c794b3Sgavinm #include <sys/fm/util.h> 3620c794b3Sgavinm #include <sys/fm/protocol.h> 3720c794b3Sgavinm #include <sys/sysevent.h> 3820c794b3Sgavinm #include <sys/pghw.h> 3920c794b3Sgavinm #include <sys/cyclic.h> 4020c794b3Sgavinm #include <sys/pci_cfgspace.h> 4120c794b3Sgavinm #include <sys/mc_intel.h> 4220c794b3Sgavinm #include <sys/smbios.h> 4320c794b3Sgavinm #include <sys/pci.h> 449a12e1bdSjveta #include <sys/pcie.h> 4520c794b3Sgavinm #include "nb5000.h" 4620c794b3Sgavinm #include "nb_log.h" 4720c794b3Sgavinm #include "dimm_phys.h" 4820c794b3Sgavinm #include "rank.h" 4920c794b3Sgavinm 5020c794b3Sgavinm int nb_hw_memory_scrub_enable = 1; 5120c794b3Sgavinm static int nb_sw_scrub_disabled = 0; 5220c794b3Sgavinm 5320c794b3Sgavinm int nb_5000_memory_controller = 0; 5420c794b3Sgavinm int nb_number_memory_controllers = NB_5000_MAX_MEM_CONTROLLERS; 5520c794b3Sgavinm int nb_dimms_per_channel = 0; 5620c794b3Sgavinm 5720c794b3Sgavinm nb_dimm_t **nb_dimms; 5820c794b3Sgavinm int nb_ndimm; 5920c794b3Sgavinm uint32_t nb_chipset; 6020c794b3Sgavinm enum nb_memory_mode nb_mode; 615de8e333Saf bank_select_t nb_banks[NB_MAX_MEM_BRANCH_SELECT]; 625de8e333Saf rank_select_t nb_ranks[NB_5000_MAX_MEM_CONTROLLERS][NB_MAX_MEM_RANK_SELECT]; 6320c794b3Sgavinm uint32_t top_of_low_memory; 6420c794b3Sgavinm uint8_t spare_rank[NB_5000_MAX_MEM_CONTROLLERS]; 6520c794b3Sgavinm 6630cfc677SAdrian Frost extern int nb_no_smbios; 6730cfc677SAdrian Frost 6820c794b3Sgavinm errorq_t *nb_queue; 6920c794b3Sgavinm kmutex_t nb_mutex; 7020c794b3Sgavinm 7130cfc677SAdrian Frost static int nb_dimm_slots; 7230cfc677SAdrian Frost 73*9ff4cbe7SAdrian Frost static uint32_t nb_err0_int; 74*9ff4cbe7SAdrian Frost static uint32_t nb_err1_int; 75*9ff4cbe7SAdrian Frost static uint32_t nb_err2_int; 76*9ff4cbe7SAdrian Frost static uint32_t nb_mcerr_int; 775f28a827Saf static uint32_t nb_emask_int; 7820c794b3Sgavinm 7920c794b3Sgavinm static uint32_t nb_err0_fbd; 8020c794b3Sgavinm static uint32_t nb_err1_fbd; 8120c794b3Sgavinm static uint32_t nb_err2_fbd; 8220c794b3Sgavinm static uint32_t nb_mcerr_fbd; 8320c794b3Sgavinm static uint32_t nb_emask_fbd; 8420c794b3Sgavinm 8520c794b3Sgavinm static uint16_t nb_err0_fsb; 8620c794b3Sgavinm static uint16_t nb_err1_fsb; 8720c794b3Sgavinm static uint16_t nb_err2_fsb; 8820c794b3Sgavinm static uint16_t nb_mcerr_fsb; 8920c794b3Sgavinm static uint16_t nb_emask_fsb; 9020c794b3Sgavinm 915f28a827Saf static uint16_t nb_err0_thr; 925f28a827Saf static uint16_t nb_err1_thr; 935f28a827Saf static uint16_t nb_err2_thr; 945f28a827Saf static uint16_t nb_mcerr_thr; 955f28a827Saf static uint16_t nb_emask_thr; 965f28a827Saf 9720c794b3Sgavinm static uint32_t emask_uncor_pex[NB_PCI_DEV]; 9820c794b3Sgavinm static uint32_t emask_cor_pex[NB_PCI_DEV]; 9920c794b3Sgavinm static uint32_t emask_rp_pex[NB_PCI_DEV]; 10020c794b3Sgavinm static uint32_t docmd_pex[NB_PCI_DEV]; 10120c794b3Sgavinm static uint32_t uncerrsev[NB_PCI_DEV]; 10220c794b3Sgavinm 103*9ff4cbe7SAdrian Frost static uint32_t l_mcerr_int; 10420c794b3Sgavinm static uint32_t l_mcerr_fbd; 10520c794b3Sgavinm static uint16_t l_mcerr_fsb; 1065f28a827Saf static uint16_t l_mcerr_thr; 10720c794b3Sgavinm 1085f28a827Saf uint_t nb5000_emask_fbd = EMASK_5000_FBD_RES; 1095f28a827Saf uint_t nb5400_emask_fbd = 0; 11020c794b3Sgavinm int nb5000_reset_emask_fbd = 1; 11120c794b3Sgavinm uint_t nb5000_mask_poll_fbd = EMASK_FBD_NF; 11220c794b3Sgavinm uint_t nb5000_mask_bios_fbd = EMASK_FBD_FATAL; 1135f28a827Saf uint_t nb5400_mask_poll_fbd = EMASK_5400_FBD_NF; 1145f28a827Saf uint_t nb5400_mask_bios_fbd = EMASK_5400_FBD_FATAL; 11520c794b3Sgavinm 11620c794b3Sgavinm uint_t nb5000_emask_fsb = 0; 11720c794b3Sgavinm int nb5000_reset_emask_fsb = 1; 11820c794b3Sgavinm uint_t nb5000_mask_poll_fsb = EMASK_FSB_NF; 11920c794b3Sgavinm uint_t nb5000_mask_bios_fsb = EMASK_FSB_FATAL; 12020c794b3Sgavinm 121*9ff4cbe7SAdrian Frost uint_t nb5400_emask_int = EMASK_INT_5400; 1225f28a827Saf 12320c794b3Sgavinm uint_t nb7300_emask_int = EMASK_INT_7300; 12420c794b3Sgavinm uint_t nb7300_emask_int_step0 = EMASK_INT_7300_STEP_0; 12520c794b3Sgavinm uint_t nb5000_emask_int = EMASK_INT_5000; 12620c794b3Sgavinm int nb5000_reset_emask_int = 1; 12720c794b3Sgavinm uint_t nb5000_mask_poll_int = EMASK_INT_NF; 12820c794b3Sgavinm uint_t nb5000_mask_bios_int = EMASK_INT_FATAL; 12920c794b3Sgavinm 1305f28a827Saf uint_t nb_mask_poll_thr = EMASK_THR_NF; 1315f28a827Saf uint_t nb_mask_bios_thr = EMASK_THR_FATAL; 1325f28a827Saf 13320c794b3Sgavinm int nb5000_reset_uncor_pex = 0; 13420c794b3Sgavinm uint_t nb5000_mask_uncor_pex = 0; 1355f28a827Saf int nb5000_reset_cor_pex = 0; 13620c794b3Sgavinm uint_t nb5000_mask_cor_pex = 0xffffffff; 1379a12e1bdSjveta uint32_t nb5000_rp_pex = 0x1; 13820c794b3Sgavinm 13920c794b3Sgavinm int nb_mask_mc_set; 14020c794b3Sgavinm 1419d6aa643Saf typedef struct find_dimm_label { 1429d6aa643Saf void (*label_function)(int, char *, int); 1439d6aa643Saf } find_dimm_label_t; 1449d6aa643Saf 1459d6aa643Saf static void x8450_dimm_label(int, char *, int); 1469d6aa643Saf 1479d6aa643Saf static struct platform_label { 1489d6aa643Saf const char *sys_vendor; /* SMB_TYPE_SYSTEM vendor prefix */ 1499d6aa643Saf const char *sys_product; /* SMB_TYPE_SYSTEM product prefix */ 1509d6aa643Saf find_dimm_label_t dimm_label; 1519d6aa643Saf int dimms_per_channel; 1529d6aa643Saf } platform_label[] = { 1539d6aa643Saf { "SUN MICROSYSTEMS", "SUN BLADE X8450 SERVER MODULE", 1549d6aa643Saf x8450_dimm_label, 8 }, 1559d6aa643Saf { NULL, NULL, NULL, 0 } 1569d6aa643Saf }; 1579d6aa643Saf 15820c794b3Sgavinm static unsigned short 15920c794b3Sgavinm read_spd(int bus) 16020c794b3Sgavinm { 16120c794b3Sgavinm unsigned short rt = 0; 16220c794b3Sgavinm int branch = bus >> 1; 16320c794b3Sgavinm int channel = bus & 1; 16420c794b3Sgavinm 16520c794b3Sgavinm rt = SPD_RD(branch, channel); 16620c794b3Sgavinm 16720c794b3Sgavinm return (rt); 16820c794b3Sgavinm } 16920c794b3Sgavinm 17020c794b3Sgavinm static void 17120c794b3Sgavinm write_spdcmd(int bus, uint32_t val) 17220c794b3Sgavinm { 17320c794b3Sgavinm int branch = bus >> 1; 17420c794b3Sgavinm int channel = bus & 1; 17520c794b3Sgavinm SPDCMD_WR(branch, channel, val); 17620c794b3Sgavinm } 17720c794b3Sgavinm 17820c794b3Sgavinm static int 17920c794b3Sgavinm read_spd_eeprom(int bus, int slave, int addr) 18020c794b3Sgavinm { 18120c794b3Sgavinm int retry = 4; 18220c794b3Sgavinm int wait; 18320c794b3Sgavinm int spd; 18420c794b3Sgavinm uint32_t cmd; 18520c794b3Sgavinm 18620c794b3Sgavinm for (;;) { 18720c794b3Sgavinm wait = 1000; 18820c794b3Sgavinm for (;;) { 18920c794b3Sgavinm spd = read_spd(bus); 19020c794b3Sgavinm if ((spd & SPD_BUSY) == 0) 19120c794b3Sgavinm break; 19220c794b3Sgavinm if (--wait == 0) 19320c794b3Sgavinm return (-1); 19420c794b3Sgavinm drv_usecwait(10); 19520c794b3Sgavinm } 19620c794b3Sgavinm cmd = SPD_EEPROM_WRITE | SPD_ADDR(slave, addr); 19720c794b3Sgavinm write_spdcmd(bus, cmd); 19820c794b3Sgavinm wait = 1000; 19920c794b3Sgavinm for (;;) { 20020c794b3Sgavinm spd = read_spd(bus); 20120c794b3Sgavinm if ((spd & SPD_BUSY) == 0) 20220c794b3Sgavinm break; 20320c794b3Sgavinm if (--wait == 0) { 20420c794b3Sgavinm spd = SPD_BUS_ERROR; 20520c794b3Sgavinm break; 20620c794b3Sgavinm } 20720c794b3Sgavinm drv_usecwait(10); 20820c794b3Sgavinm } 20920c794b3Sgavinm while ((spd & SPD_BUS_ERROR) == 0 && 21020c794b3Sgavinm (spd & (SPD_READ_DATA_VALID|SPD_BUSY)) != 21120c794b3Sgavinm SPD_READ_DATA_VALID) { 21220c794b3Sgavinm spd = read_spd(bus); 21320c794b3Sgavinm if (--wait == 0) 21420c794b3Sgavinm return (-1); 21520c794b3Sgavinm } 21620c794b3Sgavinm if ((spd & SPD_BUS_ERROR) == 0) 21720c794b3Sgavinm break; 21820c794b3Sgavinm if (--retry == 0) 21920c794b3Sgavinm return (-1); 22020c794b3Sgavinm } 22120c794b3Sgavinm return (spd & 0xff); 22220c794b3Sgavinm } 22320c794b3Sgavinm 22420c794b3Sgavinm static void 22520c794b3Sgavinm nb_fini() 22620c794b3Sgavinm { 22720c794b3Sgavinm int i, j; 22820c794b3Sgavinm int nchannels = nb_number_memory_controllers * 2; 22920c794b3Sgavinm nb_dimm_t **dimmpp; 23020c794b3Sgavinm nb_dimm_t *dimmp; 23120c794b3Sgavinm 23220c794b3Sgavinm dimmpp = nb_dimms; 23320c794b3Sgavinm for (i = 0; i < nchannels; i++) { 23420c794b3Sgavinm for (j = 0; j < nb_dimms_per_channel; j++) { 23520c794b3Sgavinm dimmp = *dimmpp; 23620c794b3Sgavinm if (dimmp) { 23720c794b3Sgavinm kmem_free(dimmp, sizeof (nb_dimm_t)); 23820c794b3Sgavinm *dimmpp = NULL; 23920c794b3Sgavinm } 24020c794b3Sgavinm dimmp++; 24120c794b3Sgavinm } 24220c794b3Sgavinm } 24330cfc677SAdrian Frost kmem_free(nb_dimms, sizeof (nb_dimm_t *) * nb_dimm_slots); 24420c794b3Sgavinm nb_dimms = NULL; 24520c794b3Sgavinm dimm_fini(); 24620c794b3Sgavinm } 24720c794b3Sgavinm 24820c794b3Sgavinm void 24920c794b3Sgavinm nb_scrubber_enable() 25020c794b3Sgavinm { 25120c794b3Sgavinm uint32_t mc; 25220c794b3Sgavinm 25320c794b3Sgavinm if (!nb_hw_memory_scrub_enable) 25420c794b3Sgavinm return; 25520c794b3Sgavinm 25620c794b3Sgavinm mc = MC_RD(); 25720c794b3Sgavinm if ((mc & MC_MIRROR) != 0) /* mirror mode */ 25820c794b3Sgavinm mc |= MC_PATROL_SCRUB; 25920c794b3Sgavinm else 26020c794b3Sgavinm mc |= MC_PATROL_SCRUB|MC_DEMAND_SCRUB; 26120c794b3Sgavinm MC_WR(mc); 26220c794b3Sgavinm 26320c794b3Sgavinm if (nb_sw_scrub_disabled++) 264e4b86885SCheng Sean Ye cmi_mc_sw_memscrub_disable(); 26520c794b3Sgavinm } 26620c794b3Sgavinm 26720c794b3Sgavinm static nb_dimm_t * 26820c794b3Sgavinm nb_dimm_init(int channel, int dimm, uint16_t mtr) 26920c794b3Sgavinm { 27020c794b3Sgavinm nb_dimm_t *dp; 27120c794b3Sgavinm int i, t; 27220c794b3Sgavinm int spd_sz; 27320c794b3Sgavinm 2749d6aa643Saf if (MTR_PRESENT(mtr) == 0) 2759d6aa643Saf return (NULL); 27620c794b3Sgavinm t = read_spd_eeprom(channel, dimm, 2) & 0xf; 27720c794b3Sgavinm 27820c794b3Sgavinm if (t != 9) 27920c794b3Sgavinm return (NULL); 28020c794b3Sgavinm 28120c794b3Sgavinm dp = kmem_zalloc(sizeof (nb_dimm_t), KM_SLEEP); 2829d6aa643Saf 28320c794b3Sgavinm t = read_spd_eeprom(channel, dimm, 0) & 0xf; 28420c794b3Sgavinm if (t == 1) 28520c794b3Sgavinm spd_sz = 128; 28620c794b3Sgavinm else if (t == 2) 28720c794b3Sgavinm spd_sz = 176; 28820c794b3Sgavinm else 28920c794b3Sgavinm spd_sz = 256; 29020c794b3Sgavinm dp->manufacture_id = read_spd_eeprom(channel, dimm, 117) | 29120c794b3Sgavinm (read_spd_eeprom(channel, dimm, 118) << 8); 29220c794b3Sgavinm dp->manufacture_location = read_spd_eeprom(channel, dimm, 119); 29320c794b3Sgavinm dp->serial_number = 29420c794b3Sgavinm (read_spd_eeprom(channel, dimm, 122) << 24) | 29520c794b3Sgavinm (read_spd_eeprom(channel, dimm, 123) << 16) | 29620c794b3Sgavinm (read_spd_eeprom(channel, dimm, 124) << 8) | 29720c794b3Sgavinm read_spd_eeprom(channel, dimm, 125); 29820c794b3Sgavinm t = read_spd_eeprom(channel, dimm, 121); 29920c794b3Sgavinm dp->manufacture_week = (t >> 4) * 10 + (t & 0xf); 30020c794b3Sgavinm dp->manufacture_year = read_spd_eeprom(channel, dimm, 120); 30120c794b3Sgavinm if (spd_sz > 128) { 30220c794b3Sgavinm for (i = 0; i < sizeof (dp->part_number); i++) { 30320c794b3Sgavinm dp->part_number[i] = 30420c794b3Sgavinm read_spd_eeprom(channel, dimm, 128 + i); 30520c794b3Sgavinm } 30620c794b3Sgavinm for (i = 0; i < sizeof (dp->revision); i++) { 30720c794b3Sgavinm dp->revision[i] = 30820c794b3Sgavinm read_spd_eeprom(channel, dimm, 146 + i); 30920c794b3Sgavinm } 31020c794b3Sgavinm } 3115de8e333Saf dp->mtr_present = MTR_PRESENT(mtr); 31220c794b3Sgavinm dp->nranks = MTR_NUMRANK(mtr); 31320c794b3Sgavinm dp->nbanks = MTR_NUMBANK(mtr); 31420c794b3Sgavinm dp->ncolumn = MTR_NUMCOL(mtr); 31520c794b3Sgavinm dp->nrow = MTR_NUMROW(mtr); 31620c794b3Sgavinm dp->width = MTR_WIDTH(mtr); 31720c794b3Sgavinm dp->dimm_size = MTR_DIMMSIZE(mtr); 31820c794b3Sgavinm 31920c794b3Sgavinm return (dp); 32020c794b3Sgavinm } 32120c794b3Sgavinm 32220c794b3Sgavinm static uint64_t 32320c794b3Sgavinm mc_range(int controller, uint64_t base) 32420c794b3Sgavinm { 32520c794b3Sgavinm int i; 32620c794b3Sgavinm uint64_t limit = 0; 32720c794b3Sgavinm 32820c794b3Sgavinm for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) { 32920c794b3Sgavinm if (nb_banks[i].way[controller] && base >= nb_banks[i].base && 33020c794b3Sgavinm base < nb_banks[i].limit) { 33120c794b3Sgavinm limit = nb_banks[i].limit; 33220c794b3Sgavinm if (base <= top_of_low_memory && 33320c794b3Sgavinm limit > top_of_low_memory) { 33420c794b3Sgavinm limit -= TLOW_MAX - top_of_low_memory; 33520c794b3Sgavinm } 33620c794b3Sgavinm if (nb_banks[i].way[0] && nb_banks[i].way[1] && 33720c794b3Sgavinm nb_mode != NB_MEMORY_MIRROR) { 33820c794b3Sgavinm limit = limit / 2; 33920c794b3Sgavinm } 34020c794b3Sgavinm } 34120c794b3Sgavinm } 34220c794b3Sgavinm return (limit); 34320c794b3Sgavinm } 34420c794b3Sgavinm 34520c794b3Sgavinm void 34620c794b3Sgavinm nb_mc_init() 34720c794b3Sgavinm { 34820c794b3Sgavinm uint16_t tolm; 34920c794b3Sgavinm uint16_t mir; 35020c794b3Sgavinm uint32_t hole_base; 35120c794b3Sgavinm uint32_t hole_size; 35220c794b3Sgavinm uint32_t dmir; 35320c794b3Sgavinm uint64_t base; 35420c794b3Sgavinm uint64_t limit; 35520c794b3Sgavinm uint8_t way0, way1, rank0, rank1, rank2, rank3, branch_interleave; 35620c794b3Sgavinm int i, j, k; 35720c794b3Sgavinm uint8_t interleave; 35820c794b3Sgavinm 35920c794b3Sgavinm base = 0; 36020c794b3Sgavinm tolm = TOLM_RD(); 36120c794b3Sgavinm top_of_low_memory = ((uint32_t)(tolm >> 12) & 0xf) << 28; 36220c794b3Sgavinm for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) { 36320c794b3Sgavinm mir = MIR_RD(i); 36420c794b3Sgavinm limit = (uint64_t)(mir >> 4) << 28; 36520c794b3Sgavinm way0 = mir & 1; 36620c794b3Sgavinm way1 = (mir >> 1) & 1; 36720c794b3Sgavinm if (way0 == 0 && way1 == 0) { 36820c794b3Sgavinm way0 = 1; 36920c794b3Sgavinm way1 = 1; 37020c794b3Sgavinm } 37120c794b3Sgavinm if (limit > top_of_low_memory) 37220c794b3Sgavinm limit += TLOW_MAX - top_of_low_memory; 37320c794b3Sgavinm nb_banks[i].base = base; 37420c794b3Sgavinm nb_banks[i].limit = limit; 37520c794b3Sgavinm nb_banks[i].way[0] = way0; 37620c794b3Sgavinm nb_banks[i].way[1] = way1; 37720c794b3Sgavinm base = limit; 37820c794b3Sgavinm } 37920c794b3Sgavinm for (i = 0; i < nb_number_memory_controllers; i++) { 38020c794b3Sgavinm base = 0; 38120c794b3Sgavinm 38220c794b3Sgavinm for (j = 0; j < NB_MEM_RANK_SELECT; j++) { 38320c794b3Sgavinm dmir = DMIR_RD(i, j); 38420c794b3Sgavinm limit = ((uint64_t)(dmir >> 16) & 0xff) << 28; 38520c794b3Sgavinm if (limit == 0) { 38620c794b3Sgavinm limit = mc_range(i, base); 38720c794b3Sgavinm } 38820c794b3Sgavinm branch_interleave = 0; 38920c794b3Sgavinm hole_base = 0; 39020c794b3Sgavinm hole_size = 0; 3919d6aa643Saf DMIR_RANKS(dmir, rank0, rank1, rank2, rank3); 39220c794b3Sgavinm if (rank0 == rank1) 39320c794b3Sgavinm interleave = 1; 39420c794b3Sgavinm else if (rank0 == rank2) 39520c794b3Sgavinm interleave = 2; 39620c794b3Sgavinm else 39720c794b3Sgavinm interleave = 4; 39820c794b3Sgavinm if (nb_mode != NB_MEMORY_MIRROR && 39920c794b3Sgavinm nb_mode != NB_MEMORY_SINGLE_CHANNEL) { 40020c794b3Sgavinm for (k = 0; k < NB_MEM_BRANCH_SELECT; k++) { 40120c794b3Sgavinm if (base >= nb_banks[k].base && 40220c794b3Sgavinm base < nb_banks[k].limit) { 40320c794b3Sgavinm if (nb_banks[i].way[0] && 40420c794b3Sgavinm nb_banks[i].way[1]) { 40520c794b3Sgavinm interleave *= 2; 40620c794b3Sgavinm limit *= 2; 40720c794b3Sgavinm branch_interleave = 1; 40820c794b3Sgavinm } 40920c794b3Sgavinm break; 41020c794b3Sgavinm } 41120c794b3Sgavinm } 41220c794b3Sgavinm } 41320c794b3Sgavinm if (base < top_of_low_memory && 41420c794b3Sgavinm limit > top_of_low_memory) { 41520c794b3Sgavinm hole_base = top_of_low_memory; 41620c794b3Sgavinm hole_size = TLOW_MAX - top_of_low_memory; 41720c794b3Sgavinm limit += hole_size; 41820c794b3Sgavinm } else if (base > top_of_low_memory) { 41920c794b3Sgavinm limit += TLOW_MAX - top_of_low_memory; 42020c794b3Sgavinm } 42120c794b3Sgavinm nb_ranks[i][j].base = base; 42220c794b3Sgavinm nb_ranks[i][j].limit = limit; 42320c794b3Sgavinm nb_ranks[i][j].rank[0] = rank0; 42420c794b3Sgavinm nb_ranks[i][j].rank[1] = rank1; 42520c794b3Sgavinm nb_ranks[i][j].rank[2] = rank2; 42620c794b3Sgavinm nb_ranks[i][j].rank[3] = rank3; 42720c794b3Sgavinm nb_ranks[i][j].interleave = interleave; 42820c794b3Sgavinm nb_ranks[i][j].branch_interleave = branch_interleave; 42920c794b3Sgavinm nb_ranks[i][j].hole_base = hole_base; 43020c794b3Sgavinm nb_ranks[i][j].hole_size = hole_size; 43120c794b3Sgavinm if (limit > base) { 43220c794b3Sgavinm dimm_add_rank(i, rank0, branch_interleave, 0, 43320c794b3Sgavinm base, hole_base, hole_size, interleave, 43420c794b3Sgavinm limit); 43520c794b3Sgavinm if (rank0 != rank1) { 43620c794b3Sgavinm dimm_add_rank(i, rank1, 43720c794b3Sgavinm branch_interleave, 1, base, 43820c794b3Sgavinm hole_base, hole_size, interleave, 43920c794b3Sgavinm limit); 44020c794b3Sgavinm if (rank0 != rank2) { 44120c794b3Sgavinm dimm_add_rank(i, rank2, 44220c794b3Sgavinm branch_interleave, 2, base, 44320c794b3Sgavinm hole_base, hole_size, 44420c794b3Sgavinm interleave, limit); 44520c794b3Sgavinm dimm_add_rank(i, rank3, 44620c794b3Sgavinm branch_interleave, 3, base, 44720c794b3Sgavinm hole_base, hole_size, 44820c794b3Sgavinm interleave, limit); 44920c794b3Sgavinm } 45020c794b3Sgavinm } 45120c794b3Sgavinm } 45220c794b3Sgavinm base = limit; 45320c794b3Sgavinm } 45420c794b3Sgavinm } 45520c794b3Sgavinm } 45620c794b3Sgavinm 45720c794b3Sgavinm void 45820c794b3Sgavinm nb_used_spare_rank(int branch, int bad_rank) 45920c794b3Sgavinm { 46020c794b3Sgavinm int i; 46120c794b3Sgavinm int j; 46220c794b3Sgavinm 46320c794b3Sgavinm for (i = 0; i < NB_MEM_RANK_SELECT; i++) { 46420c794b3Sgavinm for (j = 0; j < NB_RANKS_IN_SELECT; j++) { 46520c794b3Sgavinm if (nb_ranks[branch][i].rank[j] == bad_rank) { 46620c794b3Sgavinm nb_ranks[branch][i].rank[j] = 46720c794b3Sgavinm spare_rank[branch]; 46820c794b3Sgavinm i = NB_MEM_RANK_SELECT; 46920c794b3Sgavinm break; 47020c794b3Sgavinm } 47120c794b3Sgavinm } 47220c794b3Sgavinm } 47320c794b3Sgavinm } 47420c794b3Sgavinm 4759d6aa643Saf find_dimm_label_t * 47620c794b3Sgavinm find_dimms_per_channel() 47720c794b3Sgavinm { 4789d6aa643Saf struct platform_label *pl; 4799d6aa643Saf smbios_info_t si; 4809d6aa643Saf smbios_system_t sy; 4819d6aa643Saf id_t id; 48230cfc677SAdrian Frost int i, j; 48330cfc677SAdrian Frost uint16_t mtr; 4849d6aa643Saf find_dimm_label_t *rt = NULL; 4859d6aa643Saf 48630cfc677SAdrian Frost if (ksmbios != NULL && nb_no_smbios == 0) { 4879d6aa643Saf if ((id = smbios_info_system(ksmbios, &sy)) != SMB_ERR && 4889d6aa643Saf smbios_info_common(ksmbios, id, &si) != SMB_ERR) { 4899d6aa643Saf for (pl = platform_label; pl->sys_vendor; pl++) { 4909d6aa643Saf if (strncmp(pl->sys_vendor, 4919d6aa643Saf si.smbi_manufacturer, 4929d6aa643Saf strlen(pl->sys_vendor)) == 0 && 4939d6aa643Saf strncmp(pl->sys_product, si.smbi_product, 4949d6aa643Saf strlen(pl->sys_product)) == 0) { 4959d6aa643Saf nb_dimms_per_channel = 4969d6aa643Saf pl->dimms_per_channel; 4979d6aa643Saf rt = &pl->dimm_label; 4989d6aa643Saf break; 4999d6aa643Saf } 5009d6aa643Saf } 5019d6aa643Saf } 5029d6aa643Saf } 5039d6aa643Saf if (nb_dimms_per_channel == 0) { 50430cfc677SAdrian Frost /* 50530cfc677SAdrian Frost * Scan all memory channels if we find a channel which has more 50630cfc677SAdrian Frost * dimms then we have seen before set nb_dimms_per_channel to 50730cfc677SAdrian Frost * the number of dimms on the channel 50830cfc677SAdrian Frost */ 50930cfc677SAdrian Frost for (i = 0; i < nb_number_memory_controllers; i++) { 51030cfc677SAdrian Frost for (j = nb_dimms_per_channel; 51130cfc677SAdrian Frost j < NB_MAX_DIMMS_PER_CHANNEL; j++) { 51230cfc677SAdrian Frost mtr = MTR_RD(i, j); 51330cfc677SAdrian Frost if (MTR_PRESENT(mtr)) 51430cfc677SAdrian Frost nb_dimms_per_channel = j + 1; 51530cfc677SAdrian Frost } 51620c794b3Sgavinm } 51720c794b3Sgavinm } 5189d6aa643Saf return (rt); 51920c794b3Sgavinm } 52020c794b3Sgavinm 521*9ff4cbe7SAdrian Frost struct smb_dimm_rec { 522*9ff4cbe7SAdrian Frost int dimms; 523*9ff4cbe7SAdrian Frost int slots; 524*9ff4cbe7SAdrian Frost int populated; 525*9ff4cbe7SAdrian Frost nb_dimm_t **dimmpp; 526*9ff4cbe7SAdrian Frost }; 527*9ff4cbe7SAdrian Frost 52820c794b3Sgavinm static int 52920c794b3Sgavinm dimm_label(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg) 53020c794b3Sgavinm { 531*9ff4cbe7SAdrian Frost struct smb_dimm_rec *rp = (struct smb_dimm_rec *)arg; 532*9ff4cbe7SAdrian Frost nb_dimm_t ***dimmpp; 53320c794b3Sgavinm nb_dimm_t *dimmp; 53420c794b3Sgavinm smbios_memdevice_t md; 53520c794b3Sgavinm 536*9ff4cbe7SAdrian Frost dimmpp = &rp->dimmpp; 53720c794b3Sgavinm if (sp->smbstr_type == SMB_TYPE_MEMDEVICE) { 53830cfc677SAdrian Frost if (*dimmpp >= &nb_dimms[nb_dimm_slots]) 53930cfc677SAdrian Frost return (-1); 54020c794b3Sgavinm dimmp = **dimmpp; 54130cfc677SAdrian Frost if (smbios_info_memdevice(shp, sp->smbstr_id, &md) == 0 && 54230cfc677SAdrian Frost md.smbmd_dloc != NULL) { 54330cfc677SAdrian Frost if (md.smbmd_size) { 544*9ff4cbe7SAdrian Frost if (dimmp == NULL && 545*9ff4cbe7SAdrian Frost (rp->slots == nb_dimm_slots || 546*9ff4cbe7SAdrian Frost rp->dimms < rp->populated)) { 547*9ff4cbe7SAdrian Frost (*dimmpp)++; 548*9ff4cbe7SAdrian Frost return (0); 549*9ff4cbe7SAdrian Frost } 55030cfc677SAdrian Frost /* 55130cfc677SAdrian Frost * if there is no physical dimm for this smbios 55230cfc677SAdrian Frost * record it is because this system has less 55330cfc677SAdrian Frost * physical slots than the controller supports 55430cfc677SAdrian Frost * so skip empty slots to find the slot this 55530cfc677SAdrian Frost * smbios record belongs too 55630cfc677SAdrian Frost */ 55730cfc677SAdrian Frost while (dimmp == NULL) { 558*9ff4cbe7SAdrian Frost (*dimmpp)++; 55930cfc677SAdrian Frost if (*dimmpp >= &nb_dimms[nb_dimm_slots]) 56030cfc677SAdrian Frost return (-1); 561*9ff4cbe7SAdrian Frost dimmp = **dimmpp; 56230cfc677SAdrian Frost } 56330cfc677SAdrian Frost (void) snprintf(dimmp->label, 56430cfc677SAdrian Frost sizeof (dimmp->label), "%s", md.smbmd_dloc); 56530cfc677SAdrian Frost (*dimmpp)++; 56630cfc677SAdrian Frost } 56720c794b3Sgavinm } 56820c794b3Sgavinm } 56920c794b3Sgavinm return (0); 57020c794b3Sgavinm } 57120c794b3Sgavinm 572*9ff4cbe7SAdrian Frost static int 573*9ff4cbe7SAdrian Frost check_memdevice(smbios_hdl_t *shp, const smbios_struct_t *sp, void *arg) 574*9ff4cbe7SAdrian Frost { 575*9ff4cbe7SAdrian Frost struct smb_dimm_rec *rp = (struct smb_dimm_rec *)arg; 576*9ff4cbe7SAdrian Frost smbios_memdevice_t md; 577*9ff4cbe7SAdrian Frost 578*9ff4cbe7SAdrian Frost if (sp->smbstr_type == SMB_TYPE_MEMDEVICE) { 579*9ff4cbe7SAdrian Frost if (smbios_info_memdevice(shp, sp->smbstr_id, &md) == 0) { 580*9ff4cbe7SAdrian Frost rp->slots++; 581*9ff4cbe7SAdrian Frost if (md.smbmd_size) { 582*9ff4cbe7SAdrian Frost rp->populated++; 583*9ff4cbe7SAdrian Frost } 584*9ff4cbe7SAdrian Frost } 585*9ff4cbe7SAdrian Frost } 586*9ff4cbe7SAdrian Frost return (0); 587*9ff4cbe7SAdrian Frost } 588*9ff4cbe7SAdrian Frost 58920c794b3Sgavinm void 59020c794b3Sgavinm nb_smbios() 59120c794b3Sgavinm { 592*9ff4cbe7SAdrian Frost struct smb_dimm_rec r; 593*9ff4cbe7SAdrian Frost int i; 59420c794b3Sgavinm 59530cfc677SAdrian Frost if (ksmbios != NULL && nb_no_smbios == 0) { 596*9ff4cbe7SAdrian Frost r.dimms = 0; 597*9ff4cbe7SAdrian Frost r.slots = 0; 598*9ff4cbe7SAdrian Frost r.populated = 0; 599*9ff4cbe7SAdrian Frost r.dimmpp = nb_dimms; 600*9ff4cbe7SAdrian Frost for (i = 0; i < nb_dimm_slots; i++) { 601*9ff4cbe7SAdrian Frost if (nb_dimms[i] != NULL) 602*9ff4cbe7SAdrian Frost r.dimms++; 603*9ff4cbe7SAdrian Frost } 604*9ff4cbe7SAdrian Frost (void) smbios_iter(ksmbios, check_memdevice, &r); 605*9ff4cbe7SAdrian Frost (void) smbios_iter(ksmbios, dimm_label, &r); 60620c794b3Sgavinm } 60720c794b3Sgavinm } 60820c794b3Sgavinm 60920c794b3Sgavinm static void 6109d6aa643Saf x8450_dimm_label(int dimm, char *label, int label_sz) 61120c794b3Sgavinm { 6129d6aa643Saf int channel = dimm >> 3; 6139d6aa643Saf 6149d6aa643Saf dimm = dimm & 0x7; 6159d6aa643Saf (void) snprintf(label, label_sz, "D%d", (dimm * 4) + channel); 6169d6aa643Saf } 6179d6aa643Saf 6189d6aa643Saf static void 6199d6aa643Saf nb_dimms_init(find_dimm_label_t *label_function) 6209d6aa643Saf { 6219d6aa643Saf int i, j, k, l; 62220c794b3Sgavinm uint16_t mtr; 62320c794b3Sgavinm uint32_t mc, mca; 62420c794b3Sgavinm uint32_t spcpc; 62520c794b3Sgavinm uint8_t spcps; 62620c794b3Sgavinm nb_dimm_t **dimmpp; 62720c794b3Sgavinm 62820c794b3Sgavinm mca = MCA_RD(); 62920c794b3Sgavinm mc = MC_RD(); 63020c794b3Sgavinm if (mca & MCA_SCHDIMM) /* single-channel mode */ 63120c794b3Sgavinm nb_mode = NB_MEMORY_SINGLE_CHANNEL; 63220c794b3Sgavinm else if ((mc & MC_MIRROR) != 0) /* mirror mode */ 63320c794b3Sgavinm nb_mode = NB_MEMORY_MIRROR; 63420c794b3Sgavinm else 63520c794b3Sgavinm nb_mode = NB_MEMORY_NORMAL; 63630cfc677SAdrian Frost nb_dimm_slots = nb_number_memory_controllers * 2 * nb_dimms_per_channel; 63720c794b3Sgavinm nb_dimms = (nb_dimm_t **)kmem_zalloc(sizeof (nb_dimm_t *) * 63830cfc677SAdrian Frost nb_dimm_slots, KM_SLEEP); 63920c794b3Sgavinm dimmpp = nb_dimms; 64020c794b3Sgavinm for (i = 0; i < nb_number_memory_controllers; i++) { 64120c794b3Sgavinm if (nb_mode == NB_MEMORY_NORMAL) { 64220c794b3Sgavinm spcpc = SPCPC_RD(i); 64320c794b3Sgavinm spcps = SPCPS_RD(i); 64420c794b3Sgavinm if ((spcpc & SPCPC_SPARE_ENABLE) != 0 && 64520c794b3Sgavinm (spcps & SPCPS_SPARE_DEPLOYED) != 0) 64620c794b3Sgavinm nb_mode = NB_MEMORY_SPARE_RANK; 64720c794b3Sgavinm spare_rank[i] = SPCPC_SPRANK(spcpc); 64820c794b3Sgavinm } 64920c794b3Sgavinm for (j = 0; j < nb_dimms_per_channel; j++) { 65020c794b3Sgavinm mtr = MTR_RD(i, j); 65120c794b3Sgavinm k = i * 2; 65220c794b3Sgavinm dimmpp[j] = nb_dimm_init(k, j, mtr); 65320c794b3Sgavinm if (dimmpp[j]) { 65420c794b3Sgavinm nb_ndimm ++; 65520c794b3Sgavinm dimm_add_geometry(i, j, dimmpp[j]->nbanks, 65620c794b3Sgavinm dimmpp[j]->width, dimmpp[j]->ncolumn, 65720c794b3Sgavinm dimmpp[j]->nrow); 6589d6aa643Saf if (label_function) { 6599d6aa643Saf label_function->label_function( 6609d6aa643Saf (k * nb_dimms_per_channel) + j, 6619d6aa643Saf dimmpp[j]->label, 6629d6aa643Saf sizeof (dimmpp[j]->label)); 6639d6aa643Saf } 66420c794b3Sgavinm } 66520c794b3Sgavinm dimmpp[j + nb_dimms_per_channel] = 66620c794b3Sgavinm nb_dimm_init(k + 1, j, mtr); 6679d6aa643Saf l = j + nb_dimms_per_channel; 6689d6aa643Saf if (dimmpp[l]) { 6699d6aa643Saf if (label_function) { 6709d6aa643Saf label_function->label_function( 6719d6aa643Saf (k * nb_dimms_per_channel) + l, 6729d6aa643Saf dimmpp[l]->label, 6739d6aa643Saf sizeof (dimmpp[l]->label)); 6749d6aa643Saf } 67520c794b3Sgavinm nb_ndimm ++; 6769d6aa643Saf } 67720c794b3Sgavinm } 67820c794b3Sgavinm dimmpp += nb_dimms_per_channel * 2; 67920c794b3Sgavinm } 6809d6aa643Saf if (label_function == NULL) 6819d6aa643Saf nb_smbios(); 68220c794b3Sgavinm } 68320c794b3Sgavinm 6843221df98SKrishna Elango 6853221df98SKrishna Elango /* Setup the ESI port registers to enable SERR for southbridge */ 68620c794b3Sgavinm static void 68720c794b3Sgavinm nb_pex_init() 68820c794b3Sgavinm { 6893221df98SKrishna Elango int i = 0; /* ESI port */ 6903221df98SKrishna Elango uint16_t regw; 6913221df98SKrishna Elango 6923221df98SKrishna Elango emask_uncor_pex[i] = EMASK_UNCOR_PEX_RD(i); 6933221df98SKrishna Elango emask_cor_pex[i] = EMASK_COR_PEX_RD(i); 6943221df98SKrishna Elango emask_rp_pex[i] = EMASK_RP_PEX_RD(i); 6953221df98SKrishna Elango docmd_pex[i] = PEX_ERR_DOCMD_RD(i); 6963221df98SKrishna Elango uncerrsev[i] = UNCERRSEV_RD(i); 6973221df98SKrishna Elango 6983221df98SKrishna Elango if (nb5000_reset_uncor_pex) 6993221df98SKrishna Elango EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex); 7003221df98SKrishna Elango if (nb5000_reset_cor_pex) 7013221df98SKrishna Elango EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex); 702*9ff4cbe7SAdrian Frost if (nb_chipset == INTEL_NB_5400) { 703*9ff4cbe7SAdrian Frost /* disable masking of ERR pins used by DOCMD */ 704*9ff4cbe7SAdrian Frost PEX_ERR_PIN_MASK_WR(i, 0x10); 7053221df98SKrishna Elango } 7069a12e1bdSjveta 7073221df98SKrishna Elango /* RP error message (CE/NFE/FE) detect mask */ 7083221df98SKrishna Elango EMASK_RP_PEX_WR(i, nb5000_rp_pex); 7099a12e1bdSjveta 7103221df98SKrishna Elango /* Command Register - Enable SERR */ 7113221df98SKrishna Elango regw = nb_pci_getw(0, i, 0, PCI_CONF_COMM, 0); 7123221df98SKrishna Elango nb_pci_putw(0, i, 0, PCI_CONF_COMM, 7133221df98SKrishna Elango regw | PCI_COMM_SERR_ENABLE); 7149a12e1bdSjveta 7153221df98SKrishna Elango /* Root Control Register - SERR on NFE/FE */ 7163221df98SKrishna Elango PEXROOTCTL_WR(i, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | 7173221df98SKrishna Elango PCIE_ROOTCTL_SYS_ERR_ON_FE_EN); 7189a12e1bdSjveta 7193221df98SKrishna Elango /* AER UE Mask - Mask UR */ 7203221df98SKrishna Elango UNCERRMSK_WR(i, PCIE_AER_UCE_UR); 72120c794b3Sgavinm } 72220c794b3Sgavinm 72320c794b3Sgavinm static void 72420c794b3Sgavinm nb_pex_fini() 72520c794b3Sgavinm { 7263221df98SKrishna Elango int i = 0; /* ESI port */ 72720c794b3Sgavinm 7283221df98SKrishna Elango EMASK_UNCOR_PEX_WR(i, emask_uncor_pex[i]); 7293221df98SKrishna Elango EMASK_COR_PEX_WR(i, emask_cor_pex[i]); 7303221df98SKrishna Elango EMASK_RP_PEX_WR(i, emask_rp_pex[i]); 7313221df98SKrishna Elango PEX_ERR_DOCMD_WR(i, docmd_pex[i]); 7323221df98SKrishna Elango 7333221df98SKrishna Elango if (nb5000_reset_uncor_pex) 7343221df98SKrishna Elango EMASK_UNCOR_PEX_WR(i, nb5000_mask_uncor_pex); 7353221df98SKrishna Elango if (nb5000_reset_cor_pex) 7363221df98SKrishna Elango EMASK_COR_PEX_WR(i, nb5000_mask_cor_pex); 73720c794b3Sgavinm } 73820c794b3Sgavinm 73920c794b3Sgavinm void 74020c794b3Sgavinm nb_int_init() 74120c794b3Sgavinm { 742*9ff4cbe7SAdrian Frost uint32_t err0_int; 743*9ff4cbe7SAdrian Frost uint32_t err1_int; 744*9ff4cbe7SAdrian Frost uint32_t err2_int; 745*9ff4cbe7SAdrian Frost uint32_t mcerr_int; 7465f28a827Saf uint32_t emask_int; 74720c794b3Sgavinm uint16_t stepping; 74820c794b3Sgavinm 74920c794b3Sgavinm err0_int = ERR0_INT_RD(); 75020c794b3Sgavinm err1_int = ERR1_INT_RD(); 75120c794b3Sgavinm err2_int = ERR2_INT_RD(); 75220c794b3Sgavinm mcerr_int = MCERR_INT_RD(); 75320c794b3Sgavinm emask_int = EMASK_INT_RD(); 75420c794b3Sgavinm 75520c794b3Sgavinm nb_err0_int = err0_int; 75620c794b3Sgavinm nb_err1_int = err1_int; 75720c794b3Sgavinm nb_err2_int = err2_int; 75820c794b3Sgavinm nb_mcerr_int = mcerr_int; 75920c794b3Sgavinm nb_emask_int = emask_int; 76020c794b3Sgavinm 761*9ff4cbe7SAdrian Frost ERR0_INT_WR(ERR_INT_ALL); 762*9ff4cbe7SAdrian Frost ERR1_INT_WR(ERR_INT_ALL); 763*9ff4cbe7SAdrian Frost ERR2_INT_WR(ERR_INT_ALL); 764*9ff4cbe7SAdrian Frost MCERR_INT_WR(ERR_INT_ALL); 765*9ff4cbe7SAdrian Frost EMASK_INT_WR(ERR_INT_ALL); 76620c794b3Sgavinm 76720c794b3Sgavinm mcerr_int &= ~nb5000_mask_bios_int; 76820c794b3Sgavinm mcerr_int |= nb5000_mask_bios_int & (~err0_int | ~err1_int | ~err2_int); 76920c794b3Sgavinm mcerr_int |= nb5000_mask_poll_int; 77020c794b3Sgavinm err0_int |= nb5000_mask_poll_int; 77120c794b3Sgavinm err1_int |= nb5000_mask_poll_int; 77220c794b3Sgavinm err2_int |= nb5000_mask_poll_int; 77320c794b3Sgavinm 77420c794b3Sgavinm l_mcerr_int = mcerr_int; 77520c794b3Sgavinm ERR0_INT_WR(err0_int); 77620c794b3Sgavinm ERR1_INT_WR(err1_int); 77720c794b3Sgavinm ERR2_INT_WR(err2_int); 77820c794b3Sgavinm MCERR_INT_WR(mcerr_int); 77920c794b3Sgavinm if (nb5000_reset_emask_int) { 78020c794b3Sgavinm if (nb_chipset == INTEL_NB_7300) { 78120c794b3Sgavinm stepping = NB5000_STEPPING(); 78220c794b3Sgavinm if (stepping == 0) 7835f28a827Saf EMASK_5000_INT_WR(nb7300_emask_int_step0); 78420c794b3Sgavinm else 7855f28a827Saf EMASK_5000_INT_WR(nb7300_emask_int); 7865f28a827Saf } else if (nb_chipset == INTEL_NB_5400) { 7875f28a827Saf EMASK_5400_INT_WR(nb5400_emask_int | 7885f28a827Saf (emask_int & EMASK_INT_RES)); 78920c794b3Sgavinm } else { 7905f28a827Saf EMASK_5000_INT_WR(nb5000_emask_int); 79120c794b3Sgavinm } 79220c794b3Sgavinm } else { 79320c794b3Sgavinm EMASK_INT_WR(nb_emask_int); 79420c794b3Sgavinm } 79520c794b3Sgavinm } 79620c794b3Sgavinm 79720c794b3Sgavinm void 79820c794b3Sgavinm nb_int_fini() 79920c794b3Sgavinm { 800*9ff4cbe7SAdrian Frost ERR0_INT_WR(ERR_INT_ALL); 801*9ff4cbe7SAdrian Frost ERR1_INT_WR(ERR_INT_ALL); 802*9ff4cbe7SAdrian Frost ERR2_INT_WR(ERR_INT_ALL); 803*9ff4cbe7SAdrian Frost MCERR_INT_WR(ERR_INT_ALL); 804*9ff4cbe7SAdrian Frost EMASK_INT_WR(ERR_INT_ALL); 80520c794b3Sgavinm 80620c794b3Sgavinm ERR0_INT_WR(nb_err0_int); 80720c794b3Sgavinm ERR1_INT_WR(nb_err1_int); 80820c794b3Sgavinm ERR2_INT_WR(nb_err2_int); 80920c794b3Sgavinm MCERR_INT_WR(nb_mcerr_int); 81020c794b3Sgavinm EMASK_INT_WR(nb_emask_int); 81120c794b3Sgavinm } 81220c794b3Sgavinm 81320c794b3Sgavinm void 8145f28a827Saf nb_int_mask_mc(uint32_t mc_mask_int) 81520c794b3Sgavinm { 8165f28a827Saf uint32_t emask_int; 81720c794b3Sgavinm 81820c794b3Sgavinm emask_int = MCERR_INT_RD(); 81920c794b3Sgavinm if ((emask_int & mc_mask_int) != mc_mask_int) { 82020c794b3Sgavinm MCERR_INT_WR(emask_int|mc_mask_int); 82120c794b3Sgavinm nb_mask_mc_set = 1; 82220c794b3Sgavinm } 82320c794b3Sgavinm } 82420c794b3Sgavinm 82520c794b3Sgavinm void 82620c794b3Sgavinm nb_fbd_init() 82720c794b3Sgavinm { 82820c794b3Sgavinm uint32_t err0_fbd; 82920c794b3Sgavinm uint32_t err1_fbd; 83020c794b3Sgavinm uint32_t err2_fbd; 83120c794b3Sgavinm uint32_t mcerr_fbd; 83220c794b3Sgavinm uint32_t emask_fbd; 8335f28a827Saf uint32_t emask_bios_fbd; 8345f28a827Saf uint32_t emask_poll_fbd; 83520c794b3Sgavinm 83620c794b3Sgavinm err0_fbd = ERR0_FBD_RD(); 83720c794b3Sgavinm err1_fbd = ERR1_FBD_RD(); 83820c794b3Sgavinm err2_fbd = ERR2_FBD_RD(); 83920c794b3Sgavinm mcerr_fbd = MCERR_FBD_RD(); 84020c794b3Sgavinm emask_fbd = EMASK_FBD_RD(); 84120c794b3Sgavinm 84220c794b3Sgavinm nb_err0_fbd = err0_fbd; 84320c794b3Sgavinm nb_err1_fbd = err1_fbd; 84420c794b3Sgavinm nb_err2_fbd = err2_fbd; 84520c794b3Sgavinm nb_mcerr_fbd = mcerr_fbd; 84620c794b3Sgavinm nb_emask_fbd = emask_fbd; 84720c794b3Sgavinm 84820c794b3Sgavinm ERR0_FBD_WR(0xffffffff); 84920c794b3Sgavinm ERR1_FBD_WR(0xffffffff); 85020c794b3Sgavinm ERR2_FBD_WR(0xffffffff); 85120c794b3Sgavinm MCERR_FBD_WR(0xffffffff); 85220c794b3Sgavinm EMASK_FBD_WR(0xffffffff); 85320c794b3Sgavinm 85420c794b3Sgavinm if (nb_chipset == INTEL_NB_7300 && nb_mode == NB_MEMORY_MIRROR) { 85520c794b3Sgavinm /* MCH 7300 errata 34 */ 8565f28a827Saf emask_bios_fbd = nb5000_mask_bios_fbd & ~EMASK_FBD_M23; 8575f28a827Saf emask_poll_fbd = nb5000_mask_poll_fbd; 85820c794b3Sgavinm mcerr_fbd |= EMASK_FBD_M23; 8595f28a827Saf } else if (nb_chipset == INTEL_NB_5400) { 8605f28a827Saf emask_bios_fbd = nb5400_mask_bios_fbd; 8615f28a827Saf emask_poll_fbd = nb5400_mask_poll_fbd; 8625f28a827Saf } else { 8635f28a827Saf emask_bios_fbd = nb5000_mask_bios_fbd; 8645f28a827Saf emask_poll_fbd = nb5000_mask_poll_fbd; 86520c794b3Sgavinm } 8665f28a827Saf mcerr_fbd &= ~emask_bios_fbd; 8675f28a827Saf mcerr_fbd |= emask_bios_fbd & (~err0_fbd | ~err1_fbd | ~err2_fbd); 8685f28a827Saf mcerr_fbd |= emask_poll_fbd; 8695f28a827Saf err0_fbd |= emask_poll_fbd; 8705f28a827Saf err1_fbd |= emask_poll_fbd; 8715f28a827Saf err2_fbd |= emask_poll_fbd; 87220c794b3Sgavinm 87320c794b3Sgavinm l_mcerr_fbd = mcerr_fbd; 87420c794b3Sgavinm ERR0_FBD_WR(err0_fbd); 87520c794b3Sgavinm ERR1_FBD_WR(err1_fbd); 87620c794b3Sgavinm ERR2_FBD_WR(err2_fbd); 87720c794b3Sgavinm MCERR_FBD_WR(mcerr_fbd); 8785f28a827Saf if (nb5000_reset_emask_fbd) { 8795f28a827Saf if (nb_chipset == INTEL_NB_5400) 8805f28a827Saf EMASK_FBD_WR(nb5400_emask_fbd); 8815f28a827Saf else 8825f28a827Saf EMASK_FBD_WR(nb5000_emask_fbd); 8835f28a827Saf } else { 88420c794b3Sgavinm EMASK_FBD_WR(nb_emask_fbd); 8855f28a827Saf } 88620c794b3Sgavinm } 88720c794b3Sgavinm 88820c794b3Sgavinm void 88920c794b3Sgavinm nb_fbd_mask_mc(uint32_t mc_mask_fbd) 89020c794b3Sgavinm { 89120c794b3Sgavinm uint32_t emask_fbd; 89220c794b3Sgavinm 89320c794b3Sgavinm emask_fbd = MCERR_FBD_RD(); 89420c794b3Sgavinm if ((emask_fbd & mc_mask_fbd) != mc_mask_fbd) { 89520c794b3Sgavinm MCERR_FBD_WR(emask_fbd|mc_mask_fbd); 89620c794b3Sgavinm nb_mask_mc_set = 1; 89720c794b3Sgavinm } 89820c794b3Sgavinm } 89920c794b3Sgavinm 90020c794b3Sgavinm void 90120c794b3Sgavinm nb_fbd_fini() 90220c794b3Sgavinm { 90320c794b3Sgavinm ERR0_FBD_WR(0xffffffff); 90420c794b3Sgavinm ERR1_FBD_WR(0xffffffff); 90520c794b3Sgavinm ERR2_FBD_WR(0xffffffff); 90620c794b3Sgavinm MCERR_FBD_WR(0xffffffff); 90720c794b3Sgavinm EMASK_FBD_WR(0xffffffff); 90820c794b3Sgavinm 90920c794b3Sgavinm ERR0_FBD_WR(nb_err0_fbd); 91020c794b3Sgavinm ERR1_FBD_WR(nb_err1_fbd); 91120c794b3Sgavinm ERR2_FBD_WR(nb_err2_fbd); 91220c794b3Sgavinm MCERR_FBD_WR(nb_mcerr_fbd); 91320c794b3Sgavinm EMASK_FBD_WR(nb_emask_fbd); 91420c794b3Sgavinm } 91520c794b3Sgavinm 91620c794b3Sgavinm static void 91720c794b3Sgavinm nb_fsb_init() 91820c794b3Sgavinm { 91920c794b3Sgavinm uint16_t err0_fsb; 92020c794b3Sgavinm uint16_t err1_fsb; 92120c794b3Sgavinm uint16_t err2_fsb; 92220c794b3Sgavinm uint16_t mcerr_fsb; 92320c794b3Sgavinm uint16_t emask_fsb; 92420c794b3Sgavinm 92520c794b3Sgavinm err0_fsb = ERR0_FSB_RD(0); 92620c794b3Sgavinm err1_fsb = ERR1_FSB_RD(0); 92720c794b3Sgavinm err2_fsb = ERR2_FSB_RD(0); 92820c794b3Sgavinm mcerr_fsb = MCERR_FSB_RD(0); 92920c794b3Sgavinm emask_fsb = EMASK_FSB_RD(0); 93020c794b3Sgavinm 93120c794b3Sgavinm ERR0_FSB_WR(0, 0xffff); 93220c794b3Sgavinm ERR1_FSB_WR(0, 0xffff); 93320c794b3Sgavinm ERR2_FSB_WR(0, 0xffff); 93420c794b3Sgavinm MCERR_FSB_WR(0, 0xffff); 93520c794b3Sgavinm EMASK_FSB_WR(0, 0xffff); 93620c794b3Sgavinm 93720c794b3Sgavinm ERR0_FSB_WR(1, 0xffff); 93820c794b3Sgavinm ERR1_FSB_WR(1, 0xffff); 93920c794b3Sgavinm ERR2_FSB_WR(1, 0xffff); 94020c794b3Sgavinm MCERR_FSB_WR(1, 0xffff); 94120c794b3Sgavinm EMASK_FSB_WR(1, 0xffff); 94220c794b3Sgavinm 94320c794b3Sgavinm nb_err0_fsb = err0_fsb; 94420c794b3Sgavinm nb_err1_fsb = err1_fsb; 94520c794b3Sgavinm nb_err2_fsb = err2_fsb; 94620c794b3Sgavinm nb_mcerr_fsb = mcerr_fsb; 94720c794b3Sgavinm nb_emask_fsb = emask_fsb; 94820c794b3Sgavinm 94920c794b3Sgavinm mcerr_fsb &= ~nb5000_mask_bios_fsb; 95020c794b3Sgavinm mcerr_fsb |= nb5000_mask_bios_fsb & (~err2_fsb | ~err1_fsb | ~err0_fsb); 95120c794b3Sgavinm mcerr_fsb |= nb5000_mask_poll_fsb; 95220c794b3Sgavinm err0_fsb |= nb5000_mask_poll_fsb; 95320c794b3Sgavinm err1_fsb |= nb5000_mask_poll_fsb; 95420c794b3Sgavinm err2_fsb |= nb5000_mask_poll_fsb; 95520c794b3Sgavinm 95620c794b3Sgavinm l_mcerr_fsb = mcerr_fsb; 95720c794b3Sgavinm ERR0_FSB_WR(0, err0_fsb); 95820c794b3Sgavinm ERR1_FSB_WR(0, err1_fsb); 95920c794b3Sgavinm ERR2_FSB_WR(0, err2_fsb); 96020c794b3Sgavinm MCERR_FSB_WR(0, mcerr_fsb); 9615f28a827Saf if (nb5000_reset_emask_fsb) { 96220c794b3Sgavinm EMASK_FSB_WR(0, nb5000_emask_fsb); 9635f28a827Saf } else { 96420c794b3Sgavinm EMASK_FSB_WR(0, nb_emask_fsb); 9655f28a827Saf } 96620c794b3Sgavinm 96720c794b3Sgavinm ERR0_FSB_WR(1, err0_fsb); 96820c794b3Sgavinm ERR1_FSB_WR(1, err1_fsb); 96920c794b3Sgavinm ERR2_FSB_WR(1, err2_fsb); 97020c794b3Sgavinm MCERR_FSB_WR(1, mcerr_fsb); 9715f28a827Saf if (nb5000_reset_emask_fsb) { 97220c794b3Sgavinm EMASK_FSB_WR(1, nb5000_emask_fsb); 9735f28a827Saf } else { 97420c794b3Sgavinm EMASK_FSB_WR(1, nb_emask_fsb); 9755f28a827Saf } 97620c794b3Sgavinm 97720c794b3Sgavinm if (nb_chipset == INTEL_NB_7300) { 97820c794b3Sgavinm ERR0_FSB_WR(2, 0xffff); 97920c794b3Sgavinm ERR1_FSB_WR(2, 0xffff); 98020c794b3Sgavinm ERR2_FSB_WR(2, 0xffff); 98120c794b3Sgavinm MCERR_FSB_WR(2, 0xffff); 98220c794b3Sgavinm EMASK_FSB_WR(2, 0xffff); 98320c794b3Sgavinm 98420c794b3Sgavinm ERR0_FSB_WR(3, 0xffff); 98520c794b3Sgavinm ERR1_FSB_WR(3, 0xffff); 98620c794b3Sgavinm ERR2_FSB_WR(3, 0xffff); 98720c794b3Sgavinm MCERR_FSB_WR(3, 0xffff); 98820c794b3Sgavinm EMASK_FSB_WR(3, 0xffff); 98920c794b3Sgavinm 99020c794b3Sgavinm ERR0_FSB_WR(2, err0_fsb); 99120c794b3Sgavinm ERR1_FSB_WR(2, err1_fsb); 99220c794b3Sgavinm ERR2_FSB_WR(2, err2_fsb); 99320c794b3Sgavinm MCERR_FSB_WR(2, mcerr_fsb); 9945f28a827Saf if (nb5000_reset_emask_fsb) { 99520c794b3Sgavinm EMASK_FSB_WR(2, nb5000_emask_fsb); 9965f28a827Saf } else { 99720c794b3Sgavinm EMASK_FSB_WR(2, nb_emask_fsb); 9985f28a827Saf } 99920c794b3Sgavinm 100020c794b3Sgavinm ERR0_FSB_WR(3, err0_fsb); 100120c794b3Sgavinm ERR1_FSB_WR(3, err1_fsb); 100220c794b3Sgavinm ERR2_FSB_WR(3, err2_fsb); 100320c794b3Sgavinm MCERR_FSB_WR(3, mcerr_fsb); 10045f28a827Saf if (nb5000_reset_emask_fsb) { 100520c794b3Sgavinm EMASK_FSB_WR(3, nb5000_emask_fsb); 10065f28a827Saf } else { 100720c794b3Sgavinm EMASK_FSB_WR(3, nb_emask_fsb); 10085f28a827Saf } 100920c794b3Sgavinm } 101020c794b3Sgavinm } 101120c794b3Sgavinm 101220c794b3Sgavinm static void 101320c794b3Sgavinm nb_fsb_fini() { 101420c794b3Sgavinm ERR0_FSB_WR(0, 0xffff); 101520c794b3Sgavinm ERR1_FSB_WR(0, 0xffff); 101620c794b3Sgavinm ERR2_FSB_WR(0, 0xffff); 101720c794b3Sgavinm MCERR_FSB_WR(0, 0xffff); 101820c794b3Sgavinm EMASK_FSB_WR(0, 0xffff); 101920c794b3Sgavinm 102020c794b3Sgavinm ERR0_FSB_WR(0, nb_err0_fsb); 102120c794b3Sgavinm ERR1_FSB_WR(0, nb_err1_fsb); 102220c794b3Sgavinm ERR2_FSB_WR(0, nb_err2_fsb); 102320c794b3Sgavinm MCERR_FSB_WR(0, nb_mcerr_fsb); 102420c794b3Sgavinm EMASK_FSB_WR(0, nb_emask_fsb); 102520c794b3Sgavinm 102620c794b3Sgavinm ERR0_FSB_WR(1, 0xffff); 102720c794b3Sgavinm ERR1_FSB_WR(1, 0xffff); 102820c794b3Sgavinm ERR2_FSB_WR(1, 0xffff); 102920c794b3Sgavinm MCERR_FSB_WR(1, 0xffff); 103020c794b3Sgavinm EMASK_FSB_WR(1, 0xffff); 103120c794b3Sgavinm 103220c794b3Sgavinm ERR0_FSB_WR(1, nb_err0_fsb); 103320c794b3Sgavinm ERR1_FSB_WR(1, nb_err1_fsb); 103420c794b3Sgavinm ERR2_FSB_WR(1, nb_err2_fsb); 103520c794b3Sgavinm MCERR_FSB_WR(1, nb_mcerr_fsb); 103620c794b3Sgavinm EMASK_FSB_WR(1, nb_emask_fsb); 103720c794b3Sgavinm 103820c794b3Sgavinm if (nb_chipset == INTEL_NB_7300) { 103920c794b3Sgavinm ERR0_FSB_WR(2, 0xffff); 104020c794b3Sgavinm ERR1_FSB_WR(2, 0xffff); 104120c794b3Sgavinm ERR2_FSB_WR(2, 0xffff); 104220c794b3Sgavinm MCERR_FSB_WR(2, 0xffff); 104320c794b3Sgavinm EMASK_FSB_WR(2, 0xffff); 104420c794b3Sgavinm 104520c794b3Sgavinm ERR0_FSB_WR(2, nb_err0_fsb); 104620c794b3Sgavinm ERR1_FSB_WR(2, nb_err1_fsb); 104720c794b3Sgavinm ERR2_FSB_WR(2, nb_err2_fsb); 104820c794b3Sgavinm MCERR_FSB_WR(2, nb_mcerr_fsb); 104920c794b3Sgavinm EMASK_FSB_WR(2, nb_emask_fsb); 105020c794b3Sgavinm 105120c794b3Sgavinm ERR0_FSB_WR(3, 0xffff); 105220c794b3Sgavinm ERR1_FSB_WR(3, 0xffff); 105320c794b3Sgavinm ERR2_FSB_WR(3, 0xffff); 105420c794b3Sgavinm MCERR_FSB_WR(3, 0xffff); 105520c794b3Sgavinm EMASK_FSB_WR(3, 0xffff); 105620c794b3Sgavinm 105720c794b3Sgavinm ERR0_FSB_WR(3, nb_err0_fsb); 105820c794b3Sgavinm ERR1_FSB_WR(3, nb_err1_fsb); 105920c794b3Sgavinm ERR2_FSB_WR(3, nb_err2_fsb); 106020c794b3Sgavinm MCERR_FSB_WR(3, nb_mcerr_fsb); 106120c794b3Sgavinm EMASK_FSB_WR(3, nb_emask_fsb); 106220c794b3Sgavinm } 106320c794b3Sgavinm } 106420c794b3Sgavinm 106520c794b3Sgavinm void 106620c794b3Sgavinm nb_fsb_mask_mc(int fsb, uint16_t mc_mask_fsb) 106720c794b3Sgavinm { 106820c794b3Sgavinm uint16_t emask_fsb; 106920c794b3Sgavinm 107020c794b3Sgavinm emask_fsb = MCERR_FSB_RD(fsb); 107120c794b3Sgavinm if ((emask_fsb & mc_mask_fsb) != mc_mask_fsb) { 107220c794b3Sgavinm MCERR_FSB_WR(fsb, emask_fsb|mc_mask_fsb|EMASK_FBD_RES); 107320c794b3Sgavinm nb_mask_mc_set = 1; 107420c794b3Sgavinm } 107520c794b3Sgavinm } 107620c794b3Sgavinm 10775f28a827Saf static void 10785f28a827Saf nb_thr_init() 10795f28a827Saf { 10805f28a827Saf uint16_t err0_thr; 10815f28a827Saf uint16_t err1_thr; 10825f28a827Saf uint16_t err2_thr; 10835f28a827Saf uint16_t mcerr_thr; 10845f28a827Saf uint16_t emask_thr; 10855f28a827Saf 10865f28a827Saf if (nb_chipset == INTEL_NB_5400) { 10875f28a827Saf err0_thr = ERR0_THR_RD(0); 10885f28a827Saf err1_thr = ERR1_THR_RD(0); 10895f28a827Saf err2_thr = ERR2_THR_RD(0); 10905f28a827Saf mcerr_thr = MCERR_THR_RD(0); 10915f28a827Saf emask_thr = EMASK_THR_RD(0); 10925f28a827Saf 10935f28a827Saf ERR0_THR_WR(0xffff); 10945f28a827Saf ERR1_THR_WR(0xffff); 10955f28a827Saf ERR2_THR_WR(0xffff); 10965f28a827Saf MCERR_THR_WR(0xffff); 10975f28a827Saf EMASK_THR_WR(0xffff); 10985f28a827Saf 10995f28a827Saf nb_err0_thr = err0_thr; 11005f28a827Saf nb_err1_thr = err1_thr; 11015f28a827Saf nb_err2_thr = err2_thr; 11025f28a827Saf nb_mcerr_thr = mcerr_thr; 11035f28a827Saf nb_emask_thr = emask_thr; 11045f28a827Saf 11055f28a827Saf mcerr_thr &= ~nb_mask_bios_thr; 11065f28a827Saf mcerr_thr |= nb_mask_bios_thr & 11075f28a827Saf (~err2_thr | ~err1_thr | ~err0_thr); 11085f28a827Saf mcerr_thr |= nb_mask_poll_thr; 11095f28a827Saf err0_thr |= nb_mask_poll_thr; 11105f28a827Saf err1_thr |= nb_mask_poll_thr; 11115f28a827Saf err2_thr |= nb_mask_poll_thr; 11125f28a827Saf 11135f28a827Saf l_mcerr_thr = mcerr_thr; 11145f28a827Saf ERR0_THR_WR(err0_thr); 11155f28a827Saf ERR1_THR_WR(err1_thr); 11165f28a827Saf ERR2_THR_WR(err2_thr); 11175f28a827Saf MCERR_THR_WR(mcerr_thr); 11185f28a827Saf EMASK_THR_WR(nb_emask_thr); 11195f28a827Saf } 11205f28a827Saf } 11215f28a827Saf 11225f28a827Saf static void 11235f28a827Saf nb_thr_fini() 11245f28a827Saf { 11255f28a827Saf if (nb_chipset == INTEL_NB_5400) { 11265f28a827Saf ERR0_THR_WR(0xffff); 11275f28a827Saf ERR1_THR_WR(0xffff); 11285f28a827Saf ERR2_THR_WR(0xffff); 11295f28a827Saf MCERR_THR_WR(0xffff); 11305f28a827Saf EMASK_THR_WR(0xffff); 11315f28a827Saf 11325f28a827Saf ERR0_THR_WR(nb_err0_thr); 11335f28a827Saf ERR1_THR_WR(nb_err1_thr); 11345f28a827Saf ERR2_THR_WR(nb_err2_thr); 11355f28a827Saf MCERR_THR_WR(nb_mcerr_thr); 11365f28a827Saf EMASK_THR_WR(nb_emask_thr); 11375f28a827Saf } 11385f28a827Saf } 11395f28a827Saf 11405f28a827Saf void 11415f28a827Saf nb_thr_mask_mc(uint16_t mc_mask_thr) 11425f28a827Saf { 11435f28a827Saf uint16_t emask_thr; 11445f28a827Saf 11455f28a827Saf emask_thr = MCERR_THR_RD(0); 11465f28a827Saf if ((emask_thr & mc_mask_thr) != mc_mask_thr) { 11475f28a827Saf MCERR_THR_WR(emask_thr|mc_mask_thr); 11485f28a827Saf nb_mask_mc_set = 1; 11495f28a827Saf } 11505f28a827Saf } 11515f28a827Saf 115220c794b3Sgavinm void 115320c794b3Sgavinm nb_mask_mc_reset() 115420c794b3Sgavinm { 115520c794b3Sgavinm MCERR_FBD_WR(l_mcerr_fbd); 115620c794b3Sgavinm MCERR_INT_WR(l_mcerr_int); 115720c794b3Sgavinm MCERR_FSB_WR(0, l_mcerr_fsb); 115820c794b3Sgavinm MCERR_FSB_WR(1, l_mcerr_fsb); 115920c794b3Sgavinm if (nb_chipset == INTEL_NB_7300) { 116020c794b3Sgavinm MCERR_FSB_WR(2, l_mcerr_fsb); 116120c794b3Sgavinm MCERR_FSB_WR(3, l_mcerr_fsb); 116220c794b3Sgavinm } 11635f28a827Saf if (nb_chipset == INTEL_NB_5400) { 11645f28a827Saf MCERR_THR_WR(l_mcerr_thr); 11655f28a827Saf } 116620c794b3Sgavinm } 116720c794b3Sgavinm 116820c794b3Sgavinm int 116920c794b3Sgavinm nb_dev_init() 117020c794b3Sgavinm { 11719d6aa643Saf find_dimm_label_t *label_function_p; 11729d6aa643Saf 11739d6aa643Saf label_function_p = find_dimms_per_channel(); 117420c794b3Sgavinm mutex_init(&nb_mutex, NULL, MUTEX_DRIVER, NULL); 117520c794b3Sgavinm nb_queue = errorq_create("nb_queue", nb_drain, NULL, NB_MAX_ERRORS, 117620c794b3Sgavinm sizeof (nb_logout_t), 1, ERRORQ_VITAL); 117720c794b3Sgavinm if (nb_queue == NULL) { 117820c794b3Sgavinm mutex_destroy(&nb_mutex); 117920c794b3Sgavinm return (EAGAIN); 118020c794b3Sgavinm } 11819d6aa643Saf nb_int_init(); 11825f28a827Saf nb_thr_init(); 118320c794b3Sgavinm dimm_init(); 11849d6aa643Saf nb_dimms_init(label_function_p); 118520c794b3Sgavinm nb_mc_init(); 118620c794b3Sgavinm nb_pex_init(); 118720c794b3Sgavinm nb_fbd_init(); 118820c794b3Sgavinm nb_fsb_init(); 118920c794b3Sgavinm nb_scrubber_enable(); 119020c794b3Sgavinm return (0); 119120c794b3Sgavinm } 119220c794b3Sgavinm 119320c794b3Sgavinm int 119420c794b3Sgavinm nb_init() 119520c794b3Sgavinm { 1196e4b86885SCheng Sean Ye /* return ENOTSUP if there is no PCI config space support. */ 1197e4b86885SCheng Sean Ye if (pci_getl_func == NULL) 1198e4b86885SCheng Sean Ye return (ENOTSUP); 1199e4b86885SCheng Sean Ye 120020c794b3Sgavinm /* get vendor and device */ 120120c794b3Sgavinm nb_chipset = (*pci_getl_func)(0, 0, 0, PCI_CONF_VENID); 120220c794b3Sgavinm switch (nb_chipset) { 120320c794b3Sgavinm default: 120420c794b3Sgavinm if (nb_5000_memory_controller == 0) 120520c794b3Sgavinm return (ENOTSUP); 120620c794b3Sgavinm break; 120720c794b3Sgavinm case INTEL_NB_7300: 120820c794b3Sgavinm case INTEL_NB_5000P: 120920c794b3Sgavinm case INTEL_NB_5000X: 121020c794b3Sgavinm break; 121120c794b3Sgavinm case INTEL_NB_5000V: 121220c794b3Sgavinm case INTEL_NB_5000Z: 121320c794b3Sgavinm nb_number_memory_controllers = 1; 121420c794b3Sgavinm break; 12155f28a827Saf case INTEL_NB_5400: 12165f28a827Saf case INTEL_NB_5400A: 12175f28a827Saf case INTEL_NB_5400B: 12185f28a827Saf nb_chipset = INTEL_NB_5400; 12195f28a827Saf break; 122020c794b3Sgavinm } 122120c794b3Sgavinm return (0); 122220c794b3Sgavinm } 122320c794b3Sgavinm 122420c794b3Sgavinm void 122520c794b3Sgavinm nb_dev_reinit() 122620c794b3Sgavinm { 122720c794b3Sgavinm int i, j; 122820c794b3Sgavinm int nchannels = nb_number_memory_controllers * 2; 122920c794b3Sgavinm nb_dimm_t **dimmpp; 123020c794b3Sgavinm nb_dimm_t *dimmp; 123120c794b3Sgavinm nb_dimm_t **old_nb_dimms; 123220c794b3Sgavinm int old_nb_dimms_per_channel; 12339d6aa643Saf find_dimm_label_t *label_function_p; 123430cfc677SAdrian Frost int dimm_slot = nb_dimm_slots; 123520c794b3Sgavinm 123620c794b3Sgavinm old_nb_dimms = nb_dimms; 123720c794b3Sgavinm old_nb_dimms_per_channel = nb_dimms_per_channel; 123820c794b3Sgavinm 123920c794b3Sgavinm dimm_fini(); 124030cfc677SAdrian Frost nb_dimms_per_channel = 0; 12419d6aa643Saf label_function_p = find_dimms_per_channel(); 124220c794b3Sgavinm dimm_init(); 12439d6aa643Saf nb_dimms_init(label_function_p); 124420c794b3Sgavinm nb_mc_init(); 124520c794b3Sgavinm nb_pex_init(); 124620c794b3Sgavinm nb_int_init(); 12475f28a827Saf nb_thr_init(); 124820c794b3Sgavinm nb_fbd_init(); 124920c794b3Sgavinm nb_fsb_init(); 125020c794b3Sgavinm nb_scrubber_enable(); 125120c794b3Sgavinm 125220c794b3Sgavinm dimmpp = old_nb_dimms; 125320c794b3Sgavinm for (i = 0; i < nchannels; i++) { 125420c794b3Sgavinm for (j = 0; j < old_nb_dimms_per_channel; j++) { 125520c794b3Sgavinm dimmp = *dimmpp; 125620c794b3Sgavinm if (dimmp) { 125720c794b3Sgavinm kmem_free(dimmp, sizeof (nb_dimm_t)); 125820c794b3Sgavinm *dimmpp = NULL; 125920c794b3Sgavinm } 126020c794b3Sgavinm dimmp++; 126120c794b3Sgavinm } 126220c794b3Sgavinm } 126330cfc677SAdrian Frost kmem_free(old_nb_dimms, sizeof (nb_dimm_t *) * dimm_slot); 126420c794b3Sgavinm } 126520c794b3Sgavinm 126620c794b3Sgavinm void 126720c794b3Sgavinm nb_dev_unload() 126820c794b3Sgavinm { 126920c794b3Sgavinm errorq_destroy(nb_queue); 127020c794b3Sgavinm nb_queue = NULL; 127120c794b3Sgavinm mutex_destroy(&nb_mutex); 127220c794b3Sgavinm nb_int_fini(); 12735f28a827Saf nb_thr_fini(); 127420c794b3Sgavinm nb_fbd_fini(); 127520c794b3Sgavinm nb_fsb_fini(); 127620c794b3Sgavinm nb_pex_fini(); 127720c794b3Sgavinm nb_fini(); 127820c794b3Sgavinm } 127920c794b3Sgavinm 128020c794b3Sgavinm void 128120c794b3Sgavinm nb_unload() 128220c794b3Sgavinm { 128320c794b3Sgavinm } 1284