e1000g_main.c revision 0f70fbf80d71251e7928b3122fb4848c2f92a5c6
/*
* This file is provided under a CDDLv1 license. When using or
* redistributing this file, you may do so under this license.
* In redistributing this file this license must be included
* and no other modification of this header file is permitted.
*
* CDDL LICENSE SUMMARY
*
* Copyright(c) 1999 - 2007 Intel Corporation. All rights reserved.
*
* The contents of this file are subject to the terms of Version
* 1.0 of the Common Development and Distribution License (the "License").
*
* You should have received a copy of the License with this software.
* You can obtain a copy of the License at
* See the License for the specific language governing permissions
* and limitations under the License.
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms of the CDDLv1.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* **********************************************************************
* *
* Module Name: *
* e1000g_main.c *
* *
* Abstract: *
* This file contains the interface routine for the solaris OS. *
* It has all DDI entry point routines and GLD entry point *
* routines. *
* This file also contains routines that takes care of initialization *
* uninit routine and interrupt routine *
* *
* *
* Environment: *
* Kernel Mode - *
* *
* **********************************************************************
*/
#include "e1000g_sw.h"
#include "e1000g_debug.h"
#define E1000_RX_INTPT_TIME 128
#define E1000_RX_PKT_CNT 8
static char ident[] = "Intel PRO/1000 Ethernet 5.1.9";
static char e1000g_string[] = "Intel(R) PRO/1000 Network Connection";
static char e1000g_version[] = "Driver Ver. 5.1.9";
/*
* Proto types for DDI entry points
*/
/*
* init and intr routines prototype
*/
#pragma inline(e1000g_intr_work)
static int e1000g_init(struct e1000g *);
static int e1000g_start(struct e1000g *);
static void e1000g_stop(struct e1000g *);
static int e1000g_m_start(void *);
static void e1000g_m_stop(void *);
static int e1000g_m_promisc(void *, boolean_t);
static int e1000g_m_unicst(void *, const uint8_t *);
static int e1000g_m_unicst_add(void *, mac_multi_addr_t *);
static int e1000g_m_unicst_remove(void *, mac_addr_slot_t);
static int e1000g_m_unicst_modify(void *, mac_multi_addr_t *);
static int e1000g_m_unicst_get(void *, mac_multi_addr_t *);
static void e1000g_m_resources(void *);
/*
* Local routines
*/
static void e1000g_link_timer(void *);
static void e1000g_LocalTimer(void *);
static void e1000g_smartspeed(struct e1000g *);
static int e1000g_getprop(struct e1000g *, char *, int, int, int);
#ifdef __sparc
#endif
nulldev, /* cb_open */
nulldev, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
nodev, /* cb_read */
nodev, /* cb_write */
nodev, /* cb_ioctl */
nodev, /* cb_devmap */
nodev, /* cb_mmap */
nodev, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
NULL, /* cb_stream */
CB_REV, /* cb_rev */
nodev, /* cb_aread */
nodev /* cb_awrite */
};
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
NULL, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
e1000gattach, /* devo_attach */
e1000gdetach, /* devo_detach */
nodev, /* devo_reset */
&cb_ws_ops, /* devo_cb_ops */
NULL, /* devo_bus_ops */
ddi_power /* devo_power */
};
&mod_driverops, /* Type of module. This one is a driver */
ident, /* Discription string */
&ws_ops, /* driver ops */
};
static struct modlinkage modlinkage = {
};
/*
* DMA access attributes <Little Endian Card>
*/
static ddi_device_acc_attr_t accattr1 = {
};
static mac_callbacks_t e1000g_m_callbacks = {
};
/*
* Global variables
*/
/*
* Here we maintain a private dev_info list if e1000g_force_detach is
* enabled. If we force the driver to detach while there are still some
* rx buffers retained in the upper layer, we have to keep a copy of the
* dev_info. In some cases (Dynamic Reconfiguration), the dev_info data
* structure will be freed after the driver is detached. However when we
* finally free those rx buffers released by the upper layer, we need to
* refer to the dev_info to free the dma buffers. So we save a copy of
* the dev_info for this purpose.
*/
/*
* The rwlock is defined to protect the whole processing of rx recycling
* and the rx packets release in detach processing to make them mutually
* exclusive.
* The rx recycling processes different rx packets in different threads,
* so it will be protected with RW_READER and it won't block any other rx
* recycling threads.
* While the detach processing will be protected with RW_WRITER to make
* it mutually exclusive with the rx recycling.
*/
/*
* The rwlock e1000g_dma_type_lock is defined to protect the global flag
* e1000g_dma_type. For SPARC, the initial value of the flag is "USE_DVMA".
* If there are many e1000g instances, the system may run out of DVMA
* resources during the initialization of the instances, then the flag will
* be changed to "USE_DMA". Because different e1000g instances are initialized
* in parallel, we need to use this lock to protect the flag.
*/
/*
* Loadable module configuration entry points for the driver
*/
/*
* **********************************************************************
* Name: _init *
* *
* Description: *
* Initializes a loadable module. It is called before *
* any other routine in a loadable module. *
* All global locks are intialised here and it returns the retun *
* value from mod_install() *
* This is mandotary function for the driver *
* Parameter Passed: *
* None *
* Return Value: *
* 0 on success *
* Functions called *
* mod_install() (system call) *
* *
* **********************************************************************
*/
int
_init(void)
{
int status;
if (status != DDI_SUCCESS)
else {
}
return (status);
}
/*
* **********************************************************************
* Name: _fini *
* *
* Description: *
* Prepares a loadable module for unloading. It is *
* called when the system wants to unload a module. *
* This is mandotary function for the driver *
* Parameter Passed: *
* None *
* Return Value: *
* 0 on success *
* Functions called *
* mod_remove() (system call) *
* *
* *
* *
* **********************************************************************
*/
int
_fini(void)
{
int status;
if (e1000g_mblks_pending != 0) {
return (EBUSY);
}
if (status == DDI_SUCCESS) {
if (e1000g_force_detach) {
while (e1000g_private_devi_list != NULL) {
sizeof (struct dev_info));
sizeof (private_devi_list_t));
}
}
}
return (status);
}
/*
* **********************************************************************
* Name: _info *
* *
* Description: *
* Returns information about a loadable module. *
* This is mandotary function for the driver *
* Parameter Passed: *
* module info structure *
* Return Value: *
* 0 on success *
* Functions called *
* mod_info() (system call) *
* *
* *
* **********************************************************************
*/
int
{
}
/*
* Interface exists: make available by filling in network interface
* record. System will initialize the interface when it is ready
* to accept packets.
*/
/*
* **********************************************************************
* Name: e1000gattach *
* *
* Description: *
* This function is the device-specific initialization *
* entry point. This entry point is required and must be writ- *
* ten. The DDI_ATTACH command must be provided in the attach *
* entry point. When attach() is called with cmd set to DDI_ATTACH, *
* all normal kernel services (such as kmem_alloc(9F)) are *
* available for use by the driver. Device interrupts are not *
* blocked when attaching a device to the system. *
* *
* The attach() function will be called once for each instance *
* of the device on the system with cmd set to DDI_ATTACH. *
* Until attach() succeeds, the only driver entry points which *
* may be called are open(9E) and getinfo(9E). *
* *
* *
* *
* Parameter Passed: *
* *
* Return Value: *
* *
* Functions called *
* *
* *
* **********************************************************************
*/
static int
{
int instance;
switch (cmd) {
default:
"Unsupported command send to e1000gattach... ");
return (DDI_FAILURE);
case DDI_RESUME:
return (e1000g_resume(devinfo));
case DDI_ATTACH:
break;
}
/*
* get device instance number
*/
/*
* Allocate soft data structure
*/
Adapter =
if (e1000g_force_detach) {
break;
}
}
if (devi_existed) {
} else {
sizeof (struct dev_info));
}
}
/*
* Map in the device registers.
*
* first get the size of device register to be mapped. The
* second parameter is the register we are interested. I our
* wiseman 0 is for config registers and 1 is for memory mapped
* registers Mem size should have memory mapped region size
*/
!= DDI_SUCCESS) {
goto attach_fail;
}
/*
* PCI Configure
*/
"PCI configuration could not be read.");
goto attach_fail;
}
hw->revision_id =
hw->subsystem_id =
/*
* Initialize driver parameters
*/
goto attach_fail;
}
/*
* Initialize interrupts
*/
goto attach_fail;
}
/*
* Initialize mutex's for this device.
* Do this before enabling the interrupt handler and
* register the softint to avoid the condition where
* interrupt handler can try using uninitialized mutex
*/
goto attach_fail;
}
/*
* Initialize Driver Counters
*/
goto attach_fail;
}
/*
* Allocate dma resources for descriptors and buffers
*/
goto attach_fail;
}
/*
* Initialize chip hardware and software structures
*/
goto attach_fail;
}
/*
* Initialize NDD parameters
*/
goto attach_fail;
}
/*
* Register the driver to the MAC
*/
goto attach_fail;
}
/*
* Now that mutex locks are initialized, and the chip is also
* initialized, enable interrupts.
*/
goto attach_fail;
}
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
static int
{
int err;
return (DDI_FAILURE);
}
static int
{
#ifdef __sparc
#endif
/* Set Mac Type */
if (e1000_set_mac_type(hw) != 0) {
"Could not identify hardware");
return (DDI_FAILURE);
}
/* ich8 needs to map flash memory */
/* get flash size */
"ddi_dev_regsize for ich8 flash failed");
return (DDI_FAILURE);
}
/* map flash in */
&accattr1,
"ddi_regs_map_setup for for ich8 flash failed");
return (DDI_FAILURE);
}
}
/* get mem_base addr */
/* get io_base addr */
/* IO BAR is different for 64 bit BAR mode */
} else {
/* normal 32-bit BAR mode */
}
} else {
/* no I/O access for adapters prior to 82544 */
}
/* Set the wait_autoneg_complete flag to B_FALSE */
/* Adaptive IFS related changes */
/* set phy init script revision */
/* Enable the TTL workaround for TnT: DCR 49 */
/* Get conf file properties */
hw->min_frame_size =
#ifdef __sparc
/* Get the system page size */
if (iommu_pagesize != 0) {
if (iommu_pagesize > 0x4000)
} else {
}
}
#endif
switch (hw->max_frame_size) {
case ETHERMAX:
break;
case FRAME_SIZE_UPTO_4K:
break;
case FRAME_SIZE_UPTO_8K:
break;
case FRAME_SIZE_UPTO_10K:
case FRAME_SIZE_UPTO_16K:
break;
default:
break;
}
/*
* For Wiseman adapters we have an requirement of having receive
* buffers aligned at 256 byte boundary. Since Livengood does not
* require this and forcing it for all hardwares will have
* performance implications, I am making it applicable only for
* Wiseman and for Jumbo frames enabled mode as rest of the time,
* it is okay to have normal frames...but it does involve a
* potential risk where we may loose data if buffer is not
* aligned...so all wiseman boards to have 256 byte aligned
* buffers
*/
else
/*
* For livengood, there is no such Rcv buf alignment
* requirement
*/
/* DmaFairness */
else
hw->dma_fairness = 0;
/* MasterLatencyTimer */
/* MWIEnable */
/* profile jumbo traffic */
/* copper options */
}
return (DDI_SUCCESS);
}
/*
* **********************************************************************
* Name: e1000gdettach *
* *
* Description: *
* The detach() function is the complement of the attach routine. *
* If cmd is set to DDI_DETACH, detach() is used to remove the *
* state associated with a given instance of a device node *
* prior to the removal of that instance from the system. *
* *
* The detach() function will be called once for each instance *
* of the device for which there has been a successful attach() *
* once there are no longer any opens on the device. *
* *
* Interrupts routine are disabled, All memory allocated by this *
* driver are freed. *
* *
* Parameter Passed: *
* devinfo structure, cmd *
* *
* Return Value: *
* DDI_SUCCESS on success *
* *
* Functions called *
* *
* *
* **********************************************************************
*/
static int
{
switch (cmd) {
default:
return (DDI_FAILURE);
case DDI_SUSPEND:
return (e1000g_suspend(devinfo));
case DDI_DETACH:
break;
}
return (DDI_FAILURE);
if (!e1000g_rx_drain(Adapter)) {
if (!e1000g_force_detach)
return (DDI_FAILURE);
}
"Disable DDI interrupts failed");
return (DDI_FAILURE);
}
"Unregister MAC failed");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static void
{
(void) e1000g_disable_intrs(Adapter);
}
}
}
(void) e1000g_rem_intrs(Adapter);
}
}
(void) ddi_prop_remove_all(devinfo);
}
}
timeout_id_t tid = 0;
/* Disable the link timer */
if (tid != 0)
}
}
}
}
}
/*
* Another hotplug spec requirement,
* run ddi_set_driver_private(devinfo, null);
*/
}
static void
{
}
static void
{
}
static int
{
return (DDI_FAILURE);
if (e1000g_start(Adapter))
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
static int
{
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
static int
{
/* Preserve manageability features */
/*
* reset to put the hardware in a known state
* before we try to do anything with the eeprom
*/
(void) e1000_reset_hw(hw);
(void) e1000_init_eeprom_params(hw);
if (e1000_validate_eeprom_checksum(hw) < 0) {
/*
* Some PCI-E parts fail the first check due to
* the link being in sleep state. Call it again,
* if it fails a second time its a real issue.
*/
if (e1000_validate_eeprom_checksum(hw) < 0) {
"Invalid EEPROM checksum. Please contact "
"the vendor to update the EEPROM.");
goto init_fail;
}
}
#ifdef __sparc
/*
* Firstly, we try to get the local ethernet address from OBP. If
* fail, we get from EEPROM of NIC card.
*/
if (!e1000g_find_mac_address(Adapter)) {
if (e1000_read_mac_addr(hw) < 0) {
goto init_fail;
}
}
#else
/* Get the local ethernet address. */
if (e1000_read_mac_addr(hw) < 0) {
goto init_fail;
}
#endif
/* check for valid mac address */
goto init_fail;
}
/* Master Latency Timer implementation */
if (Adapter->MasterLatencyTimer) {
}
/*
* Total FIFO is 64K
*/
else
/*
* Total FIFO is 48K
*/
else
} else {
/*
* Total FIFO is 40K
*/
else
}
/*
* These parameters set thresholds for the adapter's generation(Tx)
* and response(Rx) to Ethernet PAUSE frames. These are just threshold
* settings. Flow control is enabled or disabled in the configuration
* file.
* High-water mark is set down from the top of the rx fifo (not
* sensitive to max_frame_size) and low-water is set just below
* high-water mark.
*/
hw->fc_high_water =
hw->fc_low_water =
/*
* Reset the adapter hardware the second time.
*/
(void) e1000_reset_hw(hw);
/* disable wakeup control by default */
/* MWI setup */
} else
/*
* Configure/Initialize hardware
*/
if (e1000_init_hw(hw) < 0) {
goto init_fail;
}
/* Disable Smart Power Down */
/*
* Initialize unicast addresses.
*/
/*
* Setup and initialize the transmit structures.
*/
/*
* Setup and initialize the mctable structures. After this routine
* completes Multicast table will be set
*/
/*
* Setup and initialize the receive structures. After this routine
* completes we can receive packets off of the wire.
*/
/*
* Implement Adaptive IFS
*/
/* Setup Interrupt Throttling Register */
/* Start the timer for link setup */
else
if (hw->wait_autoneg_complete) {
} else {
(void *)Adapter, link_timeout);
}
/* Enable PCI-Ex master */
}
Adapter->init_count++;
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
/*
* Check if the link is up
*/
static boolean_t
{
/* Ensure this is set to get accurate copper link status */
(!hw->serdes_link_down))) {
} else {
}
return (link_up);
}
static void
{
int err;
return;
}
case LB_GET_INFO_SIZE:
case LB_GET_INFO:
case LB_GET_MODE:
case LB_SET_MODE:
break;
case ND_GET:
case ND_SET:
break;
case E1000G_IOC_REG_PEEK:
case E1000G_IOC_REG_POKE:
break;
case E1000G_IOC_CHIP_RESET:
e1000gp->reset_count++;
if (e1000g_reset(e1000gp))
else
break;
default:
break;
}
/*
* Decide how to reply
*/
switch (status) {
default:
case IOC_INVAL:
/*
* Error, reply with a NAK and EINVAL or the specified error
*/
break;
case IOC_DONE:
/*
* OK, reply already sent
*/
break;
case IOC_ACK:
/*
* OK, reply with an ACK
*/
break;
case IOC_REPLY:
/*
* OK, send prepared reply as ACK or NAK
*/
break;
}
}
{
/*
* Adjust ITR (Interrupt Throttling Register) to coalesce
* interrupts. This formula and its coefficient come from
* our experiments.
*/
if (Adapter->intr_adaptive) {
}
}
static void
e1000g_m_resources(void *arg)
{
}
static int
e1000g_m_start(void *arg)
{
return (e1000g_start(Adapter));
}
static int
{
"Adapter initialization failed");
return (ENOTACTIVE);
}
}
if (Adapter->tx_intr_enable)
return (0);
}
static void
e1000g_m_stop(void *arg)
{
}
static void
{
/* Set stop flags */
/* Drain tx sessions */
(void) e1000g_tx_drain(Adapter);
/* Disable timers */
/* Disable the tx timer for 82547 chipset */
tx_ring->timer_id_82547 = 0;
if (tid != 0)
/* Disable the link timer */
if (tid != 0)
/* Stop the chip and release pending resources */
/* Release resources still held by the TX descriptors */
/* Clean the pending rx jumbo packet fragment */
Adapter->rx_packet_len = 0;
}
}
static void
{
/*
* Here we don't need to protect the lists using
* the usedlist_lock and freelist_lock, for they
* have been protected by the chip_lock.
*/
packet_count = 0;
/* Assemble the message chain */
} else {
}
/* Disconnect the message from the sw packet */
}
packet_count++;
packet = (PTX_SW_PACKET)
}
} else {
}
}
if (packet_count > 0) {
/* Setup TX descriptor pointers */
/* Setup our HW Tx Head & Tail descriptor pointers */
}
}
static boolean_t
{
int i;
/* Allow up to 'wsdraintime' for pending xmit's to complete. */
for (i = 0; i < WSDRAINTIME; i++) {
if (done)
break;
msec_delay(1);
}
return (done);
}
static boolean_t
{
return (done);
}
{
if (e1000g_start(Adapter)) {
return (B_FALSE);
}
return (B_TRUE);
}
/*
* **********************************************************************
* Name: e1000g_intr_pciexpress *
* *
* Description: *
* This interrupt service routine is for PCI-Express adapters. *
* The ICR contents is valid only when the E1000_ICR_INT_ASSERTED *
* bit is set. *
* *
* Parameter Passed: *
* *
* Return Value: *
* *
* Functions called: *
* e1000g_intr_work *
* *
* **********************************************************************
*/
static uint_t
{
if (ICRContents & E1000_ICR_INT_ASSERTED) {
/*
* E1000_ICR_INT_ASSERTED bit was set:
* Read(Clear) the ICR, claim this interrupt,
* look for work to do.
*/
return (DDI_INTR_CLAIMED);
} else {
/*
* E1000_ICR_INT_ASSERTED bit was not set:
* Don't claim this interrupt, return immediately.
*/
return (DDI_INTR_UNCLAIMED);
}
}
/*
* **********************************************************************
* Name: e1000g_intr *
* *
* Description: *
* We check the ICR contents no matter the E1000_ICR_INT_ASSERTED *
* bit is set or not. *
* *
* Parameter Passed: *
* *
* Return Value: *
* *
* Functions called: *
* e1000g_intr_work *
* *
* **********************************************************************
*/
static uint_t
{
if (ICRContents) {
/*
* Any bit was set in ICR:
* Read(Clear) the ICR, claim this interrupt,
* look for work to do.
*/
return (DDI_INTR_CLAIMED);
} else {
/*
* No bit was set in ICR:
* Don't claim this interrupt, return immediately.
*/
return (DDI_INTR_UNCLAIMED);
}
}
/*
* **********************************************************************
* Name: e1000g_intr_work *
* *
* Description: *
* Called from interrupt service routines. *
* Read(clear) the ICR contents and call appropriate interrupt *
* processing routines. *
* *
* Parameter Passed: *
* *
* Return Value: *
* *
* Functions called: *
* e1000g_receive *
* e1000g_link_check *
* e1000g_recycle *
* *
* **********************************************************************
*/
static void
{
if (ICRContents & E1000_ICR_RXT0) {
/*
* Here we need to check the "started" flag to ensure the
* receive routine will not execute when the adapter is
* stopped or being reset.
*/
} else {
}
}
/*
* The Receive Sequence errors RXSEQ and the link status change LSC
* are checked to detect that the cable has been pulled out. For
* the Wiseman 2.0 silicon, the receive sequence errors interrupt
* are an indication that cable is not connected.
*/
if ((ICRContents & E1000_ICR_RXSEQ) ||
(ICRContents & E1000_ICR_LSC) ||
(ICRContents & E1000_ICR_GPI_EN1)) {
timeout_id_t tid = 0;
/*
* Encountered RX Sequence Error!!! Link maybe forced and
* the cable may have just been disconnected so we will
* read the LOS to see.
*/
if (ICRContents & E1000_ICR_RXSEQ)
Adapter->rx_seq_intr++;
/* e1000g_link_check takes care of link status change */
/*
* If the link timer has not timed out, we'll not notify
* the upper layer with any link state until the link
* is up.
*/
} else {
}
}
if (link_changed) {
if (tid != 0)
/*
* Workaround for esb2. Data stuck in fifo on a link
* down event. Reset the adapter to recover it.
*/
(void) e1000g_reset(Adapter);
}
}
if (ICRContents & E1000G_ICR_TX_INTR) {
if (!Adapter->tx_intr_enable)
/* Schedule the re-transmit */
if (Adapter->resched_needed) {
Adapter->tx_reschedule++;
}
if (Adapter->tx_intr_enable) {
/* Recycle the tx descriptors */
/* Free the recycled messages */
NULL);
}
}
}
static void
{
int slot;
if (Adapter->init_count == 0) {
/* Initialize the multiple unicast addresses */
Adapter->unicst_total--;
/* Store the default mac address */
} else {
/* Recover the default mac address */
/* Store the default mac address */
/* Re-configure the RAR registers */
}
}
static int
{
/* Store the default MAC address */
/* Set MAC address in address slot 0, which is the default address */
}
static int
{
/*
* Error if the address specified is a multicast or broadcast
* address.
*/
return (EINVAL);
/*
* The first revision of Wiseman silicon (rev 2.0) has an errata
* that requires the receiver to be in reset when any of the
* receive address registers (RAR regs) are accessed. The first
* rev of Wiseman silicon also requires MWI to be disabled when
* a global reset or a receive reset is issued. So before we
* initialize the RARs, we check the rev of the Wiseman controller
* and work around any necessary HW errata.
*/
}
if (slot == 0) {
}
/*
* If we are using Wiseman rev 2.0 silicon, we will have previously
* put the receive in reset, and disabled MWI, to work around some
* HW errata. Now we should take the receiver out of reset, and
* re-enabled if MWI if it was previously enabled by the PCI BIOS.
*/
}
return (0);
}
/*
* e1000g_m_unicst_add() - will find an unused address slot, set the
* address value to the one specified, reserve that slot and enable
* the NIC to start filtering on the new MAC address.
* Returns 0 on success.
*/
static int
{
int err;
return (EINVAL);
if (Adapter->unicst_avail == 0) {
/* no slots available */
return (ENOSPC);
}
/*
* are the multiple MAC addresses. So multiple MAC address 0
* is in slot 1, 1 in slot 2, and so on. So the first multiple
* MAC address resides in slot 1.
*/
break;
}
}
Adapter->unicst_avail--;
Adapter->unicst_avail++;
}
return (err);
}
/*
* e1000g_m_unicst_remove() - removes a MAC address that was added by a
* call to e1000g_m_unicst_add(). The slot number that was returned in
* e1000g_m_unicst_add() is passed in the call to remove the address.
* Returns 0 on success.
*/
static int
{
int err;
return (EINVAL);
Adapter->unicst_avail++;
/* Copy the default address to the passed slot */
Adapter->unicst_avail--;
}
return (err);
}
return (EINVAL);
}
/*
* e1000g_m_unicst_modify() - modifies the value of an address that
* has been added by e1000g_m_unicst_add(). The new address, address
* length and the slot number that was returned in the call to add
* should be passed to e1000g_m_unicst_modify(). mma_flags should be
* set to 0. Returns 0 on success.
*/
static int
{
return (EINVAL);
return (EINVAL);
}
return (EINVAL);
}
/*
* e1000g_m_unicst_get() - will get the MAC address and all other
* information related to the address slot passed in mac_multi_addr_t.
* mma_flags should be set to 0 in the call.
* On return, mma_flags can take the following values:
* 1) MMAC_SLOT_UNUSED
* 2) MMAC_SLOT_USED | MMAC_VENDOR_ADDR
* 3) MMAC_SLOT_UNUSED | MMAC_VENDOR_ADDR
* 4) MMAC_SLOT_USED
*/
static int
{
return (EINVAL);
} else {
}
return (0);
}
static int
{
unsigned i;
int res = 0;
if ((multiaddr[0] & 01) == 0) {
goto done;
}
goto done;
}
Adapter->mcast_count++;
/*
* Update the MC table in the hardware
*/
done:
return (res);
}
static int
{
unsigned i;
for (i = 0; i < Adapter->mcast_count; i++) {
ETHERADDRL) == 0) {
for (i++; i < Adapter->mcast_count; i++) {
Adapter->mcast_table[i];
}
Adapter->mcast_count--;
break;
}
}
/*
* Update the MC table in the hardware
*/
done:
return (0);
}
int
{
}
int
{
if (on)
RctlRegValue |=
else
return (0);
}
static boolean_t
{
switch (cap) {
case MAC_CAPAB_HCKSUM: {
/*
* In Jumbo mode, enabling hardware checksum will cause
* port hang.
*/
return (B_FALSE);
/*
*
* If the chip is flagged as not capable of (correctly)
* handling FULL checksumming, we don't enable it on either
* Rx or Tx side. Otherwise, we take this chip's settings
* from the patchable global defaults.
*
* We advertise our capabilities only if TX offload is
* enabled. On receive, the stack will accept checksummed
* packets anyway, even if we haven't said we can deliver
* them.
*/
/*
* Switch on hardware checksum offload of
* chip 82540, 82545, 82546
*/
case e1000_82540:
case e1000_82544: /* pci8086,1008 */
case e1000_82545:
case e1000_82545_rev_3: /* pci8086,1026 */
case e1000_82571:
case e1000_82572:
case e1000_82573:
case e1000_80003es2lan:
break;
case e1000_82546: /* 82546EB. devID: 1010, 101d */
case e1000_82546_rev_3: /* 82546GB. devID: 1079, 107a */
/* Workaround for Galaxy on 32bit */
return (B_FALSE);
#else
break;
#endif
/*
* We don't have the following PRO 1000 chip types at
* hand and haven't tested their hardware checksum
* offload capability. We had better switch them off.
* e1000_undefined = 0,
* e1000_82542_rev2_0,
* e1000_82542_rev2_1,
* e1000_82543,
* e1000_82541,
* e1000_82541_rev_2,
* e1000_82547,
* e1000_82547_rev_2,
* e1000_num_macs
*/
default:
return (B_FALSE);
}
break;
}
case MAC_CAPAB_POLL:
/*
* There's nothing for us to fill in, simply returning
* B_TRUE stating that we support polling is sufficient.
*/
break;
case MAC_CAPAB_MULTIADDRESS: {
/*
* The number of MAC addresses made available by
* this capability is one less than the total as
* the primary address in slot 0 is counted in
* the total.
*/
/* No multiple factory addresses, set mma_flag to 0 */
mmacp->maddr_flag = 0;
break;
}
default:
return (B_FALSE);
}
return (B_TRUE);
}
/*
* **********************************************************************
* Name: e1000g_getparam *
* *
* Description: This routine gets user-configured values out of the *
* configuration file e1000g.conf. *
* For each configurable value, there is a minimum, a maximum, and a *
* default. *
* If user does not configure a value, use the default. *
* If user configures below the minimum, use the minumum. *
* If user configures above the maximum, use the maxumum. *
* *
* Arguments: *
* Adapter - A pointer to our adapter structure *
* *
* Returns: None *
* **********************************************************************
*/
static void
{
/*
* get each configurable property from e1000g.conf
*/
/*
* NumTxDescriptors
*/
/*
* NumRxDescriptors
*/
/*
* NumRxFreeList
*/
/*
* NumTxPacketList
*/
/*
* FlowControl
*/
/* 4 is the setting that says "let the eeprom decide" */
/*
* MaxNumReceivePackets
*/
/*
* TxInterruptDelay
*/
/*
* PHY master slave setting
*/
/*
* Parameter which controls TBI mode workaround, which is only
* needed on certain switches such as Cisco 6500/Foundry
*/
0, 1, DEFAULTTBICOMPATIBILITYENABLE);
/*
* MSI Enable
*/
0, 1, DEFAULTMSIENABLE);
/*
* Interrupt Throttling Rate
*/
/*
* It is enabled by default
*/
}
/*
* **********************************************************************
* Name: e1000g_getprop *
* *
* Description: get a user-configure property value out of the *
* configuration file e1000g.conf. *
* Caller provides name of the property, a default value, a *
* minimum value, and a maximum value. *
* *
* Returns: configured value of the property, with default, minimum and *
* maximum properly applied. *
* **********************************************************************
*/
static int
char *propname, /* name of the property */
int minval, /* minimum acceptable value */
int maxval, /* maximim acceptable value */
int defval) /* default value */
{
int propval; /* value returned for requested property */
int *props; /* point to array of properties returned */
/*
* get the array of properties from the config file
*/
/* got some properties, test if we got enough */
} else {
/* not enough properties configured */
"Not Enough %s values found in e1000g.conf"
" - set to %d\n",
}
/* free memory allocated for properties */
} else {
}
/*
* enforce limits
*/
"Too High %s value in e1000g.conf - set to %d\n",
}
"Too Low %s value in e1000g.conf - set to %d\n",
}
return (propval);
}
static boolean_t
{
if (e1000g_link_up(Adapter)) {
/*
* The Link is up, check whether it was marked as down earlier
*/
Adapter->tx_link_down_timeout = 0;
if (speed == SPEED_1000)
else
}
"Adapter %dMbps %s %s link is up.", speed,
((duplex == FULL_DUPLEX) ?
"full duplex" : "half duplex"),
"copper" : "fiber"));
}
Adapter->smartspeed = 0;
} else {
Adapter->link_speed = 0;
Adapter->link_duplex = 0;
"Adapter %s link is down.",
"copper" : "fiber"));
/*
* resolution.
*/
}
} else {
}
if (Adapter->tx_link_down_timeout <
} else if (Adapter->tx_link_down_timeout ==
}
}
}
return (link_changed);
}
static void
e1000g_LocalTimer(void *ws)
{
if (e1000g_stall_check(Adapter)) {
"Tx stall detected. Activate automatic recovery.\n");
Adapter->StallWatchdog = 0;
Adapter->tx_recycle_fail = 0;
Adapter->reset_count++;
(void) e1000g_reset(Adapter);
}
if (Adapter->link_complete)
if (link_changed) {
/*
* Workaround for esb2. Data stuck in fifo on a link
* down event. Reset the adapter to recover it.
*/
(void) e1000g_reset(Adapter);
}
/*
* With 82571 controllers, any locally administered address will
* be overwritten when there is a reset on the other port.
* Detect this circumstance and correct it.
*/
}
}
/*
* RP: ttl_workaround : DCR 49
*/
/*
* Check for Adaptive IFS settings If there are lots of collisions
* change the value in steps...
* These properties should only be set for 10/100
*/
}
/*
* Set Timer Interrupts
*/
}
/*
* The function e1000g_link_timer() is called when the timer for link setup
* is expired, which indicates the completion of the link setup. The link
* state will not be updated until the link setup is completed. And the
* link state will not be sent to the upper layer through mac_link_update()
* in this function. It will be updated in the local timer routine or the
* interrupt service routine after the interface is started (plumbed).
*/
static void
e1000g_link_timer(void *arg)
{
}
/*
* **********************************************************************
* Name: e1000g_force_speed_duplex *
* *
* Description: *
* This function forces speed and duplex for 10/100 Mbps speeds *
* and also for 1000 Mbps speeds, it advertises half or full duplex *
* *
* Parameter Passed: *
* struct e1000g* (information of adpater) *
* *
* Return Value: *
* *
* Functions called: *
* **********************************************************************
*/
static void
{
int forced;
/*
* get value out of config file
*/
switch (forced) {
case GDIAG_10_HALF:
/*
* Disable Auto Negotiation
*/
break;
case GDIAG_10_FULL:
/*
* Disable Auto Negotiation
*/
break;
case GDIAG_100_HALF:
/*
* Disable Auto Negotiation
*/
break;
case GDIAG_100_FULL:
/*
* Disable Auto Negotiation
*/
break;
case GDIAG_1000_FULL:
/*
* The gigabit spec requires autonegotiation. Therefore,
* when the user wants to force the speed to 1000Mbps, we
* enable AutoNeg, but only allow the harware to advertise
* 1000Mbps. This is different from 10/100 operation, where
* we are allowed to link without any negotiation.
*/
break;
default: /* obey the setting of AutoNegAdvertised */
break;
} /* switch */
}
/*
* **********************************************************************
* Name: e1000g_get_max_frame_size *
* *
* Description: *
* This function reads MaxFrameSize from e1000g.conf and sets it for *
* adapter. *
* *
* Parameter Passed: *
* struct e1000g* (information of adpater) *
* *
* Return Value: *
* *
* Functions called: *
* **********************************************************************
*/
static void
{
int max_frame;
/*
* get value out of config file
*/
switch (max_frame) {
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
else
break;
default:
break;
} /* switch */
/* ich8 does not do jumbo frames */
}
}
static void
{
}
static void
{
if (!Adapter->timeout_enabled) {
}
}
static void
{
Adapter->WatchDogTimer_id = 0;
if (tid != 0)
}
static void
{
if (Adapter->timeout_enabled) {
if (!Adapter->timeout_started) {
}
}
}
static void
{
if (Adapter->timeout_started)
}
static void
{
Adapter->WatchDogTimer_id = 0;
if (tid != 0)
}
void
{
0xffffffff & ~E1000_IMC_RXSEQ);
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
*value =
}
#ifndef __sparc
void
{
}
{
}
#endif
static void
{
/*
* If we're not T-or-T, or we're not autoneg'ing, or we're not
* advertising 1000Full, we don't even use the workaround
*/
return;
/*
* True if this is the first call of this function or after every
* 30 seconds of not having link
*/
if (adapter->smartspeed == 0) {
/*
* assume back-to-back
*/
&phy_status);
if (!(phy_status & SR_1000T_MS_CONFIG_FAULT))
return;
&phy_status);
if (!(phy_status & SR_1000T_MS_CONFIG_FAULT))
return;
/*
* We're assuming back-2-back because our status register
* relationship that was "negotiated"
*/
&phy_ctrl);
/*
* Is the phy configured for manual configuration of
*/
if (phy_ctrl & CR_1000T_MS_ENABLE) {
/*
* Yes. Then disable manual configuration (enable
*/
/*
* Effectively starting the clock
*/
adapter->smartspeed++;
/*
* Restart autonegotiation
*/
&phy_ctrl)) {
phy_ctrl |= (MII_CR_AUTO_NEG_EN |
}
}
return;
/*
* Has 6 seconds transpired still without link? Remember,
* you should reset the smartspeed counter once you obtain
* link
*/
/*
* Yes. Remember, we did at the start determine that
* still assuming there's someone on the other end, but we
* just haven't yet been able to talk to it. We then
* we're running 2/3 pair cables.
*/
/*
* If still no link, perhaps using 2/3 pair cable
*/
&phy_ctrl);
phy_ctrl);
/*
* Restart autoneg with phy enabled for manual
*/
&phy_ctrl)) {
phy_ctrl |=
phy_ctrl);
}
/*
* Hopefully, there are no more faults and we've obtained
* link as a result.
*/
}
/*
* Restart process after E1000_SMARTSPEED_MAX iterations (30
* seconds)
*/
adapter->smartspeed = 0;
}
static boolean_t
{
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
return (B_FALSE);
return (B_TRUE);
}
/*
* **********************************************************************
* Name: *
* e1000g_stall_check *
* *
* Description: *
* This function checks if the adapter is stalled. (In transmit) *
* *
* It is called each time the timeout is invoked. *
* If the transmit descriptor reclaim continuously fails, *
* the watchdog value will increment by 1. If the watchdog *
* value exceeds the threshold, the adapter is assumed to *
* have stalled and need to be reset. *
* *
* Arguments: *
* Adapter - A pointer to our context sensitive "Adapter" *
* structure. *
* *
* Returns: *
* B_TRUE - The dapter is assumed to have stalled. *
* B_FALSE *
* *
* **********************************************************************
*/
static boolean_t
{
return (B_FALSE);
if (Adapter->tx_recycle_fail > 0)
Adapter->StallWatchdog++;
else
Adapter->StallWatchdog = 0;
return (B_FALSE);
return (B_TRUE);
}
static enum ioc_reply
{
case E1000G_IOC_REG_PEEK:
break;
case E1000G_IOC_REG_POKE:
break;
"e1000g_diag_ioctl: invalid ioctl command 0x%X\n",
return (IOC_INVAL);
}
/*
* Validate format of ioctl
*/
return (IOC_INVAL);
return (IOC_INVAL);
/*
* Validate request parameters
*/
switch (ppd->pp_acc_space) {
default:
"e1000g_diag_ioctl: invalid access space 0x%X\n",
ppd->pp_acc_space);
return (IOC_INVAL);
case E1000G_PP_SPACE_REG:
/*
* Memory-mapped I/O space
*/
return (IOC_INVAL);
return (IOC_INVAL);
mem_va = 0;
maxoff = 0x10000;
break;
case E1000G_PP_SPACE_E1000G:
/*
* E1000g data structure!
*/
break;
}
return (IOC_INVAL);
return (IOC_INVAL);
/*
* All OK - go!
*/
}
static void
{
handle =
regaddr =
}
static void
{
handle =
regaddr =
}
static void
{
void *vaddr;
switch (ppd->pp_acc_size) {
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
}
"e1000g_ioc_peek_mem($%p, $%p) peeked 0x%llx from $%p\n",
}
static void
{
void *vaddr;
"e1000g_ioc_poke_mem($%p, $%p) poking 0x%llx at $%p\n",
switch (ppd->pp_acc_size) {
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
}
}
/*
* Loopback Support
*/
static lb_property_t lb_normal =
static lb_property_t lb_external1000 =
static lb_property_t lb_external100 =
static lb_property_t lb_external10 =
static lb_property_t lb_phy =
static enum ioc_reply
{
return (IOC_INVAL);
default:
return (IOC_INVAL);
case LB_GET_INFO_SIZE:
size = sizeof (lb_info_sz_t);
return (IOC_INVAL);
if ((phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
case e1000_82571:
case e1000_82572:
value += sizeof (lb_external1000);
break;
}
}
if ((phy_status & MII_SR_100X_FD_CAPS) ||
value += sizeof (lb_external100);
if (phy_status & MII_SR_10T_FD_CAPS)
value += sizeof (lb_external10);
break;
case LB_GET_INFO:
if ((phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
case e1000_82571:
case e1000_82572:
value += sizeof (lb_external1000);
break;
}
}
if ((phy_status & MII_SR_100X_FD_CAPS) ||
value += sizeof (lb_external100);
if (phy_status & MII_SR_10T_FD_CAPS)
value += sizeof (lb_external10);
return (IOC_INVAL);
value = 0;
if ((phy_ext_status & IEEE_ESR_1000T_FD_CAPS) ||
case e1000_82571:
case e1000_82572:
break;
}
}
if ((phy_status & MII_SR_100X_FD_CAPS) ||
if (phy_status & MII_SR_10T_FD_CAPS)
break;
case LB_GET_MODE:
return (IOC_INVAL);
break;
case LB_SET_MODE:
size = 0;
return (IOC_INVAL);
return (IOC_INVAL);
break;
}
return (IOC_REPLY);
}
static boolean_t
{
#ifndef __sparc
#endif
int i, times;
return (B_TRUE);
times = 0;
switch (mode) {
default:
return (B_FALSE);
case E1000G_LB_NONE:
/* Get original speed and duplex settings */
/* Reset the chip */
(void) e1000g_reset(Adapter);
break;
case E1000G_LB_EXTERNAL_1000:
break;
case E1000G_LB_EXTERNAL_100:
break;
case E1000G_LB_EXTERNAL_10:
break;
case E1000G_LB_INTERNAL_PHY:
break;
}
times++;
switch (mode) {
case E1000G_LB_EXTERNAL_1000:
case E1000G_LB_EXTERNAL_100:
case E1000G_LB_EXTERNAL_10:
case E1000G_LB_INTERNAL_PHY:
#ifndef __sparc
/* Enable the CRC stripping for loopback */
#endif
/* Wait for link up */
for (i = (PHY_FORCE_TIME * 2); i > 0; i--)
msec_delay(100);
if (!e1000g_link_up(Adapter)) {
"Failed to get the link up");
if (times < 2) {
/* Reset the link */
"Reset the link ...");
(void) e1000g_reset(Adapter);
goto again;
}
}
break;
}
return (B_TRUE);
}
/*
* The following loopback settings are from Intel's technical
* document - "How To Loopback". All the register settings and
* time delay values are directly inherited from the document
* without more explanations available.
*/
static void
{
/* Disable Smart Power Down */
case e1000_82540:
case e1000_82545:
case e1000_82545_rev_3:
case e1000_82546:
case e1000_82546_rev_3:
case e1000_82573:
/* Reset PHY to auto-neg off and force 1000 */
phy_ctrl | MII_CR_RESET);
break;
}
/* Set loopback */
msec_delay(250);
E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */
E1000_CTRL_FD); /* Force Duplex to FULL */
case e1000_82540:
case e1000_82545:
case e1000_82545_rev_3:
case e1000_82546:
case e1000_82546_rev_3:
/*
* For some serdes we'll need to commit the writes now
* so that the status is updated on link
*/
msec_delay(100);
}
/* Invert Loss of Signal */
ctrl |= E1000_CTRL_ILOS;
} else {
/* Set ILOS on fiber nic if half duplex is detected */
if ((status & E1000_STATUS_FD) == 0)
}
break;
case e1000_82571:
case e1000_82572:
/* Set ILOS on fiber nic if half duplex is detected */
if ((status & E1000_STATUS_FD) == 0)
}
break;
case e1000_82573:
ctrl |= E1000_CTRL_ILOS;
break;
}
/*
* Disable PHY receiver for 82540/545/546 and 82573 Family.
* For background, see comments above e1000g_set_internal_loopback().
*/
case e1000_82540:
case e1000_82545:
case e1000_82545_rev_3:
case e1000_82546:
case e1000_82546_rev_3:
case e1000_82573:
break;
}
}
static void
{
/* Disable Smart Power Down */
switch (hw->media_type) {
case e1000_media_type_copper:
/* Force link up (Must be done before the PHY writes) */
rctl |= (E1000_RCTL_EN |
E1000_RCTL_BAM); /* 0x803E */
E1000_CTRL_EXT_SDP7_DIR); /* 0x0DD0 */
/*
* This sequence tunes the PHY's SDP and no customer
* settable values. For background, see comments above
* e1000g_set_internal_loopback().
*/
msec_delay(10);
msec_delay(50);
break;
case e1000_media_type_fiber:
if (((status & E1000_STATUS_LU) == 0) ||
}
/* Disable autoneg by setting bit 31 of TXCW to zero */
/*
* Write 0x410 to Serdes Control register
* to enable Serdes analog loopback
*/
msec_delay(10);
break;
default:
break;
}
}
static void
{
/* Disable Smart Power Down */
/* Force 100/FD, reset PHY */
msec_delay(10);
/* Force 100/FD */
phy_ctrl); /* 0x2100 */
msec_delay(10);
E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
E1000_CTRL_SPD_100 | /* Force Speed to 100 */
E1000_CTRL_FD); /* Force Duplex to FULL */
}
static void
{
/* Disable Smart Power Down */
/* Force 10/FD, reset PHY */
msec_delay(10);
/* Force 10/FD */
phy_ctrl); /* 0x0100 */
msec_delay(10);
E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
E1000_CTRL_SPD_10 | /* Force Speed to 10 */
E1000_CTRL_FD); /* Force Duplex to FULL */
}
#ifdef __sparc
static boolean_t
{
struct ether_addr sysaddr;
int err;
/*
* The "vendor's factory-set address" may already have
* been extracted from the chip, but if the property
* "local-mac-address" is set we use that instead.
*
* We check whether it looks like an array of 6
* bytes (which it should, if OBP set it). If we can't
* make sense of it this way, we'll ignore it.
*/
if (err == DDI_PROP_SUCCESS) {
if (nelts == ETHERADDRL) {
while (nelts--)
}
}
/*
* Look up the OBP property "local-mac-address?". If the user has set
* 'local-mac-address? = false', use "the system address" instead.
*/
}
}
}
/*
* Finally(!), if there's a valid "mac-address" property (created
* if we netbooted from this interface), we must use this instead
* get confused by the address changing as Solaris takes over!
*/
if (err == DDI_PROP_SUCCESS) {
if (nelts == ETHERADDRL) {
while (nelts--)
}
}
if (found) {
}
return (found);
}
#endif
static int
{
int intr_types;
int rc;
/* Get supported interrupt types */
if (rc != DDI_SUCCESS) {
"Get supported interrupt types failed: %d\n", rc);
return (DDI_FAILURE);
}
/*
* Based on Intel Technical Advisory document (TA-160), there are some
* cases where some older Intel PCI-X NICs may "advertise" to the OS
* that it supports MSI, but in fact has problems.
* So we should only enable MSI for PCI-E NICs and disable MSI for old
*/
if (rc != DDI_SUCCESS) {
"Add MSI failed, trying Legacy interrupts\n");
} else {
}
}
(intr_types & DDI_INTR_TYPE_FIXED)) {
if (rc != DDI_SUCCESS) {
"Add Legacy interrupts failed\n");
return (DDI_FAILURE);
}
}
"No interrupts registered\n");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
*/
static int
{
int flag;
/* get number of interrupts */
"Get interrupt number failed. Return: %d, count: %d\n",
return (DDI_FAILURE);
}
/* get number of available interrupts */
"Get interrupt available number failed. "
return (DDI_FAILURE);
}
"Interrupts count: %d, available: %d\n",
}
/* Allocate an array of interrupt handles */
/* Set NORMAL behavior for both MSI and FIXED interrupt */
/* call ddi_intr_alloc() */
"Allocate interrupts failed: %d\n", rc);
return (DDI_FAILURE);
}
"Interrupts requested: %d, received: %d\n",
}
/* Get priority for first msi, assume remaining are all the same */
if (rc != DDI_SUCCESS) {
"Get interrupt priority failed: %d\n", rc);
/* Free already allocated intr */
for (y = 0; y < actual; y++)
return (DDI_FAILURE);
}
/*
* In Legacy Interrupt mode, for PCI-Express adapters, we should
* use the interrupt service routine e1000g_intr_pciexpress()
* to avoid interrupt stealing when sharing interrupt with other
* devices.
*/
else
/* Call ddi_intr_add_handler() */
for (x = 0; x < actual; x++) {
if (rc != DDI_SUCCESS) {
"Add interrupt handler failed: %d\n", rc);
/* Remove already added handler */
for (y = 0; y < x; y++)
(void) ddi_intr_remove_handler(
/* Free already allocated intr */
for (y = 0; y < actual; y++)
return (DDI_FAILURE);
}
}
if (rc != DDI_SUCCESS) {
"Get interrupt cap failed: %d\n", rc);
/* Free already allocated intr */
for (y = 0; y < actual; y++) {
}
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static int
{
int x;
int rc;
if (rc != DDI_SUCCESS) {
"Remove intr handler failed: %d\n", rc);
return (DDI_FAILURE);
}
if (rc != DDI_SUCCESS) {
"Free intr failed: %d\n", rc);
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
static int
{
int x;
int rc;
/* Enable interrupts */
/* Call ddi_intr_block_enable() for MSI */
if (rc != DDI_SUCCESS) {
"Enable block intr failed: %d\n", rc);
return (DDI_FAILURE);
}
} else {
if (rc != DDI_SUCCESS) {
"Enable intr failed: %d\n", rc);
return (DDI_FAILURE);
}
}
}
return (DDI_SUCCESS);
}
static int
{
int x;
int rc;
/* Disable all interrupts */
if (rc != DDI_SUCCESS) {
"Disable block intr failed: %d\n", rc);
return (DDI_FAILURE);
}
} else {
if (rc != DDI_SUCCESS) {
"Disable intr failed: %d\n", rc);
return (DDI_FAILURE);
}
}
}
return (DDI_SUCCESS);
}
/*
* phy_spd_state - set smart-power-down (SPD) state
*
* This only acts on the 82541/47 family and the 82571/72 family.
* For any others, return without doing anything.
*/
void
{
case e1000_82541:
case e1000_82547:
case e1000_82541_rev_2:
case e1000_82547_rev_2:
break;
case e1000_82571:
case e1000_82572:
break;
default:
return; /* no action */
}
if (enable)
else
}
/*
* The real intent of this routine is to return the value from pci-e
* config space at offset reg into the capability space.
* ICH devices are "PCI Express"-ish. They have a configuration space,
* but do not contain PCI Express Capability registers, so this returns
* the equivalent of "not supported"
*/
{
PCI_EX_CONF_CAP + reg);
return (0);
}
/*
* Enables PCI-Express master access.
*
* hw: Struct containing variables accessed by shared code
*
* returns: - none.
*/
void
{
return;
}