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