/*
* 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
*/
/*
*/
/*
* AMD memory enumeration
*/
#include <unistd.h>
#include <stropts.h>
#include <fm/topo_mod.h>
#include <strings.h>
#include <fcntl.h>
#include "chip.h"
extern const topo_method_t rank_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 }
};
{ NULL }
};
/*
* Serials, Labels are obtained from SMBIOS, so
* we leave out the related methods, any other
* methods that will be added to gen_cs_methods
* should be added to x86pi_gen_cs_methods too
*/
{ NULL }
};
{ 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 E and
* models 00h - 0Fh of family 0x15.
*/
/*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 to E of family 0x10, and for models 00h - 0Fh
* of family 0x15 (for the list of models in each revision, refer
* We cover all family 0x10 models, till model A.
*/
switch (family) {
case 0xf:
/* supports all revisions of family 0xf */
break;
case 0x10:
/* supports revisions A to E of family 0x10 */
if (model > 0xa)
return (1);
break;
case 0x15:
/* supports family 0x15 models 00h-0Fh */
if (model > 0xf)
return (1);
break;
default:
return (1);
}
MAX_CHANNUM) < 0) {
"channels failed\n");
return (-1);
}
int err;
&fmri) != 0) {
"failed\n");
return (-1);
}
"bind failed\n");
return (-1);
}
if (FM_AWARE_SMBIOS(mod)) {
"topo_node_label_set\n");
"topo_node_fru_set failed\n");
}
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.
* If SMBIOS meets FMA needs, derive labels & serials
* for DIMMS and apply to chip-select nodes.
* If deriving from SMBIOS, skip IPMI
*/
if (FM_AWARE_SMBIOS(mod)) {
x86pi_gen_cs_methods) < 0)
"amd_generic_mc_create: "
"method registration failed\n");
} else {
gen_cs_methods) < 0)
"amd_generic_mc_create: method"
"registration failed\n");
}
TOPO_ASRU_COMPUTE, &err);
/*
* If SMBIOS meets FMA needs, set DIMM as the FRU for
* the chip-select node. Use the channel & chip-select
* numbers to get the DIMM instance.
* Send via inst : dram channel number
* Receive via inst : dimm instance
*/
if (FM_AWARE_SMBIOS(mod)) {
int inst;
const char *serial;
const char *part;
const char *rev;
char *label;
(void) topo_pgroup_create(csnode,
/*
* We apply DIMM labels to chip-select nodes,
* FRU for chip-selects should be DIMMs, and
* we do not derive dimm nodes for Family 0x10
* so FRU fmri is NULL, but FRU Labels are set,
* the FRU labels point to the DIMM.
*/
}
}
}
return (0);
}
static nvlist_t *
{
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 (FM_AWARE_SMBIOS(mod))
else
/*
* 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
{
int perr = 0;
const char *serial;
const char *part;
const char *rev;
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;
}
if (FM_AWARE_SMBIOS(mod)) {
DIMM_NODE_NAME, i, NULL);
serial);
part);
rev);
if (perr != 0)
"nvlist_add_string failed\n");
}
== NULL) {
"failed\n");
continue;
}
if (!FM_AWARE_SMBIOS(mod))
if (topo_method_register(mod,
dimmnode, dimm_methods) < 0)
"topo_method_register failed");
if (FM_AWARE_SMBIOS(mod)) {
char *label;
(void) topo_node_resource(dimmnode,
&perr) == -1)
"to set label\n");
}
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 topology for earlier
* families.
*/
if (family < 0xf)
return;
return;
if (FM_AWARE_SMBIOS(mod)) {
}
if (FM_AWARE_SMBIOS(mod))
return;
}
if (FM_AWARE_SMBIOS(mod)) {
}
return;
}
if (FM_AWARE_SMBIOS(mod)) {
}
"add node id\n");
/*
* 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]);
}
}
}