xge.c revision 7eced415e5dd557aef2d78483b5a7785f0e13670
/*
* 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"
/*
* Copyright (c) 2002-2005 Neterion, Inc.
* All right Reserved.
*
* FileName : xge.c
*
* Description: Xge main Solaris specific initialization & routines
* for upper layer driver
*
*/
#include "xgell.h"
/* Standard Module linkage initialization for a Streams driver */
extern struct mod_ops mod_driverops;
&mod_driverops, /* Type of module. This one is a driver */
XGELL_DESC, /* short description */
&xge_ops /* driver specific ops */
};
static struct modlinkage modlinkage = {
};
/* Xge device attributes */
};
/*
* xge_event
*
* This function called by HAL to notify upper layer that some any
* event been produced.
*/
void
{
switch (item->event_type) {
if (lldev->is_initialized) {
>= XGELL_TX_LEVEL_HIGH) {
"mac_tx_update happened!");
}
}
break;
default:
break;
}
}
/*
* xgell_callback_crit_err
*
* This function called by HAL on Serious Error event. XGE_HAL_EVENT_SERR.
* Upper layer must analyze it based on %type.
*/
static void
{
(void) xgell_onerr_reset(userdata);
}
/*
* xge_xpak_alarm_log
* This function called by HAL on XPAK alarms. Upper layer must log the msg
* based on the xpak alarm type
*/
static void
{
switch (type) {
"service. Excessive temperatures may result in "
"premature transceiver failure \n");
break;
"service Excessive bias currents may indicate "
"imminent laser diode failure \n");
break;
"service Excessive laser output power may saturate "
"far-end receiver\n");
break;
default:
break;
}
}
/*
* xge_queue_produce context
*/
static void
{
if (event_type == XGELL_EVENT_RESCHED_NEEDED) {
}
}
/*
* xge_driver_init_hal
*
* To initialize HAL portion of driver.
*/
static xge_hal_status_e
xge_driver_init_hal(void)
{
static xge_hal_driver_config_t driver_config;
}
/*
* _init
*
* Solaris standard _init function for a device driver
*/
int
_init(void)
{
int ret = 0;
if (status != XGE_HAL_OK) {
status);
return (EINVAL);
}
xge_hal_driver_debug_module_mask_set(0xffffffff);
"Unable to install the driver");
return (ret);
}
return (0);
}
/*
* _fini
*
* Solaris standard _fini function for device driver
*/
int
_fini(void)
{
int ret;
if (ret == 0) {
}
return (ret);
}
/*
* _info
*
* Solaris standard _info function for device driver
*/
int
{
}
/* ARGSUSED */
/*
* xge_isr
* @arg: pointer to device private strucutre(hldev)
*
* This is the ISR scheduled by the OS to indicate to the
*/
static uint_t
{
if (!lldev->is_initialized) {
return (DDI_INTR_UNCLAIMED);
}
return ((status == XGE_HAL_ERR_WRONG_IRQ) ?
}
/*
* Interrupt handler for transmit when MSI-X interrupt mechasnism is used
*/
/* ARGSUSED */
static uint_t
{
int got_tx;
if (!lldev->is_initialized) {
return (DDI_INTR_UNCLAIMED);
}
return (DDI_INTR_CLAIMED);
}
/*
* Interrupt handler for receive when MSI-X interrupt mechasnism is used
*/
/* ARGSUSED */
static uint_t
{
int got_rx;
if (!lldev->is_initialized) {
return (DDI_INTR_UNCLAIMED);
}
return (DDI_INTR_CLAIMED);
}
/*
* Configure single ring
*/
static void
{
/* no point to configure it further if unconfigured */
return;
#if defined(__sparc)
#endif
} else {
}
}
"ring%d_backoff_interval_us", num);
/* enable RTH steering by default */
}
}
/*
* Configure single fifo
*/
static void
{
/* no point to configure it further */
return;
#if defined(__sparc)
#endif
} else {
}
}
/*
* TTI 0 configuration
*/
}
/*
* xge_configuration_init
* @device_config: pointer to xge_hal_device_config_t
*
* This function will lookup properties from .conf file to init
* the configuration data structure. If a property is not in .conf
* file, the default value should be set.
*/
static void
{
int i, rings_configured = 0, fifos_configured = 0;
/*
* Initialize common properties
*/
/*
* Initialize ring properties
*/
/*
* Bimodal Interrupts - TTI 56 configuration
*/
/*
* MSI-X switch
*/
/*
* Go through all possibly configured rings. Each ring could be
* set ring->configured = [1|0].
*
* By default *all* rings enabled.
*/
for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
}
/*
* Initialize mac properties
*/
1); /* HAL never provide a good named macro */
/*
* Initialize fifo properties
*/
#ifdef XGE_HAL_ALIGN_XMIT
#endif
/*
* Go through all possibly configured fifos. Each fifo could be
* set fifo->configured = [0|1].
*
* By default *all* fifos enabled.
*/
for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++) {
}
/*
* Initialize errors dumping
*/
0);
0);
0);
/*
* LRO tunables
*/
/*
* Initialize link layer configuration
*/
}
/*
* xge_alloc_intrs:
*
* Allocate FIXED or MSIX interrupts.
*/
static int
{
int i, intr_behavior, ret;
} else {
}
/* Get number of interrupts */
goto _err_exit0;
}
/* Get number of available interrupts */
goto _err_exit0;
}
goto _err_exit0;
}
/* Allocate an array of interrupt handles */
/* Call ddi_intr_alloc() */
goto _err_exit1;
}
goto _err_exit2;
}
/*
* Get priority for first msi, assume remaining are all the same
*/
DDI_SUCCESS) {
goto _err_exit2;
}
return (DDI_SUCCESS);
/* Free already allocated intr */
for (i = 0; i < actual; i++) {
}
return (DDI_FAILURE);
}
/*
* xge_free_intrs:
*
* Free previously allocated interrupts.
*/
static void
{
int i;
/* Free already allocated intr */
}
}
/*
* xge_add_intrs:
*
* Register FIXED or MSI interrupts.
*/
int
{
int i, ret;
XGELL_MAX_FIFO_DEFAULT + 1];
case DDI_INTR_TYPE_FIXED:
if (ret != DDI_SUCCESS) {
"failed %d", ret);
return (DDI_FAILURE);
}
break;
case DDI_INTR_TYPE_MSIX:
i = 0;
msix_idx++;
}
} else {
msix_idx++;
}
}
}
/* partition MSIX vectors */
if (i == 0) {
"Channel-A: using MSI-X #0");
"using MSI-X #%d",
"using MSI-X #%d",
}
if (ret != DDI_SUCCESS) {
int j;
"ddi_intr_add_handler()"
" failed %d", ret);
for (j = 0; j < i; j++) {
(void) ddi_intr_remove_handler(
lldev->intr_table[j]);
}
return (DDI_FAILURE);
}
}
for (i = 1; i < msix_idx; i++)
(void) xge_hal_channel_msix_set(assigned[i], i);
break;
default:
break;
}
if (ret != DDI_SUCCESS) {
}
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* xge_enable_intrs:
*
* Enable FIXED or MSI interrupts
*/
int
{
int ret, i;
/* Call ddi_intr_block_enable() for MSI(X) interrupts */
"ret 0x%x", ret);
return (DDI_FAILURE);
}
} else {
/* Call ddi_intr_enable for MSI(X) or FIXED interrupts */
!= DDI_SUCCESS) {
int j;
"failed, ret 0x%x", ret);
/* unwind */
for (j = 0; j < i; j++) {
(void) ddi_intr_disable(
lldev->intr_table[j]);
}
return (DDI_FAILURE);
}
}
}
return (DDI_SUCCESS);
}
/*
* xge_disable_intrs:
*
* Disable FIXED or MSI interrupts
*/
void
{
int i;
/* Call ddi_intr_block_disable() */
} else {
}
}
}
/*
* xge_rem_intrs:
*
* Unregister FIXED or MSI interrupts
*/
void
{
int i;
/* Call ddi_intr_remove_handler() */
}
}
/*
* xge_attach
* @dev_info: pointer to dev_info_t structure
* @cmd: attach command to process
*
* This is a solaris standard attach function. This
* function initializes the Xframe identified
* by the dev_info_t structure and setup the driver
* data structures corresponding to the Xframe Card.
* This function also registers the XFRAME device
* instance with the MAC Layer.
* If this function returns success then the OS
* will attach the HBA controller to this
* driver.
*/
static int
{
xgelldev_t *ll;
int ret, intr_types, i;
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
case DDI_PM_RESUME:
ret = DDI_FAILURE;
goto _exit0;
default:
ret = DDI_FAILURE;
goto _exit0;
}
/* Init device_config by lookup up properties from .conf file */
/* Determine which types of interrupts supported */
"fixed type interrupt is not supported");
goto _exit0a;
}
/* map BAR0 */
if (ret != DDI_SUCCESS) {
goto _exit0a;
}
/* map BAR1 */
if (ret != DDI_SUCCESS) {
goto _exit1;
}
/* map BAR2 MSI(X) */
if (ret != DDI_SUCCESS) {
goto _exit1a;
}
/* preallocate memory for new HAL device and private LL part */
/* Get the PCI Configuartion space handle */
if (ret != DDI_SUCCESS) {
goto _exit2a;
}
if (ret != DDI_SUCCESS) {
"%s",
"unable to allocate new LL device");
goto _exit3;
}
for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++)
for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++)
} else {
}
ll_config.msix_enable = 0;
"Unable to allocate MSI-X handlers"
" - defaulting to IRQA");
continue;
}
goto _exit3a;
}
} else {
}
/* initialize HW */
if (status != XGE_HAL_OK) {
switch (status) {
"driver is not initialized");
ret = DDI_FAILURE;
goto _exit3b;
"device is not quiescent");
goto _exit3b;
"unable to allocate memory");
ret = DDI_ENOMEM;
goto _exit3b;
default:
"can't initialize the device: %d", status);
ret = DDI_FAILURE;
goto _exit3b;
}
}
/* register interrupt handler for handling xge device interrupts */
if (ret != DDI_SUCCESS)
goto _exit4;
/* allocate and register Link Layer */
if (ret != DDI_SUCCESS) {
goto _exit5;
}
/* store ll as a HAL private part */
return (DDI_SUCCESS);
return (ret);
}
/*
* xge_detach
* @dev_info: pointer to dev_info_t structure
* @cmd: attach command to process
*
* This function is called by OS when the system is about
* to shutdown or when the super user tries to unload
* the driver. This function frees all the memory allocated
* during xge_attch() and also unregisters the Xframe
* device instance from the GLD framework.
*/
static int
{
switch (cmd) {
case DDI_DETACH:
break;
case DDI_PM_SUSPEND:
return (DDI_FAILURE);
default:
return (DDI_FAILURE);
}
if (lldev->is_initialized) {
"can not detach: device is not unplumbed");
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}