Commit 9b37fb9b authored by David Dillow's avatar David Dillow

Bug fixes:

* Avoid short timeouts when waiting for a reset
* Fix issue with loading runtime image on newer versions of the sleep image
* Fix link status reporting
parent 84e35d55
...@@ -85,8 +85,8 @@ static const int multicast_filter_limit = 32; ...@@ -85,8 +85,8 @@ static const int multicast_filter_limit = 32;
#define PKT_BUF_SZ 1536 #define PKT_BUF_SZ 1536
#define DRV_MODULE_NAME "typhoon" #define DRV_MODULE_NAME "typhoon"
#define DRV_MODULE_VERSION "1.5.1" #define DRV_MODULE_VERSION "1.5.2"
#define DRV_MODULE_RELDATE "03/06/26" #define DRV_MODULE_RELDATE "03/11/25"
#define PFX DRV_MODULE_NAME ": " #define PFX DRV_MODULE_NAME ": "
#define ERR_PFX KERN_ERR PFX #define ERR_PFX KERN_ERR PFX
...@@ -127,7 +127,7 @@ static const int multicast_filter_limit = 32; ...@@ -127,7 +127,7 @@ static const int multicast_filter_limit = 32;
static char version[] __devinitdata = static char version[] __devinitdata =
"typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("David Dillow <dillowd@y12.doe.gov>"); MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)"); MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(rx_copybreak, "i");
...@@ -146,11 +146,12 @@ struct typhoon_card_info { ...@@ -146,11 +146,12 @@ struct typhoon_card_info {
int capabilities; int capabilities;
}; };
#define TYPHOON_CRYPTO_NONE 0 #define TYPHOON_CRYPTO_NONE 0x00
#define TYPHOON_CRYPTO_DES 1 #define TYPHOON_CRYPTO_DES 0x01
#define TYPHOON_CRYPTO_3DES 2 #define TYPHOON_CRYPTO_3DES 0x02
#define TYPHOON_CRYPTO_VARIABLE 4 #define TYPHOON_CRYPTO_VARIABLE 0x04
#define TYPHOON_FIBER 8 #define TYPHOON_FIBER 0x08
#define TYPHOON_WAKEUP_NEEDS_RESET 0x10
enum typhoon_cards { enum typhoon_cards {
TYPHOON_TX = 0, TYPHOON_TX95, TYPHOON_TX97, TYPHOON_SVR, TYPHOON_TX = 0, TYPHOON_TX95, TYPHOON_TX97, TYPHOON_SVR,
...@@ -307,7 +308,8 @@ enum state_values { ...@@ -307,7 +308,8 @@ enum state_values {
/* We'll wait up to six seconds for a reset, and half a second normally. /* We'll wait up to six seconds for a reset, and half a second normally.
*/ */
#define TYPHOON_UDELAY 50 #define TYPHOON_UDELAY 50
#define TYPHOON_RESET_TIMEOUT (6 * HZ) #define TYPHOON_RESET_TIMEOUT_SLEEP (6 * HZ)
#define TYPHOON_RESET_TIMEOUT_NOSLEEP ((6 * 1000000) / TYPHOON_UDELAY)
#define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY) #define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28)
...@@ -375,10 +377,12 @@ static int ...@@ -375,10 +377,12 @@ static int
typhoon_reset(unsigned long ioaddr, int wait_type) typhoon_reset(unsigned long ioaddr, int wait_type)
{ {
int i, err = 0; int i, err = 0;
int timeout = TYPHOON_RESET_TIMEOUT; int timeout;
if(wait_type == WaitNoSleep) if(wait_type == WaitNoSleep)
timeout = (timeout * 1000000) / (HZ * TYPHOON_UDELAY); timeout = TYPHOON_RESET_TIMEOUT_NOSLEEP;
else
timeout = TYPHOON_RESET_TIMEOUT_SLEEP;
writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
...@@ -1858,6 +1862,11 @@ typhoon_sleep(struct typhoon *tp, int state, u16 events) ...@@ -1858,6 +1862,11 @@ typhoon_sleep(struct typhoon *tp, int state, u16 events)
if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_SLEEPING) < 0) if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_SLEEPING) < 0)
return -ETIMEDOUT; return -ETIMEDOUT;
/* Since we cannot monitor the status of the link while sleeping,
* tell the world it went away.
*/
netif_carrier_off(tp->dev);
pci_enable_wake(tp->pdev, state, 1); pci_enable_wake(tp->pdev, state, 1);
pci_disable_device(pdev); pci_disable_device(pdev);
return pci_set_power_state(pdev, state); return pci_set_power_state(pdev, state);
...@@ -1872,8 +1881,13 @@ typhoon_wakeup(struct typhoon *tp, int wait_type) ...@@ -1872,8 +1881,13 @@ typhoon_wakeup(struct typhoon *tp, int wait_type)
pci_set_power_state(pdev, 0); pci_set_power_state(pdev, 0);
pci_restore_state(pdev, tp->pci_state); pci_restore_state(pdev, tp->pci_state);
/* 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); writel(TYPHOON_BOOTCMD_WAKEUP, ioaddr + TYPHOON_REG_COMMAND);
if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0 ||
(tp->capabilities & TYPHOON_WAKEUP_NEEDS_RESET))
return typhoon_reset(ioaddr, wait_type); return typhoon_reset(ioaddr, wait_type);
return 0; return 0;
...@@ -2251,7 +2265,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2251,7 +2265,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
void *shared; void *shared;
dma_addr_t shared_dma; dma_addr_t shared_dma;
struct cmd_desc xp_cmd; struct cmd_desc xp_cmd;
struct resp_desc xp_resp; struct resp_desc xp_resp[3];
int i; int i;
int err = 0; int err = 0;
...@@ -2380,15 +2394,15 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2380,15 +2394,15 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
} }
INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_MAC_ADDRESS); INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_MAC_ADDRESS);
if(typhoon_issue_command(tp, 1, &xp_cmd, 1, &xp_resp) < 0) { if(typhoon_issue_command(tp, 1, &xp_cmd, 1, xp_resp) < 0) {
printk(ERR_PFX "%s: cannot read MAC address\n", printk(ERR_PFX "%s: cannot read MAC address\n",
pci_name(pdev)); pci_name(pdev));
err = -EIO; err = -EIO;
goto error_out_reset; goto error_out_reset;
} }
*(u16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp.parm1)); *(u16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
*(u32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp.parm2)); *(u32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
if(!is_valid_ether_addr(dev->dev_addr)) { if(!is_valid_ether_addr(dev->dev_addr)) {
printk(ERR_PFX "%s: Could not obtain valid ethernet address, " printk(ERR_PFX "%s: Could not obtain valid ethernet address, "
...@@ -2396,6 +2410,28 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2396,6 +2410,28 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto error_out_reset; goto error_out_reset;
} }
/* Read the Sleep Image version last, so the response is valid
* later when we print out the version reported.
*/
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);
goto error_out_reset;
}
tp->capabilities = typhoon_card_info[card_id].capabilities;
tp->xcvr_select = TYPHOON_XCVR_AUTONEG;
/* Typhoon 1.0 Sleep Images return one response descriptor to the
* READ_VERSIONS command. Those versions are OK after waking up
* from sleep without needing a reset. Typhoon 1.1+ Sleep Images
* seem to need a little extra help to get started. Since we don't
* know how to nudge it along, just kick it.
*/
if(xp_resp[0].numDesc != 0)
tp->capabilities |= TYPHOON_WAKEUP_NEEDS_RESET;
if(typhoon_sleep(tp, 3, 0) < 0) { if(typhoon_sleep(tp, 3, 0) < 0) {
printk(ERR_PFX "%s: cannot put adapter to sleep\n", printk(ERR_PFX "%s: cannot put adapter to sleep\n",
pci_name(pdev)); pci_name(pdev));
...@@ -2403,9 +2439,6 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2403,9 +2439,6 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto error_out_reset; goto error_out_reset;
} }
tp->capabilities = typhoon_card_info[card_id].capabilities;
tp->xcvr_select = TYPHOON_XCVR_AUTONEG;
/* The chip-specific entries in the device structure. */ /* The chip-specific entries in the device structure. */
dev->open = typhoon_open; dev->open = typhoon_open;
dev->hard_start_xmit = typhoon_start_tx; dev->hard_start_xmit = typhoon_start_tx;
...@@ -2442,6 +2475,32 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2442,6 +2475,32 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x\n", dev->dev_addr[i]); printk("%2.2x\n", dev->dev_addr[i]);
/* xp_resp still contains the response to the READ_VERSIONS command.
* For debugging, let the user know what version he has.
*/
if(xp_resp[0].numDesc == 0) {
/* This is the Typhoon 1.0 type Sleep Image, last 16 bits
* of version is Month/Day of build.
*/
u16 monthday = le32_to_cpu(xp_resp[0].parm2) & 0xffff;
printk(KERN_INFO "%s: Typhoon 1.0 Sleep Image built "
"%02u/%02u/2000\n", dev->name, monthday >> 8,
monthday & 0xff);
} else if(xp_resp[0].numDesc == 2) {
/* This is the Typhoon 1.1+ type Sleep Image
*/
u32 sleep_ver = le32_to_cpu(xp_resp[0].parm2);
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),
ver_string);
} else {
printk(KERN_WARNING "%s: Unknown Sleep Image version "
"(%u:%04x)\n", dev->name, xp_resp[0].numDesc,
le32_to_cpu(xp_resp[0].parm2));
}
return 0; return 0;
error_out_reset: error_out_reset:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment