chip_amd.c revision 88045cff0aae4ed8823cd0989168e8f56927f83e
/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* AMD memory enumeration
*/
#include <unistd.h>
#include <stropts.h>
#include <fm/topo_mod.h>
#include <strings.h>
#include <fcntl.h>
#include "chip.h"
#define MAX_CHANNUM 1
#define MAX_DIMMNUM 7
#define MAX_CSNUM 7
static const topo_pgroup_info_t cs_pgroup =
static const topo_pgroup_info_t dimm_pgroup =
static const topo_pgroup_info_t mc_pgroup =
static const topo_pgroup_info_t rank_pgroup =
static const topo_pgroup_info_t chan_pgroup =
static const topo_method_t dimm_methods[] = {
{ SIMPLE_DIMM_LBL, "Property method", 0,
{ SIMPLE_DIMM_LBL_MP, "Property method", 0,
{ SEQ_DIMM_LBL, "Property method", 0,
{ G4_DIMM_LBL, "Property method", 0,
{ G12F_DIMM_LBL, "Property method", 0,
{ GET_DIMM_SERIAL, "Property method", 0,
{ NULL }
};
const topo_method_t rank_methods[] = {
{ NULL }
};
const topo_method_t ntv_page_retire_methods[] = {
{ NULL }
};
static const topo_method_t gen_cs_methods[] = {
{ SIMPLE_CS_LBL_MP, "Property method", 0,
{ GET_DIMM_SERIAL, "Property method", 0,
{ NULL }
};
/*
* Called when there is no memory-controller driver to provide topology
* information. Generate a maximal memory topology that is appropriate
* for the chip revision. The memory-controller node has already been
* bound as mcnode, and the parent of that is cnode.
*
* We create a tree of dram-channel and chip-select nodes below the
* memory-controller node. There will be two dram channels and 8 chip-selects
* below each, regardless of actual socket type, processor revision and so on.
* This is adequate for generic diagnosis up to family 0x10 revision C.
* When support for revision D is implemented (or maybe C) we should take
* the opportunity to rework the topology tree completely (socket change will
* mean there can be no diagnosis history tied to the topology).
*/
/*ARGSUSED*/
static int
{
/*
* Elsewhere we have already returned for families less than 0xf.
* This "generic" topology is adequate for all of family 0xf and
* for revisions A, B and C of family 0x10 (for the list of models
* We cover all family 0x10 models, till model 8.
*/
return (1);
MAX_CHANNUM) < 0) {
"channels failed\n");
return (-1);
}
int err;
&fmri) != 0) {
"failed\n");
return (-1);
}
"bind failed\n");
return (-1);
}
0, MAX_CSNUM) < 0) {
"range create for cs failed\n");
return (-1);
}
&fmri) != 0) {
"mkrsrc for cs failed\n");
return (-1);
}
"bind for cs failed\n");
return (-1);
}
/*
* Dynamic ASRU for page faults within a chip-select.
* The topology does not represent pages (there are
* too many) so when a page is faulted we generate
* an ASRU to represent the individual page.
*/
gen_cs_methods) < 0)
"method registration failed\n");
TOPO_ASRU_COMPUTE, &err);
}
}
return (0);
}
static nvlist_t *
{
char path[64];
if (fd == -1) {
/*
* Some v20z and v40z systems may have had the 3rd-party
* link. So try again via /devices.
*/
MC_AMD_DEV_OFFSET + id);
}
if (fd == -1)
return (NULL); /* do not whinge */
return (NULL);
}
return (NULL);
} else if (ver != MC_NVLIST_VERS1) {
return (NULL);
}
}
int
{
char **csnamearr;
int nerr = 0;
int err;
int i;
return (nerr);
}
"failed\n");
return (nerr);
}
return (nerr);
}
&err) == 0) {
} else {
"size\n");
return (nerr);
}
for (i = 0; i < ncs; i++) {
continue;
}
"failed\n");
continue;
}
/*
* If a rank is faulted the asru is the associated
* chip-select, but if a page within a rank is faulted
* the asru is just that page. Hence the dual preconstructed
* and computed ASRU.
*/
"topo_method_register failed");
ntv_page_retire_methods) < 0)
"topo_method_register failed");
TOPO_ASRU_COMPUTE, &err);
}
return (nerr);
}
static int
{
return (-1);
}
if (ndimm == 0)
return (0); /* no dimms present on this node */
return (-1);
}
for (i = 0; i < ndimm; i++) {
"missing\n");
continue;
}
continue;
}
== NULL) {
"failed\n");
continue;
}
"topo_method_register failed");
continue; /* used in amd_rank_create() */
}
}
return (nerr == 0 ? 0 : -1);
}
static int
{
return (-1);
if (ncs == 0)
return (0); /* no chip-selects configured on this node */
return (-1);
for (i = 0; i < ncs; i++) {
"missing\n");
continue;
}
continue;
}
== NULL) {
continue;
}
}
}
return (nerr == 0 ? 0 : -1);
}
static int
{
char *socket;
int i, nchan;
/*
* We will enumerate the number of channels present even if only
* channel A is in use (i.e., running in 64-bit mode). Only
* the socket 754 package has a single channel.
*/
nchan = 1;
else
nchan = 2;
return (-1);
for (i = 0; i < nchan; i++) {
"failed\n");
continue;
}
== NULL) {
"failed\n");
continue;
}
if (pfmri)
}
if (pfmri)
return (nerr == 0 ? 0 : -1);
}
static int
{
int nerr = 0;
return (-1);
}
nerr++;
}
return (nerr == 0 ? 0 : -1);
}
void
{
int i, err;
/*
* Return with no error for anything before AMD family 0xf - we
* won't generate even a generic memory topolofy for earlier
* families.
*/
if (family < 0xf)
return;
return;
}
return;
}
return;
}
/*
* If a memory-controller driver exists for this chip model
* it has not attached or has otherwise malfunctioned;
* alternatively no memory-controller driver exists for this
* (presumably newly-released) cpu model. We fallback to
* creating a generic maximal topology.
*/
"mc_create: amd_generic_mc_create failed\n");
return;
}
/*
* Add memory controller properties
*/
if (type == DATA_TYPE_NVLIST_ARRAY &&
continue;
} else if (type == DATA_TYPE_UINT8 &&
continue;
} else if (type == DATA_TYPE_NVLIST &&
"mc_create: amd_htconfig failed\n");
} else {
"mc_create: nvprop_add failed\n");
}
}
/*
* Free the fmris for the chip-selects allocated in amd_cs_create
*/
for (i = 0; i < MC_CHIP_NCS; i++) {
nvlist_free(cs_fmri[i]);
}
}
}