dmfe_ndd.c revision 0d2a8e5eea8ac6ea0f5c517f0c481329b57d5459
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/dmfe_impl.h>
/*
* The following variables are used for configuring link-operation
* for all the "dmfe" interfaces in the system. Later these parameters
* may be changed per interface using "ndd" command. These parameters
* may also be specified as properties using the .conf file mechanism
* for each interface.
*/
static int adv_autoneg_cap = 1;
static int adv_10hdx_cap = 1;
static int adv_10fdx_cap = 1;
static int adv_100hdx_cap = 1;
static int adv_100fdx_cap = 1;
static int adv_100T4_cap = 0;
/*
* Property names
*/
static char transfer_speed_propname[] = "transfer-speed";
static char speed_propname[] = "speed";
static char duplex_propname[] = "full-duplex";
/*
* Notes:
* <name> field terminates the array.
*
* The <info> field is used here to provide the index of the
* parameter to be initialised; thus it doesn't matter whether
* this table is kept ordered or not.
*
* The <info> field in the per-instance copy, on the other hand,
* is used to count assignments so that we can tell when a magic
* parameter has been set via ndd (see dmfe_param_set()).
*/
static const nd_param_t nd_template[] = {
/* info min max init r/w+name */
{ PARAM_COUNT, 0, 0, 0, NULL }
};
/* ============== NDD Support Functions =============== */
/*
* Extracts the value from the dmfe parameter array and prints
* the parameter value. cp points to the required parameter.
*/
static int
{
return (0);
}
/*
* Validates the request to set a DMFE parameter to a specific value.
* If the request is OK, the parameter is set. Also the <info> field
* is incremented to show that the parameter was touched, even though
* it may have been set to the same value it already had.
*/
static int
{
char *end;
return (EACCES); /* shouldn't happen! */
return (EINVAL);
return (EINVAL);
return (0);
}
/*
* Initialise the per-instance parameter array from the global prototype,
* and register each element with the named dispatch handler using nd_load()
*/
static boolean_t
{
const nd_param_t *tmplp;
char *nm;
/*
* Copy the template from nd_template[] into the
* proper slot in the per-instance parameters, and
* then register it with nd_load()
*/
goto nd_fail;
}
DMFE_DEBUG(("dmfe_param_register: OK"));
return (B_TRUE);
DMFE_DEBUG(("dmfe_param_register: FAILED at index %d [info %d]",
return (B_FALSE);
}
int
{
int duplex;
int speed;
int pval;
return (-1);
/*
* Set up the start-up values for user-configurable parameters.
* Get the values from the global variables first.
*/
/*
* The link speed may be forced to either 10 Mbps or 100 Mbps
* using the property "transfer-speed". This may be done in OBP
* by using the command "apply transfer-speed=<speed> <device>".
* The speed may be 10 or 100 - other values will be ignored.
* Note that this does *enables* autonegotiation, but restricts
* it to the speed specified by the property.
*/
0, transfer_speed_propname, -1);
if (speed != -1) {
switch (speed) {
case 100:
dmfep->param_anar_10hdx = 0;
dmfep->param_anar_10fdx = 0;
break;
case 10:
dmfep->param_anar_100hdx = 0;
dmfep->param_anar_100fdx = 0;
break;
default:
break;
}
}
/*
* Get the parameter values configured in .conf file.
* These override both the global defaults AND any
* value derived from the "transfer-speed" property.
*/
if (pval != -1)
if (pval != -1)
if (pval != -1)
if (pval != -1)
if (pval != -1)
if (pval != -1)
/*
* Finally, check the "speed" and "full-duplex" properties that
* may be specified in the .conf file. Setting either one of
* these properties will override all other settings and *disable*
* autonegotiation, with the consequence that both should be
* specified if either one is. Otherwise, the unspecified
* parameter will be set to a default value (100Mb/s, half-duplex).
*/
/* force speed */
dmfep->param_anar_100T4 = 0;
dmfep->param_autoneg = 0;
switch (speed) {
case 10:
dmfep->param_anar_100hdx = 0;
dmfep->param_anar_100fdx = 0;
break;
case 100:
default:
dmfep->param_anar_10hdx = 0;
dmfep->param_anar_10fdx = 0;
break;
}
switch (duplex) {
case 1:
dmfep->param_anar_10hdx = 0;
dmfep->param_anar_100hdx = 0;
break;
default:
case 0:
dmfep->param_anar_10fdx = 0;
dmfep->param_anar_100fdx = 0;
break;
}
}
return (0);
}
enum ioc_reply
{
int ok;
switch (cmd) {
default:
/*
* This should never happen ...
*/
return (IOC_INVAL);
case DMFE_ND_GET:
/*
* If nd_getset() returns B_FALSE, the command was
* not valid (e.g. unknown name), so we just tell the
* top-level ioctl code to send a NAK (with code EINVAL).
*
* Otherwise, nd_getset() will have built the reply to
* be sent (but not actually sent it), so we tell our
* caller to send the prepared reply.
*/
case DMFE_ND_SET:
/*
* Before calling nd_getset(), we save the <info> field
* of the 'autonegotiation' parameter so that we can tell
* whether it was assigned (even if its value doesn't
* actually change).
*
* If nd_getset() returns B_FALSE, the command was
* not valid (e.g. unknown name), so we just tell the
* top-level ioctl code to send a NAK (with code EINVAL).
*
* Otherwise, nd_getset() will have built the reply to
* be sent (but not actually sent it). If the command
* didn't touch the magic 'autonegotiation' parameter,
* we can just tell our caller to send the prepared reply.
*
* If the 'autonegotiation' parameter *was* touched, we
* flag it so the top-level ioctl code knows to update
* the PHY and restart the chip before replying ...
*/
DMFE_DEBUG(("dmfe_nd_ioctl: set %s autoneg %d info %d/%d",
if (!ok)
return (IOC_INVAL);
return (IOC_REPLY);
return (IOC_RESTART);
}
}
/* Free the Named Dispatch Table by calling nd_free */
void
{
}