* for registers, link status and other minor fixes.
* 0.28: 21 Jun 2004: Big cleanup, making driver mostly endian safe
* 0.29: 31 Aug 2004: Add backup timer for link change notification.
+ * 0.30: 25 Sep 2004: rx checksum support for nf 250 Gb. Add rx reset
+ * into nv_close, otherwise reenabling for wol can
+ * cause DMA to kfree'd memory.
+ * 0.31: 14 Nov 2004: ethtool support for getting/setting link
+ * capabilities.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
-#define FORCEDETH_VERSION "0.29"
+#define FORCEDETH_VERSION "0.31"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
#define NVREG_LINKSPEED_10 1000
#define NVREG_LINKSPEED_100 100
#define NVREG_LINKSPEED_1000 50
+#define NVREG_LINKSPEED_MASK (0xFFF)
NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31 (1<<31)
NvRegUnknownSetupReg3 = 0x13c,
#define NVREG_TXRXCTL_BIT2 0x0004
#define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010
+#define NVREG_TXRXCTL_RXCHECK 0x0400
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
#define NV_RX_ERROR (1<<30)
#define NV_RX_AVAIL (1<<31)
+#define NV_RX2_CHECKSUMMASK (0x1C000000)
+#define NV_RX2_CHECKSUMOK1 (0x10000000)
+#define NV_RX2_CHECKSUMOK2 (0x14000000)
+#define NV_RX2_CHECKSUMOK3 (0x18000000)
#define NV_RX2_DESCRIPTORVALID (1<<29)
#define NV_RX2_SUBSTRACT1 (1<<25)
#define NV_RX2_ERROR1 (1<<18)
#define POLL_WAIT (1+HZ/100)
#define LINK_TIMEOUT (3*HZ)
+/*
+ * desc_ver values:
+ * This field has two purposes:
+ * - Newer nics uses a different ring layout. The layout is selected by
+ * comparing np->desc_ver with DESC_VER_xy.
+ * - It contains bits that are forced on when writing to NvRegTxRxControl.
+ */
#define DESC_VER_1 0x0
-#define DESC_VER_2 0x02100
+#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK)
/* PHY defines */
#define PHY_OUI_MARVELL 0x5043
int in_shutdown;
u32 linkspeed;
int duplex;
+ int autoneg;
+ int fixed_mode;
int phyaddr;
int wolenabled;
unsigned int phy_oui;
u32 irqmask;
u32 desc_ver;
+ void __iomem *base;
+
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
static inline struct fe_priv *get_nvpriv(struct net_device *dev)
{
- return (struct fe_priv *) dev->priv;
+ return netdev_priv(dev);
}
-static inline u8 *get_hwbase(struct net_device *dev)
+static inline u8 __iomem *get_hwbase(struct net_device *dev)
{
- return (u8 *) dev->base_addr;
+ return get_nvpriv(dev)->base;
}
-static inline void pci_push(u8 * base)
+static inline void pci_push(u8 __iomem *base)
{
/* force out pending posted writes */
readl(base);
static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
int delay, int delaymax, const char *msg)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
pci_push(base);
do {
*/
static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 reg;
int retval;
static int phy_init(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg;
/* set advertise register */
static void nv_start_rx(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
/* Already running? Stop it. */
static void nv_stop_rx(struct net_device *dev)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name);
writel(0, base + NvRegReceiverControl);
static void nv_start_tx(struct net_device *dev)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name);
writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl);
static void nv_stop_tx(struct net_device *dev)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name);
writel(0, base + NvRegTransmitterControl);
static void nv_txrx_reset(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl);
return &np->stats;
}
-static int nv_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
-{
- struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
- u32 ethcmd;
-
- if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd)))
- return -EFAULT;
-
- switch (ethcmd) {
- case ETHTOOL_GDRVINFO:
- {
- struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
- strcpy(info.driver, "forcedeth");
- strcpy(info.version, FORCEDETH_VERSION);
- strcpy(info.bus_info, pci_name(np->pci_dev));
- if (copy_to_user(useraddr, &info, sizeof (info)))
- return -EFAULT;
- return 0;
- }
- case ETHTOOL_GLINK:
- {
- struct ethtool_value edata = { ETHTOOL_GLINK };
-
- edata.data = !!netif_carrier_ok(dev);
-
- if (copy_to_user(useraddr, &edata, sizeof(edata)))
- return -EFAULT;
- return 0;
- }
- case ETHTOOL_GWOL:
- {
- struct ethtool_wolinfo wolinfo;
- memset(&wolinfo, 0, sizeof(wolinfo));
- wolinfo.supported = WAKE_MAGIC;
-
- spin_lock_irq(&np->lock);
- if (np->wolenabled)
- wolinfo.wolopts = WAKE_MAGIC;
- spin_unlock_irq(&np->lock);
-
- if (copy_to_user(useraddr, &wolinfo, sizeof(wolinfo)))
- return -EFAULT;
- return 0;
- }
- case ETHTOOL_SWOL:
- {
- struct ethtool_wolinfo wolinfo;
- if (copy_from_user(&wolinfo, useraddr, sizeof(wolinfo)))
- return -EFAULT;
-
- spin_lock_irq(&np->lock);
- if (wolinfo.wolopts == 0) {
- writel(0, base + NvRegWakeUpFlags);
- np->wolenabled = 0;
- }
- if (wolinfo.wolopts & WAKE_MAGIC) {
- writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags);
- np->wolenabled = 1;
- }
- spin_unlock_irq(&np->lock);
- return 0;
- }
-
- default:
- break;
- }
-
- return -EOPNOTSUPP;
-}
-/*
- * nv_ioctl: dev->do_ioctl function
- * Called with rtnl_lock held.
- */
-static int nv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- switch(cmd) {
- case SIOCETHTOOL:
- return nv_ethtool_ioctl(dev, rq->ifr_data);
-
- default:
- return -EOPNOTSUPP;
- }
-}
-
/*
* nv_alloc_rx: fill rx ring entries.
* Return 1 if the allocations for the skbs failed and the
static void nv_tx_timeout(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name,
readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK);
goto next_pkt;
}
}
+ Flags &= NV_RX2_CHECKSUMMASK;
+ if (Flags == NV_RX2_CHECKSUMOK1 ||
+ Flags == NV_RX2_CHECKSUMOK2 ||
+ Flags == NV_RX2_CHECKSUMOK3) {
+ dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
+ np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name);
+ }
}
/* got a valid packet - forward it to the network core */
skb = np->rx_skbuff[i];
static void nv_set_multicast(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 addr[2];
u32 mask[2];
u32 pff;
static int nv_update_linkspeed(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
int adv, lpa;
int newls = np->linkspeed;
int newdup = np->duplex;
goto set_speed;
}
+ if (np->autoneg == 0) {
+ dprintk(KERN_DEBUG "%s: nv_update_linkspeed: autoneg off, PHY set to 0x%04x.\n",
+ dev->name, np->fixed_mode);
+ if (np->fixed_mode & LPA_100FULL) {
+ newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;
+ newdup = 1;
+ } else if (np->fixed_mode & LPA_100HALF) {
+ newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100;
+ newdup = 0;
+ } else if (np->fixed_mode & LPA_10FULL) {
+ newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
+ newdup = 1;
+ } else {
+ newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
+ newdup = 0;
+ }
+ retval = 1;
+ goto set_speed;
+ }
/* check auto negotiation is complete */
if (!(mii_status & BMSR_ANEGCOMPLETE)) {
/* still in autonegotiation - configure nic for 10 MBit HD and wait. */
if ((control_1000 & ADVERTISE_1000FULL) &&
(status_1000 & LPA_1000FULL)) {
- dprintk(KERN_DEBUG "%s: nv_update_linkspeed: GBit ethernet detected.\n",
+ dprintk(KERN_DEBUG "%s: nv_update_linkspeed: GBit ethernet detected.\n",
dev->name);
newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_1000;
newdup = 1;
phyreg &= ~(PHY_HALF|PHY_100|PHY_1000);
if (np->duplex == 0)
phyreg |= PHY_HALF;
- if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
+ if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_100)
phyreg |= PHY_100;
- else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
+ else if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000)
phyreg |= PHY_1000;
writel(phyreg, base + NvRegPhyInterface);
static void nv_link_irq(struct net_device *dev)
{
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 miistat;
miistat = readl(base + NvRegMIIStatus);
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
u32 events;
int i;
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
disable_irq(dev->irq);
/* FIXME: Do we need synchronize_irq(dev->irq) here? */
enable_irq(dev->irq);
}
+static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+ strcpy(info->driver, "forcedeth");
+ strcpy(info->version, FORCEDETH_VERSION);
+ strcpy(info->bus_info, pci_name(np->pci_dev));
+}
+
+static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+ wolinfo->supported = WAKE_MAGIC;
+
+ spin_lock_irq(&np->lock);
+ if (np->wolenabled)
+ wolinfo->wolopts = WAKE_MAGIC;
+ spin_unlock_irq(&np->lock);
+}
+
+static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
+{
+ struct fe_priv *np = get_nvpriv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ spin_lock_irq(&np->lock);
+ if (wolinfo->wolopts == 0) {
+ writel(0, base + NvRegWakeUpFlags);
+ np->wolenabled = 0;
+ }
+ if (wolinfo->wolopts & WAKE_MAGIC) {
+ writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags);
+ np->wolenabled = 1;
+ }
+ spin_unlock_irq(&np->lock);
+ return 0;
+}
+
+static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ int adv;
+
+ spin_lock_irq(&np->lock);
+ ecmd->port = PORT_MII;
+ if (!netif_running(dev)) {
+ /* We do not track link speed / duplex setting if the
+ * interface is disabled. Force a link check */
+ nv_update_linkspeed(dev);
+ }
+ switch(np->linkspeed & (NVREG_LINKSPEED_MASK)) {
+ case NVREG_LINKSPEED_10:
+ ecmd->speed = SPEED_10;
+ break;
+ case NVREG_LINKSPEED_100:
+ ecmd->speed = SPEED_100;
+ break;
+ case NVREG_LINKSPEED_1000:
+ ecmd->speed = SPEED_1000;
+ break;
+ }
+ ecmd->duplex = DUPLEX_HALF;
+ if (np->duplex)
+ ecmd->duplex = DUPLEX_FULL;
+
+ ecmd->autoneg = np->autoneg;
+
+ ecmd->advertising = ADVERTISED_MII;
+ if (np->autoneg) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
+ } else {
+ adv = np->fixed_mode;
+ }
+ if (adv & ADVERTISE_10HALF)
+ ecmd->advertising |= ADVERTISED_10baseT_Half;
+ if (adv & ADVERTISE_10FULL)
+ ecmd->advertising |= ADVERTISED_10baseT_Full;
+ if (adv & ADVERTISE_100HALF)
+ ecmd->advertising |= ADVERTISED_100baseT_Half;
+ if (adv & ADVERTISE_100FULL)
+ ecmd->advertising |= ADVERTISED_100baseT_Full;
+ if (np->autoneg && np->gigabit == PHY_GIGABIT) {
+ adv = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ);
+ if (adv & ADVERTISE_1000FULL)
+ ecmd->advertising |= ADVERTISED_1000baseT_Full;
+ }
+
+ ecmd->supported = (SUPPORTED_Autoneg |
+ SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+ SUPPORTED_MII);
+ if (np->gigabit == PHY_GIGABIT)
+ ecmd->supported |= SUPPORTED_1000baseT_Full;
+
+ ecmd->phy_address = np->phyaddr;
+ ecmd->transceiver = XCVR_EXTERNAL;
+
+ /* ignore maxtxpkt, maxrxpkt for now */
+ spin_unlock_irq(&np->lock);
+ return 0;
+}
+
+static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ struct fe_priv *np = netdev_priv(dev);
+
+ if (ecmd->port != PORT_MII)
+ return -EINVAL;
+ if (ecmd->transceiver != XCVR_EXTERNAL)
+ return -EINVAL;
+ if (ecmd->phy_address != np->phyaddr) {
+ /* TODO: support switching between multiple phys. Should be
+ * trivial, but not enabled due to lack of test hardware. */
+ return -EINVAL;
+ }
+ if (ecmd->autoneg == AUTONEG_ENABLE) {
+ u32 mask;
+
+ mask = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+ if (np->gigabit == PHY_GIGABIT)
+ mask |= ADVERTISED_1000baseT_Full;
+
+ if ((ecmd->advertising & mask) == 0)
+ return -EINVAL;
+
+ } else if (ecmd->autoneg == AUTONEG_DISABLE) {
+ /* Note: autonegotiation disable, speed 1000 intentionally
+ * forbidden - noone should need that. */
+
+ if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
+ return -EINVAL;
+ if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+ return -EINVAL;
+ } else {
+ return -EINVAL;
+ }
+
+ spin_lock_irq(&np->lock);
+ if (ecmd->autoneg == AUTONEG_ENABLE) {
+ int adv, bmcr;
+
+ np->autoneg = 1;
+
+ /* advertise only what has been requested */
+ adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+ if (ecmd->advertising & ADVERTISED_10baseT_Half)
+ adv |= ADVERTISE_10HALF;
+ if (ecmd->advertising & ADVERTISED_10baseT_Full)
+ adv |= ADVERTISE_10FULL;
+ if (ecmd->advertising & ADVERTISED_100baseT_Half)
+ adv |= ADVERTISE_100HALF;
+ if (ecmd->advertising & ADVERTISED_100baseT_Full)
+ adv |= ADVERTISE_100FULL;
+ mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv);
+
+ if (np->gigabit == PHY_GIGABIT) {
+ adv = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ);
+ adv &= ~ADVERTISE_1000FULL;
+ if (ecmd->advertising & ADVERTISED_1000baseT_Full)
+ adv |= ADVERTISE_1000FULL;
+ mii_rw(dev, np->phyaddr, MII_1000BT_CR, adv);
+ }
+
+ bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+
+ } else {
+ int adv, bmcr;
+
+ np->autoneg = 0;
+
+ adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+ if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF)
+ adv |= ADVERTISE_10HALF;
+ if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL)
+ adv |= ADVERTISE_10FULL;
+ if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF)
+ adv |= ADVERTISE_100HALF;
+ if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL)
+ adv |= ADVERTISE_100FULL;
+ mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv);
+ np->fixed_mode = adv;
+
+ if (np->gigabit == PHY_GIGABIT) {
+ adv = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ);
+ adv &= ~ADVERTISE_1000FULL;
+ mii_rw(dev, np->phyaddr, MII_1000BT_CR, adv);
+ }
+
+ bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+ bmcr |= ~(BMCR_ANENABLE|BMCR_SPEED100|BMCR_FULLDPLX);
+ if (adv & (ADVERTISE_10FULL|ADVERTISE_100FULL))
+ bmcr |= BMCR_FULLDPLX;
+ if (adv & (ADVERTISE_100HALF|ADVERTISE_100FULL))
+ bmcr |= BMCR_SPEED100;
+ mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+
+ if (netif_running(dev)) {
+ /* Wait a bit and then reconfigure the nic. */
+ udelay(10);
+ nv_linkchange(dev);
+ }
+ }
+ spin_unlock_irq(&np->lock);
+
+ return 0;
+}
+
+static struct ethtool_ops ops = {
+ .get_drvinfo = nv_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_wol = nv_get_wol,
+ .set_wol = nv_set_wol,
+ .get_settings = nv_get_settings,
+ .set_settings = nv_set_settings,
+};
+
static int nv_open(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
int ret, oom, i;
dprintk(KERN_DEBUG "nv_open: begin\n");
base + NvRegRingSizes);
/* 5) continue setup */
- np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
- np->duplex = 0;
-
writel(np->linkspeed, base + NvRegLinkSpeed);
writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3);
writel(np->desc_ver, base + NvRegTxRxControl);
static int nv_close(struct net_device *dev)
{
struct fe_priv *np = get_nvpriv(dev);
- u8 *base;
+ u8 __iomem *base;
spin_lock_irq(&np->lock);
np->in_shutdown = 1;
spin_lock_irq(&np->lock);
nv_stop_tx(dev);
nv_stop_rx(dev);
- base = get_hwbase(dev);
+ nv_txrx_reset(dev);
/* disable interrupts on the nic or we will lock up */
+ base = get_hwbase(dev);
writel(0, base + NvRegIrqMask);
pci_push(base);
dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name);
struct net_device *dev;
struct fe_priv *np;
unsigned long addr;
- u8 *base;
+ u8 __iomem *base;
int err, i;
dev = alloc_etherdev(sizeof(struct fe_priv));
np->desc_ver = DESC_VER_2;
err = -ENOMEM;
- dev->base_addr = (unsigned long) ioremap(addr, NV_PCI_REGSZ);
- if (!dev->base_addr)
+ np->base = ioremap(addr, NV_PCI_REGSZ);
+ if (!np->base)
goto out_relreg;
+ dev->base_addr = (unsigned long)np->base;
dev->irq = pci_dev->irq;
np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING),
&np->ring_addr);
dev->get_stats = nv_get_stats;
dev->change_mtu = nv_change_mtu;
dev->set_multicast_list = nv_set_multicast;
- dev->do_ioctl = nv_ioctl;
+ SET_ETHTOOL_OPS(dev, &ops);
dev->tx_timeout = nv_tx_timeout;
dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
phy_init(dev);
}
+ /* set default link speed settings */
+ np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10;
+ np->duplex = 0;
+ np->autoneg = 1;
+
err = register_netdev(dev);
if (err) {
printk(KERN_INFO "forcedeth: unable to register netdev: %d\n", err);
{
struct net_device *dev = pci_get_drvdata(pci_dev);
struct fe_priv *np = get_nvpriv(dev);
- u8 *base = get_hwbase(dev);
+ u8 __iomem *base = get_hwbase(dev);
unregister_netdev(dev);