X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Ftyphoon.c;h=8f3392989a06e83188a1323341d04ff3f4176bca;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=39949dbb1599bff0cb482b87853a7fa41fcdc0e7;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 39949dbb1..8f3392989 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1,6 +1,6 @@ /* typhoon.c: A Linux Ethernet device driver for 3Com 3CR990 family of NICs */ /* - Written 2002-2003 by David Dillow + Written 2002-2004 by David Dillow Based on code written 1998-2000 by Donald Becker and Linux 2.2.x driver by David P. McLean . @@ -33,8 +33,16 @@ *) Waiting for a command response takes 8ms due to non-preemptable polling. Only significant for getting stats and creating SAs, but an ugly wart never the less. - *) I've not tested multicast. I think it works, but reports welcome. + + TODO: *) Doesn't do IPSEC offloading. Yet. Keep yer pants on, it's coming. + *) Add more support for ethtool (especially for NIC stats) + *) Allow disabling of RX checksum offloading + *) Fix MAC changing to work while the interface is up + (Need to put commands on the TX ring, which changes + the locking) + *) Add in FCS to {rx,tx}_bytes, since the hardware doesn't. See + http://oss.sgi.com/cgi-bin/mesg.cgi?a=netdev&i=20031215152211.7003fe8e.rddunlap%40osdl.org */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -42,6 +50,13 @@ */ static int rx_copybreak = 200; +/* Should we use MMIO or Port IO? + * 0: Port IO + * 1: MMIO + * 2: Try MMIO, fallback to Port IO + */ +static unsigned int use_mmio = 2; + /* end user-configurable values */ /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). @@ -85,17 +100,11 @@ static const int multicast_filter_limit = 32; #define PKT_BUF_SZ 1536 #define DRV_MODULE_NAME "typhoon" -#define DRV_MODULE_VERSION "1.5.3" -#define DRV_MODULE_RELDATE "03/12/15" +#define DRV_MODULE_VERSION "1.5.7" +#define DRV_MODULE_RELDATE "05/01/07" #define PFX DRV_MODULE_NAME ": " #define ERR_PFX KERN_ERR PFX -#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) -#warning You must compile this file with the correct options! -#warning See the last lines of the source file. -#error You must compile this driver with "-O". -#endif - #include #include #include @@ -113,13 +122,14 @@ static const int multicast_filter_limit = 32; #include #include #include +#include #include -#include #include #include #include #include #include +#include #include "typhoon.h" #include "typhoon-firmware.h" @@ -128,9 +138,16 @@ static char version[] __devinitdata = "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("David Dillow "); +MODULE_VERSION(DRV_MODULE_VERSION); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)"); -MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM_DESC(rx_copybreak, "Packets smaller than this are copied and " + "the buffer given back to the NIC. Default " + "is 200."); +MODULE_PARM_DESC(use_mmio, "Use MMIO (1) or PIO(0) to access the NIC. " + "Default is to try MMIO and fallback to PIO."); +module_param(rx_copybreak, int, 0); +module_param(use_mmio, int, 0); #if defined(NETIF_F_TSO) && MAX_SKB_FRAGS > 32 #warning Typhoon only supports 32 entries in its SG list for TSO, disabling TSO @@ -254,11 +271,11 @@ struct typhoon { /* Tx cache line section */ struct transmit_ring txLoRing ____cacheline_aligned; struct pci_dev * tx_pdev; - unsigned long tx_ioaddr; + void __iomem *tx_ioaddr; u32 txlo_dma_addr; /* Irq/Rx cache line section */ - unsigned long ioaddr ____cacheline_aligned; + void __iomem *ioaddr ____cacheline_aligned; struct typhoon_indexes *indexes; u8 awaiting_resp; u8 duplex; @@ -285,7 +302,6 @@ struct typhoon { u16 xcvr_select; u16 wol_events; u32 offload; - u32 pci_state[16]; /* unused stuff (future use) */ int capabilities; @@ -308,7 +324,7 @@ enum state_values { * cannot pass a read, so this forces current writes to post. */ #define typhoon_post_pci_writes(x) \ - do { readl(x + TYPHOON_REG_HEARTBEAT); } while(0) + do { if(likely(use_mmio)) ioread32(x+TYPHOON_REG_HEARTBEAT); } while(0) /* We'll wait up to six seconds for a reset, and half a second normally. */ @@ -379,7 +395,7 @@ typhoon_inc_rx_index(u32 *index, const int count) } static int -typhoon_reset(unsigned long ioaddr, int wait_type) +typhoon_reset(void __iomem *ioaddr, int wait_type) { int i, err = 0; int timeout; @@ -389,17 +405,17 @@ typhoon_reset(unsigned long ioaddr, int wait_type) else timeout = TYPHOON_RESET_TIMEOUT_SLEEP; - writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); - writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); + iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); + iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); - writel(TYPHOON_RESET_ALL, ioaddr + TYPHOON_REG_SOFT_RESET); + iowrite32(TYPHOON_RESET_ALL, ioaddr + TYPHOON_REG_SOFT_RESET); typhoon_post_pci_writes(ioaddr); udelay(1); - writel(TYPHOON_RESET_NONE, ioaddr + TYPHOON_REG_SOFT_RESET); + iowrite32(TYPHOON_RESET_NONE, ioaddr + TYPHOON_REG_SOFT_RESET); if(wait_type != NoWait) { for(i = 0; i < timeout; i++) { - if(readl(ioaddr + TYPHOON_REG_STATUS) == + if(ioread32(ioaddr + TYPHOON_REG_STATUS) == TYPHOON_STATUS_WAITING_FOR_HOST) goto out; @@ -414,32 +430,33 @@ typhoon_reset(unsigned long ioaddr, int wait_type) } out: - writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); - writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); - udelay(100); - return err; + iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); + iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); /* The 3XP seems to need a little extra time to complete the load * of the sleep image before we can reliably boot it. Failure to * do this occasionally results in a hung adapter after boot in * typhoon_init_one() while trying to read the MAC address or * putting the card to sleep. 3Com's driver waits 5ms, but - * that seems to be overkill -- with a 50usec delay, it survives - * 35000 typhoon_init_one() calls, where it only make it 25-100 - * without it. - * - * As it turns out, still occasionally getting a hung adapter, - * so I'm bumping it to 100us. + * that seems to be overkill. However, if we can sleep, we might + * as well give it that much time. Otherwise, we'll give it 500us, + * which should be enough (I've see it work well at 100us, but still + * saw occasional problems.) */ + if(wait_type == WaitSleep) + msleep(5); + else + udelay(500); + return err; } static int -typhoon_wait_status(unsigned long ioaddr, u32 wait_value) +typhoon_wait_status(void __iomem *ioaddr, u32 wait_value) { int i, err = 0; for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) { - if(readl(ioaddr + TYPHOON_REG_STATUS) == wait_value) + if(ioread32(ioaddr + TYPHOON_REG_STATUS) == wait_value) goto out; udelay(TYPHOON_UDELAY); } @@ -475,7 +492,7 @@ typhoon_hello(struct typhoon *tp) INIT_COMMAND_NO_RESPONSE(cmd, TYPHOON_CMD_HELLO_RESP); smp_wmb(); - writel(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY); + iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY); spin_unlock(&tp->command_lock); } } @@ -630,7 +647,7 @@ typhoon_issue_command(struct typhoon *tp, int num_cmd, struct cmd_desc *cmd, /* "I feel a presence... another warrior is on the the mesa." */ wmb(); - writel(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY); + iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY); typhoon_post_pci_writes(tp->ioaddr); if((cmd->flags & TYPHOON_CMD_RESPOND) == 0) @@ -684,7 +701,7 @@ out: * is the case. */ if(indexes->respCleared != indexes->respReady) - writel(1, tp->ioaddr + TYPHOON_REG_SELF_INTERRUPT); + iowrite32(1, tp->ioaddr + TYPHOON_REG_SELF_INTERRUPT); } spin_unlock(&tp->command_lock); @@ -694,7 +711,7 @@ out: static void typhoon_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); struct cmd_desc xp_cmd; int err; @@ -732,7 +749,7 @@ typhoon_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) static void typhoon_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); spin_lock_bh(&tp->state_lock); if(tp->vlgrp) tp->vlgrp->vlan_devices[vid] = NULL; @@ -763,7 +780,7 @@ typhoon_tso_fill(struct sk_buff *skb, struct transmit_ring *txRing, static int typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) { - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); struct transmit_ring *txRing; struct tx_desc *txd, *first_txd; dma_addr_t skb_dma; @@ -886,7 +903,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) /* Kick the 3XP */ wmb(); - writel(txRing->lastWrite, tp->tx_ioaddr + txRing->writeRegister); + iowrite32(txRing->lastWrite, tp->tx_ioaddr + txRing->writeRegister); dev->trans_start = jiffies; @@ -914,7 +931,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) static void typhoon_set_rx_mode(struct net_device *dev) { - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); struct cmd_desc xp_cmd; u32 mc_filter[2]; u16 filter; @@ -971,6 +988,9 @@ typhoon_do_get_stats(struct typhoon *tp) /* 3Com's Linux driver uses txMultipleCollisions as it's * collisions value, but there is some other collision info as well... + * + * The extra status reported would be a good candidate for + * ethtool_ops->get_{strings,stats}() */ stats->tx_packets = le32_to_cpu(s->txPackets); stats->tx_bytes = le32_to_cpu(s->txBytes); @@ -1008,7 +1028,7 @@ typhoon_do_get_stats(struct typhoon *tp) static struct net_device_stats * typhoon_get_stats(struct net_device *dev) { - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); struct net_device_stats *stats = &tp->stats; struct net_device_stats *saved = &tp->stats_saved; @@ -1036,9 +1056,10 @@ typhoon_set_mac_address(struct net_device *dev, void *addr) return 0; } -static inline void -typhoon_ethtool_gdrvinfo(struct typhoon *tp, struct ethtool_drvinfo *info) +static void +typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { + struct typhoon *tp = netdev_priv(dev); struct pci_dev *pci_dev = tp->pdev; struct cmd_desc xp_cmd; struct resp_desc xp_resp[3]; @@ -1051,8 +1072,10 @@ typhoon_ethtool_gdrvinfo(struct typhoon *tp, struct ethtool_drvinfo *info) if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) { strcpy(info->fw_version, "Unknown runtime"); } else { - strncpy(info->fw_version, (char *) &xp_resp[1], 32); - info->fw_version[31] = 0; + u32 sleep_ver = xp_resp[0].parm2; + snprintf(info->fw_version, 32, "%02x.%03x.%03x", + sleep_ver >> 24, (sleep_ver >> 12) & 0xfff, + sleep_ver & 0xfff); } } @@ -1061,9 +1084,11 @@ typhoon_ethtool_gdrvinfo(struct typhoon *tp, struct ethtool_drvinfo *info) strcpy(info->bus_info, pci_name(pci_dev)); } -static inline void -typhoon_ethtool_gset(struct typhoon *tp, struct ethtool_cmd *cmd) +static int +typhoon_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { + struct typhoon *tp = netdev_priv(dev); + cmd->supported = SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg; @@ -1113,15 +1138,19 @@ typhoon_ethtool_gset(struct typhoon *tp, struct ethtool_cmd *cmd) cmd->autoneg = AUTONEG_DISABLE; cmd->maxtxpkt = 1; cmd->maxrxpkt = 1; + + return 0; } -static inline int -typhoon_ethtool_sset(struct typhoon *tp, struct ethtool_cmd *cmd) +static int +typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { + struct typhoon *tp = netdev_priv(dev); struct cmd_desc xp_cmd; int xcvr; int err; + err = -EINVAL; if(cmd->autoneg == AUTONEG_ENABLE) { xcvr = TYPHOON_XCVR_AUTONEG; } else { @@ -1131,23 +1160,23 @@ typhoon_ethtool_sset(struct typhoon *tp, struct ethtool_cmd *cmd) else if(cmd->speed == SPEED_100) xcvr = TYPHOON_XCVR_100HALF; else - return -EINVAL; + goto out; } else if(cmd->duplex == DUPLEX_FULL) { if(cmd->speed == SPEED_10) xcvr = TYPHOON_XCVR_10FULL; else if(cmd->speed == SPEED_100) xcvr = TYPHOON_XCVR_100FULL; else - return -EINVAL; + goto out; } else - return -EINVAL; + goto out; } INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_XCVR_SELECT); xp_cmd.parm1 = cpu_to_le16(xcvr); err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL); if(err < 0) - return err; + goto out; tp->xcvr_select = xcvr; if(cmd->autoneg == AUTONEG_ENABLE) { @@ -1158,100 +1187,87 @@ typhoon_ethtool_sset(struct typhoon *tp, struct ethtool_cmd *cmd) tp->duplex = cmd->duplex; } - return 0; +out: + return err; } -static inline int -typhoon_ethtool_ioctl(struct net_device *dev, void *useraddr) +static void +typhoon_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct typhoon *tp = (struct typhoon *) dev->priv; - u32 ethcmd; - - if(copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) - return -EFAULT; - - switch (ethcmd) { - case ETHTOOL_GDRVINFO: { - struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; - - typhoon_ethtool_gdrvinfo(tp, &info); - if(copy_to_user(useraddr, &info, sizeof(info))) - return -EFAULT; - return 0; - } - case ETHTOOL_GSET: { - struct ethtool_cmd cmd = { ETHTOOL_GSET }; + struct typhoon *tp = netdev_priv(dev); + + wol->supported = WAKE_PHY | WAKE_MAGIC; + wol->wolopts = 0; + if(tp->wol_events & TYPHOON_WAKE_LINK_EVENT) + wol->wolopts |= WAKE_PHY; + if(tp->wol_events & TYPHOON_WAKE_MAGIC_PKT) + wol->wolopts |= WAKE_MAGIC; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} - typhoon_ethtool_gset(tp, &cmd); - if(copy_to_user(useraddr, &cmd, sizeof(cmd))) - return -EFAULT; - return 0; - } - case ETHTOOL_SSET: { - struct ethtool_cmd cmd; - if(copy_from_user(&cmd, useraddr, sizeof(cmd))) - return -EFAULT; +static int +typhoon_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct typhoon *tp = netdev_priv(dev); - return typhoon_ethtool_sset(tp, &cmd); - } - case ETHTOOL_GLINK:{ - struct ethtool_value edata = { ETHTOOL_GLINK }; + if(wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC)) + return -EINVAL; - edata.data = netif_carrier_ok(dev) ? 1 : 0; - if(copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - case ETHTOOL_GWOL: { - struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; - - if(tp->wol_events & TYPHOON_WAKE_LINK_EVENT) - wol.wolopts |= WAKE_PHY; - if(tp->wol_events & TYPHOON_WAKE_MAGIC_PKT) - wol.wolopts |= WAKE_MAGIC; - if(copy_to_user(useraddr, &wol, sizeof(wol))) - return -EFAULT; - return 0; - } - case ETHTOOL_SWOL: { - struct ethtool_wolinfo wol; - - if(copy_from_user(&wol, useraddr, sizeof(wol))) - return -EFAULT; - tp->wol_events = 0; - if(wol.wolopts & WAKE_PHY) - tp->wol_events |= TYPHOON_WAKE_LINK_EVENT; - if(wol.wolopts & WAKE_MAGIC) - tp->wol_events |= TYPHOON_WAKE_MAGIC_PKT; - return 0; - } - default: - break; - } + tp->wol_events = 0; + if(wol->wolopts & WAKE_PHY) + tp->wol_events |= TYPHOON_WAKE_LINK_EVENT; + if(wol->wolopts & WAKE_MAGIC) + tp->wol_events |= TYPHOON_WAKE_MAGIC_PKT; - return -EOPNOTSUPP; + return 0; } -static int -typhoon_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static u32 +typhoon_get_rx_csum(struct net_device *dev) { - switch (cmd) { - case SIOCETHTOOL: - return typhoon_ethtool_ioctl(dev, (void *) ifr->ifr_data); - default: - break; - } + /* For now, we don't allow turning off RX checksums. + */ + return 1; +} - return -EOPNOTSUPP; +static void +typhoon_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) +{ + ering->rx_max_pending = RXENT_ENTRIES; + ering->rx_mini_max_pending = 0; + ering->rx_jumbo_max_pending = 0; + ering->tx_max_pending = TXLO_ENTRIES - 1; + + ering->rx_pending = RXENT_ENTRIES; + ering->rx_mini_pending = 0; + ering->rx_jumbo_pending = 0; + ering->tx_pending = TXLO_ENTRIES - 1; } +static struct ethtool_ops typhoon_ethtool_ops = { + .get_settings = typhoon_get_settings, + .set_settings = typhoon_set_settings, + .get_drvinfo = typhoon_get_drvinfo, + .get_wol = typhoon_get_wol, + .set_wol = typhoon_set_wol, + .get_link = ethtool_op_get_link, + .get_rx_csum = typhoon_get_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_tso = ethtool_op_get_tso, + .set_tso = ethtool_op_set_tso, + .get_ringparam = typhoon_get_ringparam, +}; + static int -typhoon_wait_interrupt(unsigned long ioaddr) +typhoon_wait_interrupt(void __iomem *ioaddr) { int i, err = 0; for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) { - if(readl(ioaddr + TYPHOON_REG_INTR_STATUS) & + if(ioread32(ioaddr + TYPHOON_REG_INTR_STATUS) & TYPHOON_INTR_BOOTCMD) goto out; udelay(TYPHOON_UDELAY); @@ -1260,7 +1276,7 @@ typhoon_wait_interrupt(unsigned long ioaddr) err = -ETIMEDOUT; out: - writel(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS); + iowrite32(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS); return err; } @@ -1354,7 +1370,7 @@ typhoon_init_rings(struct typhoon *tp) static int typhoon_download_firmware(struct typhoon *tp) { - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct pci_dev *pdev = tp->pdev; struct typhoon_file_header *fHdr; struct typhoon_section_header *sHdr; @@ -1394,11 +1410,11 @@ typhoon_download_firmware(struct typhoon *tp) goto err_out; } - irqEnabled = readl(ioaddr + TYPHOON_REG_INTR_ENABLE); - writel(irqEnabled | TYPHOON_INTR_BOOTCMD, + irqEnabled = ioread32(ioaddr + TYPHOON_REG_INTR_ENABLE); + iowrite32(irqEnabled | TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_ENABLE); - irqMasked = readl(ioaddr + TYPHOON_REG_INTR_MASK); - writel(irqMasked | TYPHOON_INTR_BOOTCMD, + irqMasked = ioread32(ioaddr + TYPHOON_REG_INTR_MASK); + iowrite32(irqMasked | TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_MASK); err = -ETIMEDOUT; @@ -1410,24 +1426,24 @@ typhoon_download_firmware(struct typhoon *tp) numSections = le32_to_cpu(fHdr->numSections); load_addr = le32_to_cpu(fHdr->startAddr); - writel(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS); - writel(load_addr, ioaddr + TYPHOON_REG_DOWNLOAD_BOOT_ADDR); + iowrite32(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS); + iowrite32(load_addr, ioaddr + TYPHOON_REG_DOWNLOAD_BOOT_ADDR); hmac = le32_to_cpu(fHdr->hmacDigest[0]); - writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_0); + iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_0); hmac = le32_to_cpu(fHdr->hmacDigest[1]); - writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_1); + iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_1); hmac = le32_to_cpu(fHdr->hmacDigest[2]); - writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_2); + iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_2); hmac = le32_to_cpu(fHdr->hmacDigest[3]); - writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_3); + iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_3); hmac = le32_to_cpu(fHdr->hmacDigest[4]); - writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_4); + iowrite32(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_4); typhoon_post_pci_writes(ioaddr); - writel(TYPHOON_BOOTCMD_RUNTIME_IMAGE, ioaddr + TYPHOON_REG_COMMAND); + iowrite32(TYPHOON_BOOTCMD_RUNTIME_IMAGE, ioaddr + TYPHOON_REG_COMMAND); image_data += sizeof(struct typhoon_file_header); - /* The readl() in typhoon_wait_interrupt() will force the + /* The ioread32() in typhoon_wait_interrupt() will force the * last write to the command register to post, so * we don't need a typhoon_post_pci_writes() after it. */ @@ -1441,7 +1457,7 @@ typhoon_download_firmware(struct typhoon *tp) len = min_t(u32, section_len, PAGE_SIZE); if(typhoon_wait_interrupt(ioaddr) < 0 || - readl(ioaddr + TYPHOON_REG_STATUS) != + ioread32(ioaddr + TYPHOON_REG_STATUS) != TYPHOON_STATUS_WAITING_FOR_SEGMENT) { printk(KERN_ERR "%s: segment ready timeout\n", tp->name); @@ -1458,13 +1474,14 @@ typhoon_download_firmware(struct typhoon *tp) csum = csum_fold(csum); csum = le16_to_cpu(csum); - writel(len, ioaddr + TYPHOON_REG_BOOT_LENGTH); - writel(csum, ioaddr + TYPHOON_REG_BOOT_CHECKSUM); - writel(load_addr, ioaddr + TYPHOON_REG_BOOT_DEST_ADDR); - writel(0, ioaddr + TYPHOON_REG_BOOT_DATA_HI); - writel(dpage_dma, ioaddr + TYPHOON_REG_BOOT_DATA_LO); + iowrite32(len, ioaddr + TYPHOON_REG_BOOT_LENGTH); + iowrite32(csum, ioaddr + TYPHOON_REG_BOOT_CHECKSUM); + iowrite32(load_addr, + ioaddr + TYPHOON_REG_BOOT_DEST_ADDR); + iowrite32(0, ioaddr + TYPHOON_REG_BOOT_DATA_HI); + iowrite32(dpage_dma, ioaddr + TYPHOON_REG_BOOT_DATA_LO); typhoon_post_pci_writes(ioaddr); - writel(TYPHOON_BOOTCMD_SEG_AVAILABLE, + iowrite32(TYPHOON_BOOTCMD_SEG_AVAILABLE, ioaddr + TYPHOON_REG_COMMAND); image_data += len; @@ -1474,25 +1491,25 @@ typhoon_download_firmware(struct typhoon *tp) } if(typhoon_wait_interrupt(ioaddr) < 0 || - readl(ioaddr + TYPHOON_REG_STATUS) != + ioread32(ioaddr + TYPHOON_REG_STATUS) != TYPHOON_STATUS_WAITING_FOR_SEGMENT) { printk(KERN_ERR "%s: final segment ready timeout\n", tp->name); goto err_out_irq; } - writel(TYPHOON_BOOTCMD_DNLD_COMPLETE, ioaddr + TYPHOON_REG_COMMAND); + iowrite32(TYPHOON_BOOTCMD_DNLD_COMPLETE, ioaddr + TYPHOON_REG_COMMAND); if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_BOOT) < 0) { printk(KERN_ERR "%s: boot ready timeout, status 0x%0x\n", - tp->name, readl(ioaddr + TYPHOON_REG_STATUS)); + tp->name, ioread32(ioaddr + TYPHOON_REG_STATUS)); goto err_out_irq; } err = 0; err_out_irq: - writel(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK); - writel(irqEnabled, ioaddr + TYPHOON_REG_INTR_ENABLE); + iowrite32(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK); + iowrite32(irqEnabled, ioaddr + TYPHOON_REG_INTR_ENABLE); pci_free_consistent(pdev, PAGE_SIZE, dpage, dpage_dma); @@ -1503,31 +1520,32 @@ err_out: static int typhoon_boot_3XP(struct typhoon *tp, u32 initial_status) { - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; if(typhoon_wait_status(ioaddr, initial_status) < 0) { printk(KERN_ERR "%s: boot ready timeout\n", tp->name); goto out_timeout; } - writel(0, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_HI); - writel(tp->shared_dma, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_LO); + iowrite32(0, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_HI); + iowrite32(tp->shared_dma, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_LO); typhoon_post_pci_writes(ioaddr); - writel(TYPHOON_BOOTCMD_REG_BOOT_RECORD, ioaddr + TYPHOON_REG_COMMAND); + iowrite32(TYPHOON_BOOTCMD_REG_BOOT_RECORD, + ioaddr + TYPHOON_REG_COMMAND); if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_RUNNING) < 0) { printk(KERN_ERR "%s: boot finish timeout (status 0x%x)\n", - tp->name, readl(ioaddr + TYPHOON_REG_STATUS)); + tp->name, ioread32(ioaddr + TYPHOON_REG_STATUS)); goto out_timeout; } /* Clear the Transmit and Command ready registers */ - writel(0, ioaddr + TYPHOON_REG_TX_HI_READY); - writel(0, ioaddr + TYPHOON_REG_CMD_READY); - writel(0, ioaddr + TYPHOON_REG_TX_LO_READY); + iowrite32(0, ioaddr + TYPHOON_REG_TX_HI_READY); + iowrite32(0, ioaddr + TYPHOON_REG_CMD_READY); + iowrite32(0, ioaddr + TYPHOON_REG_TX_LO_READY); typhoon_post_pci_writes(ioaddr); - writel(TYPHOON_BOOTCMD_BOOT, ioaddr + TYPHOON_REG_COMMAND); + iowrite32(TYPHOON_BOOTCMD_BOOT, ioaddr + TYPHOON_REG_COMMAND); return 0; @@ -1687,8 +1705,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready, skb = rxb->skb; dma_addr = rxb->dma_addr; - rxaddr += sizeof(struct rx_desc); - rxaddr %= RX_ENTRIES * sizeof(struct rx_desc); + typhoon_inc_rx_index(&rxaddr, 1); if(rx->flags & TYPHOON_RX_ERROR) { typhoon_recycle_rx_skb(tp, idx); @@ -1762,7 +1779,7 @@ typhoon_fill_free_ring(struct typhoon *tp) static int typhoon_poll(struct net_device *dev, int *total_budget) { - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); struct typhoon_indexes *indexes = tp->indexes; int orig_budget = *total_budget; int budget, work_done, done; @@ -1807,7 +1824,8 @@ typhoon_poll(struct net_device *dev, int *total_budget) if(done) { netif_rx_complete(dev); - writel(TYPHOON_INTR_NONE, tp->ioaddr + TYPHOON_REG_INTR_MASK); + iowrite32(TYPHOON_INTR_NONE, + tp->ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(tp->ioaddr); } @@ -1818,17 +1836,18 @@ static irqreturn_t typhoon_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = (struct net_device *) dev_instance; - unsigned long ioaddr = dev->base_addr; + struct typhoon *tp = dev->priv; + void __iomem *ioaddr = tp->ioaddr; u32 intr_status; - intr_status = readl(ioaddr + TYPHOON_REG_INTR_STATUS); + intr_status = ioread32(ioaddr + TYPHOON_REG_INTR_STATUS); if(!(intr_status & TYPHOON_INTR_HOST_INT)) return IRQ_NONE; - writel(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS); + iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS); if(netif_rx_schedule_prep(dev)) { - writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); + iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(ioaddr); __netif_rx_schedule(dev); } else { @@ -1855,10 +1874,10 @@ typhoon_free_rx_rings(struct typhoon *tp) } static int -typhoon_sleep(struct typhoon *tp, int state, u16 events) +typhoon_sleep(struct typhoon *tp, pci_power_t state, u16 events) { struct pci_dev *pdev = tp->pdev; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct cmd_desc xp_cmd; int err; @@ -1887,25 +1906,25 @@ typhoon_sleep(struct typhoon *tp, int state, u16 events) */ netif_carrier_off(tp->dev); - pci_enable_wake(tp->pdev, state, 1); + pci_enable_wake(tp->pdev, pci_choose_state(pdev, state), 1); pci_disable_device(pdev); - return pci_set_power_state(pdev, state); + return pci_set_power_state(pdev, pci_choose_state(pdev, state)); } static int typhoon_wakeup(struct typhoon *tp, int wait_type) { struct pci_dev *pdev = tp->pdev; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; - pci_set_power_state(pdev, 0); - pci_restore_state(pdev, tp->pci_state); + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); /* Post 2.x.x versions of the Sleep Image require a reset before * we can download the Runtime Image. But let's not make users of * the old firmware pay for the reset. */ - writel(TYPHOON_BOOTCMD_WAKEUP, ioaddr + TYPHOON_REG_COMMAND); + iowrite32(TYPHOON_BOOTCMD_WAKEUP, ioaddr + TYPHOON_REG_COMMAND); if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0 || (tp->capabilities & TYPHOON_WAKEUP_NEEDS_RESET)) return typhoon_reset(ioaddr, wait_type); @@ -1917,7 +1936,7 @@ static int typhoon_start_runtime(struct typhoon *tp) { struct net_device *dev = tp->dev; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct cmd_desc xp_cmd; int err; @@ -1994,8 +2013,8 @@ typhoon_start_runtime(struct typhoon *tp) tp->card_state = Running; smp_wmb(); - writel(TYPHOON_INTR_ENABLE_ALL, ioaddr + TYPHOON_REG_INTR_ENABLE); - writel(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_MASK); + iowrite32(TYPHOON_INTR_ENABLE_ALL, ioaddr + TYPHOON_REG_INTR_ENABLE); + iowrite32(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(ioaddr); return 0; @@ -2012,7 +2031,7 @@ typhoon_stop_runtime(struct typhoon *tp, int wait_type) { struct typhoon_indexes *indexes = tp->indexes; struct transmit_ring *txLo = &tp->txLoRing; - unsigned long ioaddr = tp->ioaddr; + void __iomem *ioaddr = tp->ioaddr; struct cmd_desc xp_cmd; int i; @@ -2020,7 +2039,7 @@ typhoon_stop_runtime(struct typhoon *tp, int wait_type) * when called with !netif_running(). This will be posted * when we force the posting of the command. */ - writel(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_ENABLE); + iowrite32(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_ENABLE); INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_RX_DISABLE); typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL); @@ -2074,9 +2093,9 @@ typhoon_stop_runtime(struct typhoon *tp, int wait_type) static void typhoon_tx_timeout(struct net_device *dev) { - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); - if(typhoon_reset(dev->base_addr, WaitNoSleep) < 0) { + if(typhoon_reset(tp->ioaddr, WaitNoSleep) < 0) { printk(KERN_WARNING "%s: could not reset in tx timeout\n", dev->name); goto truely_dead; @@ -2097,14 +2116,14 @@ typhoon_tx_timeout(struct net_device *dev) truely_dead: /* Reset the hardware, and turn off carrier to avoid more timeouts */ - typhoon_reset(dev->base_addr, NoWait); + typhoon_reset(tp->ioaddr, NoWait); netif_carrier_off(dev); } static int typhoon_open(struct net_device *dev) { - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); int err; err = typhoon_wakeup(tp, WaitSleep); @@ -2132,11 +2151,11 @@ out_sleep: if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) { printk(KERN_ERR "%s: unable to reboot into sleep img\n", dev->name); - typhoon_reset(dev->base_addr, NoWait); + typhoon_reset(tp->ioaddr, NoWait); goto out; } - if(typhoon_sleep(tp, 3, 0) < 0) + if(typhoon_sleep(tp, PCI_D3hot, 0) < 0) printk(KERN_ERR "%s: unable to go back to sleep\n", dev->name); out: @@ -2146,7 +2165,7 @@ out: static int typhoon_close(struct net_device *dev) { - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); netif_stop_queue(dev); @@ -2163,7 +2182,7 @@ typhoon_close(struct net_device *dev) if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) printk(KERN_ERR "%s: unable to boot sleep image\n", dev->name); - if(typhoon_sleep(tp, 3, 0) < 0) + if(typhoon_sleep(tp, PCI_D3hot, 0) < 0) printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name); return 0; @@ -2174,7 +2193,7 @@ static int typhoon_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); /* If we're down, resume when we are upped. */ @@ -2198,15 +2217,15 @@ typhoon_resume(struct pci_dev *pdev) return 0; reset: - typhoon_reset(dev->base_addr, NoWait); + typhoon_reset(tp->ioaddr, NoWait); return -EBUSY; } static int -typhoon_suspend(struct pci_dev *pdev, u32 state) +typhoon_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); - struct typhoon *tp = (struct typhoon *) dev->priv; + struct typhoon *tp = netdev_priv(dev); struct cmd_desc xp_cmd; /* If we're down, we're already suspended. @@ -2268,12 +2287,58 @@ need_resume: } static int -typhoon_enable_wake(struct pci_dev *pdev, u32 state, int enable) +typhoon_enable_wake(struct pci_dev *pdev, pci_power_t state, int enable) { return pci_enable_wake(pdev, state, enable); } #endif +static int __devinit +typhoon_test_mmio(struct pci_dev *pdev) +{ + void __iomem *ioaddr = pci_iomap(pdev, 1, 128); + int mode = 0; + u32 val; + + if(!ioaddr) + goto out; + + if(ioread32(ioaddr + TYPHOON_REG_STATUS) != + TYPHOON_STATUS_WAITING_FOR_HOST) + goto out_unmap; + + iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); + iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); + iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_ENABLE); + + /* Ok, see if we can change our interrupt status register by + * sending ourselves an interrupt. If so, then MMIO works. + * The 50usec delay is arbitrary -- it could probably be smaller. + */ + val = ioread32(ioaddr + TYPHOON_REG_INTR_STATUS); + if((val & TYPHOON_INTR_SELF) == 0) { + iowrite32(1, ioaddr + TYPHOON_REG_SELF_INTERRUPT); + ioread32(ioaddr + TYPHOON_REG_INTR_STATUS); + udelay(50); + val = ioread32(ioaddr + TYPHOON_REG_INTR_STATUS); + if(val & TYPHOON_INTR_SELF) + mode = 1; + } + + iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); + iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); + iowrite32(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_ENABLE); + ioread32(ioaddr + TYPHOON_REG_INTR_STATUS); + +out_unmap: + pci_iounmap(pdev, ioaddr); + +out: + if(!mode) + printk(KERN_INFO PFX "falling back to port IO\n"); + return mode; +} + static int __devinit typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -2281,7 +2346,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct net_device *dev; struct typhoon *tp; int card_id = (int) ent->driver_data; - unsigned long ioaddr; + void __iomem *ioaddr; void *shared; dma_addr_t shared_dma; struct cmd_desc xp_cmd; @@ -2309,56 +2374,67 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto error_out_dev; } - /* If we transitioned from D3->D0 in pci_enable_device(), - * we lost our configuration and need to restore it to the - * conditions at boot. - */ - pci_restore_state(pdev, NULL); + err = pci_set_mwi(pdev); + if(err < 0) { + printk(ERR_PFX "%s: unable to set MWI\n", pci_name(pdev)); + goto error_out_disable; + } - err = pci_set_dma_mask(pdev, 0xffffffffULL); + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if(err < 0) { printk(ERR_PFX "%s: No usable DMA configuration\n", pci_name(pdev)); - goto error_out_dev; + goto error_out_mwi; } - /* sanity checks, resource #1 is our mmio area + /* sanity checks on IO and MMIO BARs */ + if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) { + printk(ERR_PFX + "%s: region #1 not a PCI IO resource, aborting\n", + pci_name(pdev)); + err = -ENODEV; + goto error_out_mwi; + } + if(pci_resource_len(pdev, 0) < 128) { + printk(ERR_PFX "%s: Invalid PCI IO region size, aborting\n", + pci_name(pdev)); + err = -ENODEV; + goto error_out_mwi; + } if(!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { printk(ERR_PFX "%s: region #1 not a PCI MMIO resource, aborting\n", pci_name(pdev)); err = -ENODEV; - goto error_out_dev; + goto error_out_mwi; } if(pci_resource_len(pdev, 1) < 128) { printk(ERR_PFX "%s: Invalid PCI MMIO region size, aborting\n", pci_name(pdev)); err = -ENODEV; - goto error_out_dev; + goto error_out_mwi; } err = pci_request_regions(pdev, "typhoon"); if(err < 0) { printk(ERR_PFX "%s: could not request regions\n", pci_name(pdev)); - goto error_out_dev; + goto error_out_mwi; } - pci_set_master(pdev); - pci_set_mwi(pdev); - - /* map our MMIO region + /* map our registers */ - ioaddr = pci_resource_start(pdev, 1); - ioaddr = (unsigned long) ioremap(ioaddr, 128); - if(!ioaddr) { - printk(ERR_PFX "%s: cannot remap MMIO, aborting\n", + if(use_mmio != 0 && use_mmio != 1) + use_mmio = typhoon_test_mmio(pdev); + + ioaddr = pci_iomap(pdev, use_mmio, 128); + if (!ioaddr) { + printk(ERR_PFX "%s: cannot remap registers, aborting\n", pci_name(pdev)); err = -EIO; goto error_out_regions; } - dev->base_addr = ioaddr; /* allocate pci dma space for rx and tx descriptor rings */ @@ -2372,18 +2448,15 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } dev->irq = pdev->irq; - tp = dev->priv; + tp = netdev_priv(dev); tp->shared = (struct typhoon_shared *) shared; tp->shared_dma = shared_dma; tp->pdev = pdev; tp->tx_pdev = pdev; - tp->ioaddr = dev->base_addr; - tp->tx_ioaddr = dev->base_addr; + tp->ioaddr = ioaddr; + tp->tx_ioaddr = ioaddr; tp->dev = dev; - /* need to be able to restore PCI state after a suspend */ - pci_save_state(pdev, tp->pci_state); - /* Init sequence: * 1) Reset the adapter to clear any bad juju * 2) Reload the sleep image @@ -2391,12 +2464,19 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) * 4) Get the hardware address. * 5) Put the card to sleep. */ - if(typhoon_reset(ioaddr, WaitSleep) < 0) { + if (typhoon_reset(ioaddr, WaitSleep) < 0) { printk(ERR_PFX "%s: could not reset 3XP\n", pci_name(pdev)); err = -EIO; goto error_out_dma; } + /* Now that we've reset the 3XP and are sure it's not going to + * write all over memory, enable bus mastering, and save our + * state for resuming after a suspend. + */ + pci_set_master(pdev); + pci_save_state(pdev); + /* dev->name is not valid until we register, but we need to * use some common routines to initialize the card. So that those * routines print the right name, we keep our oun pointer to the name @@ -2436,7 +2516,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS); if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) { printk(ERR_PFX "%s: Could not get Sleep Image version\n", - pdev->slot_name); + pci_name(pdev)); goto error_out_reset; } @@ -2452,7 +2532,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if(xp_resp[0].numDesc != 0) tp->capabilities |= TYPHOON_WAKEUP_NEEDS_RESET; - if(typhoon_sleep(tp, 3, 0) < 0) { + if(typhoon_sleep(tp, PCI_D3hot, 0) < 0) { printk(ERR_PFX "%s: cannot put adapter to sleep\n", pci_name(pdev)); err = -EIO; @@ -2470,9 +2550,9 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->watchdog_timeo = TX_TIMEOUT; dev->get_stats = typhoon_get_stats; dev->set_mac_address = typhoon_set_mac_address; - dev->do_ioctl = typhoon_ioctl; dev->vlan_rx_register = typhoon_vlan_rx_register; dev->vlan_rx_kill_vid = typhoon_vlan_rx_kill_vid; + SET_ETHTOOL_OPS(dev, &typhoon_ethtool_ops); /* We can handle scatter gather, up to 16 entries, and * we can do IP checksumming (only version 4, doh...) @@ -2489,8 +2569,9 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, typhoon_card_info[card_id].name, ioaddr); + printk(KERN_INFO "%s: %s at %s 0x%lx, ", + dev->name, typhoon_card_info[card_id].name, + use_mmio ? "MMIO" : "IO", pci_resource_start(pdev, use_mmio)); for(i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x\n", dev->dev_addr[i]); @@ -2513,7 +2594,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) u8 *ver_string = (u8 *) &xp_resp[1]; ver_string[25] = 0; printk(KERN_INFO "%s: Typhoon 1.1+ Sleep Image version " - "%u.%u.%u.%u %s\n", dev->name, HIPQUAD(sleep_ver), + "%02x.%03x.%03x %s\n", dev->name, sleep_ver >> 24, + (sleep_ver >> 12) & 0xfff, sleep_ver & 0xfff, ver_string); } else { printk(KERN_WARNING "%s: Unknown Sleep Image version " @@ -2530,9 +2612,13 @@ error_out_dma: pci_free_consistent(pdev, sizeof(struct typhoon_shared), shared, shared_dma); error_out_remap: - iounmap((void *) ioaddr); + pci_iounmap(pdev, ioaddr); error_out_regions: pci_release_regions(pdev); +error_out_mwi: + pci_clear_mwi(pdev); +error_out_disable: + pci_disable_device(pdev); error_out_dev: free_netdev(dev); error_out: @@ -2543,16 +2629,17 @@ static void __devexit typhoon_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct typhoon *tp = (struct typhoon *) (dev->priv); + struct typhoon *tp = netdev_priv(dev); unregister_netdev(dev); - pci_set_power_state(pdev, 0); - pci_restore_state(pdev, tp->pci_state); - typhoon_reset(dev->base_addr, NoWait); - iounmap((char *) (dev->base_addr)); + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + typhoon_reset(tp->ioaddr, NoWait); + pci_iounmap(pdev, tp->ioaddr); pci_free_consistent(pdev, sizeof(struct typhoon_shared), tp->shared, tp->shared_dma); pci_release_regions(pdev); + pci_clear_mwi(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_netdev(dev);