skge.c revision a734c64bff58bda2fa48c2795453e092167b0ff7
/*
* iPXE driver for Marvell Yukon chipset and SysKonnect Gigabit
* Ethernet adapters. Derived from Linux skge driver (v1.13), which was
* based on earlier sk98lin, e100 and FreeBSD if_sk drivers.
*
* This driver intentionally does not support all the features of the
* original driver such as link fail-over and link management because
* those should be done at higher levels.
*
* Copyright (C) 2004, 2005 Stephen Hemminger <shemminger@osdl.org>
*
* Modified for iPXE, July 2008 by Michael Decker <mrd999@gmail.com>
* Tested and Modified in December 2009 by
* Thomas Miletich <thomas.miletich@gmail.com>
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_ONLY );
#include <stdint.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <ipxe/netdevice.h>
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
#include "skge.h"
static struct pci_device_id skge_id_table[] = {
};
static struct net_device_operations skge_operations = {
.irq = skge_net_irq
};
/* Avoid conditionals by using array */
/* Determine supported/advertised modes based on hardware.
* Note: ethtool ADVERTISED_xxx == SUPPORTED_xxx
*/
{
} else
return supported;
}
/* Chip internal frequency for clock calculations */
{
}
/* Microseconds to chip HZ */
{
}
{
switch (mode) {
case LED_MODE_OFF:
else {
}
break;
case LED_MODE_ON:
break;
case LED_MODE_TST:
else {
}
}
} else {
switch (mode) {
case LED_MODE_OFF:
break;
case LED_MODE_ON:
PHY_M_LED_MO_100(MO_LED_ON) : 0));
break;
case LED_MODE_TST:
}
}
}
/*
* I've left in these EEPROM and VPD functions, as someone may desire to
* integrate them in the future. -mdeck
*
* static int skge_get_eeprom_len(struct net_device *dev)
* {
* struct skge_port *skge = netdev_priv(dev);
* u32 reg2;
*
* pci_read_config_dword(skge->hw->pdev, PCI_DEV_REG2, ®2);
* return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
* }
*
* static u32 skge_vpd_read(struct pci_dev *pdev, int cap, u16 offset)
* {
* u32 val;
*
* pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset);
*
* do {
* pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
* } while (!(offset & PCI_VPD_ADDR_F));
*
* pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val);
* return val;
* }
*
* static void skge_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val)
* {
* pci_write_config_dword(pdev, cap + PCI_VPD_DATA, val);
* pci_write_config_word(pdev, cap + PCI_VPD_ADDR,
* offset | PCI_VPD_ADDR_F);
*
* do {
* pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
* } while (offset & PCI_VPD_ADDR_F);
* }
*
* static int skge_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
* u8 *data)
* {
* struct skge_port *skge = netdev_priv(dev);
* struct pci_dev *pdev = skge->hw->pdev;
* int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD);
* int length = eeprom->len;
* u16 offset = eeprom->offset;
*
* if (!cap)
* return -EINVAL;
*
* eeprom->magic = SKGE_EEPROM_MAGIC;
*
* while (length > 0) {
* u32 val = skge_vpd_read(pdev, cap, offset);
* int n = min_t(int, length, sizeof(val));
*
* memcpy(data, &val, n);
* length -= n;
* data += n;
* offset += n;
* }
* return 0;
* }
*
* static int skge_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
* u8 *data)
* {
* struct skge_port *skge = netdev_priv(dev);
* struct pci_dev *pdev = skge->hw->pdev;
* int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD);
* int length = eeprom->len;
* u16 offset = eeprom->offset;
*
* if (!cap)
* return -EINVAL;
*
* if (eeprom->magic != SKGE_EEPROM_MAGIC)
* return -EINVAL;
*
* while (length > 0) {
* u32 val;
* int n = min_t(int, length, sizeof(val));
*
* if (n < sizeof(val))
* val = skge_vpd_read(pdev, cap, offset);
* memcpy(&val, data, n);
*
* skge_vpd_write(pdev, cap, offset, val);
*
* length -= n;
* data += n;
* offset += n;
* }
* return 0;
* }
*/
/*
* Allocate ring elements and chain them together
* One-to-one association of board descriptors with ring elements
*/
{
struct skge_tx_desc *d;
struct skge_element *e;
unsigned int i;
return -ENOMEM;
e->desc = d;
if (i == num - 1) {
d->next_offset = base;
} else {
e->next = e + 1;
}
}
return 0;
}
/* Allocate and setup a new buffer for receiving */
struct skge_element *e,
{
wmb();
}
/* Resume receiving using existing skb,
* Note: DMA address is not changed by chip.
* MTU not changed while receiver active.
*/
{
wmb();
}
/* Free all buffers in receive ring, assumes receiver stopped */
{
struct skge_element *e;
do {
if (e->iob) {
}
}
{
}
{
}
{
if (netdev_link_ok(dev))
}
{
int i;
goto ready;
for (i = 0; i < PHY_RETRIES; i++) {
goto ready;
udelay(1);
}
return -ETIMEDOUT;
return 0;
}
{
u16 v = 0;
return v;
}
{
int i;
for (i = 0; i < PHY_RETRIES; i++) {
goto ready;
udelay(1);
}
return -EIO;
for (i = 0; i < PHY_RETRIES; i++) {
return 0;
udelay(1);
}
return -ETIMEDOUT;
}
{
/* set blink source counter */
/* configure mac arbiter */
/* configure mac arbiter timeout values */
/* configure packet arbiter timeout */
}
{
/* reset the statistics module */
/* disable Broadcom PHY IRQ */
/* Flush TX and RX fifo */
}
/* Convert mode to MII values */
static const u16 phy_pause_map[] = {
[FLOW_MODE_NONE] = 0,
};
/* special defines for FIBER (88E1011S only) */
static const u16 fiber_pause_map[] = {
};
/* Check status of Broadcom phy link */
{
/* read twice because of latch */
if ((status & PHY_ST_LSYNC) == 0) {
return;
}
if (!(status & PHY_ST_AN_OVER))
return;
if (lpa & PHY_B_AN_RF) {
return;
}
/* Check Duplex mismatch */
switch (aux & PHY_B_AS_AN_RES_MSK) {
case PHY_B_RES_1000FD:
break;
case PHY_B_RES_1000HD:
break;
default:
return;
}
switch (aux & PHY_B_AS_PAUSE_MSK) {
case PHY_B_AS_PAUSE_MSK:
break;
case PHY_B_AS_PRR:
break;
case PHY_B_AS_PRT:
break;
default:
}
}
if (!netdev_link_ok(dev))
}
/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional
* Phy on for 100 or 10Mbit operation
*/
{
unsigned int i;
/* magic workaround patterns for Broadcom */
static const struct {
} A1hack[] = {
{ 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 },
{ 0x17, 0x0013 }, { 0x15, 0x0404 }, { 0x17, 0x8006 },
{ 0x15, 0x0132 }, { 0x17, 0x8006 }, { 0x15, 0x0232 },
{ 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
}, C0hack[] = {
{ 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 },
{ 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 },
};
/* read Id from external PHY (all have the same address) */
/* Optimize MDIO transfer by suppressing preamble. */
r |= XM_MMU_NO_PRE;
switch (id1) {
case PHY_BCOM_ID1_C0:
/*
* Workaround BCOM Errata for the C0 type.
* Write magic patterns to reserved registers.
*/
for (i = 0; i < ARRAY_SIZE(C0hack); i++)
break;
case PHY_BCOM_ID1_A1:
/*
* Workaround BCOM Errata for the A1 type.
* Write magic patterns to reserved registers.
*/
for (i = 0; i < ARRAY_SIZE(A1hack); i++)
break;
}
/*
* Workaround BCOM Errata (#10523) for all BCom PHYs.
* Disable Power Management after reset.
*/
r |= PHY_B_AC_DIS_PM;
/* Dummy read */
/*
* Workaround BCOM Errata #1 for the C5 type.
* 1000Base-T Link Acquisition Failure in Slave Mode
*/
adv |= PHY_B_1000C_AHD;
adv |= PHY_B_1000C_AFD;
} else {
ctl |= PHY_CT_DUP_MD;
/* Force to slave */
}
/* Set autonegotiation pause parameters */
/* Use link status change interrupt */
}
{
ctrl |= PHY_X_AN_HD;
ctrl |= PHY_X_AN_FD;
/* Restart Auto-negotiation */
} else {
/* Set DuplexMode in Config register */
ctrl |= PHY_CT_DUP_MD;
/*
* Do NOT enable Auto-negotiation here. This would hold
* the link down because no IDLEs are transmitted
*/
}
/* Poll PHY for status changes */
}
{
/* read twice because of latch */
if ((status & PHY_ST_LSYNC) == 0) {
return 0;
}
if (!(status & PHY_ST_AN_OVER))
return 0;
if (lpa & PHY_B_AN_RF) {
return 0;
}
/* Check Duplex mismatch */
case PHY_X_RS_FD:
break;
case PHY_X_RS_HD:
break;
default:
return 0;
}
(lpa & PHY_X_P_SYM_MD))
/* Enable PAUSE receive, disable PAUSE transmit */
/* Disable PAUSE receive, enable PAUSE transmit */
else
}
if (!netdev_link_ok(dev))
return 1;
}
/* Poll to check for link coming up.
*
* Since internal PHY is wired to a level triggered pin, can't
* get an interrupt when carrier is detected, need to poll for
* link coming up.
*/
{
int i;
/*
* Verify that the link by checking GPIO register three times.
* This pin has the signal from the link_sync pin connected to it.
*/
for (i = 0; i < 3; i++) {
return;
}
/* Re-enable interrupt to detect link down */
if (xm_check_link(dev)) {
msk &= ~XM_IS_INP_ASS;
}
}
{
int i;
u32 r;
for (i = 0; i < 10; i++) {
goto reset_ok;
udelay(1);
}
/* Unreset the XMAC. */
/*
* Perform additional initialization for external PHYs,
* namely for the 1000baseTX cards that use the XMAC's
* GMII mode.
*/
/* Take external Phy out of reset */
if (port == 0)
else
/* Enable GMII interface */
}
case SK_PHY_XMAC:
break;
case SK_PHY_BCOM:
}
/* Set Station Address */
/* We don't use match addresses so clear */
for (i = 1; i < 16; i++)
/* Clear MIB counters */
/* Clear two times according to Errata #3 */
/* configure Rx High Water Mark (XM_RX_HI_WM) */
/* We don't need the FCS appended to the packet. */
r = XM_RX_LENERR_OK | XM_RX_STRIP_FCS;
/*
* If in manual half duplex mode the other side might be in
* full duplex mode, so ignore if a carrier extension is not seen
* on frames received
*/
r |= XM_RX_DIS_CEXT;
}
/* We want short frames padded to 60 bytes. */
/*
* Enable the reception of all error frames. This is is
* a necessary evil due to the design of the XMAC. The
* XMAC's receive FIFO is only 8K in size, however jumbo
* frames can be up to 9000 bytes in length. When bad
* frame filtering is enabled, the XMAC's RX FIFO operates
* in 'store and forward' mode. For this to work, the
* entire frame has to fit into the FIFO, but that means
* that jumbo frames larger than 8192 bytes will be
* truncated. Disabling all bad frame filtering causes
* the RX FIFO to operate in streaming mode, in which
* case the XMAC will start transferring frames out of the
* RX FIFO as soon as the FIFO threshold is reached.
*/
/*
* Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
* - Enable all bits excepting 'Octets Rx OK Low CntOv'
* and 'Octets Rx OK Hi Cnt Ov'.
*/
/*
* Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
* - Enable all bits excepting 'Octets Tx OK Low CntOv'
* and 'Octets Tx OK Hi Cnt Ov'.
*/
/* Configure MAC arbiter */
/* configure timeout values */
/* Configure Rx MAC FIFO */
/* Configure Tx MAC FIFO */
/* enable timeout timers */
}
{
unsigned retries = 1000;
/* Disable Tx and Rx */
/* Clear Tx packet arbiter timeout IRQ */
/* Reset the MAC */
do {
break;
} while (--retries > 0);
/* For external PHYs there must be special handling */
if (port == 0) {
} else {
}
}
& ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
}
{
/*
* enabling pause frame reception is required for 1000BT
* because the XMAC is not reset if the link is going down
*/
/* Disable Pause Frame Reception */
cmd |= XM_MMU_IGN_PF;
else
/* Enable Pause Frame Reception */
cmd &= ~XM_MMU_IGN_PF;
/*
* Configure Pause Frame Generation
* Use internal and external Pause Frame Generation.
* Sending pause frames is edge triggered.
* Send a Pause frame with the maximum pause time if
* internal oder external FIFO full condition occurs.
* Send a zero pause time frame to re-start transmission.
*/
/* XM_PAUSE_DA = '010000C28001' (default) */
/* XM_MAC_PTIME = 0xffff (maximum) */
/* remember this value is defined in big endian (!) */
mode |= XM_PAUSE_MODE;
} else {
/*
* disable pause frame generation is required for 1000BT
* because the XMAC is not reset if the link is going down
*/
/* Disable Pause Mode in Mode Register */
mode &= ~XM_PAUSE_MODE;
}
/* Turn on detection of Tx underrun */
msk &= ~XM_IS_TXF_UR;
/* get MMU Command Reg. */
cmd |= XM_MMU_GMII_FD;
/*
* Workaround BCOM Errata (#10523) for all BCom Phys
* Enable Power Management after link up
*/
& ~PHY_B_AC_DIS_PM);
}
}
{
if (isrc & PHY_B_IS_PSE)
/* Workaround BCom Errata:
* enable and disable loopback mode if "NO HCD" occurs.
*/
if (isrc & PHY_B_IS_NO_HDCL) {
ctrl | PHY_CT_LOOP);
ctrl & ~PHY_CT_LOOP);
}
}
{
int i;
for (i = 0; i < PHY_RETRIES; i++) {
udelay(1);
return 0;
}
return -EIO;
}
{
int i;
for (i = 0; i < PHY_RETRIES; i++) {
udelay(1);
goto ready;
}
return -ETIMEDOUT;
return 0;
}
{
u16 v = 0;
return v;
}
/* Marvell Phy Initialization */
{
}
ctrl &= ~PHY_CT_ANE;
ctrl |= PHY_CT_RESET;
ctrl = 0;
ct1000 = 0;
adv = PHY_AN_CSMA;
adv |= PHY_M_AN_100_FD;
adv |= PHY_M_AN_100_HD;
adv |= PHY_M_AN_10_FD;
adv |= PHY_M_AN_10_HD;
/* Set Flow-control capabilities */
} else {
}
/* Restart Auto-negotiation */
} else {
ctrl |= PHY_CT_DUP_MD;
case SPEED_1000:
ctrl |= PHY_CT_SP1000;
break;
case SPEED_100:
ctrl |= PHY_CT_SP100;
break;
}
ctrl |= PHY_CT_RESET;
}
/* Enable phy interrupt on autonegotiation complete (or link up) */
else
}
{
}
/* Apparently, early versions of Yukon-Lite had wrong chip_id? */
{
int ret;
return 0;
return ret;
}
{
int i;
/* WA code for COMA mode -- set PHY reset */
}
/* hard reset */
/* WA code for COMA mode -- clear PHY reset */
}
/* Set hardware config mode */
/* Clear GMC reset */
case SPEED_1000:
reg &= ~GM_GPCR_SPEED_100;
break;
case SPEED_100:
reg &= ~GM_GPCR_SPEED_1000;
reg |= GM_GPCR_SPEED_100;
break;
case SPEED_10:
break;
}
reg |= GM_GPCR_DUP_FULL;
} else
switch (skge->flow_control) {
case FLOW_MODE_NONE:
break;
case FLOW_MODE_LOC_SEND:
/* disable Rx flow-control */
break;
case FLOW_MODE_SYMMETRIC:
case FLOW_MODE_SYM_OR_REM:
/* enable Tx & Rx flow-control */
break;
}
/* MIB clear */
for (i = 0; i < GM_MIB_CNT_SIZE; i++)
/* transmit control */
/* receive control reg: unicast + multicast + no FCS */
/* transmit flow control */
/* transmit parameter */
/* configure the Serial Mode Register */
/* physical address: used for pause frames */
/* virtual address for data */
/* enable interrupt mask for counter overflows */
/* Initialize Mac Fifo */
/* Configure Rx MAC FIFO */
/* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */
if (is_yukon_lite_a0(hw))
reg &= ~GMF_RX_F_FL_ON;
/*
* because Pause Packet Truncation in GMAC is not working
* we have to increase the Flush Threshold to 64 bytes
* in order to flush pause packets in Rx FIFO on Yukon-1
*/
/* Configure Tx MAC FIFO */
}
/* Go into power down mode */
{
ctrl |= PHY_CT_RESET;
/* switch IEEE compatible power down mode on */
ctrl |= PHY_CT_PDOWN;
}
{
& ~(GM_GPCR_TX_ENA|GM_GPCR_RX_ENA));
/* set GPHY Control reset */
}
{
switch (aux & PHY_M_PS_SPEED_MSK) {
case PHY_M_PS_SPEED_1000:
return SPEED_1000;
case PHY_M_PS_SPEED_100:
return SPEED_100;
default:
return SPEED_10;
}
}
{
/* Enable Transmit FIFO Underrun */
reg |= GM_GPCR_DUP_FULL;
}
{
ctrl |= PHY_M_AN_ASP;
/* restore Asymmetric Pause bit */
}
}
{
if (istatus & PHY_M_IS_AN_COMPL) {
& PHY_M_AN_RF) {
reason = "remote fault";
goto failed;
}
goto failed;
}
if (!(phystat & PHY_M_PS_SPDUP_RES)) {
goto failed;
}
? DUPLEX_FULL : DUPLEX_HALF;
switch (phystat & PHY_M_PS_PAUSE_MSK) {
case PHY_M_PS_PAUSE_MSK:
break;
case PHY_M_PS_RX_P_EN:
break;
case PHY_M_PS_TX_P_EN:
break;
default:
}
else
return;
}
if (istatus & PHY_M_IS_LSP_CHANGE)
if (istatus & PHY_M_IS_DUP_CHANGE)
if (istatus & PHY_M_IS_LST_CHANGE) {
if (phystat & PHY_M_PS_LINK_UP)
else
}
return;
/* XXX restart autonegotiation? */
}
{
start /= 8;
len /= 8;
/* Set thresholds on receive queue's */
} else {
/* Enable store & forward on Tx queue's because
* Tx FIFO is only 4K on Genesis and 1K on Yukon
*/
}
}
/* Setup Bus Memory Interface */
const struct skge_element *e)
{
/* optimization to reduce window on 32bit/33mhz */
watermark /= 2;
}
{
}
{
int err;
return -ENOMEM;
/* FIXME: find out whether 64 bit iPXE will be loaded > 4GB */
goto err;
}
if (err)
goto err;
/* this call relies on e->iob and d->control to be 0
* This is assured by calling memset() on skge->mem and using zalloc()
* for the skge_element structures.
*/
if (err)
goto err;
/* Initialize MAC */
else
/* Start receiver BMU */
wmb();
return 0;
err:
return err;
}
/* stop receiver */
{
}
{
return;
skge->use_xm_link_timer = 0;
else
/* Stop transmitter */
/* Disable Force Sync bit and Enable Alloc bit */
/* Stop Interval Timer and Limit Counter of Tx Arbiter */
/* Reset PCI FIFO */
/* Reset the RAM Buffer async Tx queue */
} else {
}
return;
}
{
mb();
}
{
struct skge_element *e;
struct skge_tx_desc *td;
return -EBUSY;
/* Make sure all the descriptors written */
wmb();
wmb();
wmb();
}
return 0;
}
/* Free all buffers in transmit ring */
{
struct skge_element *e;
}
}
{
return status >> XMR_FS_LEN_SHIFT;
else
return status >> GMR_FS_LEN_SHIFT;
}
{
else
return (status & GMR_FS_ANY_ERR) ||
(status & GMR_FS_RX_OK) == 0;
}
/* Free all buffers in Tx ring which are no longer owned by device */
{
struct skge_element *e;
break;
}
/* Can run lockless until we need to synchronize to restart queue. */
mb();
}
{
struct skge_element *e;
struct skge_rx_desc *rd;
int i;
for (i = 0; i < NUM_RX_DESC; i++) {
/* nothing to do here */
continue;
if (iob) {
} else {
DBG("descr %zd: alloc_iob() failed\n",
/* We pass the descriptor to the NIC even if the
* allocation failed. The card will stop as soon as it
* encounters a descriptor with the OWN bit set to 0,
* thus never getting to the next descriptor that might
* contain a valid io_buffer. This would effectively
* stall the receive.
*/
}
}
}
{
struct skge_rx_desc *rd;
struct skge_element *e;
int i;
for (i = 0; i < NUM_RX_DESC; i++) {
rmb();
break;
if (!iob)
continue;
/* catch RX errors */
/* report receive errors */
DBG("rx error\n");
} else {
}
/* io_buffer passed to core, make sure we don't reuse it */
e = e->next;
}
}
{
/* reading this register ACKs interrupts */
/* Link event? */
if (status & IS_EXT_REG) {
if (skge->use_xm_link_timer)
}
/* restart receiver */
wmb();
return;
}
{
int port;
}
}
static const struct {
const char *name;
} skge_chips[] = {
{ CHIP_ID_GENESIS, "Genesis" },
{ CHIP_ID_YUKON, "Yukon" },
{ CHIP_ID_YUKON_LITE, "Yukon-Lite"},
{ CHIP_ID_YUKON_LP, "Yukon-LP"},
};
{
unsigned int i;
static char buf[16];
for (i = 0; i < ARRAY_SIZE(skge_chips); i++)
return skge_chips[i].name;
return buf;
}
/*
* Setup the board data structure, but don't bring up
* the port(s)
*/
{
int i;
/* do a SW reset */
/* clear PCI errors, if any */
/* restore CLK_RUN bits (for Yukon-Lite) */
case CHIP_ID_GENESIS:
case SK_PHY_XMAC:
break;
case SK_PHY_BCOM:
break;
default:
return -EOPNOTSUPP;
}
break;
case CHIP_ID_YUKON:
case CHIP_ID_YUKON_LITE:
case CHIP_ID_YUKON_LP:
break;
default:
return -EOPNOTSUPP;
}
/* read the adapters RAM size */
if (t8 == 3) {
/* special case: 4 x 64k x 36, offset = 0x80000 */
} else
}
else if (t8 == 0)
else
/* Use PHY IRQ for all but fiber based Genesis board */
else {
/* switch power to VCC (WA for VAUX problem) */
/* avoid boards with stuck Hardware error bits */
}
/* Clear PHY COMA */
reg &= ~PCI_PHY_COMA;
}
}
/* turn off hardware timer (unused) */
/* enable the Tx Arbiters */
/* Initialize ram interface */
/* Set interrupt moderation for Transmit only
* Receive interrupts avoided by NAPI
*/
genesis_reset(hw, i);
else
yukon_reset(hw, i);
}
return 0;
}
/* Initialize network device */
{
if (!dev) {
return NULL;
}
/* Auto speed and flow control */
/* read the mac address */
return dev;
}
{
}
{
if (!hw) {
goto err_out_free_regions;
}
goto err_out_free_hw;
}
if (err)
goto err_out_iounmap;
if (!dev)
goto err_out_led_off;
if (err) {
goto err_out_free_netdev;
}
if (register_netdev(dev1) == 0)
else {
/* Failure to register second port need not be fatal */
}
}
return 0;
return err;
}
{
if (!hw)
return;
if (dev1) {
}
}
/*
* Enable or disable IRQ masking.
*
* @v netdev Device to control.
* @v enable Zero to mask off IRQ, non-zero to enable IRQ.
*
* This is a iPXE Network Driver API function.
*/
if (enable)
else
}
.ids = skge_id_table,
.probe = skge_probe,
};