mirror of
https://github.com/torvalds/linux.git
synced 2026-06-09 23:23:53 +02:00
net: wireless: bcmdhd: Fix FW hang recovery
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
This commit is contained in:
parent
23016defd7
commit
0660b6fac4
|
|
@ -135,6 +135,9 @@ DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
|
|||
#if defined(OOB_INTR_ONLY)
|
||||
extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
|
||||
#endif /* defined(OOB_INTR_ONLY) */
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
|
||||
static void dhd_hang_process(struct work_struct *work);
|
||||
#endif
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
|
||||
MODULE_LICENSE("GPL v2");
|
||||
#endif /* LinuxVer */
|
||||
|
|
@ -257,6 +260,9 @@ typedef struct dhd_info {
|
|||
#endif /* DHDTHREAD */
|
||||
bool dhd_tasklet_create;
|
||||
tsk_ctl_t thr_sysioc_ctl;
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
|
||||
struct work_struct work_hang;
|
||||
#endif
|
||||
|
||||
/* Wakelocks */
|
||||
#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
|
||||
|
|
@ -2058,6 +2064,7 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr)
|
|||
|
||||
static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
|
||||
{
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
|
||||
if (!dhdp)
|
||||
return FALSE;
|
||||
if ((error == -ETIMEDOUT) || ((dhdp->busstate == DHD_BUS_DOWN) &&
|
||||
|
|
@ -2067,6 +2074,7 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
|
|||
net_os_send_hang_message(net);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -2333,7 +2341,7 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
|
|||
static int
|
||||
dhd_stop(struct net_device *net)
|
||||
{
|
||||
int ifidx;
|
||||
int ifidx = 0;
|
||||
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
|
||||
DHD_OS_WAKE_LOCK(&dhd->pub);
|
||||
DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net));
|
||||
|
|
@ -2368,15 +2376,15 @@ dhd_stop(struct net_device *net)
|
|||
/* Stop the protocol module */
|
||||
dhd_prot_stop(&dhd->pub);
|
||||
|
||||
OLD_MOD_DEC_USE_COUNT;
|
||||
exit:
|
||||
#if defined(WL_CFG80211)
|
||||
if (ifidx == 0 && !dhd_download_fw_on_driverload)
|
||||
wl_android_wifi_off(net);
|
||||
#endif
|
||||
dhd->pub.hang_was_sent = 0;
|
||||
#endif
|
||||
dhd->pub.rxcnt_timeout = 0;
|
||||
dhd->pub.txcnt_timeout = 0;
|
||||
OLD_MOD_DEC_USE_COUNT;
|
||||
exit:
|
||||
|
||||
DHD_OS_WAKE_UNLOCK(&dhd->pub);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2400,6 +2408,7 @@ dhd_open(struct net_device *net)
|
|||
firmware_path[0] = '\0';
|
||||
}
|
||||
|
||||
dhd->pub.hang_was_sent = 0;
|
||||
#if !defined(WL_CFG80211)
|
||||
/*
|
||||
* Force start if ifconfig_up gets called before START command
|
||||
|
|
@ -2801,7 +2810,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
|
|||
dhd->thr_sysioc_ctl.thr_pid = -1;
|
||||
}
|
||||
dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
|
||||
INIT_WORK(&dhd->work_hang, dhd_hang_process);
|
||||
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
|
||||
/*
|
||||
* Save the dhd_info into the priv
|
||||
*/
|
||||
|
|
@ -3655,6 +3666,9 @@ void dhd_detach(dhd_pub_t *dhdp)
|
|||
}
|
||||
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
|
||||
cancel_work_sync(&dhd->work_hang);
|
||||
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
|
||||
|
||||
#if defined(CONFIG_WIRELESS_EXT)
|
||||
if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
|
||||
|
|
@ -3985,14 +3999,11 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
|
|||
* Can be changed by another processor.
|
||||
*/
|
||||
smp_mb();
|
||||
while (!(*condition) && (!signal_pending(current) && timeout)) {
|
||||
while (!(*condition) && timeout) {
|
||||
timeout = schedule_timeout(timeout);
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
if (signal_pending(current))
|
||||
*pending = TRUE;
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&dhd->ioctl_resp_wait, &wait);
|
||||
|
||||
|
|
@ -4523,6 +4534,28 @@ dhd_dev_get_pno_status(struct net_device *dev)
|
|||
|
||||
#endif /* PNO_SUPPORT */
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
|
||||
static void dhd_hang_process(struct work_struct *work)
|
||||
{
|
||||
dhd_info_t *dhd;
|
||||
struct net_device *dev;
|
||||
|
||||
dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang);
|
||||
dev = dhd->iflist[0]->net;
|
||||
|
||||
if (dev) {
|
||||
rtnl_lock();
|
||||
dev_close(dev);
|
||||
rtnl_unlock();
|
||||
#if defined(WL_WIRELESS_EXT)
|
||||
wl_iw_send_priv_event(dev, "HANG");
|
||||
#endif
|
||||
#if defined(WL_CFG80211)
|
||||
wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int net_os_send_hang_message(struct net_device *dev)
|
||||
{
|
||||
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
|
||||
|
|
@ -4531,18 +4564,12 @@ int net_os_send_hang_message(struct net_device *dev)
|
|||
if (dhd) {
|
||||
if (!dhd->pub.hang_was_sent) {
|
||||
dhd->pub.hang_was_sent = 1;
|
||||
#if defined(CONFIG_WIRELESS_EXT)
|
||||
ret = wl_iw_send_priv_event(dev, "HANG");
|
||||
#endif
|
||||
#if defined(WL_CFG80211)
|
||||
ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
|
||||
dev_close(dev);
|
||||
dev_open(dev);
|
||||
#endif
|
||||
schedule_work(&dhd->work_hang);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user