X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Ftyphoon.c;h=8f3392989a06e83188a1323341d04ff3f4176bca;hb=f7f1b0f1e2fbadeab12d24236000e778aa9b1ead;hp=5712cac903d41a7d0ddd1c45f641eaf03f55b2d9;hpb=e3f6fb6212a7102bdb56ba38fa1e98fe72950475;p=linux-2.6.git diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 5712cac90..8f3392989 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -50,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). @@ -93,8 +100,8 @@ static const int multicast_filter_limit = 32; #define PKT_BUF_SZ 1536 #define DRV_MODULE_NAME "typhoon" -#define DRV_MODULE_VERSION "1.5.4" -#define DRV_MODULE_RELDATE "04/09/09" +#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 @@ -131,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 @@ -310,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. */ @@ -391,17 +405,17 @@ typhoon_reset(void __iomem *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; @@ -416,8 +430,8 @@ typhoon_reset(void __iomem *ioaddr, int wait_type) } out: - 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); /* 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 @@ -442,7 +456,7 @@ 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); } @@ -478,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); } } @@ -633,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) @@ -687,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); @@ -889,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; @@ -1058,8 +1072,10 @@ typhoon_get_drvinfo(struct net_device *dev, 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); } } @@ -1251,7 +1267,7 @@ 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(void __iomem *ioaddr) err = -ETIMEDOUT; out: - writel(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS); + iowrite32(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS); return err; } @@ -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); @@ -1510,24 +1527,25 @@ typhoon_boot_3XP(struct typhoon *tp, u32 initial_status) 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; @@ -1806,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); } @@ -1821,14 +1840,14 @@ typhoon_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) 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,7 +1874,7 @@ 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; void __iomem *ioaddr = tp->ioaddr; @@ -1887,7 +1906,7 @@ 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, pci_choose_state(pdev, state)); } @@ -1905,7 +1924,7 @@ typhoon_wakeup(struct typhoon *tp, int wait_type) * 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); @@ -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; @@ -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); @@ -2136,7 +2155,7 @@ out_sleep: 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: @@ -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; @@ -2203,7 +2222,7 @@ reset: } 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 = netdev_priv(dev); @@ -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,8 +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_mapped; + void __iomem *ioaddr; void *shared; dma_addr_t shared_dma; struct cmd_desc xp_cmd; @@ -2323,8 +2387,21 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 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", @@ -2346,12 +2423,14 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto error_out_mwi; } - /* map our MMIO region + /* map our registers */ - ioaddr = pci_resource_start(pdev, 1); - ioaddr_mapped = ioremap(ioaddr, 128); - if (!ioaddr_mapped) { - 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; @@ -2374,13 +2453,10 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->shared_dma = shared_dma; tp->pdev = pdev; tp->tx_pdev = pdev; - tp->ioaddr = ioaddr_mapped; - tp->tx_ioaddr = ioaddr_mapped; + 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); - /* Init sequence: * 1) Reset the adapter to clear any bad juju * 2) Reload the sleep image @@ -2388,16 +2464,18 @@ 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_mapped, 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. + * 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 @@ -2438,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; } @@ -2454,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; @@ -2491,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]); @@ -2515,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 " @@ -2526,13 +2606,13 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; error_out_reset: - typhoon_reset(ioaddr_mapped, NoWait); + typhoon_reset(ioaddr, NoWait); error_out_dma: pci_free_consistent(pdev, sizeof(struct typhoon_shared), shared, shared_dma); error_out_remap: - iounmap(ioaddr_mapped); + pci_iounmap(pdev, ioaddr); error_out_regions: pci_release_regions(pdev); error_out_mwi: @@ -2555,7 +2635,7 @@ typhoon_remove_one(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); typhoon_reset(tp->ioaddr, NoWait); - iounmap(tp->ioaddr); + pci_iounmap(pdev, tp->ioaddr); pci_free_consistent(pdev, sizeof(struct typhoon_shared), tp->shared, tp->shared_dma); pci_release_regions(pdev);