diff options
Diffstat (limited to 'drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c')
-rw-r--r-- | drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 93 |
1 files changed, 70 insertions, 23 deletions
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index bf18491a33a5..406b367c284c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -579,7 +579,8 @@ static int brcmf_netdev_stop(struct net_device *ndev) brcmf_cfg80211_down(ndev); - brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear", NULL, 0); + if (ifp->drvr->bus_if->state == BRCMF_BUS_UP) + brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear", NULL, 0); brcmf_net_setcarrier(ifp, false); @@ -1085,6 +1086,29 @@ static void brcmf_core_bus_reset(struct work_struct *work) brcmf_bus_reset(drvr->bus_if); } +static ssize_t bus_reset_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct brcmf_pub *drvr = file->private_data; + u8 value; + + if (kstrtou8_from_user(user_buf, count, 0, &value)) + return -EINVAL; + + if (value != 1) + return -EINVAL; + + schedule_work(&drvr->bus_reset); + + return count; +} + +static const struct file_operations bus_reset_fops = { + .open = simple_open, + .llseek = no_llseek, + .write = bus_reset_write, +}; + static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops) { int ret = -1; @@ -1160,6 +1184,8 @@ static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops) /* populate debugfs */ brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read); + debugfs_create_file("reset", 0600, brcmf_debugfs_get_devdir(drvr), drvr, + &bus_reset_fops); brcmf_feat_debugfs_create(drvr); brcmf_proto_debugfs_create(drvr); brcmf_bus_debugfs_create(bus_if); @@ -1183,13 +1209,11 @@ fail: return ret; } -int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) +int brcmf_alloc(struct device *dev, struct brcmf_mp_device *settings) { struct wiphy *wiphy; struct cfg80211_ops *ops; struct brcmf_pub *drvr = NULL; - int ret = 0; - int i; brcmf_dbg(TRACE, "Enter\n"); @@ -1198,12 +1222,30 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) return -ENOMEM; wiphy = wiphy_new(ops, sizeof(*drvr)); - if (!wiphy) + if (!wiphy) { + kfree(ops); return -ENOMEM; + } set_wiphy_dev(wiphy, dev); drvr = wiphy_priv(wiphy); drvr->wiphy = wiphy; + drvr->ops = ops; + drvr->bus_if = dev_get_drvdata(dev); + drvr->bus_if->drvr = drvr; + drvr->settings = settings; + + return 0; +} + +int brcmf_attach(struct device *dev) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; + int ret = 0; + int i; + + brcmf_dbg(TRACE, "Enter\n"); for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++) drvr->if2bss[i] = BRCMF_BSSIDX_INVALID; @@ -1212,9 +1254,6 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) /* Link to bus module */ drvr->hdrlen = 0; - drvr->bus_if = dev_get_drvdata(dev); - drvr->bus_if->drvr = drvr; - drvr->settings = settings; /* Attach and link in the protocol */ ret = brcmf_proto_attach(drvr); @@ -1230,18 +1269,16 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) /* attach firmware event handler */ brcmf_fweh_attach(drvr); - ret = brcmf_bus_started(drvr, ops); + ret = brcmf_bus_started(drvr, drvr->ops); if (ret != 0) { bphy_err(drvr, "dongle is not responding: err=%d\n", ret); goto fail; } - drvr->config->ops = ops; return 0; fail: brcmf_detach(dev); - kfree(ops); return ret; } @@ -1307,27 +1344,37 @@ void brcmf_detach(struct device *dev) unregister_inet6addr_notifier(&drvr->inet6addr_notifier); #endif - /* stop firmware event handling */ - brcmf_fweh_detach(drvr); - if (drvr->config) - brcmf_p2p_detach(&drvr->config->p2p); - brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN); + brcmf_bus_stop(drvr->bus_if); - brcmf_proto_detach_pre_delif(drvr); + brcmf_fweh_detach(drvr); + brcmf_proto_detach(drvr); /* make sure primary interface removed last */ - for (i = BRCMF_MAX_IFS-1; i > -1; i--) - brcmf_remove_interface(drvr->iflist[i], false); + for (i = BRCMF_MAX_IFS - 1; i > -1; i--) { + if (drvr->iflist[i]) + brcmf_del_if(drvr, drvr->iflist[i]->bsscfgidx, false); + } - brcmf_cfg80211_detach(drvr->config); - drvr->config = NULL; + if (drvr->config) { + brcmf_p2p_detach(&drvr->config->p2p); + brcmf_cfg80211_detach(drvr->config); + drvr->config = NULL; + } +} - brcmf_bus_stop(drvr->bus_if); +void brcmf_free(struct device *dev) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_pub *drvr = bus_if->drvr; - brcmf_proto_detach_post_delif(drvr); + if (!drvr) + return; bus_if->drvr = NULL; + + kfree(drvr->ops); + wiphy_free(drvr->wiphy); } |