/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/controlregs.h>
#include <sys/sysevent.h>
#include <sys/pci_cfgspace.h>
#include <sys/mc_intel.h>
#include "nb5000.h"
#include "nb_log.h"
#include "dimm_phys.h"
#include "rank.h"
static int nb_sw_scrub_disabled = 0;
int nb_5000_memory_controller = 0;
int nb_dimms_per_channel = 0;
int nb_ndimm;
extern int nb_no_smbios;
static int nb_dimm_slots;
int nb5000_reset_uncor_pex = 0;
int nb5000_reset_cor_pex = 0;
int nb_mask_mc_set;
typedef struct find_dimm_label {
void (*label_function)(int, char *, int);
static void x8450_dimm_label(int, char *, int);
static void cp3250_dimm_label(int, char *, int);
static struct platform_label {
int dimms_per_channel;
} platform_label[] = {
{ "SUN MICROSYSTEMS", "SUN BLADE X8450 SERVER MODULE",
x8450_dimm_label, 8 },
};
static unsigned short
{
unsigned short rt = 0;
return (rt);
}
static void
{
}
static int
{
int wait;
int spd;
for (;;) {
wait = 1000;
for (;;) {
break;
if (--wait == 0)
return (-1);
drv_usecwait(10);
}
wait = 1000;
for (;;) {
break;
if (--wait == 0) {
spd = SPD_BUS_ERROR;
break;
}
drv_usecwait(10);
}
while ((spd & SPD_BUS_ERROR) == 0 &&
if (--wait == 0)
return (-1);
}
if ((spd & SPD_BUS_ERROR) == 0)
break;
if (--retry == 0)
return (-1);
}
return (spd & 0xff);
}
static void
nb_fini()
{
int i, j;
for (i = 0; i < nchannels; i++) {
for (j = 0; j < nb_dimms_per_channel; j++) {
if (dimmp) {
}
dimmpp++;
}
}
dimm_fini();
}
void
{
return;
mc |= MC_PATROL_SCRUB;
else
if (nb_sw_scrub_disabled++)
}
static void
{
int i, t;
int spd_sz;
if (t == 1)
spd_sz = 128;
else if (t == 2)
spd_sz = 176;
else
spd_sz = 256;
dp->serial_number =
if (spd_sz > 128) {
for (i = 0; i < sizeof (dp->part_number); i++) {
dp->part_number[i] =
}
}
}
}
/* read the manR of the DDR2 dimm */
static void
{
int i, t;
int slave;
/* byte[3]: number of row addresses */
/* byte[4]: number of column addresses */
/* byte[5]: numranks; 0 means one rank */
/* byte[6]: data width */
/* byte[17]: number of banks */
/* manufacture-id - byte[64-65] */
/* location - byte[72] */
/* serial number - byte[95-98] */
dp->serial_number =
/* week - byte[94] */
/* week - byte[93] */
/* part number - byte[73-81] */
for (i = 0; i < 8; i++) {
}
/* revision - byte[91-92] */
for (i = 0; i < 2; i++) {
}
}
static boolean_t
{
if (nb_chipset == INTEL_NB_5100) {
int t, slave;
/* read the type field from the dimm and check for DDR2 type */
return (B_FALSE);
} else {
}
return (rc);
}
static nb_dimm_t *
{
return (NULL);
/* The 1st rank of the dimm takes on this value */
return (dp);
}
static nb_dimm_t *
{
int t;
if (MTR_PRESENT(mtr) == 0)
return (NULL);
/* check for the dimm type */
if (t != SPD_FBDIMM)
return (NULL);
return (dp);
}
static uint64_t
{
int i;
for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) {
if (base <= top_of_low_memory &&
limit > top_of_low_memory) {
}
nb_mode != NB_MEMORY_MIRROR) {
}
}
}
return (limit);
}
void
{
int i, j, k;
base = 0;
for (i = 0; i < NB_MEM_BRANCH_SELECT; i++) {
way0 = 1;
way1 = 1;
}
if (limit > top_of_low_memory)
}
for (i = 0; i < nb_number_memory_controllers; i++) {
base = 0;
for (j = 0; j < NB_MEM_RANK_SELECT; j++) {
if (limit == 0) {
}
branch_interleave = 0;
hole_base = 0;
hole_size = 0;
interleave = 1;
interleave = 2;
else
interleave = 4;
if (nb_mode != NB_MEMORY_MIRROR &&
for (k = 0; k < NB_MEM_BRANCH_SELECT; k++) {
interleave *= 2;
limit *= 2;
branch_interleave = 1;
}
break;
}
}
}
if (base < top_of_low_memory &&
limit > top_of_low_memory) {
} else if (base > top_of_low_memory) {
}
dimm_add_rank(i, rank1,
limit);
dimm_add_rank(i, rank2,
interleave, limit);
dimm_add_rank(i, rank3,
interleave, limit);
}
}
}
}
}
}
void
{
int i;
int j;
for (i = 0; i < NB_MEM_RANK_SELECT; i++) {
for (j = 0; j < NB_RANKS_IN_SELECT; j++) {
i = NB_MEM_RANK_SELECT;
break;
}
}
}
}
{
int i, j;
break;
}
}
}
}
if (nb_dimms_per_channel == 0) {
/*
* Scan all memory channels if we find a channel which has more
* dimms then we have seen before set nb_dimms_per_channel to
* the number of dimms on the channel
*/
for (i = 0; i < nb_number_memory_controllers; i++) {
for (j = nb_dimms_per_channel;
j < NB_MAX_DIMMS_PER_CHANNEL; j++) {
if (nb_dimm_present(i, j))
nb_dimms_per_channel = j + 1;
}
}
}
return (rt);
}
struct smb_dimm_rec {
int dimms;
int slots;
int populated;
};
static int
{
return (-1);
if (md.smbmd_size) {
(*dimmpp)++;
return (0);
}
/*
* if there is no physical dimm for this smbios
* record it is because this system has less
* physical slots than the controller supports
* so skip empty slots to find the slot this
* smbios record belongs too
*/
(*dimmpp)++;
return (-1);
}
(*dimmpp)++;
}
}
}
return (0);
}
static int
{
if (md.smbmd_size) {
}
}
}
return (0);
}
void
{
struct smb_dimm_rec r;
int i;
r.dimms = 0;
r.slots = 0;
r.populated = 0;
for (i = 0; i < nb_dimm_slots; i++) {
r.dimms++;
}
}
}
static void
{
}
/*
* CP3250 DIMM labels
* Channel Dimm Label
* 0 0 A0
* 1 0 B0
* 0 1 A1
* 1 1 B1
* 0 2 A2
* 1 2 B2
*/
static void
{
dimm);
}
/*
* Map the rank id to dimm id of a channel
* For the 5100 chipset, walk through the dimm list of channel the check if
* the given rank id is within the rank range assigned to the dimm.
* For other chipsets, the dimm is rank/2.
*/
int
{
int i;
if (nb_chipset != INTEL_NB_5100)
return (rank >> 1);
for (i = 0; i < nb_dimms_per_channel; i++) {
return (i);
}
}
return (-1);
}
static void
{
int i, j;
int start_rank;
for (i = 0; i < nb_number_memory_controllers; i++) {
if (nb_mode == NB_MEMORY_NORMAL) {
if ((spcpc & SPCPC_SPARE_ENABLE) != 0 &&
(spcps & SPCPS_SPARE_DEPLOYED) != 0)
}
/* The 1st dimm of a channel starts at rank 0 */
start_rank = 0;
for (j = 0; j < nb_dimms_per_channel; j++) {
if (dimmpp[j]) {
nb_ndimm ++;
if (label_function) {
(i * nb_dimms_per_channel) + j,
}
/*
* add an extra rank because
* single-ranked dimm still takes on two ranks.
*/
start_rank++;
}
}
}
/*
* single channel is supported.
*/
}
}
static void
{
int i, j, k, l;
else
for (i = 0; i < nb_number_memory_controllers; i++) {
if (nb_mode == NB_MEMORY_NORMAL) {
if ((spcpc & SPCPC_SPARE_ENABLE) != 0 &&
(spcps & SPCPS_SPARE_DEPLOYED) != 0)
}
for (j = 0; j < nb_dimms_per_channel; j++) {
k = i * 2;
if (dimmpp[j]) {
nb_ndimm ++;
if (label_function) {
(k * nb_dimms_per_channel) + j,
}
}
dimmpp[j + nb_dimms_per_channel] =
l = j + nb_dimms_per_channel;
if (dimmpp[l]) {
if (label_function) {
(k * nb_dimms_per_channel) + l,
}
nb_ndimm ++;
}
}
}
}
static void
{
if (nb_chipset == INTEL_NB_5100)
else
if (label_function == NULL)
nb_smbios();
}
/* Setup the ESI port registers to enable SERR for southbridge */
static void
{
int i = 0; /* ESI port */
emask_uncor_pex[i] = EMASK_UNCOR_PEX_RD(i);
emask_cor_pex[i] = EMASK_COR_PEX_RD(i);
emask_rp_pex[i] = EMASK_RP_PEX_RD(i);
docmd_pex[i] = PEX_ERR_DOCMD_RD(i);
uncerrsev[i] = UNCERRSEV_RD(i);
if (nb5000_reset_cor_pex)
if (nb_chipset == INTEL_NB_5400) {
/* disable masking of ERR pins used by DOCMD */
PEX_ERR_PIN_MASK_WR(i, 0x10);
}
/* Command Register - Enable SERR */
nb_pci_putw(0, i, 0, PCI_CONF_COMM,
/* AER UE Mask - Mask UR */
}
static void
{
int i = 0; /* ESI port */
EMASK_UNCOR_PEX_WR(i, emask_uncor_pex[i]);
EMASK_COR_PEX_WR(i, emask_cor_pex[i]);
EMASK_RP_PEX_WR(i, emask_rp_pex[i]);
PEX_ERR_DOCMD_WR(i, docmd_pex[i]);
if (nb5000_reset_cor_pex)
}
void
{
if (nb_chipset == INTEL_NB_5100) {
} else {
}
err0_int = ERR0_INT_RD();
err1_int = ERR1_INT_RD();
err2_int = ERR2_INT_RD();
mcerr_int = MCERR_INT_RD();
emask_int = EMASK_INT_RD();
if (nb5000_reset_emask_int) {
if (nb_chipset == INTEL_NB_7300) {
stepping = NB5000_STEPPING();
if (stepping == 0)
else
} else if (nb_chipset == INTEL_NB_5400) {
(emask_int & EMASK_INT_RES));
} else if (nb_chipset == INTEL_NB_5100) {
} else {
}
} else {
}
}
void
{
}
void
{
emask_int = MCERR_INT_RD();
nb_mask_mc_set = 1;
}
}
static void
{
err0_fbd = ERR0_FBD_RD();
err1_fbd = ERR1_FBD_RD();
err2_fbd = ERR2_FBD_RD();
mcerr_fbd = MCERR_FBD_RD();
emask_fbd = EMASK_FBD_RD();
ERR0_FBD_WR(0xffffffff);
ERR1_FBD_WR(0xffffffff);
ERR2_FBD_WR(0xffffffff);
MCERR_FBD_WR(0xffffffff);
EMASK_FBD_WR(0xffffffff);
if (nb_chipset == INTEL_NB_7300) {
if (nb_mode == NB_MEMORY_MIRROR) {
/* MCH 7300 errata 34 */
} else {
}
} else if (nb_chipset == INTEL_NB_5400) {
} else {
}
mcerr_fbd &= ~emask_bios_fbd;
if (nb5000_reset_emask_fbd) {
if (nb_chipset == INTEL_NB_5400)
else
} else {
}
}
void
{
emask_fbd = MCERR_FBD_RD();
nb_mask_mc_set = 1;
}
}
static void
{
ERR0_FBD_WR(0xffffffff);
ERR1_FBD_WR(0xffffffff);
ERR2_FBD_WR(0xffffffff);
MCERR_FBD_WR(0xffffffff);
EMASK_FBD_WR(0xffffffff);
}
static void
{
err0_mem = ERR0_MEM_RD();
err1_mem = ERR1_MEM_RD();
err2_mem = ERR2_MEM_RD();
mcerr_mem = MCERR_MEM_RD();
emask_mem = EMASK_MEM_RD();
ERR0_MEM_WR(0xffffffff);
ERR1_MEM_WR(0xffffffff);
ERR2_MEM_WR(0xffffffff);
MCERR_MEM_WR(0xffffffff);
EMASK_MEM_WR(0xffffffff);
if (nb5100_reset_emask_mem) {
} else {
}
}
void
{
emask_mem = MCERR_MEM_RD();
nb_mask_mc_set = 1;
}
}
static void
{
ERR0_MEM_WR(0xffffffff);
ERR1_MEM_WR(0xffffffff);
ERR2_MEM_WR(0xffffffff);
MCERR_MEM_WR(0xffffffff);
EMASK_MEM_WR(0xffffffff);
}
static void
{
err0_fsb = ERR0_FSB_RD(0);
err1_fsb = ERR1_FSB_RD(0);
err2_fsb = ERR2_FSB_RD(0);
mcerr_fsb = MCERR_FSB_RD(0);
emask_fsb = EMASK_FSB_RD(0);
ERR0_FSB_WR(0, 0xffff);
ERR1_FSB_WR(0, 0xffff);
ERR2_FSB_WR(0, 0xffff);
MCERR_FSB_WR(0, 0xffff);
EMASK_FSB_WR(0, 0xffff);
ERR0_FSB_WR(0, err0_fsb);
ERR1_FSB_WR(0, err1_fsb);
ERR2_FSB_WR(0, err2_fsb);
MCERR_FSB_WR(0, mcerr_fsb);
if (nb5000_reset_emask_fsb) {
} else {
EMASK_FSB_WR(0, nb_emask_fsb);
}
if (nb5000_reset_emask_fsb) {
} else {
}
if (nb_chipset == INTEL_NB_7300) {
if (nb5000_reset_emask_fsb) {
} else {
}
if (nb5000_reset_emask_fsb) {
} else {
}
}
}
static void
nb_fsb_fini() {
ERR0_FSB_WR(0, 0xffff);
ERR1_FSB_WR(0, 0xffff);
ERR2_FSB_WR(0, 0xffff);
MCERR_FSB_WR(0, 0xffff);
EMASK_FSB_WR(0, 0xffff);
ERR0_FSB_WR(0, nb_err0_fsb);
ERR1_FSB_WR(0, nb_err1_fsb);
ERR2_FSB_WR(0, nb_err2_fsb);
MCERR_FSB_WR(0, nb_mcerr_fsb);
EMASK_FSB_WR(0, nb_emask_fsb);
if (nb_chipset == INTEL_NB_7300) {
}
}
void
{
nb_mask_mc_set = 1;
}
}
static void
{
if (nb_chipset == INTEL_NB_5400) {
err0_thr = ERR0_THR_RD(0);
err1_thr = ERR1_THR_RD(0);
err2_thr = ERR2_THR_RD(0);
mcerr_thr = MCERR_THR_RD(0);
emask_thr = EMASK_THR_RD(0);
ERR0_THR_WR(0xffff);
ERR1_THR_WR(0xffff);
ERR2_THR_WR(0xffff);
MCERR_THR_WR(0xffff);
EMASK_THR_WR(0xffff);
}
}
static void
{
if (nb_chipset == INTEL_NB_5400) {
ERR0_THR_WR(0xffff);
ERR1_THR_WR(0xffff);
ERR2_THR_WR(0xffff);
MCERR_THR_WR(0xffff);
EMASK_THR_WR(0xffff);
}
}
void
{
emask_thr = MCERR_THR_RD(0);
nb_mask_mc_set = 1;
}
}
void
{
if (nb_chipset == INTEL_NB_5100)
else
MCERR_FSB_WR(0, l_mcerr_fsb);
if (nb_chipset == INTEL_NB_7300) {
}
if (nb_chipset == INTEL_NB_5400) {
}
}
int
{
return (EAGAIN);
}
nb_int_init();
nb_thr_init();
dimm_init();
nb_mc_init();
nb_pex_init();
if (nb_chipset == INTEL_NB_5100)
nb_mem_init();
else
nb_fbd_init();
nb_fsb_init();
return (0);
}
int
nb_init()
{
/* return ENOTSUP if there is no PCI config space support. */
if (pci_getl_func == NULL)
return (ENOTSUP);
/* get vendor and device */
switch (nb_chipset) {
default:
if (nb_5000_memory_controller == 0)
return (ENOTSUP);
break;
case INTEL_NB_7300:
case INTEL_NB_5000P:
case INTEL_NB_5000X:
break;
case INTEL_NB_5000V:
case INTEL_NB_5000Z:
break;
case INTEL_NB_5100:
break;
case INTEL_NB_5400:
case INTEL_NB_5400A:
case INTEL_NB_5400B:
break;
}
return (0);
}
void
{
int i, j;
dimm_fini();
nb_dimms_per_channel = 0;
dimm_init();
nb_mc_init();
nb_pex_init();
nb_int_init();
nb_thr_init();
if (nb_chipset == INTEL_NB_5100)
nb_mem_init();
else
nb_fbd_init();
nb_fsb_init();
for (i = 0; i < nchannels; i++) {
for (j = 0; j < old_nb_dimms_per_channel; j++) {
if (dimmp) {
}
dimmpp++;
}
}
}
void
{
nb_int_fini();
nb_thr_fini();
if (nb_chipset == INTEL_NB_5100)
nb_mem_fini();
else
nb_fbd_fini();
nb_fsb_fini();
nb_pex_fini();
nb_fini();
}
void
{
}