nb5000_init.c revision 5de8e333fea6455895155795aae363a0737b8e8e
/*
* 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
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/controlregs.h>
#include <sys/sysevent.h>
#include <sys/pci_cfgspace.h>
#include <sys/mc_intel.h>
#include <sys/cpu_module_impl.h>
#include <sys/machsystm.h>
#include "nb5000.h"
#include "nb_log.h"
#include "dimm_phys.h"
#include "rank.h"
int nb_hw_memory_scrub_enable = 1;
static int nb_sw_scrub_disabled = 0;
int nb_5000_memory_controller = 0;
int nb_dimms_per_channel = 0;
static int ndimms = 0;
int nb_ndimm;
enum nb_memory_mode nb_mode;
static uint8_t nb_err0_int;
static uint8_t nb_err1_int;
static uint8_t nb_err2_int;
static uint8_t nb_mcerr_int;
static uint8_t nb_emask_int;
static uint32_t nb_err0_fbd;
static uint32_t nb_err1_fbd;
static uint32_t nb_err2_fbd;
static uint32_t nb_mcerr_fbd;
static uint32_t nb_emask_fbd;
static uint16_t nb_err0_fsb;
static uint16_t nb_err1_fsb;
static uint16_t nb_err2_fsb;
static uint16_t nb_mcerr_fsb;
static uint16_t nb_emask_fsb;
static uint8_t l_mcerr_int;
static uint32_t l_mcerr_fbd;
static uint16_t l_mcerr_fsb;
int nb5000_reset_emask_fbd = 1;
uint_t nb5000_emask_fsb = 0;
int nb5000_reset_emask_fsb = 1;
int nb5000_reset_emask_int = 1;
int nb5000_reset_uncor_pex = 0;
int nb5000_reset_cor_pex = 1;
int nb_mask_mc_set;
static unsigned short
{
unsigned short rt = 0;
return (rt);
}
static void
{
}
static int
{
int retry = 4;
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) {
}
dimmp++;
}
}
dimm_fini();
}
void
{
return;
mc |= MC_PATROL_SCRUB;
else
if (nb_sw_scrub_disabled++)
}
static nb_dimm_t *
{
int i, t;
int spd_sz;
if (t != 9)
return (NULL);
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] =
}
}
}
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) {
}
limit);
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;
}
}
}
}
/*ARGSUSED*/
static int
{
}
return (0);
}
void
{
if (nb_dimms_per_channel == 0) {
(nb_number_memory_controllers * 2);
}
if (nb_dimms_per_channel == 0) {
if (nb_chipset == INTEL_NB_7300)
nb_dimms_per_channel = 8;
else
nb_dimms_per_channel = 4;
}
}
}
static int
{
}
(*dimmpp)++;
}
return (0);
}
void
{
}
}
static void
{
int i, j, k;
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 ++;
}
dimmpp[j + nb_dimms_per_channel] =
if (dimmpp[j + nb_dimms_per_channel])
nb_ndimm ++;
}
}
nb_smbios();
}
static void
{
int i;
for (i = 0; i < NB_PCI_DEV; i++) {
switch (nb_chipset) {
case INTEL_NB_5000P:
case INTEL_NB_5000X:
if (i == 1)
continue;
break;
case INTEL_NB_5000V:
if (i == 1 || i > 3)
continue;
break;
case INTEL_NB_5000Z:
if (i == 1 || i > 5)
continue;
break;
case INTEL_NB_7300:
break;
}
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)
}
}
static void
{
int i;
for (i = 0; i < NB_PCI_DEV; i++) {
switch (nb_chipset) {
case INTEL_NB_5000P:
case INTEL_NB_5000X:
if (i == 1)
continue;
break;
case INTEL_NB_5000V:
if (i == 1 || i > 3)
continue;
break;
case INTEL_NB_5000Z:
if (i == 1 || i > 5)
continue;
break;
case INTEL_NB_7300:
break;
}
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]);
UNCERRSEV_WR(i, uncerrsev[i]);
if (nb5000_reset_cor_pex)
}
}
void
{
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();
ERR0_INT_WR(0xff);
ERR1_INT_WR(0xff);
ERR2_INT_WR(0xff);
MCERR_INT_WR(0xff);
EMASK_INT_WR(0xff);
if (nb5000_reset_emask_int) {
if (nb_chipset == INTEL_NB_7300) {
stepping = NB5000_STEPPING();
if (stepping == 0)
else
} else {
}
} else {
}
}
void
{
ERR0_INT_WR(0xff);
ERR1_INT_WR(0xff);
ERR2_INT_WR(0xff);
MCERR_INT_WR(0xff);
EMASK_INT_WR(0xff);
}
void
{
emask_int = MCERR_INT_RD();
nb_mask_mc_set = 1;
}
}
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);
/* MCH 7300 errata 34 */
}
else
}
void
{
emask_fbd = MCERR_FBD_RD();
nb_mask_mc_set = 1;
}
}
void
{
ERR0_FBD_WR(0xffffffff);
ERR1_FBD_WR(0xffffffff);
ERR2_FBD_WR(0xffffffff);
MCERR_FBD_WR(0xffffffff);
EMASK_FBD_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);
else
EMASK_FSB_WR(0, nb_emask_fsb);
else
if (nb_chipset == INTEL_NB_7300) {
else
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;
}
}
void
{
MCERR_FSB_WR(0, l_mcerr_fsb);
if (nb_chipset == INTEL_NB_7300) {
}
}
int
{
return (EAGAIN);
}
dimm_init();
nb_mc_init();
nb_pex_init();
nb_int_init();
nb_fbd_init();
nb_fsb_init();
return (0);
}
int
nb_init()
{
/* 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;
}
return (0);
}
void
{
int i, j;
dimm_fini();
dimm_init();
nb_mc_init();
nb_pex_init();
nb_int_init();
nb_fbd_init();
nb_fsb_init();
for (i = 0; i < nchannels; i++) {
for (j = 0; j < old_nb_dimms_per_channel; j++) {
if (dimmp) {
}
dimmp++;
}
}
}
void
{
nb_int_fini();
nb_fbd_fini();
nb_fsb_fini();
nb_pex_fini();
nb_fini();
}
void
{
}