/*
* 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.
*/
/*
* This plugin creates memory configuration nodes and properties in the
* PICL tree for Cheetah platforms.
*
* Subtree of memory-controller in the physical aspect.
* memory-controller --- memory-module-group --- memory-module
*
* Subtree of memory in the logical aspect.
* memory --- memory-segment --- memory-bank
* Add property _memory-module-group_ at memory-segment referring to the
* memory-module-group if InterleaveFactor is one, or at memory-bank
* if InterleaveFactor is greater than one.
*
* Undo strategy:
* Create all nodes and properties, or none if it fails in physical and
* logical memory tree respectively. It keeps on creating logic
* memory tree although it falis on physical logic tree, but no link to
* memory module group.
*
* NOTE:
* It depends on PICL devtree plugin and currently
* there is no refresh routine for DR.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <alloca.h>
#include <syslog.h>
#include <string.h>
#include <libintl.h>
#include <picl.h>
#include <picltree.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <mc.h>
#include <libnvpair.h>
#include <limits.h>
#include "piclmemcfg.h"
/*
* Plugin registration entry points
*/
static void piclmemcfg_register(void);
static void piclmemcfg_init(void);
static void piclmemcfg_fini(void);
/*
* PICL event handler
*/
#pragma init(piclmemcfg_register)
"SUNW_piclmemcfg",
};
/*
* Log message texts
*/
#define EM_PHYSIC_MEM_TREE_FAILED \
gettext("SUNW_piclmemcfg physical memory tree failed!\n")
#define EM_LOGIC_MEM_TREE_FAILED \
gettext("SUNW_piclmemcfg logical memory tree failed!\n")
#define EM_INIT_MC_FAILED \
gettext("SUNW_piclmemcfg init mc failed!\n")
/*
* Global variables for Memory Controllers
*/
static int transfersize;
/*
* Memory-module-group node handle list, a singal linking list, where
* memory module group id is the key to match.
*
* It is allocated and added to the head of list, and freed as well.
* The mmgh field is cleared if failure is encountered in the physical
* memory tree.
*
* This list is accessed in the logical memory tree, and allocated memory
* is released at the end of plugin.
*/
typedef struct memmodgrp_info {
int mmgid;
/*
* Release the allocated memory of mmodgrp_info
*/
static void
free_allocated_mem(void)
{
while (mmghdl) {
currmmghdl = mmghdl;
}
head2mmodgrp = NULL;
}
/*
* Delete nodes whose MC is gone at mmodgrp_info
*/
static void
{
mmghdl = nextmmghdl) {
if (prevmmghdl == NULL)
/* we are at the head */
else
} else
prevmmghdl = mmghdl;
}
}
/*
* Search the memory module group node in the mmodgrp_info by global id.
* The matched memory-module-group node handle will be assigned to
* the second parameter.
*/
static int
{
while (mmghdl) {
err = PICL_SUCCESS;
break;
}
}
return (err);
}
/*
* Delete nodes and properties created in the physical memory tree.
*/
static void
undo_phymem_tree(void)
{
while (mmghdl) {
/*
* Delete nodes and properties of memory-module-group(s)
*/
continue;
/*
* Clear out the saved node handle of memory module group
* so that logic memory tree won't link to it.
*/
}
}
/*
* Create all memory-banks under the given memory-segment.
*/
static int
{
int i;
/*
* Get all bank information via ioctl
*/
return (PICL_FAILURE);
/*
* Create memory-bank node under memory-segment node
*/
if (err != PICL_SUCCESS)
break;
/*
* Add property, Size to memory-bank node
*/
if (err != PICL_SUCCESS)
break;
NULL);
if (err != PICL_SUCCESS)
break;
/*
* Add property, AddressMask to memory-bank node
*/
if (err != PICL_SUCCESS)
break;
NULL);
if (err != PICL_SUCCESS)
break;
/*
* Add property, AddressMatch to memory-bank node
*/
if (err != PICL_SUCCESS)
break;
if (err != PICL_SUCCESS)
break;
/*
* Add global id of bank to property, ID memory-bank node
*/
if (err != PICL_SUCCESS)
break;
NULL);
if (err != PICL_SUCCESS)
break;
/*
* Add property, _memory-module-group_ to memory-bank node
*/
&mmodgrph)) != PICL_SUCCESS)
continue;
/*
* The number of memory modules > 1 means there needs
* memory module group, and then refers to it. Otherwise,
* it refers to memory module node handle instead.
*/
if (err != PICL_SUCCESS)
break;
NULL);
if (err != PICL_SUCCESS)
break;
}
return (PICL_SUCCESS);
}
static void
{
int i;
/*
* Undo in the logical memory tree
*/
for (i = 0; i < nsegments; i++) {
(void) ptree_delete_node(msegh_info[i]);
(void) ptree_destroy_node(msegh_info[i]);
}
}
/*
* Create logical memory tree
* memory --- memory-segment --- memory-bank
* Get information via ioctl of memory control driver
*/
static int
{
int i;
/*
* allocate memory for mc_memory where nsegmentids are various
*/
return (PICL_FAILURE);
/*
* Get logical memory information
*/
return (PICL_FAILURE);
/*
* allocate memory for mc_segment where nbanks are various
*/
return (PICL_FAILURE);
/*
* Get all segments to create memory-segment nodes and
* add properties.
*/
for (i = 0; i < nsegments; i++) {
break;
/*
* Create memory-segment node under memory node
*/
if (err != PICL_SUCCESS)
break;
msegh_info[i] = msegh;
/*
* Add property, Size to memory-segment node
*/
if (err != PICL_SUCCESS)
break;
NULL);
if (err != PICL_SUCCESS)
break;
/*
* Add property, BaseAddress to memory-segment node
*/
if (err != PICL_SUCCESS)
break;
NULL);
if (err != PICL_SUCCESS)
break;
if (err != PICL_SUCCESS)
break;
if (err != PICL_SUCCESS)
break;
if (err != PICL_SUCCESS)
break;
}
if (err != PICL_SUCCESS) {
return (err);
}
return (err);
}
/*
* Add the size property
*/
return (err);
}
/*
* Add memory-module nodes and properties at each enabled memory-module-group.
* The formula of unique id is (id of the given memory module group *
* max number of memory modules per memory module group) + index
* of memory modules in this memory module group
*/
static int
{
int i;
/*
* Get all memory-modules of the given memory-module-group
*/
/*
* Create memory-module node under memory-module-group
*/
if (err != PICL_SUCCESS)
break;
/*
* Add property, Size to memory-module-group node
*/
if (err != PICL_SUCCESS)
break;
if (err != PICL_SUCCESS)
break;
/*
* Add property, ID to memory-module-group node
*/
if (err != PICL_SUCCESS)
break;
NULL);
if (err != PICL_SUCCESS)
break;
}
return (err);
}
/*
* Create the subtree at every enabled Memory Controller where size of
* memory module group is greater than zero.
* Get information via ioctl of memory control driver
*/
static int
{
int i, portid;
int fd;
/*
* Get portid of memory-controller as the key to get its
* configuration via ioctl.
*/
sizeof (portid));
if (err != PICL_SUCCESS)
return (err);
return (PICL_FAILURE);
return (PICL_WALK_CONTINUE);
else
return (PICL_FAILURE);
}
/*
* If returned ndevgrps is zero, Memory Controller is disable, and
* skip it.
*/
return (PICL_WALK_CONTINUE);
/*
* Get all memory module groups of the given memory controller.
*/
return (PICL_FAILURE);
/*
* Node doesn't need to be created if size is 0, i.e.
* there is no memory dimm at slot.
*/
continue;
/*
* Create memory-module-group node under memory-controller
*/
if (err != PICL_SUCCESS)
break;
/*
* Allocate space for mmodgrp_info to save the information
* so that it is easier to do the undo and setup of the
* reference property in logical memory tree.
*/
return (PICL_FAILURE);
/*
* Save the information and add it to the beginnong of list.
*/
/*
* Add property, Size to memory-module-group node
*/
if (err != PICL_SUCCESS)
break;
if (err != PICL_SUCCESS)
break;
/*
* Add property, ID to memory-module-group node
*/
if (err != PICL_SUCCESS)
break;
&mmglocalid, NULL);
if (err != PICL_SUCCESS)
break;
/*
* Create all memory-module nodes and properties.
*/
if (err != PICL_SUCCESS)
break;
}
if (err == PICL_SUCCESS)
return (PICL_WALK_CONTINUE);
return (err);
}
/*
* Create physical memory tree
* memory-controller --- memory-module-group --- memory-module
*
* It searches all memory-controller nodes in the whole devtree.
* It returns failure if encountering error in physical tree.
*/
static int
{
int err;
(void *)fd, create_physical_tree);
return (err);
}
static int
init_mc(void)
{
int fd;
int found = 0;
int valid_entry = 0;
/* open the directory */
/*
* As not all platforms have mc drivers that create the
* an entry found on which the open failed.
*/
return (-1);
}
/* start searching this directory */
/* skip . .. etc... */
continue;
/* open the memory controller driver */
found = 1;
break;
}
valid_entry = 1;
}
if (!found) {
if (valid_entry)
return (-1);
}
/*
* Initialize some global variables via ioctl
*/
return (-1);
}
return (fd);
}
/*
* executed as part of .init when the plugin is dlopen()ed
*/
void
piclmemcfg_register(void)
{
(void) picld_plugin_register(&my_reg_info);
}
/*
* init entry point of the plugin
* Creates the PICL nodes and properties in the physical and logical aspects.
*/
void
piclmemcfg_init(void)
{
/*
* Initialize the header pointer of mmodgrp_info list
*/
head2mmodgrp = NULL;
msegh_info = NULL;
return;
/*
* allocate memory to save memory-segment node handles. Thus,
* it is easier to delete them if it fails.
*/
NULL) {
return;
}
/*
* find platform node
*/
return;
}
/*
* Find the memory node
*/
return;
}
/*
* Create subtree of memory-controller in the physical aspect.
* memory-controller --- memory-module-group --- memory-module
*/
if (err != PICL_SUCCESS) {
}
/*
* Add property, TransferSize to memory node
*/
if (err != PICL_SUCCESS) {
return;
}
&transfersize, NULL);
if (err != PICL_SUCCESS) {
return;
}
/*
* Create subtree of memory in the logical aspect.
* memory --- memory-segment --- memory-bank
*/
}
}
/*
* fini entry point of the plugin
*/
void
piclmemcfg_fini(void)
{
/*
* Release all the allocated memory for global structures
*/
if (msegh_info)
}
/*
* Event handler of this plug-in
*/
/*ARGSUSED*/
static void
void *cookie)
{
int err;
int fd;
int old_nsegs;
return;
return;
}
/*
* get the memory node
*/
if (err != PICL_SUCCESS)
return;
/*
* nsegments won't be overwritten until init_mc succeeds
*/
return;
/*
* Delete the entry at the list only since class at PICL is
* deleted in devtree plugin.
*/
(void) del_plugout_mmodgrp(nodeh);
(void) undo_logical_tree(old_nsegs);
/*
* allocate memory to save memory-segment node handles. Thus,
* it is easier to delete them if it fails.
*/
NULL) {
return;
}
}