nge_chip.c revision 2d58516de420814c8fd871526b0aaa3cd9fb9443
/*
* 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"
#include "nge.h"
extern boolean_t nge_enable_msi;
static void nge_sync_mac_modes(nge_t *);
#define NGE_DBG NGE_DBG_CHIP
/*
*/
#pragma inline(nge_reg_get8)
{
}
#pragma inline(nge_reg_put8)
void
{
NGE_TRACE(("nge_reg_put8($%p, 0x%lx, 0x%x)",
}
#pragma inline(nge_reg_get16)
{
}
#pragma inline(nge_reg_put16)
void
{
NGE_TRACE(("nge_reg_put16($%p, 0x%lx, 0x%x)",
}
#pragma inline(nge_reg_get32)
{
}
#pragma inline(nge_reg_put32)
void
{
NGE_TRACE(("nge_reg_put32($%p, 0x%lx, 0x%x)",
}
#pragma no_inline(nge_chip_peek_cfg)
static int
{
int err;
NGE_TRACE(("nge_chip_peek_cfg($%p, $%p)",
err = DDI_SUCCESS;
switch (ppd->pp_acc_size) {
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
}
return (err);
}
static int
{
int err;
NGE_TRACE(("nge_chip_poke_cfg($%p, $%p)",
err = DDI_SUCCESS;
switch (ppd->pp_acc_size) {
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
}
return (err);
}
static int
{
int err;
void *regaddr;
NGE_TRACE(("nge_chip_peek_reg($%p, $%p)",
err = DDI_SUCCESS;
switch (ppd->pp_acc_size) {
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
default:
regval = 0x0ull;
break;
}
return (err);
}
static int
{
int err;
void *regaddr;
NGE_TRACE(("nge_chip_poke_reg($%p, $%p)",
err = DDI_SUCCESS;
switch (ppd->pp_acc_size) {
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
}
return (err);
}
#pragma no_inline(nge_chip_peek_mii)
static int
{
int err;
err = DDI_SUCCESS;
return (err);
}
#pragma no_inline(nge_chip_poke_mii)
static int
{
int err;
err = DDI_SUCCESS;
return (err);
}
/*
*
* This uses the chip's SEEPROM auto-access method, controlled by the
* doesn't have to fiddle with the individual bits.
*
* The caller should hold <genlock> and *also* have already acquired
* the right to access the SEEPROM.
*
* Return value:
* 0 on success,
* ENODATA on access timeout (maybe retryable: device may just be busy)
* EPROTO on other h/w or s/w errors.
*
* <*dp> is an input to a SEEPROM_ACCESS_WRITE operation, or an output
* from a (successful) SEEPROM_ACCESS_READ.
*/
static int
{
NGE_TRACE(("nge_seeprom_access($%p, %d, %x, $%p)",
/*
* Check there's no command in progress.
*
* Note: this *shouldn't* ever find that there is a command
* in progress, because we already hold the <genlock> mutex.
* Also, to ensure we don't have a conflict with the chip's
* internal firmware or a process accessing the same (shared)
* So this is just a final consistency check: we shouldn't
* see EITHER the START bit (command started but not complete)
* OR the COMPLETE bit (command completed but not cleared).
*/
break;
drv_usecwait(10);
}
/*
* This should not happen. If so, we have to restart eeprom
* state machine
*/
if (tries == 30) {
drv_usecwait(10);
/*
* Polling the status bit to make assure the eeprom is ready
*/
break;
drv_usecwait(10);
}
}
/*
* Assemble the command ...
*/
/*
* Polling whether the access is successful.
*
*/
break;
drv_usecwait(10);
}
if (tries == 30) {
return (DDI_FAILURE);
}
switch (cmd) {
default:
case SEEPROM_CMD_WRITE_ENABLE:
case SEEPROM_CMD_ERASE:
case SEEPROM_CMD_ERALSE_ALL:
case SEEPROM_CMD_WRITE_DIS:
break;
case SEEPROM_CMD_READ:
break;
case SEEPROM_CMD_WRITE:
break;
}
return (DDI_SUCCESS);
}
static int
{
int err;
return (err);
}
static int
{
int err;
return (err);
}
void
{
case DEVICE_ID_NF3_E6:
case DEVICE_ID_NF3_DF:
case DEVICE_ID_MCP04_37:
case DEVICE_ID_MCP04_38:
dev_param_p->tx_hw_checksum = 0;
break;
case DEVICE_ID_CK804_56:
case DEVICE_ID_CK804_57:
break;
case DEVICE_ID_MCP61_3EE:
case DEVICE_ID_MCP61_3EF:
case DEVICE_ID_MCP51_268:
case DEVICE_ID_MCP51_269:
dev_param_p->tx_hw_checksum = 0;
break;
case DEVICE_ID_MCP55_372:
case DEVICE_ID_MCP55_373:
break;
default:
dev_param_p->tx_hw_checksum = 0;
return;
}
}
/*
* Perform first-stage chip (re-)initialisation, using only config-space
* accesses:
*
* + Read the vendor/device/revision/subsystem/cache-line-size registers,
* returning the data in the structure pointed to by <infop>.
*/
#pragma no_inline(nge_chip_cfg_init)
void
{
NGE_TRACE(("nge_chip_cfg_init($%p, $%p, %d)",
/*
* save PCI cache line size and subsystem vendor ID
*
* Read all the config-space registers that characterise the
* and subsystem device id. We expect (but don't check) that
*/
/* reading the vendor information once */
}
if (nge_enable_msi) {
/* Disable the hidden for MSI support */
/* Disable the vector off for mcp55 */
/* Enable the MSI mapping */
}
} else {
}
command |= PCI_COMM_ME;
}
int
{
int err;
err = DDI_SUCCESS;
/* Clear any pending PHY interrupt */
/* Mask all interrupts */
reg_val &= ~NGE_INTR_ALL_EN;
/* Disable auto-polling of phy */
/* Reset buffer management & DMA */
drv_usecwait(10);
break;
}
if (tries == 5000) {
return (DDI_FAILURE);
}
/*
* For mcp55, the bits 1:31 of NGE_RX_EN and NGE_TX_EN are
* defined to be used by SMU. The newer PXE than 527 began to
* when leaving PXE to prevents the MAC from winning
*/
/* Disable rx's machine */
/* Disable tx's machine */
} else {
/* Disable rx's machine */
/* Disable tx's machine */
}
/*
* Clean the status of tx's state machine
* and Make assure the tx's channel is idle
*/
break;
drv_usecwait(10);
}
if (tries == 1000) {
return (DDI_FAILURE);
}
/*
* Clean the status of rx's state machine
* and Make assure the tx's channel is idle
*/
break;
drv_usecwait(10);
}
if (tries == 1000) {
return (DDI_FAILURE);
}
/* Disable auto-poll of rx's state machine */
/* Disable auto-polling of tx's state machine */
/* Restore buffer management */
}
if (fault)
else
return (err);
}
static void
{
/*
* Filling the address and length of rx's descriptors
*/
}
static void
{
/*
* Filling the address and length of tx's descriptors
*/
}
static int
{
/*
* Configure Rx&Tx's buffer
*/
/*
* Configure buffer attribute
*/
/*
* Enable Dma access request
*/
/*
* Enbale Buffer management
*/
/*
* Support Standoffload Descriptor
*/
/*
* Support receive hardware checksum
*/
if (dev_param_p->rx_hw_checksum) {
} else
/*
* Disable Tx PRD coarse update
*/
/*
* Disable 64-byte access
*/
/*
* Skip Rx Error Frame is not supported and if
* enable it, jumbo frame does not work any more.
*/
/*
* Can not support hot mode now
*/
if (dev_param_p->vlan) {
/* Disable the vlan strip for devices which support vlan */
/* Disable the vlan insert for devices which supprot vlan */
}
if (dev_param_p->tx_rx_64byte) {
/* Set the maximum TX PRD fetch size to 64 bytes */
/* Set the maximum RX PRD fetch size to 64 bytes */
}
/*
* Upload Rx data as it arrives, rather than waiting for full frame
*/
/*
* Normal HOT table accesses
*/
/*
* Normal HOT buffer requesting
*/
/*
* Signal controller to check for new Rx descriptors
*/
return (DDI_SUCCESS);
}
/*
* When chipset resets, the chipset can not restore the orignial
* mac address to the mac address registers.
*
* When the driver is dettached, the function will write the orignial
* mac address to the mac address registers.
*/
void
{
}
int
{
int err;
uint8_t i;
const nge_ksindex_t *ksip;
/*
* Clear the statistics by reading the statistics register
*/
}
/*
* Setup seeprom control
*/
/*
* Reading the unicast mac address table
*/
mac <<= 32;
for (i = ETHERADDRL; i-- != 0; ) {
mac >>= 8;
}
}
}
/* Program software misc register */
/* wait for 32 us */
drv_usecwait(32);
/* Program PMU registers */
/* Set the core idle limit value */
/* Set the device idle limit value */
}
/*
* Stop the chipset and clear buffer management
*/
if (err == DDI_FAILURE)
return (err);
/*
* Clear the power state bits for phy since interface no longer
* works after rebooting from Windows on a multi-boot machine
*/
/* bring phy out of coma mode */
/* disable auto reset coma bits */
/* restore power to gated clocks */
}
/*
* Reset the external phy
*/
(void) nge_phy_reset(ngep);
return (DDI_SUCCESS);
}
int
{
int err;
/*
* Setup buffer management
*/
if (err == DDI_FAILURE)
return (err);
/*
* Enable polling attribute
*/
/*
* Setup link
*/
/*
* Configure the tx's parameters
*/
if (dev_param_p->tx_pause_frame)
else
/*
* Configure the parameters of Rx's state machine
* Enabe the parameters:
* 1). Pad Strip
* 2). FCS Relay
* 3). Pause
* 4). Address filter
* 5). Runt Packet receive
* 6). Broadcast
* 7). Receive Deferral
*
* Disable the following parameters for decreasing
* the number of interrupts:
* 1). Runt Inerrupt.
* 2). Rx's Late Collision interrupt.
* 3). Rx's Max length Error Interrupt.
* 4). Rx's Length Field error Interrupt.
* 5). Rx's FCS error interrupt.
* 6). Rx's overflow error interrupt.
* 7). Rx's Frame alignment error interrupt.
*/
if (dev_param_p->rx_pause_frame)
else
/*
* Configure the watermark for the rx's statemachine
*/
/*
* Configure the deffer time slot for rx's state machine
*/
/*
* Configure the length of rx's packet
*/
/*
* Enable Tx's state machine
*/
/*
* Enable Rx's state machine
*/
/*
*/
/*
* Enable all interrupt event
*/
return (DDI_SUCCESS);
}
/*
* nge_chip_sync() -- program the chip with the unicast MAC address,
* the multicast hash table, the required level of promiscuity.
*/
void
{
uint8_t i;
macaddr = 0x0ull;
mul_addr = 0x0ull;
mul_mask = 0x0ull;
} else {
}
/*
* Transform the MAC address from host to chip format, the unicast
* MAC address(es) ...
*/
}
/*
* Reprogram the multicast address table ...
*/
}
mul_addr >>= 32;
mul_mask >>= 32;
/*
* Set or clear the PROMISCUOUS mode bit
*/
/*
* For internal PHY loopback, the link will
* not be up, so it need to sync mac modes directly.
*/
}
static void
{
if (reg010_ins.reg010_val != 0) {
/*
* Fatal error is triggered by malformed driver commands.
* Disable unless debugging.
*/
}
}
static void
{
switch (ngep->param_link_speed) {
case 10:
} else {
}
break;
case 100:
} else {
}
break;
case 1000:
} else {
}
break;
}
}
}
else
else
}
/*
* Handler for hardware link state change.
*
* When this routine is called, the hardware link state has changed
* and the new state is reflected in the param_* variables. Here
* we must update the softstate, reprogram the MAC to match, and
*/
static void
{
/*
* Update the s/w link_state
*/
if (ngep->param_link_up)
else
/*
* Reprogram the MAC modes to match
*/
}
static boolean_t
{
switch (ngep->link_state) {
case LINK_STATE_UP:
break;
case LINK_STATE_DOWN:
break;
default:
break;
}
/*
* If <check> is false, we're sure the link hasn't changed.
* If true, however, it's not yet definitive; we have to call
* nge_phys_check() to determine whether the link has settled
* into a new state yet ... and if it has, then call the link
* state change handler.But when the chip is 5700 in Dell 6650
* ,even if check is false, the link may have changed.So we
* have to call nge_phys_check() to determine the link state.
*/
if (check)
return (lchg);
}
/*
* Factotum routine to check for Tx stall, using the 'watchdog' counter
*/
static boolean_t
{
/*
* Specific check for Tx stall ...
*
* The 'watchdog' counter is incremented whenever a packet
* is queued, reset to 1 when some (but not all) buffers
* are reclaimed, reset to 0 (disabled) when all buffers
* are reclaimed, and shifted left here. If it exceeds the
* threshold value, the chip is assumed to have stalled and
* is put into the ERROR state. The factotum will then reset
* it on the next pass.
*
* All of which should ensure that we don't get into a state
* where packets are left pending indefinitely!
*/
if (dogval < nge_watchdog_count) {
ngep->stall_cknum = 0;
} else {
ngep->stall_cknum++;
}
return (B_FALSE);
} else {
ngep->stall_cknum = 0;
return (B_TRUE);
}
}
/*
* The factotum is woken up when there's something to do that we'd rather
* not do from inside a hardware interrupt handler or high-level cyclic.
* Its two main tasks are:
* reset & restart the chip after an error
* check the link status whenever necessary
*/
/* ARGSUSED */
{
if (ngep->factotum_flag == 0) {
return (DDI_INTR_UNCLAIMED);
}
ngep->factotum_flag = 0;
switch (ngep->nge_chip_state) {
default:
break;
case NGE_CHIP_RUNNING:
break;
case NGE_CHIP_FAULT:
(void) nge_restart(ngep);
break;
}
if (err)
/*
* If the link state changed, tell the world about it (if
* this version of MAC supports link state notification).
* Note: can't do this while still holding the mutex.
*/
if (linkchg)
return (result);
}
static void
{
ngep->stint_count ++;
if (btx)
if (brx)
ngep->quiet_time++;
if (ngep->quiet_time ==
ngep->quiet_time = 0;
ngep->stint_count = 0;
}
} else
ngep->quiet_time = 0;
} else {
}
} else
}
}
ngep->recv_count = 0;
/* link interrupt, check the link state */
}
}
/*
* nge_chip_intr() -- handle chip interrupts
*/
/* ARGSUSED */
{
return (DDI_INTR_UNCLAIMED);
}
/*
* Check whether chip's says it's asserting #INTA;
* if not, don't process or claim the interrupt.
*/
return (DDI_INTR_UNCLAIMED);
}
/*
* Ack the interrupt
*/
return (DDI_INTR_CLAIMED);
}
}
return (DDI_INTR_CLAIMED);
}
static enum ioc_reply
{
int err;
switch (cmd) {
default:
return (IOC_INVAL);
case NGE_PEEK:
break;
case NGE_POKE:
break;
}
/*
* Validate format of ioctl
*/
return (IOC_INVAL);
return (IOC_INVAL);
/*
* Validate request parameters
*/
switch (ppd->pp_acc_space) {
default:
return (IOC_INVAL);
case NGE_PP_SPACE_CFG:
/*
* Config space
*/
mem_va = 0;
break;
case NGE_PP_SPACE_REG:
/*
* Memory-mapped I/O space
*/
mem_va = 0;
break;
case NGE_PP_SPACE_MII:
mem_va = 0;
break;
case NGE_PP_SPACE_SEEPROM:
mem_va = 0;
break;
}
switch (ppd->pp_acc_size) {
default:
return (IOC_INVAL);
case 8:
case 4:
case 2:
case 1:
return (IOC_INVAL);
break;
}
return (IOC_INVAL);
return (IOC_INVAL);
return (IOC_INVAL);
/*
* All OK - go do it!
*/
if (ppfn)
if (err != DDI_SUCCESS)
return (IOC_INVAL);
}
#pragma no_inline(nge_diag_ioctl)
static enum ioc_reply
{
switch (cmd) {
default:
return (IOC_INVAL);
case NGE_DIAG:
return (IOC_ACK);
case NGE_PEEK:
case NGE_POKE:
case NGE_PHY_RESET:
return (IOC_RESTART_ACK);
case NGE_SOFT_RESET:
case NGE_HARD_RESET:
return (IOC_ACK);
}
/* NOTREACHED */
}
enum ioc_reply
{
int cmd;
switch (cmd) {
default:
return (IOC_INVAL);
case NGE_DIAG:
case NGE_PEEK:
case NGE_POKE:
case NGE_PHY_RESET:
case NGE_SOFT_RESET:
case NGE_HARD_RESET:
#if NGE_DEBUGGING
#else
return (IOC_INVAL);
#endif
case NGE_MII_READ:
case NGE_MII_WRITE:
return (IOC_INVAL);
#if NGE_SEE_IO32
case NGE_SEE_READ:
case NGE_SEE_WRITE:
return (IOC_INVAL);
#endif
#if NGE_FLASH_IO32
case NGE_FLASH_READ:
case NGE_FLASH_WRITE:
return (IOC_INVAL);
#endif
}
}