|
@@ -820,7 +820,7 @@ static int tg3_ape_event_lock(struct tg3 *tp, u32 timeout_us)
|
|
|
|
|
|
tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
|
|
|
|
|
|
- udelay(10);
|
|
|
+ usleep_range(10, 20);
|
|
|
timeout_us -= (timeout_us > 10) ? 10 : timeout_us;
|
|
|
}
|
|
|
|
|
@@ -922,8 +922,8 @@ static int tg3_ape_send_event(struct tg3 *tp, u32 event)
|
|
|
if (!(apedata & APE_FW_STATUS_READY))
|
|
|
return -EAGAIN;
|
|
|
|
|
|
- /* Wait for up to 1 millisecond for APE to service previous event. */
|
|
|
- err = tg3_ape_event_lock(tp, 1000);
|
|
|
+ /* Wait for up to 20 millisecond for APE to service previous event. */
|
|
|
+ err = tg3_ape_event_lock(tp, 20000);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -946,6 +946,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
|
|
|
|
|
|
switch (kind) {
|
|
|
case RESET_KIND_INIT:
|
|
|
+ tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_COUNT, tp->ape_hb++);
|
|
|
tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
|
|
|
APE_HOST_SEG_SIG_MAGIC);
|
|
|
tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
|
|
@@ -962,13 +963,6 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
|
|
|
event = APE_EVENT_STATUS_STATE_START;
|
|
|
break;
|
|
|
case RESET_KIND_SHUTDOWN:
|
|
|
- /* With the interface we are currently using,
|
|
|
- * APE does not track driver state. Wiping
|
|
|
- * out the HOST SEGMENT SIGNATURE forces
|
|
|
- * the APE to assume OS absent status.
|
|
|
- */
|
|
|
- tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0);
|
|
|
-
|
|
|
if (device_may_wakeup(&tp->pdev->dev) &&
|
|
|
tg3_flag(tp, WOL_ENABLE)) {
|
|
|
tg3_ape_write32(tp, TG3_APE_HOST_WOL_SPEED,
|
|
@@ -990,6 +984,18 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
|
|
|
tg3_ape_send_event(tp, event);
|
|
|
}
|
|
|
|
|
|
+static void tg3_send_ape_heartbeat(struct tg3 *tp,
|
|
|
+ unsigned long interval)
|
|
|
+{
|
|
|
+ /* Check if hb interval has exceeded */
|
|
|
+ if (!tg3_flag(tp, ENABLE_APE) ||
|
|
|
+ time_before(jiffies, tp->ape_hb_jiffies + interval))
|
|
|
+ return;
|
|
|
+
|
|
|
+ tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_COUNT, tp->ape_hb++);
|
|
|
+ tp->ape_hb_jiffies = jiffies;
|
|
|
+}
|
|
|
+
|
|
|
static void tg3_disable_ints(struct tg3 *tp)
|
|
|
{
|
|
|
int i;
|
|
@@ -7262,6 +7268,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL << 1);
|
|
|
return work_done;
|
|
|
|
|
|
tx_recovery:
|
|
@@ -7344,6 +7351,7 @@ static int tg3_poll(struct napi_struct *napi, int budget)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL << 1);
|
|
|
return work_done;
|
|
|
|
|
|
tx_recovery:
|
|
@@ -10732,7 +10740,7 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
|
|
|
if (tg3_flag(tp, ENABLE_APE))
|
|
|
/* Write our heartbeat update interval to APE. */
|
|
|
tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
|
|
|
- APE_HOST_HEARTBEAT_INT_DISABLE);
|
|
|
+ APE_HOST_HEARTBEAT_INT_5SEC);
|
|
|
|
|
|
tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
|
|
|
|
|
@@ -11077,6 +11085,9 @@ static void tg3_timer(struct timer_list *t)
|
|
|
tp->asf_counter = tp->asf_multiplier;
|
|
|
}
|
|
|
|
|
|
+ /* Update the APE heartbeat every 5 seconds.*/
|
|
|
+ tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL);
|
|
|
+
|
|
|
spin_unlock(&tp->lock);
|
|
|
|
|
|
restart_timer:
|
|
@@ -16653,6 +16664,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
|
|
|
pci_state_reg);
|
|
|
|
|
|
tg3_ape_lock_init(tp);
|
|
|
+ tp->ape_hb_interval =
|
|
|
+ msecs_to_jiffies(APE_HOST_HEARTBEAT_INT_5SEC);
|
|
|
}
|
|
|
|
|
|
/* Set up tp->grc_local_ctrl before calling
|