Commit 819b3114 authored by Jeff Garzik's avatar Jeff Garzik

[netdrvr e100] better debugging for command failures/timeouts

Contributed by Scott Feldman @ Intel
parent 9e9c6725
...@@ -268,6 +268,7 @@ struct driver_stats { ...@@ -268,6 +268,7 @@ struct driver_stats {
#define SCB_CUC_NOOP 0 #define SCB_CUC_NOOP 0
#define SCB_CUC_START BIT_4 /* CU Start */ #define SCB_CUC_START BIT_4 /* CU Start */
#define SCB_CUC_RESUME BIT_5 /* CU Resume */ #define SCB_CUC_RESUME BIT_5 /* CU Resume */
#define SCB_CUC_UNKNOWN BIT_7 /* CU unknown command */
/* Changed for 82558 enhancements */ /* Changed for 82558 enhancements */
#define SCB_CUC_STATIC_RESUME (BIT_5 | BIT_7) /* 82558/9 Static Resume */ #define SCB_CUC_STATIC_RESUME (BIT_5 | BIT_7) /* 82558/9 Static Resume */
#define SCB_CUC_DUMP_ADDR BIT_6 /* CU Dump Counters Address */ #define SCB_CUC_DUMP_ADDR BIT_6 /* CU Dump Counters Address */
...@@ -953,6 +954,10 @@ struct e100_private { ...@@ -953,6 +954,10 @@ struct e100_private {
u32 pci_state[16]; u32 pci_state[16];
#endif #endif
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
#ifdef E100_CU_DEBUG
u8 last_cmd;
u8 last_sub_cmd;
#endif
}; };
#define E100_AUTONEG 0 #define E100_AUTONEG 0
...@@ -964,7 +969,7 @@ struct e100_private { ...@@ -964,7 +969,7 @@ struct e100_private {
/********* function prototypes *************/ /********* function prototypes *************/
extern void e100_isolate_driver(struct e100_private *bdp); extern void e100_isolate_driver(struct e100_private *bdp);
extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd); extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd);
extern void e100_start_cu(struct e100_private *bdp, tcb_t *tcb); extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb);
extern void e100_free_non_tx_cmd(struct e100_private *bdp, extern void e100_free_non_tx_cmd(struct e100_private *bdp,
nxmit_cb_entry_t *non_tx_cmd); nxmit_cb_entry_t *non_tx_cmd);
extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp); extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp);
...@@ -976,8 +981,10 @@ extern unsigned char e100_get_link_state(struct e100_private *bdp); ...@@ -976,8 +981,10 @@ extern unsigned char e100_get_link_state(struct e100_private *bdp);
extern unsigned char e100_wait_scb(struct e100_private *bdp); extern unsigned char e100_wait_scb(struct e100_private *bdp);
extern void e100_deisolate_driver(struct e100_private *bdp, u8 full_reset); extern void e100_deisolate_driver(struct e100_private *bdp, u8 full_reset);
extern unsigned char e100_hw_reset_recover(struct e100_private *bdp, extern unsigned char e100_configure_device(struct e100_private *bdp);
u32 reset_cmd); #ifdef E100_CU_DEBUG
extern unsigned char e100_cu_unknown_state(struct e100_private *bdp);
#endif
#define ROM_TEST_FAIL 0x01 #define ROM_TEST_FAIL 0x01
#define REGISTER_TEST_FAIL 0x02 #define REGISTER_TEST_FAIL 0x02
......
...@@ -224,7 +224,7 @@ static void e100_check_options(int board, struct e100_private *bdp); ...@@ -224,7 +224,7 @@ static void e100_check_options(int board, struct e100_private *bdp);
static void e100_set_int_option(int *, int, int, int, int, char *); static void e100_set_int_option(int *, int, int, int, int, char *);
static void e100_set_bool_option(struct e100_private *bdp, int, u32, int, static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
char *); char *);
unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8); unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8);
void e100_exec_cmplx(struct e100_private *, u32, u8); void e100_exec_cmplx(struct e100_private *, u32, u8);
/** /**
...@@ -443,9 +443,21 @@ e100_wait_exec_simple(struct e100_private *bdp, u8 scb_cmd_low) ...@@ -443,9 +443,21 @@ e100_wait_exec_simple(struct e100_private *bdp, u8 scb_cmd_low)
if (!e100_wait_scb(bdp)) { if (!e100_wait_scb(bdp)) {
printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n", printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n",
bdp->device->name); bdp->device->name);
#ifdef E100_CU_DEBUG
printk(KERN_ERR "e100: %s: Last command (%x/%x) "
"timeout\n", bdp->device->name,
bdp->last_cmd, bdp->last_sub_cmd);
printk(KERN_ERR "e100: %s: Current simple command (%x) "
"can't be executed\n",
bdp->device->name, scb_cmd_low);
#endif
return false; return false;
} }
e100_exec_cmd(bdp, scb_cmd_low); e100_exec_cmd(bdp, scb_cmd_low);
#ifdef E100_CU_DEBUG
bdp->last_cmd = scb_cmd_low;
bdp->last_sub_cmd = 0;
#endif
return true; return true;
} }
...@@ -458,12 +470,24 @@ e100_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd) ...@@ -458,12 +470,24 @@ e100_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
} }
unsigned char unsigned char
e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd) e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd, u8 sub_cmd)
{ {
if (!e100_wait_scb(bdp)) { if (!e100_wait_scb(bdp)) {
#ifdef E100_CU_DEBUG
printk(KERN_ERR "e100: %s: Last command (%x/%x) "
"timeout\n", bdp->device->name,
bdp->last_cmd, bdp->last_sub_cmd);
printk(KERN_ERR "e100: %s: Current complex command "
"(%x/%x) can't be executed\n",
bdp->device->name, cmd, sub_cmd);
#endif
return false; return false;
} }
e100_exec_cmplx(bdp, phys_addr, cmd); e100_exec_cmplx(bdp, phys_addr, cmd);
#ifdef E100_CU_DEBUG
bdp->last_cmd = cmd;
bdp->last_sub_cmd = sub_cmd;
#endif
return true; return true;
} }
...@@ -494,18 +518,23 @@ e100_wait_cus_idle(struct e100_private *bdp) ...@@ -494,18 +518,23 @@ e100_wait_cus_idle(struct e100_private *bdp)
} }
/** /**
* e100_dis_intr - disable interrupts * e100_disable_clear_intr - disable and clear/ack interrupts
* @bdp: atapter's private data struct * @bdp: atapter's private data struct
* *
* This routine disables interrupts at the hardware, by setting * This routine disables interrupts at the hardware, by setting
* the M (mask) bit in the adapter's CSR SCB command word. * the M (mask) bit in the adapter's CSR SCB command word.
* It also clear/ack interrupts.
*/ */
static inline void static inline void
e100_dis_intr(struct e100_private *bdp) e100_disable_clear_intr(struct e100_private *bdp)
{ {
u16 intr_status;
/* Disable interrupts on our PCI board by setting the mask bit */ /* Disable interrupts on our PCI board by setting the mask bit */
writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi); writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi);
readw(&(bdp->scb->scb_status)); /* flushes last write, read-safe */ intr_status = readw(&bdp->scb->scb_status);
/* ack and clear intrs */
writew(intr_status, &bdp->scb->scb_status);
readw(&bdp->scb->scb_status);
} }
/** /**
...@@ -958,12 +987,12 @@ e100_open(struct net_device *dev) ...@@ -958,12 +987,12 @@ e100_open(struct net_device *dev)
goto err_exit; goto err_exit;
} }
if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) { if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) {
rc = -EAGAIN; rc = -EAGAIN;
goto err_exit; goto err_exit;
} }
if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) { if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) {
rc = -EAGAIN; rc = -EAGAIN;
goto err_exit; goto err_exit;
} }
...@@ -1240,7 +1269,8 @@ e100_init(struct e100_private *bdp) ...@@ -1240,7 +1269,8 @@ e100_init(struct e100_private *bdp)
printk(KERN_ERR "e100: hw init failed\n"); printk(KERN_ERR "e100: hw init failed\n");
return false; return false;
} }
e100_dis_intr(bdp); /* Interrupts are enabled after device reset */
e100_disable_clear_intr(bdp);
return true; return true;
} }
...@@ -1308,10 +1338,10 @@ e100_hw_init(struct e100_private *bdp, u32 reset_cmd) ...@@ -1308,10 +1338,10 @@ e100_hw_init(struct e100_private *bdp, u32 reset_cmd)
e100_sw_reset(bdp, reset_cmd); e100_sw_reset(bdp, reset_cmd);
/* Load the CU BASE (set to 0, because we use linear mode) */ /* Load the CU BASE (set to 0, because we use linear mode) */
if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
return false; return false;
if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
return false; return false;
/* Load interrupt microcode */ /* Load interrupt microcode */
...@@ -1595,6 +1625,12 @@ e100_watchdog(struct net_device *dev) ...@@ -1595,6 +1625,12 @@ e100_watchdog(struct net_device *dev)
{ {
struct e100_private *bdp = dev->priv; struct e100_private *bdp = dev->priv;
#ifdef E100_CU_DEBUG
if (e100_cu_unknown_state(bdp)) {
printk(KERN_ERR "e100: %s: CU unknown state in e100_watchdog\n",
dev->name);
}
#endif
if (!netif_running(dev)) { if (!netif_running(dev)) {
return; return;
} }
...@@ -1651,7 +1687,8 @@ e100_watchdog(struct net_device *dev) ...@@ -1651,7 +1687,8 @@ e100_watchdog(struct net_device *dev)
if (netif_running(dev)) if (netif_running(dev))
netif_wake_queue(dev); netif_wake_queue(dev);
} else { } else {
netif_stop_queue(dev); if (netif_running(dev))
netif_stop_queue(dev);
} }
rmb(); rmb();
...@@ -1779,11 +1816,8 @@ e100intr(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -1779,11 +1816,8 @@ e100intr(int irq, void *dev_inst, struct pt_regs *regs)
return; return;
} }
/* disable intr before we ack & after identifying the intr as ours */ /* disable and ack intr */
e100_dis_intr(bdp); e100_disable_clear_intr(bdp);
writew(intr_status, &bdp->scb->scb_status); /* ack intrs */
readw(&bdp->scb->scb_status);
/* the device is closed, don't continue or else bad things may happen. */ /* the device is closed, don't continue or else bad things may happen. */
if (!netif_running(dev)) { if (!netif_running(dev)) {
...@@ -2213,10 +2247,11 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb) ...@@ -2213,10 +2247,11 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
* *
* e100_start_cu must be called while holding the tx_lock ! * e100_start_cu must be called while holding the tx_lock !
*/ */
void u8
e100_start_cu(struct e100_private *bdp, tcb_t *tcb) e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
{ {
unsigned long lock_flag; unsigned long lock_flag;
u8 ret = true;
spin_lock_irqsave(&(bdp->bd_lock), lock_flag); spin_lock_irqsave(&(bdp->bd_lock), lock_flag);
switch (bdp->next_cu_cmd) { switch (bdp->next_cu_cmd) {
...@@ -2247,12 +2282,13 @@ e100_start_cu(struct e100_private *bdp, tcb_t *tcb) ...@@ -2247,12 +2282,13 @@ e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
"e100: %s: cu_start: timeout waiting for cu\n", "e100: %s: cu_start: timeout waiting for cu\n",
bdp->device->name); bdp->device->name);
if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys), if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
SCB_CUC_START)) { SCB_CUC_START, CB_TRANSMIT)) {
printk(KERN_DEBUG printk(KERN_DEBUG
"e100: %s: cu_start: timeout waiting for scb\n", "e100: %s: cu_start: timeout waiting for scb\n",
bdp->device->name); bdp->device->name);
e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys), e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
SCB_CUC_START); SCB_CUC_START);
ret = false;
} }
bdp->next_cu_cmd = RESUME_WAIT; bdp->next_cu_cmd = RESUME_WAIT;
...@@ -2264,6 +2300,7 @@ e100_start_cu(struct e100_private *bdp, tcb_t *tcb) ...@@ -2264,6 +2300,7 @@ e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
bdp->last_tcb = tcb; bdp->last_tcb = tcb;
spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
return ret;
} }
/* ====================================================================== */ /* ====================================================================== */
...@@ -2311,8 +2348,9 @@ e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result) ...@@ -2311,8 +2348,9 @@ e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result)
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ / 100 + 1); schedule_timeout(HZ / 100 + 1);
/* disable interrupts since the're now enabled */ /* disable interrupts since they are enabled */
e100_dis_intr(bdp); /* after device reset during selftest */
e100_disable_clear_intr(bdp);
/* if The First Self Test DWORD Still Zero, We've timed out. If the /* if The First Self Test DWORD Still Zero, We've timed out. If the
* second DWORD is not zero then we have an error. */ * second DWORD is not zero then we have an error. */
...@@ -2410,7 +2448,7 @@ e100_start_ru(struct e100_private *bdp) ...@@ -2410,7 +2448,7 @@ e100_start_ru(struct e100_private *bdp)
spin_lock(&bdp->bd_lock); spin_lock(&bdp->bd_lock);
if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START)) { if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START, 0)) {
printk(KERN_DEBUG printk(KERN_DEBUG
"e100: %s: start_ru: wait_scb failed\n", "e100: %s: start_ru: wait_scb failed\n",
bdp->device->name); bdp->device->name);
...@@ -2478,7 +2516,7 @@ e100_clr_cntrs(struct e100_private *bdp) ...@@ -2478,7 +2516,7 @@ e100_clr_cntrs(struct e100_private *bdp)
*pcmd_complete = 0; *pcmd_complete = 0;
wmb(); wmb();
if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR)) if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0))
return false; return false;
/* wait 10 microseconds for the command to complete */ /* wait 10 microseconds for the command to complete */
...@@ -2600,8 +2638,10 @@ e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command) ...@@ -2600,8 +2638,10 @@ e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
unsigned long lock_flag; unsigned long lock_flag;
unsigned long expiration_time; unsigned long expiration_time;
unsigned char rc = true; unsigned char rc = true;
u8 sub_cmd;
ntcb_hdr = (cb_header_t *) command->non_tx_cmd; /* get hdr of non tcb cmd */ ntcb_hdr = (cb_header_t *) command->non_tx_cmd; /* get hdr of non tcb cmd */
sub_cmd = cpu_to_le16(ntcb_hdr->cb_cmd);
/* Set the Command Block to be the last command block */ /* Set the Command Block to be the last command block */
ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT); ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT);
...@@ -2634,7 +2674,7 @@ e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command) ...@@ -2634,7 +2674,7 @@ e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
spin_lock_irqsave(&bdp->bd_lock, lock_flag); spin_lock_irqsave(&bdp->bd_lock, lock_flag);
if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START)) { if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START, sub_cmd)) {
spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag); spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
rc = false; rc = false;
goto exit; goto exit;
...@@ -2654,6 +2694,10 @@ e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command) ...@@ -2654,6 +2694,10 @@ e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
yield(); yield();
spin_lock_bh(&(bdp->bd_non_tx_lock)); spin_lock_bh(&(bdp->bd_non_tx_lock));
} else { } else {
#ifdef E100_CU_DEBUG
printk(KERN_ERR "e100: %s: non-TX command (%x) "
"timeout\n", bdp->device->name, sub_cmd);
#endif
rc = false; rc = false;
goto exit; goto exit;
} }
...@@ -2699,7 +2743,12 @@ e100_sw_reset(struct e100_private *bdp, u32 reset_cmd) ...@@ -2699,7 +2743,12 @@ e100_sw_reset(struct e100_private *bdp, u32 reset_cmd)
} }
/* Mask off our interrupt line -- its unmasked after reset */ /* Mask off our interrupt line -- its unmasked after reset */
e100_dis_intr(bdp); e100_disable_clear_intr(bdp);
#ifdef E100_CU_DEBUG
bdp->last_cmd = 0;
bdp->last_sub_cmd = 0;
#endif
} }
/** /**
...@@ -3055,63 +3104,51 @@ e100_tcb_add_C_bit(struct e100_private *bdp) ...@@ -3055,63 +3104,51 @@ e100_tcb_add_C_bit(struct e100_private *bdp)
} }
/* /*
* Procedure: e100_hw_reset_recover * Procedure: e100_configure_device
* *
* Description: This routine will recover the hw after reset. * Description: This routine will configure device
* *
* Arguments: * Arguments:
* bdp - Ptr to this card's e100_bdconfig structure * bdp - Ptr to this card's e100_bdconfig structure
* reset_cmd - s/w reset or selective reset.
* *
* Returns: * Returns:
* true upon success * true upon success
* false upon failure * false upon failure
*/ */
unsigned char unsigned char
e100_hw_reset_recover(struct e100_private *bdp, u32 reset_cmd) e100_configure_device(struct e100_private *bdp)
{ {
bdp->last_tcb = NULL; /*load CU & RU base */
if (reset_cmd == PORT_SOFTWARE_RESET) { if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
return false;
/*load CU & RU base */
if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
return false;
}
if (e100_load_microcode(bdp)) { if (e100_load_microcode(bdp))
bdp->flags |= DF_UCODE_LOADED; bdp->flags |= DF_UCODE_LOADED;
}
if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) { if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
return false; return false;
}
/* Issue the load dump counters address command */ /* Issue the load dump counters address command */
if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0))
SCB_CUC_DUMP_ADDR)) { return false;
return false;
}
if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) { if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) {
printk(KERN_ERR printk(KERN_ERR "e100: e100_configure_device: "
"e100: e100_hw_reset_recover: " "setup iaaddr failed\n");
"setup iaaddr failed\n"); return false;
return false; }
}
e100_set_multi_exec(bdp->device); e100_set_multi_exec(bdp->device);
/* Change for 82558 enhancement */
/* If 82558/9 and if the user has enabled flow control, set up * the
* Flow Control Reg. in the CSR */
if ((bdp->flags & IS_BACHELOR)
&& (bdp->params.b_params & PRM_FC)) {
writeb(DFLT_FC_THLD,
&bdp->scb->scb_ext.d101_scb.scb_fc_thld);
writeb(DFLT_FC_CMD,
&bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
}
/* Change for 82558 enhancement */
/* If 82558/9 and if the user has enabled flow control, set up */
/* flow Control Reg. in the CSR */
if ((bdp->flags & IS_BACHELOR)
&& (bdp->params.b_params & PRM_FC)) {
writeb(DFLT_FC_THLD,
&bdp->scb->scb_ext.d101_scb.scb_fc_thld);
writeb(DFLT_FC_CMD,
&bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
} }
e100_force_config(bdp); e100_force_config(bdp);
...@@ -3125,7 +3162,7 @@ e100_deisolate_driver(struct e100_private *bdp, u8 full_reset) ...@@ -3125,7 +3162,7 @@ e100_deisolate_driver(struct e100_private *bdp, u8 full_reset)
u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET; u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET;
e100_sw_reset(bdp, cmd); e100_sw_reset(bdp, cmd);
if (cmd == PORT_SOFTWARE_RESET) { if (cmd == PORT_SOFTWARE_RESET) {
if (!e100_hw_reset_recover(bdp, cmd)) if (!e100_configure_device(bdp))
printk(KERN_ERR "e100: e100_deisolate_driver:" printk(KERN_ERR "e100: e100_deisolate_driver:"
" device configuration failed\n"); " device configuration failed\n");
} }
...@@ -3948,6 +3985,8 @@ e100_non_tx_background(unsigned long ptr) ...@@ -3948,6 +3985,8 @@ e100_non_tx_background(unsigned long ptr)
struct e100_private *bdp = (struct e100_private *) ptr; struct e100_private *bdp = (struct e100_private *) ptr;
nxmit_cb_entry_t *active_command; nxmit_cb_entry_t *active_command;
int restart = true; int restart = true;
cb_header_t *non_tx_cmd;
u8 sub_cmd;
spin_lock_bh(&(bdp->bd_non_tx_lock)); spin_lock_bh(&(bdp->bd_non_tx_lock));
...@@ -3975,6 +4014,15 @@ e100_non_tx_background(unsigned long ptr) ...@@ -3975,6 +4014,15 @@ e100_non_tx_background(unsigned long ptr)
&& time_before(jiffies, active_command->expiration_time)) { && time_before(jiffies, active_command->expiration_time)) {
goto exit; goto exit;
} else { } else {
non_tx_cmd = (cb_header_t *) active_command->non_tx_cmd;
sub_cmd = CB_CMD_MASK & le16_to_cpu(non_tx_cmd->cb_cmd);
#ifdef E100_CU_DEBUG
if (!(non_tx_cmd->cb_status
& __constant_cpu_to_le16(CB_STATUS_COMPLETE)))
printk(KERN_ERR "e100: %s: Queued "
"command (%x) timeout\n",
bdp->device->name, sub_cmd);
#endif
list_del(&(active_command->list_elem)); list_del(&(active_command->list_elem));
e100_free_non_tx_cmd(bdp, active_command); e100_free_non_tx_cmd(bdp, active_command);
} }
...@@ -3997,9 +4045,10 @@ e100_non_tx_background(unsigned long ptr) ...@@ -3997,9 +4045,10 @@ e100_non_tx_background(unsigned long ptr)
bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH; bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH;
active_command = list_entry(bdp->non_tx_cmd_list.next, active_command = list_entry(bdp->non_tx_cmd_list.next,
nxmit_cb_entry_t, list_elem); nxmit_cb_entry_t, list_elem);
sub_cmd = ((cb_header_t *) active_command->non_tx_cmd)->cb_cmd;
spin_lock_irq(&(bdp->bd_lock)); spin_lock_irq(&(bdp->bd_lock));
e100_wait_exec_cmplx(bdp, active_command->dma_addr, e100_wait_exec_cmplx(bdp, active_command->dma_addr,
SCB_CUC_START); SCB_CUC_START, sub_cmd);
spin_unlock_irq(&(bdp->bd_lock)); spin_unlock_irq(&(bdp->bd_lock));
active_command->expiration_time = jiffies + HZ; active_command->expiration_time = jiffies + HZ;
cmd_type = CB_CMD_MASK & cmd_type = CB_CMD_MASK &
...@@ -4092,17 +4141,13 @@ e100_resume(struct pci_dev *pcid) ...@@ -4092,17 +4141,13 @@ e100_resume(struct pci_dev *pcid)
{ {
struct net_device *netdev = pci_get_drvdata(pcid); struct net_device *netdev = pci_get_drvdata(pcid);
struct e100_private *bdp = netdev->priv; struct e100_private *bdp = netdev->priv;
u8 full_reset = false;
pci_set_power_state(pcid, 0); pci_set_power_state(pcid, 0);
pci_enable_wake(pcid, 0, 0); /* Clear PME status and disable PME */ pci_enable_wake(pcid, 0, 0); /* Clear PME status and disable PME */
pci_restore_state(pcid, bdp->pci_state); pci_restore_state(pcid, bdp->pci_state);
if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) { /* Also do device full reset because device was in D3 state */
full_reset = true; e100_deisolate_driver(bdp, true);
}
e100_deisolate_driver(bdp, full_reset);
return 0; return 0;
} }
...@@ -4229,3 +4274,20 @@ static void e100_hwi_restore(struct e100_private *bdp) ...@@ -4229,3 +4274,20 @@ static void e100_hwi_restore(struct e100_private *bdp)
e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control); e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
return; return;
} }
#ifdef E100_CU_DEBUG
unsigned char
e100_cu_unknown_state(struct e100_private *bdp)
{
u8 scb_cmd_low;
u16 scb_status;
scb_cmd_low = bdp->scb->scb_cmd_low;
scb_status = le16_to_cpu(bdp->scb->scb_status);
/* If CU is active and executing unknown cmd */
if (scb_status & SCB_CUS_ACTIVE && scb_cmd_low & SCB_CUC_UNKNOWN)
return true;
else
return false;
}
#endif
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