diff options
Diffstat (limited to 'drivers/net/wireless/microchip')
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/cfg80211.c | 140 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/cfg80211.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/fw.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/hif.c | 135 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/hif.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/mon.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/netdev.c | 188 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/netdev.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/sdio.c | 248 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/spi.c | 110 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/wlan.c | 507 | ||||
-rw-r--r-- | drivers/net/wireless/microchip/wilc1000/wlan.h | 66 |
12 files changed, 961 insertions, 470 deletions
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index ad2509d8c99a..e7aa0f991923 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -231,6 +231,7 @@ struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl) } static int set_channel(struct wiphy *wiphy, + struct net_device *dev, struct cfg80211_chan_def *chandef) { struct wilc *wl = wiphy_priv(wiphy); @@ -356,7 +357,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, memcpy(vif->auth.ssid.ssid, sme->ssid, sme->ssid_len); vif->auth.ssid.ssid_len = sme->ssid_len; } - vif->auth.key_mgmt_suite = cpu_to_be32(sme->crypto.akm_suites[0]); + vif->auth.key_mgmt_suite = sme->crypto.akm_suites[0]; ether_addr_copy(vif->auth.bssid, sme->bssid); break; @@ -1424,7 +1425,7 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev, struct wilc_vif *vif = netdev_priv(dev); int ret; - ret = set_channel(wiphy, &settings->chandef); + ret = set_channel(wiphy, dev, &settings->chandef); if (ret != 0) netdev_err(dev, "Error in setting channel\n"); @@ -1518,7 +1519,7 @@ static struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type) { struct wilc_vif *vif; - list_for_each_entry_rcu(vif, &wl->vif_list, list) { + wilc_for_each_vif(wl, vif) { if (vif->iftype == type) return vif; } @@ -1609,7 +1610,6 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) cfg80211_unregister_netdevice(vif->ndev); vif->monitor_flag = 0; - wilc_set_operation_mode(vif, 0, 0, 0); mutex_lock(&wl->vif_mutex); list_del_rcu(&vif->list); wl->vif_num--; @@ -1618,23 +1618,6 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) return 0; } -static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) -{ - struct wilc *wl = wiphy_priv(wiphy); - - if (!wow && wilc_wlan_get_num_conn_ifcs(wl)) - wl->suspend_event = true; - else - wl->suspend_event = false; - - return 0; -} - -static int wilc_resume(struct wiphy *wiphy) -{ - return 0; -} - static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled) { struct wilc *wl = wiphy_priv(wiphy); @@ -1686,7 +1669,7 @@ static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, } static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - int *dbm) + unsigned int link_id, int *dbm) { int ret; struct wilc_vif *vif = netdev_priv(wdev->netdev); @@ -1740,8 +1723,6 @@ static const struct cfg80211_ops wilc_cfg80211_ops = { .set_power_mgmt = set_power_mgmt, .set_cqm_rssi_config = set_cqm_rssi_config, - .suspend = wilc_suspend, - .resume = wilc_resume, .set_wakeup = wilc_set_wakeup, .set_tx_power = set_tx_power, .get_tx_power = get_tx_power, @@ -1777,58 +1758,10 @@ void wlan_deinit_locks(struct wilc *wilc) cleanup_srcu_struct(&wilc->srcu); } -int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, - const struct wilc_hif_func *ops) -{ - struct wilc *wl; - struct wilc_vif *vif; - int ret, i; - - wl = wilc_create_wiphy(dev); - if (!wl) - return -EINVAL; - - wlan_init_locks(wl); - - ret = wilc_wlan_cfg_init(wl); - if (ret) - goto free_wl; - - *wilc = wl; - wl->io_type = io_type; - wl->hif_func = ops; - - for (i = 0; i < NQUEUES; i++) - INIT_LIST_HEAD(&wl->txq[i].txq_head.list); - - INIT_LIST_HEAD(&wl->rxq_head.list); - INIT_LIST_HEAD(&wl->vif_list); - - vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE, - NL80211_IFTYPE_STATION, false); - if (IS_ERR(vif)) { - ret = PTR_ERR(vif); - goto free_cfg; - } - - return 0; - -free_cfg: - wilc_wlan_cfg_deinit(wl); - -free_wl: - wlan_deinit_locks(wl); - wiphy_unregister(wl->wiphy); - wiphy_free(wl->wiphy); - return ret; -} -EXPORT_SYMBOL_GPL(wilc_cfg80211_init); - -struct wilc *wilc_create_wiphy(struct device *dev) +static struct wilc *wilc_create_wiphy(struct device *dev) { struct wiphy *wiphy; struct wilc *wl; - int ret; wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl)); if (!wiphy) @@ -1871,17 +1804,66 @@ struct wilc *wilc_create_wiphy(struct device *dev) BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT); wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - wiphy->features |= NL80211_FEATURE_SAE; set_wiphy_dev(wiphy, dev); wl->wiphy = wiphy; - ret = wiphy_register(wiphy); - if (ret) { - wiphy_free(wiphy); - return NULL; - } return wl; } +int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, + const struct wilc_hif_func *ops) +{ + struct wilc *wl; + int ret, i; + + wl = wilc_create_wiphy(dev); + if (!wl) + return -EINVAL; + + wlan_init_locks(wl); + + ret = wilc_wlan_cfg_init(wl); + if (ret) + goto free_wl; + + *wilc = wl; + wl->io_type = io_type; + wl->hif_func = ops; + + for (i = 0; i < NQUEUES; i++) + INIT_LIST_HEAD(&wl->txq[i].txq_head.list); + + INIT_LIST_HEAD(&wl->rxq_head.list); + INIT_LIST_HEAD(&wl->vif_list); + + wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, + wiphy_name(wl->wiphy)); + if (!wl->hif_workqueue) { + ret = -ENOMEM; + goto free_cfg; + } + + return 0; + +free_cfg: + wilc_wlan_cfg_deinit(wl); + +free_wl: + wlan_deinit_locks(wl); + wiphy_free(wl->wiphy); + return ret; +} +EXPORT_SYMBOL_GPL(wilc_cfg80211_init); + +int wilc_cfg80211_register(struct wilc *wilc) +{ + /* WPA3/SAE supported only on WILC1000 */ + if (is_wilc1000(wilc->chipid)) + wilc->wiphy->features |= NL80211_FEATURE_SAE; + + return wiphy_register(wilc->wiphy); +} +EXPORT_SYMBOL_GPL(wilc_cfg80211_register); + int wilc_init_host_int(struct net_device *net) { int ret; diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.h b/drivers/net/wireless/microchip/wilc1000/cfg80211.h index 8c65951cfaf9..2dc9c1c42d60 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.h +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.h @@ -10,7 +10,7 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, const struct wilc_hif_func *ops); -struct wilc *wilc_create_wiphy(struct device *dev); +int wilc_cfg80211_register(struct wilc *wilc); void wilc_deinit_host_int(struct net_device *net); int wilc_init_host_int(struct net_device *net); void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size); diff --git a/drivers/net/wireless/microchip/wilc1000/fw.h b/drivers/net/wireless/microchip/wilc1000/fw.h index 5c5cac4aab02..7a930e89614c 100644 --- a/drivers/net/wireless/microchip/wilc1000/fw.h +++ b/drivers/net/wireless/microchip/wilc1000/fw.h @@ -13,6 +13,12 @@ #define WILC_MAX_RATES_SUPPORTED 12 #define WILC_MAX_NUM_PMKIDS 16 #define WILC_MAX_NUM_SCANNED_CH 14 +#define WILC_NVMEM_MAX_NUM_BANK 6 +#define WILC_NVMEM_BANK_BASE 0x30000000 +#define WILC_NVMEM_LOW_BANK_OFFSET 0x102c +#define WILC_NVMEM_HIGH_BANK_OFFSET 0x1380 +#define WILC_NVMEM_IS_BANK_USED BIT(31) +#define WILC_NVMEM_IS_BANK_INVALID BIT(30) struct wilc_assoc_resp { __le16 capab_info; @@ -127,4 +133,11 @@ struct wilc_external_auth_param { __le32 key_mgmt_suites; __le16 status; } __packed; + +static inline u32 get_bank_offset_from_bank_index(unsigned int i) +{ + return (((i) < 2) ? WILC_NVMEM_LOW_BANK_OFFSET + ((i) * 32) : + WILC_NVMEM_HIGH_BANK_OFFSET + ((i) - 2) * 16); +} + #endif diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index 839f142663e8..cb46a39ef757 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -107,7 +107,7 @@ static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx) if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC) return NULL; - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, vif) { if (vif->idx == index) return vif; } @@ -377,38 +377,52 @@ struct wilc_join_bss_param * wilc_parse_join_bss_param(struct cfg80211_bss *bss, struct cfg80211_crypto_settings *crypto) { - struct wilc_join_bss_param *param; + const u8 *ies_data, *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; + const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; struct ieee80211_p2p_noa_attr noa_attr; + const struct cfg80211_bss_ies *ies; + struct wilc_join_bss_param *param; u8 rates_len = 0; - const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; - const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; + int ies_len; + u64 ies_tsf; int ret; - const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies); param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) return NULL; + rcu_read_lock(); + ies = rcu_dereference(bss->ies); + ies_data = kmemdup(ies->data, ies->len, GFP_ATOMIC); + if (!ies_data) { + rcu_read_unlock(); + kfree(param); + return NULL; + } + ies_len = ies->len; + ies_tsf = ies->tsf; + rcu_read_unlock(); + param->beacon_period = cpu_to_le16(bss->beacon_interval); param->cap_info = cpu_to_le16(bss->capability); param->bss_type = WILC_FW_BSS_TYPE_INFRA; param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq); ether_addr_copy(param->bssid, bss->bssid); - ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); + ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies_data, ies_len); if (ssid_elm) { if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN) memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]); } - tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); + tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies_data, ies_len); if (tim_elm && tim_elm[1] >= 2) param->dtim_period = tim_elm[3]; memset(param->p_suites, 0xFF, 3); memset(param->akm_suites, 0xFF, 3); - rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len); + rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies_data, ies_len); if (rates_ie) { rates_len = rates_ie[1]; if (rates_len > WILC_MAX_RATES_SUPPORTED) @@ -419,7 +433,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, if (rates_len < WILC_MAX_RATES_SUPPORTED) { supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, - ies->data, ies->len); + ies_data, ies_len); if (supp_rates_ie) { u8 ext_rates = supp_rates_ie[1]; @@ -434,15 +448,15 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, } } - ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len); + ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies_data, ies_len); if (ht_ie) param->ht_capable = true; - ret = cfg80211_get_p2p_attr(ies->data, ies->len, + ret = cfg80211_get_p2p_attr(ies_data, ies_len, IEEE80211_P2P_ATTR_ABSENCE_NOTICE, (u8 *)&noa_attr, sizeof(noa_attr)); if (ret > 0) { - param->tsf_lo = cpu_to_le32(ies->tsf); + param->tsf_lo = cpu_to_le32(ies_tsf); param->noa_enabled = 1; param->idx = noa_attr.index; if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) { @@ -462,7 +476,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, } wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WMM, - ies->data, ies->len); + ies_data, ies_len); if (wmm_ie) { struct ieee80211_wmm_param_ie *ie; @@ -477,13 +491,13 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, - ies->data, ies->len); + ies_data, ies_len); if (wpa_ie) { param->mode_802_11i = 1; param->rsn_found = true; } - rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len); + rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies_data, ies_len); if (rsn_ie) { int rsn_ie_len = sizeof(struct element) + rsn_ie[1]; int offset = 8; @@ -517,6 +531,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, param->akm_suites[i] = crypto->akm_suites[i] & 0xFF; } + kfree(ies_data); return (void *)param; } @@ -628,7 +643,7 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, } } - del_timer(&hif_drv->connect_timer); + timer_delete(&hif_drv->connect_timer); conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status, hif_drv->conn_info.priv); @@ -654,7 +669,7 @@ void wilc_handle_disconnect(struct wilc_vif *vif) struct host_if_drv *hif_drv = vif->hif_drv; if (hif_drv->usr_scan_req.scan_result) { - del_timer(&hif_drv->scan_timer); + timer_delete(&hif_drv->scan_timer); handle_scan_done(vif, SCAN_EVENT_ABORTED); } @@ -698,7 +713,7 @@ static void handle_rcvd_gnrl_async_info(struct work_struct *work) if (hif_drv->hif_state == HOST_IF_CONNECTED) { wilc_handle_disconnect(vif); } else if (hif_drv->usr_scan_req.scan_result) { - del_timer(&hif_drv->scan_timer); + timer_delete(&hif_drv->scan_timer); handle_scan_done(vif, SCAN_EVENT_ABORTED); } } @@ -731,7 +746,7 @@ int wilc_disconnect(struct wilc_vif *vif) conn_info = &hif_drv->conn_info; if (scan_req->scan_result) { - del_timer(&hif_drv->scan_timer); + timer_delete(&hif_drv->scan_timer); scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->priv); scan_req->scan_result = NULL; } @@ -739,7 +754,7 @@ int wilc_disconnect(struct wilc_vif *vif) if (conn_info->conn_result) { if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP || hif_drv->hif_state == HOST_IF_EXTERNAL_AUTH) - del_timer(&hif_drv->connect_timer); + timer_delete(&hif_drv->connect_timer); conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0, conn_info->priv); @@ -944,7 +959,7 @@ static void listen_timer_cb(struct timer_list *t) int result; struct host_if_msg *msg; - del_timer(&vif->hif_drv->remain_on_ch_timer); + timer_delete(&vif->hif_drv->remain_on_ch_timer); msg = wilc_alloc_work(vif, wilc_handle_listen_state_expired, false); if (IS_ERR(msg)) @@ -1051,7 +1066,7 @@ static void handle_scan_complete(struct work_struct *work) { struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - del_timer(&msg->vif->hif_drv->scan_timer); + timer_delete(&msg->vif->hif_drv->scan_timer); handle_scan_done(msg->vif, SCAN_EVENT_DONE); @@ -1281,7 +1296,7 @@ int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr) return result; } -int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr) +int wilc_set_mac_address(struct wilc_vif *vif, const u8 *mac_addr) { struct wid wid; int result; @@ -1289,7 +1304,7 @@ int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr) wid.id = WID_MAC_ADDR; wid.type = WID_STR; wid.size = ETH_ALEN; - wid.val = mac_addr; + wid.val = (u8 *)mac_addr; result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); if (result) @@ -1536,7 +1551,7 @@ int wilc_deinit(struct wilc_vif *vif) timer_shutdown_sync(&hif_drv->scan_timer); timer_shutdown_sync(&hif_drv->connect_timer); - del_timer_sync(&vif->periodic_rssi); + timer_delete_sync(&vif->periodic_rssi); timer_shutdown_sync(&hif_drv->remain_on_ch_timer); if (hif_drv->usr_scan_req.scan_result) { @@ -1555,26 +1570,28 @@ int wilc_deinit(struct wilc_vif *vif) void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) { - int result; - struct host_if_msg *msg; - int id; struct host_if_drv *hif_drv; + struct host_if_msg *msg; struct wilc_vif *vif; + int srcu_idx; + int result; + int id; id = get_unaligned_le32(&buffer[length - 4]); + srcu_idx = srcu_read_lock(&wilc->srcu); vif = wilc_get_vif_from_idx(wilc, id); if (!vif) - return; - hif_drv = vif->hif_drv; + goto out; + hif_drv = vif->hif_drv; if (!hif_drv) { netdev_err(vif->ndev, "driver not init[%p]\n", hif_drv); - return; + goto out; } msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false); if (IS_ERR(msg)) - return; + goto out; msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1; msg->body.net_info.rssi = buffer[8]; @@ -1583,7 +1600,7 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) GFP_KERNEL); if (!msg->body.net_info.mgmt) { kfree(msg); - return; + goto out; } result = wilc_enqueue_work(msg); @@ -1592,43 +1609,41 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) kfree(msg->body.net_info.mgmt); kfree(msg); } +out: + srcu_read_unlock(&wilc->srcu, srcu_idx); } void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) { - int result; - struct host_if_msg *msg; - int id; struct host_if_drv *hif_drv; + struct host_if_msg *msg; struct wilc_vif *vif; + int srcu_idx; + int result; + int id; mutex_lock(&wilc->deinit_lock); id = get_unaligned_le32(&buffer[length - 4]); + srcu_idx = srcu_read_lock(&wilc->srcu); vif = wilc_get_vif_from_idx(wilc, id); - if (!vif) { - mutex_unlock(&wilc->deinit_lock); - return; - } + if (!vif) + goto out; hif_drv = vif->hif_drv; if (!hif_drv) { - mutex_unlock(&wilc->deinit_lock); - return; + goto out; } if (!hif_drv->conn_info.conn_result) { netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); - mutex_unlock(&wilc->deinit_lock); - return; + goto out; } msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false); - if (IS_ERR(msg)) { - mutex_unlock(&wilc->deinit_lock); - return; - } + if (IS_ERR(msg)) + goto out; msg->body.mac_info.status = buffer[7]; result = wilc_enqueue_work(msg); @@ -1636,32 +1651,36 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); kfree(msg); } - +out: + srcu_read_unlock(&wilc->srcu, srcu_idx); mutex_unlock(&wilc->deinit_lock); } void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) { - int result; - int id; struct host_if_drv *hif_drv; struct wilc_vif *vif; + int srcu_idx; + int result; + int id; id = get_unaligned_le32(&buffer[length - 4]); + srcu_idx = srcu_read_lock(&wilc->srcu); vif = wilc_get_vif_from_idx(wilc, id); if (!vif) - return; - hif_drv = vif->hif_drv; + goto out; - if (!hif_drv) - return; + hif_drv = vif->hif_drv; + if (!hif_drv) { + goto out; + } if (hif_drv->usr_scan_req.scan_result) { struct host_if_msg *msg; msg = wilc_alloc_work(vif, handle_scan_complete, false); if (IS_ERR(msg)) - return; + goto out; result = wilc_enqueue_work(msg); if (result) { @@ -1670,6 +1689,8 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) kfree(msg); } } +out: + srcu_read_unlock(&wilc->srcu, srcu_idx); } int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan, @@ -1697,7 +1718,7 @@ int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie) return -EFAULT; } - del_timer(&vif->hif_drv->remain_on_ch_timer); + timer_delete(&vif->hif_drv->remain_on_ch_timer); return wilc_handle_roc_expired(vif, cookie); } diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h index 0d380586b1d9..96eeaf31d237 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.h +++ b/drivers/net/wireless/microchip/wilc1000/hif.h @@ -167,7 +167,7 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, u8 cipher_mode); int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid); int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr); -int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr); +int wilc_set_mac_address(struct wilc_vif *vif, const u8 *mac_addr); int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, size_t ies_len); int wilc_disconnect(struct wilc_vif *vif); diff --git a/drivers/net/wireless/microchip/wilc1000/mon.c b/drivers/net/wireless/microchip/wilc1000/mon.c index 03b7229a0ff5..c3d27aaec297 100644 --- a/drivers/net/wireless/microchip/wilc1000/mon.c +++ b/drivers/net/wireless/microchip/wilc1000/mon.c @@ -7,12 +7,12 @@ #include "cfg80211.h" struct wilc_wfi_radiotap_hdr { - struct ieee80211_radiotap_header hdr; + struct ieee80211_radiotap_header_fixed hdr; u8 rate; } __packed; struct wilc_wfi_radiotap_cb_hdr { - struct ieee80211_radiotap_header hdr; + struct ieee80211_radiotap_header_fixed hdr; u8 rate; u8 dump; u16 tx_flags; diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 81e8f25863f5..af298021e050 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -23,6 +23,12 @@ #define __WILC1000_FW(api) WILC1000_FW_PREFIX #api ".bin" #define WILC1000_FW(api) __WILC1000_FW(api) +#define WILC3000_API_VER 1 + +#define WILC3000_FW_PREFIX "atmel/wilc3000_wifi_firmware-" +#define __WILC3000_FW(api) WILC3000_FW_PREFIX #api ".bin" +#define WILC3000_FW(api) __WILC3000_FW(api) + static irqreturn_t isr_uh_routine(int irq, void *user_data) { struct wilc *wilc = user_data; @@ -96,7 +102,7 @@ static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header) struct wilc_vif *vif; struct ieee80211_hdr *h = (struct ieee80211_hdr *)mac_header; - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, vif) { if (vif->iftype == WILC_STATION_MODE) if (ether_addr_equal_unaligned(h->addr2, vif->bssid)) { ndev = vif->ndev; @@ -132,7 +138,7 @@ int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) struct wilc_vif *vif; srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, vif) { if (!is_zero_ether_addr(vif->bssid)) ret_val++; } @@ -140,6 +146,19 @@ int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) return ret_val; } +static void wilc_wake_tx_queues(struct wilc *wl) +{ + int srcu_idx; + struct wilc_vif *ifc; + + srcu_idx = srcu_read_lock(&wl->srcu); + wilc_for_each_vif(wl, ifc) { + if (ifc->mac_opened && netif_queue_stopped(ifc->ndev)) + netif_wake_queue(ifc->ndev); + } + srcu_read_unlock(&wl->srcu, srcu_idx); +} + static int wilc_txq_task(void *vp) { int ret; @@ -160,17 +179,7 @@ static int wilc_txq_task(void *vp) do { ret = wilc_wlan_handle_txq(wl, &txq_count); if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) { - int srcu_idx; - struct wilc_vif *ifc; - - srcu_idx = srcu_read_lock(&wl->srcu); - list_for_each_entry_rcu(ifc, &wl->vif_list, - list) { - if (ifc->mac_opened && - netif_queue_stopped(ifc->ndev)) - netif_wake_queue(ifc->ndev); - } - srcu_read_unlock(&wl->srcu, srcu_idx); + wilc_wake_tx_queues(wl); } if (ret != WILC_VMM_ENTRY_FULL_RETRY) break; @@ -192,20 +201,24 @@ static int wilc_wlan_get_firmware(struct net_device *dev) { struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; - int chip_id; const struct firmware *wilc_fw; + char *firmware; int ret; - chip_id = wilc_get_chipid(wilc, false); + if (is_wilc1000(wilc->chipid)) + firmware = WILC1000_FW(WILC1000_API_VER); + else if (is_wilc3000(wilc->chipid)) + firmware = WILC3000_FW(WILC3000_API_VER); + else + return -EINVAL; - netdev_info(dev, "ChipID [%x] loading firmware [%s]\n", chip_id, - WILC1000_FW(WILC1000_API_VER)); + netdev_info(dev, "WILC%d loading firmware [%s]\n", + is_wilc1000(wilc->chipid) ? 1000 : 3000, + firmware); - ret = request_firmware(&wilc_fw, WILC1000_FW(WILC1000_API_VER), - wilc->dev); + ret = request_firmware(&wilc_fw, firmware, wilc->dev); if (ret != 0) { - netdev_err(dev, "%s - firmware not available\n", - WILC1000_FW(WILC1000_API_VER)); + netdev_err(dev, "%s - firmware not available\n", firmware); return -EINVAL; } wilc->firmware = wilc_fw; @@ -230,7 +243,7 @@ static int wilc_start_firmware(struct net_device *dev) return 0; } -static int wilc1000_firmware_download(struct net_device *dev) +static int wilc_firmware_download(struct net_device *dev) { struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; @@ -284,7 +297,7 @@ static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif) if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, &b, 1, 0, 0)) goto fail; - b = WILC_FW_PREAMBLE_SHORT; + b = WILC_FW_PREAMBLE_AUTO; if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, &b, 1, 0, 0)) goto fail; @@ -416,7 +429,7 @@ static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif) b = 1; if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, &b, 1, - 1, 1)) + 1, 0)) goto fail; return 0; @@ -525,7 +538,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif) if (ret) goto fail_irq_enable; - ret = wilc1000_firmware_download(dev); + ret = wilc_firmware_download(dev); if (ret) goto fail_irq_enable; @@ -587,7 +600,6 @@ static int wilc_mac_open(struct net_device *ndev) struct wilc *wl = vif->wilc; int ret = 0; struct mgmt_frame_regs mgmt_regs = {}; - u8 addr[ETH_ALEN] __aligned(2); if (!wl || !wl->dev) { netdev_err(ndev, "device not ready\n"); @@ -609,20 +621,14 @@ static int wilc_mac_open(struct net_device *ndev) wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype, vif->idx); - if (is_valid_ether_addr(ndev->dev_addr)) { - ether_addr_copy(addr, ndev->dev_addr); - wilc_set_mac_address(vif, addr); - } else { - wilc_get_mac_address(vif, addr); - eth_hw_addr_set(ndev, addr); - } netdev_dbg(ndev, "Mac address: %pM\n", ndev->dev_addr); - - if (!is_valid_ether_addr(ndev->dev_addr)) { - netdev_err(ndev, "Wrong MAC address\n"); + ret = wilc_set_mac_address(vif, ndev->dev_addr); + if (ret) { + netdev_err(ndev, "Failed to enforce MAC address in chip"); wilc_deinit_host_int(ndev); - wilc_wlan_deinitialize(ndev); - return -EINVAL; + if (!wl->open_ifcs) + wilc_wlan_deinitialize(ndev); + return ret; } mgmt_regs.interface_stypes = vif->mgmt_reg_stypes; @@ -665,7 +671,7 @@ static int wilc_set_mac_addr(struct net_device *dev, void *p) /* Verify MAC Address is not already in use: */ srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(tmp_vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, tmp_vif) { wilc_get_mac_address(tmp_vif, mac_addr); if (ether_addr_equal(addr->sa_data, mac_addr)) { if (vif != tmp_vif) { @@ -678,7 +684,7 @@ static int wilc_set_mac_addr(struct net_device *dev, void *p) } srcu_read_unlock(&wilc->srcu, srcu_idx); - result = wilc_set_mac_address(vif, (u8 *)addr->sa_data); + result = wilc_set_mac_address(vif, addr->sa_data); if (result) return result; @@ -768,7 +774,7 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev) struct wilc_vif *vif; srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, vif) { if (vif->mac_opened) netif_stop_queue(vif->ndev); } @@ -811,19 +817,21 @@ static int wilc_mac_close(struct net_device *ndev) void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset) { - unsigned int frame_len = 0; - int stats; unsigned char *buff_to_send = NULL; - struct sk_buff *skb; struct net_device *wilc_netdev; + unsigned int frame_len = 0; struct wilc_vif *vif; + struct sk_buff *skb; + int srcu_idx; + int stats; if (!wilc) return; + srcu_idx = srcu_read_lock(&wilc->srcu); wilc_netdev = get_if_handler(wilc, buff); if (!wilc_netdev) - return; + goto out; buff += pkt_offset; vif = netdev_priv(wilc_netdev); @@ -834,7 +842,7 @@ void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, skb = dev_alloc_skb(frame_len); if (!skb) - return; + goto out; skb->dev = wilc_netdev; @@ -847,6 +855,8 @@ void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, stats = netif_rx(skb); netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats); } +out: + srcu_read_unlock(&wilc->srcu, srcu_idx); } void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size, bool is_auth) @@ -855,7 +865,7 @@ void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size, bool is_auth) struct wilc_vif *vif; srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + wilc_for_each_vif(wilc, vif) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buff; u16 type = le16_to_cpup((__le16 *)buff); u32 type_bit = BIT(type >> 4); @@ -890,8 +900,7 @@ static const struct net_device_ops wilc_netdev_ops = { void wilc_netdev_cleanup(struct wilc *wilc) { - struct wilc_vif *vif; - int srcu_idx, ifc_cnt = 0; + struct wilc_vif *vif, *vif_tmp; if (!wilc) return; @@ -901,36 +910,21 @@ void wilc_netdev_cleanup(struct wilc *wilc) wilc->firmware = NULL; } - srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + list_for_each_entry_safe(vif, vif_tmp, &wilc->vif_list, list) { + mutex_lock(&wilc->vif_mutex); + list_del_rcu(&vif->list); + wilc->vif_num--; + mutex_unlock(&wilc->vif_mutex); + synchronize_srcu(&wilc->srcu); if (vif->ndev) unregister_netdev(vif->ndev); } - srcu_read_unlock(&wilc->srcu, srcu_idx); wilc_wfi_deinit_mon_interface(wilc, false); destroy_workqueue(wilc->hif_workqueue); - while (ifc_cnt < WILC_NUM_CONCURRENT_IFC) { - mutex_lock(&wilc->vif_mutex); - if (wilc->vif_num <= 0) { - mutex_unlock(&wilc->vif_mutex); - break; - } - vif = wilc_get_wl_to_vif(wilc); - if (!IS_ERR(vif)) - list_del_rcu(&vif->list); - - wilc->vif_num--; - mutex_unlock(&wilc->vif_mutex); - synchronize_srcu(&wilc->srcu); - ifc_cnt++; - } - wilc_wlan_cfg_deinit(wilc); wlan_deinit_locks(wilc); - wiphy_unregister(wilc->wiphy); - wiphy_free(wilc->wiphy); } EXPORT_SYMBOL_GPL(wilc_netdev_cleanup); @@ -941,7 +935,7 @@ static u8 wilc_get_available_idx(struct wilc *wl) int srcu_idx; srcu_idx = srcu_read_lock(&wl->srcu); - list_for_each_entry_rcu(vif, &wl->vif_list, list) { + wilc_for_each_vif(wl, vif) { if (vif->idx == 0) idx = 1; else @@ -955,6 +949,7 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, int vif_type, enum nl80211_iftype type, bool rtnl_locked) { + u8 mac_address[ETH_ALEN]; struct net_device *ndev; struct wilc_vif *vif; int ret; @@ -979,6 +974,28 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, vif->priv.wdev.iftype = type; vif->priv.dev = ndev; + ndev->needs_free_netdev = true; + vif->iftype = vif_type; + vif->idx = wilc_get_available_idx(wl); + vif->mac_opened = 0; + + memcpy(mac_address, wl->nv_mac_address, ETH_ALEN); + /* WILC firmware uses locally administered MAC address for the + * second virtual interface (bit 1 of first byte set), but + * since it is possibly not loaded/running yet, reproduce this behavior + * in the driver during interface creation. + */ + if (vif->idx) + mac_address[0] |= 0x2; + + eth_hw_addr_set(vif->ndev, mac_address); + + mutex_lock(&wl->vif_mutex); + list_add_tail_rcu(&vif->list, &wl->vif_list); + wl->vif_num += 1; + mutex_unlock(&wl->vif_mutex); + synchronize_srcu(&wl->srcu); + if (rtnl_locked) ret = cfg80211_register_netdevice(ndev); else @@ -986,38 +1003,23 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, if (ret) { ret = -EFAULT; - goto error; + goto error_remove_vif; } - wl->hif_workqueue = alloc_ordered_workqueue("%s-wq", WQ_MEM_RECLAIM, - ndev->name); - if (!wl->hif_workqueue) { - ret = -ENOMEM; - goto unregister_netdev; - } + return vif; - ndev->needs_free_netdev = true; - vif->iftype = vif_type; - vif->idx = wilc_get_available_idx(wl); - vif->mac_opened = 0; +error_remove_vif: mutex_lock(&wl->vif_mutex); - list_add_tail_rcu(&vif->list, &wl->vif_list); - wl->vif_num += 1; + list_del_rcu(&vif->list); + wl->vif_num -= 1; mutex_unlock(&wl->vif_mutex); synchronize_srcu(&wl->srcu); - - return vif; - -unregister_netdev: - if (rtnl_locked) - cfg80211_unregister_netdevice(ndev); - else - unregister_netdev(ndev); - error: free_netdev(ndev); return ERR_PTR(ret); } +EXPORT_SYMBOL_GPL(wilc_netdev_ifc_init); MODULE_DESCRIPTION("Atmel WILC1000 core wireless driver"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(WILC1000_FW(WILC1000_API_VER)); +MODULE_FIRMWARE(WILC3000_FW(WILC3000_API_VER)); diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h index aafe3dc44ac6..95bc8b8fe65a 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.h +++ b/drivers/net/wireless/microchip/wilc1000/netdev.h @@ -13,6 +13,8 @@ #include <net/ieee80211_radiotap.h> #include <linux/if_arp.h> #include <linux/gpio/consumer.h> +#include <linux/rculist.h> +#include <uapi/linux/if_ether.h> #include "hif.h" #include "wlan.h" @@ -29,6 +31,11 @@ #define TX_BACKOFF_WEIGHT_MS 1 +#define wilc_for_each_vif(w, v) \ + struct wilc *_w = w; \ + list_for_each_entry_srcu(v, &_w->vif_list, list, \ + srcu_read_lock_held(&_w->srcu)) + struct wilc_wfi_stats { unsigned long rx_packets; unsigned long tx_packets; @@ -214,6 +221,13 @@ struct wilc { /* protect vif list */ struct mutex vif_mutex; + /* Sleepable RCU struct to manipulate vif list. Sleepable version is + * needed over the classic RCU version because the driver's current + * design involves some sleeping code while manipulating a vif + * retrieved from vif list (so in a SRCU critical section), like: + * - sending commands to the chip, using info from retrieved vif + * - registering a new monitoring net device + */ struct srcu_struct srcu; u8 open_ifcs; @@ -258,7 +272,6 @@ struct wilc { const struct firmware *firmware; struct device *dev; - bool suspend_event; struct workqueue_struct *hif_workqueue; struct wilc_cfg cfg; @@ -273,6 +286,7 @@ struct wilc { struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)]; struct ieee80211_supported_band band; u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)]; + u8 nv_mac_address[ETH_ALEN]; }; struct wilc_wfi_mon_priv { diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c index d6d394693090..af970f999111 100644 --- a/drivers/net/wireless/microchip/wilc1000/sdio.c +++ b/drivers/net/wireless/microchip/wilc1000/sdio.c @@ -24,6 +24,9 @@ MODULE_DEVICE_TABLE(sdio, wilc_sdio_ids); #define WILC_SDIO_BLOCK_SIZE 512 +static int wilc_sdio_init(struct wilc *wilc, bool resume); +static int wilc_sdio_deinit(struct wilc *wilc); + struct wilc_sdio { bool irq_gpio; u32 block_size; @@ -136,9 +139,11 @@ out: static int wilc_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { + struct wilc_sdio *sdio_priv; + struct wilc_vif *vif; struct wilc *wilc; int ret; - struct wilc_sdio *sdio_priv; + sdio_priv = kzalloc(sizeof(*sdio_priv), GFP_KERNEL); if (!sdio_priv) @@ -169,19 +174,46 @@ static int wilc_sdio_probe(struct sdio_func *func, wilc->bus_data = sdio_priv; wilc->dev = &func->dev; - wilc->rtc_clk = devm_clk_get_optional(&func->card->dev, "rtc"); + wilc->rtc_clk = devm_clk_get_optional_enabled(&func->card->dev, "rtc"); if (IS_ERR(wilc->rtc_clk)) { ret = PTR_ERR(wilc->rtc_clk); goto dispose_irq; } - clk_prepare_enable(wilc->rtc_clk); + + wilc_sdio_init(wilc, false); + + ret = wilc_get_chipid(wilc); + if (ret) + goto dispose_irq; + + ret = wilc_cfg80211_register(wilc); + if (ret) + goto dispose_irq; + + ret = wilc_load_mac_from_nv(wilc); + if (ret) { + pr_err("Can not retrieve MAC address from chip\n"); + goto unregister_wiphy; + } + + wilc_sdio_deinit(wilc); + + vif = wilc_netdev_ifc_init(wilc, "wlan%d", WILC_STATION_MODE, + NL80211_IFTYPE_STATION, false); + if (IS_ERR(vif)) { + ret = PTR_ERR(vif); + goto unregister_wiphy; + } dev_info(&func->dev, "Driver Initializing success\n"); return 0; +unregister_wiphy: + wiphy_unregister(wilc->wiphy); dispose_irq: irq_dispose_mapping(wilc->dev_irq_num); wilc_netdev_cleanup(wilc); + wiphy_free(wilc->wiphy); free: kfree(sdio_priv->cmd53_buf); kfree(sdio_priv); @@ -193,8 +225,9 @@ static void wilc_sdio_remove(struct sdio_func *func) struct wilc *wilc = sdio_get_drvdata(func); struct wilc_sdio *sdio_priv = wilc->bus_data; - clk_disable_unprepare(wilc->rtc_clk); wilc_netdev_cleanup(wilc); + wiphy_unregister(wilc->wiphy); + wiphy_free(wilc->wiphy); kfree(sdio_priv->cmd53_buf); kfree(sdio_priv); } @@ -225,33 +258,6 @@ static bool wilc_sdio_is_init(struct wilc *wilc) return sdio_priv->isinit; } -static int wilc_sdio_suspend(struct device *dev) -{ - struct sdio_func *func = dev_to_sdio_func(dev); - struct wilc *wilc = sdio_get_drvdata(func); - int ret; - - dev_info(dev, "sdio suspend\n"); - chip_wakeup(wilc); - - if (!IS_ERR(wilc->rtc_clk)) - clk_disable_unprepare(wilc->rtc_clk); - - if (wilc->suspend_event) { - host_sleep_notify(wilc); - chip_allow_sleep(wilc); - } - - ret = wilc_sdio_reset(wilc); - if (ret) { - dev_err(&func->dev, "Fail reset sdio\n"); - return ret; - } - sdio_claim_host(func); - - return 0; -} - static int wilc_sdio_enable_interrupt(struct wilc *dev) { struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev); @@ -617,7 +623,52 @@ static int wilc_sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) static int wilc_sdio_deinit(struct wilc *wilc) { + struct sdio_func *func = dev_to_sdio_func(wilc->dev); struct wilc_sdio *sdio_priv = wilc->bus_data; + struct sdio_cmd52 cmd; + int ret; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + + /* Disable all functions interrupts */ + cmd.address = SDIO_CCCR_IENx; + cmd.data = 0; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, "Failed to disable functions interrupts\n"); + return ret; + } + + /* Disable all functions */ + cmd.address = SDIO_CCCR_IOEx; + cmd.data = 0; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed to reset all functions\n"); + return ret; + } + + /* Disable CSA */ + cmd.read_write = 0; + cmd.address = SDIO_FBR_BASE(1); + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed to read CSA for function 1\n"); + return ret; + } + cmd.read_write = 1; + cmd.address = SDIO_FBR_BASE(1); + cmd.data &= ~SDIO_FBR_ENABLE_CSA; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed to disable CSA for function 1\n"); + return ret; + } sdio_priv->isinit = false; return 0; @@ -629,7 +680,6 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume) struct wilc_sdio *sdio_priv = wilc->bus_data; struct sdio_cmd52 cmd; int loop, ret; - u32 chipid; /** * function 0 csa enable @@ -718,18 +768,6 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume) return ret; } - /** - * make sure can read back chip id correctly - **/ - if (!resume) { - ret = wilc_sdio_read_reg(wilc, WILC_CHIPID, &chipid); - if (ret) { - dev_err(&func->dev, "Fail cmd read chip id...\n"); - return ret; - } - dev_err(&func->dev, "chipid (%08x)\n", chipid); - } - sdio_priv->isinit = true; return 0; } @@ -777,13 +815,19 @@ static int wilc_sdio_read_int(struct wilc *wilc, u32 *int_status) cmd.address = WILC_SDIO_EXT_IRQ_FLAG_REG; } else { cmd.function = 0; - cmd.address = WILC_SDIO_IRQ_FLAG_REG; + cmd.address = is_wilc1000(wilc->chipid) ? + WILC1000_SDIO_IRQ_FLAG_REG : + WILC3000_SDIO_IRQ_FLAG_REG; } cmd.raw = 0; cmd.read_write = 0; cmd.data = 0; wilc_sdio_cmd52(wilc, &cmd); irq_flags = cmd.data; + + if (sdio_priv->irq_gpio) + irq_flags &= is_wilc1000(wilc->chipid) ? 0x1f : 0x0f; + tmp |= FIELD_PREP(IRG_FLAGS_MASK, cmd.data); if (FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags)) @@ -805,22 +849,56 @@ static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val) if (sdio_priv->irq_gpio) reg = val & (BIT(MAX_NUM_INT) - 1); - /* select VMM table 0 */ - if (val & SEL_VMM_TBL0) - reg |= BIT(5); - /* select VMM table 1 */ - if (val & SEL_VMM_TBL1) - reg |= BIT(6); - /* enable VMM */ - if (val & EN_VMM) - reg |= BIT(7); + if (is_wilc1000(wilc->chipid)) { + /* select VMM table 0 */ + if (val & SEL_VMM_TBL0) + reg |= BIT(5); + /* select VMM table 1 */ + if (val & SEL_VMM_TBL1) + reg |= BIT(6); + /* enable VMM */ + if (val & EN_VMM) + reg |= BIT(7); + } else { + if (sdio_priv->irq_gpio && reg) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC3000_SDIO_IRQ_FLAG_REG; + cmd.data = reg; + + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set 0xfe data (%d) ...\n", + __LINE__); + return ret; + } + } + + reg = 0; + /* select VMM table 0 */ + if (val & SEL_VMM_TBL0) + reg |= BIT(0); + /* select VMM table 1 */ + if (val & SEL_VMM_TBL1) + reg |= BIT(1); + /* enable VMM */ + if (val & EN_VMM) + reg |= BIT(2); + } + if (reg) { struct sdio_cmd52 cmd; cmd.read_write = 1; cmd.function = 0; cmd.raw = 0; - cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG; + cmd.address = is_wilc1000(wilc->chipid) ? + WILC1000_SDIO_IRQ_CLEAR_FLAG_REG : + WILC3000_SDIO_VMM_TBL_CTRL_REG; cmd.data = reg; ret = wilc_sdio_cmd52(wilc, &cmd); @@ -838,27 +916,12 @@ static int wilc_sdio_sync_ext(struct wilc *wilc, int nint) { struct sdio_func *func = dev_to_sdio_func(wilc->dev); struct wilc_sdio *sdio_priv = wilc->bus_data; - u32 reg; if (nint > MAX_NUM_INT) { dev_err(&func->dev, "Too many interrupts (%d)...\n", nint); return -EINVAL; } - /** - * Disable power sequencer - **/ - if (wilc_sdio_read_reg(wilc, WILC_MISC, ®)) { - dev_err(&func->dev, "Failed read misc reg...\n"); - return -EINVAL; - } - - reg &= ~BIT(8); - if (wilc_sdio_write_reg(wilc, WILC_MISC, reg)) { - dev_err(&func->dev, "Failed write misc reg...\n"); - return -EINVAL; - } - if (sdio_priv->irq_gpio) { u32 reg; int ret, i; @@ -942,22 +1005,48 @@ static const struct wilc_hif_func wilc_hif_sdio = { .hif_is_init = wilc_sdio_is_init, }; +static int wilc_sdio_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct wilc *wilc = sdio_get_drvdata(func); + int ret; + + dev_info(dev, "sdio suspend\n"); + + if (!wilc->initialized) + return 0; + + if (!IS_ERR(wilc->rtc_clk)) + clk_disable_unprepare(wilc->rtc_clk); + + ret = host_sleep_notify(wilc); + if (ret) { + clk_prepare_enable(wilc->rtc_clk); + return ret; + } + + wilc_sdio_disable_interrupt(wilc); + + return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); +} + static int wilc_sdio_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct wilc *wilc = sdio_get_drvdata(func); dev_info(dev, "sdio resume\n"); - sdio_release_host(func); - chip_wakeup(wilc); - wilc_sdio_init(wilc, true); - if (wilc->suspend_event) - host_wakeup_notify(wilc); + if (!wilc->initialized) + return 0; + + if (!IS_ERR(wilc->rtc_clk)) + clk_prepare_enable(wilc->rtc_clk); - chip_allow_sleep(wilc); + wilc_sdio_init(wilc, true); + wilc_sdio_enable_interrupt(wilc); - return 0; + return host_wakeup_notify(wilc); } static const struct of_device_id wilc_of_match[] = { @@ -981,8 +1070,7 @@ static struct sdio_driver wilc_sdio_driver = { .of_match_table = wilc_of_match, } }; -module_driver(wilc_sdio_driver, - sdio_register_driver, - sdio_unregister_driver); +module_sdio_driver(wilc_sdio_driver); + MODULE_DESCRIPTION("Atmel WILC1000 SDIO wireless driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 1d8b241ce43c..5bcabb7decea 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -42,7 +42,7 @@ MODULE_PARM_DESC(enable_crc16, #define WILC_SPI_RSP_HDR_EXTRA_DATA 8 struct wilc_spi { - bool isinit; /* true if SPI protocol has been configured */ + bool isinit; /* true if wilc_spi_init was successful */ bool probing_crc; /* true if we're probing chip's CRC config */ bool crc7_enabled; /* true if crc7 is currently enabled */ bool crc16_enabled; /* true if crc16 is currently enabled */ @@ -55,6 +55,8 @@ struct wilc_spi { static const struct wilc_hif_func wilc_hif_spi; static int wilc_spi_reset(struct wilc *wilc); +static int wilc_spi_configure_bus_protocol(struct wilc *wilc); +static int wilc_validate_chipid(struct wilc *wilc); /******************************************** * @@ -192,11 +194,11 @@ static void wilc_wlan_power(struct wilc *wilc, bool on) /* assert ENABLE: */ gpiod_set_value(gpios->enable, 1); mdelay(5); - /* assert RESET: */ - gpiod_set_value(gpios->reset, 1); - } else { /* deassert RESET: */ gpiod_set_value(gpios->reset, 0); + } else { + /* assert RESET: */ + gpiod_set_value(gpios->reset, 1); /* deassert ENABLE: */ gpiod_set_value(gpios->enable, 0); } @@ -204,9 +206,10 @@ static void wilc_wlan_power(struct wilc *wilc, bool on) static int wilc_bus_probe(struct spi_device *spi) { - int ret; - struct wilc *wilc; struct wilc_spi *spi_priv; + struct wilc_vif *vif; + struct wilc *wilc; + int ret; spi_priv = kzalloc(sizeof(*spi_priv), GFP_KERNEL); if (!spi_priv) @@ -225,17 +228,53 @@ static int wilc_bus_probe(struct spi_device *spi) if (ret < 0) goto netdev_cleanup; - wilc->rtc_clk = devm_clk_get_optional(&spi->dev, "rtc"); + wilc->rtc_clk = devm_clk_get_optional_enabled(&spi->dev, "rtc"); if (IS_ERR(wilc->rtc_clk)) { ret = PTR_ERR(wilc->rtc_clk); goto netdev_cleanup; } - clk_prepare_enable(wilc->rtc_clk); + dev_info(&spi->dev, "Selected CRC config: crc7=%s, crc16=%s\n", + enable_crc7 ? "on" : "off", enable_crc16 ? "on" : "off"); + + /* we need power to configure the bus protocol and to read the chip id: */ + + wilc_wlan_power(wilc, true); + + ret = wilc_spi_configure_bus_protocol(wilc); + if (ret) + goto power_down; + + ret = wilc_get_chipid(wilc); + if (ret) + goto power_down; + + ret = wilc_cfg80211_register(wilc); + if (ret) + goto power_down; + + ret = wilc_load_mac_from_nv(wilc); + if (ret) { + pr_err("Can not retrieve MAC address from chip\n"); + goto unregister_wiphy; + } + + wilc_wlan_power(wilc, false); + vif = wilc_netdev_ifc_init(wilc, "wlan%d", WILC_STATION_MODE, + NL80211_IFTYPE_STATION, false); + if (IS_ERR(vif)) { + ret = PTR_ERR(vif); + goto unregister_wiphy; + } return 0; +unregister_wiphy: + wiphy_unregister(wilc->wiphy); +power_down: + wilc_wlan_power(wilc, false); netdev_cleanup: wilc_netdev_cleanup(wilc); + wiphy_free(wilc->wiphy); free: kfree(spi_priv); return ret; @@ -246,8 +285,9 @@ static void wilc_bus_remove(struct spi_device *spi) struct wilc *wilc = spi_get_drvdata(spi); struct wilc_spi *spi_priv = wilc->bus_data; - clk_disable_unprepare(wilc->rtc_clk); wilc_netdev_cleanup(wilc); + wiphy_unregister(wilc->wiphy); + wiphy_free(wilc->wiphy); kfree(spi_priv); } @@ -301,7 +341,6 @@ static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len) memset(&msg, 0, sizeof(msg)); spi_message_init(&msg); - msg.spi = spi; spi_message_add_tail(&tr, &msg); ret = spi_sync(spi, &msg); @@ -344,7 +383,6 @@ static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen) memset(&msg, 0, sizeof(msg)); spi_message_init(&msg); - msg.spi = spi; spi_message_add_tail(&tr, &msg); ret = spi_sync(spi, &msg); @@ -382,8 +420,6 @@ static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen) memset(&msg, 0, sizeof(msg)); spi_message_init(&msg); - msg.spi = spi; - spi_message_add_tail(&tr, &msg); ret = spi_sync(spi, &msg); if (ret < 0) @@ -477,7 +513,7 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) ********************************************/ static u8 wilc_get_crc7(u8 *buffer, u32 len) { - return crc7_be(0xfe, buffer, len); + return crc7_be(0xfe, buffer, len) | 0x01; } static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, @@ -1106,26 +1142,34 @@ static int wilc_spi_deinit(struct wilc *wilc) static int wilc_spi_init(struct wilc *wilc, bool resume) { - struct spi_device *spi = to_spi_device(wilc->dev); struct wilc_spi *spi_priv = wilc->bus_data; - u32 reg; - u32 chipid; - int ret, i; + int ret; if (spi_priv->isinit) { /* Confirm we can read chipid register without error: */ - ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); - if (ret == 0) + if (wilc_validate_chipid(wilc) == 0) return 0; - - dev_err(&spi->dev, "Fail cmd read chip id...\n"); } wilc_wlan_power(wilc, true); - /* - * configure protocol - */ + ret = wilc_spi_configure_bus_protocol(wilc); + if (ret) { + wilc_wlan_power(wilc, false); + return ret; + } + + spi_priv->isinit = true; + + return 0; +} + +static int wilc_spi_configure_bus_protocol(struct wilc *wilc) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + struct wilc_spi *spi_priv = wilc->bus_data; + u32 reg; + int ret, i; /* * Infer the CRC settings that are currently in effect. This @@ -1177,6 +1221,15 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) spi_priv->probing_crc = false; + return 0; +} + +static int wilc_validate_chipid(struct wilc *wilc) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + u32 chipid; + int ret; + /* * make sure can read chip id without protocol error */ @@ -1185,9 +1238,10 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) dev_err(&spi->dev, "Fail cmd read chip id...\n"); return ret; } - - spi_priv->isinit = true; - + if (!is_wilc1000(chipid) && !is_wilc3000(chipid)) { + dev_err(&spi->dev, "Unknown chip id 0x%x\n", chipid); + return -ENODEV; + } return 0; } diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 9eb115c79c90..9d80adc45d6b 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -12,25 +12,6 @@ #define WAKE_UP_TRIAL_RETRY 10000 -static inline bool is_wilc1000(u32 id) -{ - return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID; -} - -static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire) -{ - mutex_lock(&wilc->hif_cs); - if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode) - chip_wakeup(wilc); -} - -static inline void release_bus(struct wilc *wilc, enum bus_release release) -{ - if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode) - chip_allow_sleep(wilc); - mutex_unlock(&wilc->hif_cs); -} - static void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num, struct txq_entry_t *tqe) { @@ -560,7 +541,7 @@ static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc) return rqe; } -void chip_allow_sleep(struct wilc *wilc) +static int chip_allow_sleep_wilc1000(struct wilc *wilc) { u32 reg = 0; const struct wilc_hif_func *hif_func = wilc->hif_func; @@ -589,7 +570,7 @@ void chip_allow_sleep(struct wilc *wilc) while (--trials) { ret = hif_func->hif_read_reg(wilc, to_host_from_fw_reg, ®); if (ret) - return; + return ret; if ((reg & to_host_from_fw_bit) == 0) break; } @@ -599,28 +580,62 @@ void chip_allow_sleep(struct wilc *wilc) /* Clear bit 1 */ ret = hif_func->hif_read_reg(wilc, wakeup_reg, ®); if (ret) - return; + return ret; if (reg & wakeup_bit) { reg &= ~wakeup_bit; ret = hif_func->hif_write_reg(wilc, wakeup_reg, reg); if (ret) - return; + return ret; } ret = hif_func->hif_read_reg(wilc, from_host_to_fw_reg, ®); if (ret) - return; + return ret; if (reg & from_host_to_fw_bit) { reg &= ~from_host_to_fw_bit; ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, reg); if (ret) - return; + return ret; + } + return 0; +} + +static int chip_allow_sleep_wilc3000(struct wilc *wilc) +{ + u32 reg = 0; + int ret; + const struct wilc_hif_func *hif_func = wilc->hif_func; + + if (wilc->io_type == WILC_HIF_SDIO) { + ret = hif_func->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, ®); + if (ret) + return ret; + ret = hif_func->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG, + reg & ~WILC_SDIO_WAKEUP_BIT); + if (ret) + return ret; + } else { + ret = hif_func->hif_read_reg(wilc, WILC_SPI_WAKEUP_REG, ®); + if (ret) + return ret; + ret = hif_func->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG, + reg & ~WILC_SPI_WAKEUP_BIT); + if (ret) + return ret; } + return 0; } -EXPORT_SYMBOL_GPL(chip_allow_sleep); -void chip_wakeup(struct wilc *wilc) +static int chip_allow_sleep(struct wilc *wilc) +{ + if (is_wilc1000(wilc->chipid)) + return chip_allow_sleep_wilc1000(wilc); + else + return chip_allow_sleep_wilc3000(wilc); +} + +static int chip_wakeup_wilc1000(struct wilc *wilc) { u32 ret = 0; u32 clk_status_val = 0, trials = 0; @@ -632,15 +647,15 @@ void chip_wakeup(struct wilc *wilc) if (wilc->io_type == WILC_HIF_SDIO) { wakeup_reg = WILC_SDIO_WAKEUP_REG; wakeup_bit = WILC_SDIO_WAKEUP_BIT; - clk_status_reg = WILC_SDIO_CLK_STATUS_REG; - clk_status_bit = WILC_SDIO_CLK_STATUS_BIT; + clk_status_reg = WILC1000_SDIO_CLK_STATUS_REG; + clk_status_bit = WILC1000_SDIO_CLK_STATUS_BIT; from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG; from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT; } else { wakeup_reg = WILC_SPI_WAKEUP_REG; wakeup_bit = WILC_SPI_WAKEUP_BIT; - clk_status_reg = WILC_SPI_CLK_STATUS_REG; - clk_status_bit = WILC_SPI_CLK_STATUS_BIT; + clk_status_reg = WILC1000_SPI_CLK_STATUS_REG; + clk_status_bit = WILC1000_SPI_CLK_STATUS_BIT; from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG; from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT; } @@ -649,20 +664,20 @@ void chip_wakeup(struct wilc *wilc) ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, from_host_to_fw_bit); if (ret) - return; + return ret; /* Set wake-up bit */ ret = hif_func->hif_write_reg(wilc, wakeup_reg, wakeup_bit); if (ret) - return; + return ret; while (trials < WAKE_UP_TRIAL_RETRY) { ret = hif_func->hif_read_reg(wilc, clk_status_reg, &clk_status_val); if (ret) { pr_err("Bus error %d %x\n", ret, clk_status_val); - return; + return ret; } if (clk_status_val & clk_status_bit) break; @@ -671,29 +686,135 @@ void chip_wakeup(struct wilc *wilc) } if (trials >= WAKE_UP_TRIAL_RETRY) { pr_err("Failed to wake-up the chip\n"); - return; + return -ETIMEDOUT; } /* Sometimes spi fail to read clock regs after reading * writing clockless registers */ if (wilc->io_type == WILC_HIF_SPI) wilc->hif_func->hif_reset(wilc); + + return 0; +} + +static int chip_wakeup_wilc3000(struct wilc *wilc) +{ + u32 wakeup_reg_val, clk_status_reg_val, trials = 0; + u32 wakeup_reg, wakeup_bit; + u32 clk_status_reg, clk_status_bit; + int wake_seq_trials = 5; + const struct wilc_hif_func *hif_func = wilc->hif_func; + + if (wilc->io_type == WILC_HIF_SDIO) { + wakeup_reg = WILC_SDIO_WAKEUP_REG; + wakeup_bit = WILC_SDIO_WAKEUP_BIT; + clk_status_reg = WILC3000_SDIO_CLK_STATUS_REG; + clk_status_bit = WILC3000_SDIO_CLK_STATUS_BIT; + } else { + wakeup_reg = WILC_SPI_WAKEUP_REG; + wakeup_bit = WILC_SPI_WAKEUP_BIT; + clk_status_reg = WILC3000_SPI_CLK_STATUS_REG; + clk_status_bit = WILC3000_SPI_CLK_STATUS_BIT; + } + + hif_func->hif_read_reg(wilc, wakeup_reg, &wakeup_reg_val); + do { + hif_func->hif_write_reg(wilc, wakeup_reg, wakeup_reg_val | + wakeup_bit); + /* Check the clock status */ + hif_func->hif_read_reg(wilc, clk_status_reg, + &clk_status_reg_val); + + /* In case of clocks off, wait 1ms, and check it again. + * if still off, wait for another 1ms, for a total wait of 3ms. + * If still off, redo the wake up sequence + */ + while ((clk_status_reg_val & clk_status_bit) == 0 && + (++trials % 4) != 0) { + /* Wait for the chip to stabilize*/ + usleep_range(1000, 1100); + + /* Make sure chip is awake. This is an extra step that + * can be removed later to avoid the bus access + * overhead + */ + hif_func->hif_read_reg(wilc, clk_status_reg, + &clk_status_reg_val); + } + /* in case of failure, Reset the wakeup bit to introduce a new + * edge on the next loop + */ + if ((clk_status_reg_val & clk_status_bit) == 0) { + hif_func->hif_write_reg(wilc, wakeup_reg, + wakeup_reg_val & (~wakeup_bit)); + /* added wait before wakeup sequence retry */ + usleep_range(200, 300); + } + } while ((clk_status_reg_val & clk_status_bit) == 0 && wake_seq_trials-- > 0); + if (!wake_seq_trials) + dev_err(wilc->dev, "clocks still OFF. Wake up failed\n"); + + return 0; +} + +static int chip_wakeup(struct wilc *wilc) +{ + if (is_wilc1000(wilc->chipid)) + return chip_wakeup_wilc1000(wilc); + else + return chip_wakeup_wilc3000(wilc); +} + +static inline int acquire_bus(struct wilc *wilc, enum bus_acquire acquire) +{ + int ret = 0; + + mutex_lock(&wilc->hif_cs); + if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode) { + ret = chip_wakeup(wilc); + if (ret) + mutex_unlock(&wilc->hif_cs); + } + + return ret; +} + +static inline int release_bus(struct wilc *wilc, enum bus_release release) +{ + int ret = 0; + + if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode) + ret = chip_allow_sleep(wilc); + mutex_unlock(&wilc->hif_cs); + + return ret; } -EXPORT_SYMBOL_GPL(chip_wakeup); -void host_wakeup_notify(struct wilc *wilc) +int host_wakeup_notify(struct wilc *wilc) { - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); - wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_2, 1); - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + int ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + + if (ret) + return ret; + + wilc->hif_func->hif_write_reg(wilc, is_wilc1000(wilc->chipid) ? + WILC1000_CORTUS_INTERRUPT_2 : + WILC3000_CORTUS_INTERRUPT_2, 1); + return release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); } EXPORT_SYMBOL_GPL(host_wakeup_notify); -void host_sleep_notify(struct wilc *wilc) +int host_sleep_notify(struct wilc *wilc) { - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); - wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_1, 1); - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + int ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + + if (ret) + return ret; + + wilc->hif_func->hif_write_reg(wilc, is_wilc1000(wilc->chipid) ? + WILC1000_CORTUS_INTERRUPT_1 : + WILC3000_CORTUS_INTERRUPT_1, 1); + return release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); } EXPORT_SYMBOL_GPL(host_sleep_notify); @@ -720,6 +841,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) int srcu_idx; u8 *txb = wilc->tx_buffer; struct wilc_vif *vif; + int rv; if (wilc->quit) goto out_update_cnt; @@ -730,7 +852,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) mutex_lock(&wilc->txq_add_to_head_cs); srcu_idx = srcu_read_lock(&wilc->srcu); - list_for_each_entry_rcu(vif, &wilc->vif_list, list) + wilc_for_each_vif(wilc, vif) wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev); srcu_read_unlock(&wilc->srcu, srcu_idx); @@ -790,7 +912,10 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) goto out_unlock; vmm_table[i] = 0x0; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + goto out_unlock; + counter = 0; func = wilc->hif_func; do { @@ -823,19 +948,45 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) if (ret) break; - ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2); - if (ret) - break; + if (is_wilc1000(wilc->chipid)) { + ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2); + if (ret) + break; - do { - ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); + do { + ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); + if (ret) + break; + if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) { + entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); + break; + } + } while (--timeout); + } else { + ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0); if (ret) break; - if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) { - entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); + + /* interrupt firmware */ + ret = func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_BASE, 1); + if (ret) break; - } - } while (--timeout); + + do { + ret = func->hif_read_reg(wilc, WILC_CORTUS_INTERRUPT_BASE, ®); + if (ret) + break; + if (reg == 0) { + /* Get the entries */ + ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); + if (ret) + break; + + entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); + break; + } + } while (--timeout); + } if (timeout <= 0) { ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0); break; @@ -865,7 +1016,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) goto out_release_bus; } - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + ret = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (ret) + goto out_unlock; offset = 0; i = 0; @@ -927,7 +1080,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) for (i = 0; i < NQUEUES; i++) wilc->txq[i].fw.count += ac_pkt_num_to_chip[i]; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + goto out_unlock; ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM); if (ret) @@ -936,7 +1091,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) ret = func->hif_block_tx_ext(wilc, 0, txb, offset); out_release_bus: - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (!ret && rv) + ret = rv; out_unlock: mutex_unlock(&wilc->txq_add_to_head_cs); @@ -1065,8 +1222,14 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) void wilc_handle_isr(struct wilc *wilc) { u32 int_status; + int ret; + + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) { + dev_err_ratelimited(wilc->dev, "Cannot acquire bus\n"); + return; + } - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); wilc->hif_func->hif_read_int(wilc, &int_status); if (int_status & DATA_INT_EXT) @@ -1075,7 +1238,9 @@ void wilc_handle_isr(struct wilc *wilc) if (!(int_status & (ALL_INT_EXT))) wilc_unknown_isr_ext(wilc); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + ret = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (ret) + dev_err_ratelimited(wilc->dev, "Cannot release bus\n"); } EXPORT_SYMBOL_GPL(wilc_handle_isr); @@ -1087,6 +1252,7 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u8 *dma_buffer; int ret = 0; u32 reg = 0; + int rv; blksz = BIT(12); @@ -1097,7 +1263,9 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, offset = 0; pr_debug("%s: Downloading firmware size = %d\n", __func__, buffer_size); - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); reg &= ~BIT(10); @@ -1106,11 +1274,17 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, if (reg & BIT(10)) pr_err("%s: Failed to reset\n", __func__); - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + ret = release_bus(wilc, WILC_BUS_RELEASE_ONLY); + if (ret) + goto fail; + do { addr = get_unaligned_le32(&buffer[offset]); size = get_unaligned_le32(&buffer[offset + 4]); - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + goto fail; + offset += 8; while (((int)size) && (offset < buffer_size)) { if (size <= blksz) @@ -1128,7 +1302,9 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, offset += size2; size -= size2; } - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (!ret && rv) + ret = rv; if (ret) { pr_err("%s Bus error\n", __func__); @@ -1147,7 +1323,7 @@ fail: int wilc_wlan_start(struct wilc *wilc) { u32 reg = 0; - int ret; + int ret, rv; u32 chipid; if (wilc->io_type == WILC_HIF_SDIO) { @@ -1156,7 +1332,10 @@ int wilc_wlan_start(struct wilc *wilc) } else if (wilc->io_type == WILC_HIF_SPI) { reg = 1; } - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + if (ret) + return ret; + ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg); if (ret) goto release; @@ -1165,6 +1344,9 @@ int wilc_wlan_start(struct wilc *wilc) if (wilc->io_type == WILC_HIF_SDIO && wilc->dev_irq_num) reg |= WILC_HAVE_SDIO_IRQ_GPIO; + if (is_wilc3000(wilc->chipid)) + reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC; + ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg); if (ret) goto release; @@ -1187,38 +1369,45 @@ int wilc_wlan_start(struct wilc *wilc) wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); release: - release_bus(wilc, WILC_BUS_RELEASE_ONLY); - return ret; + rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY); + return ret ? ret : rv; } int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) { u32 reg = 0; - int ret; + int ret, rv; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; - ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®); - if (ret) { - netdev_err(vif->ndev, "Error while reading reg\n"); + ret = wilc->hif_func->hif_read_reg(wilc, GLOBAL_MODE_CONTROL, ®); + if (ret) goto release; - } - ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0, - (reg | WILC_ABORT_REQ_BIT)); - if (ret) { - netdev_err(vif->ndev, "Error while writing reg\n"); + reg &= ~WILC_GLOBAL_MODE_ENABLE_WIFI; + ret = wilc->hif_func->hif_write_reg(wilc, GLOBAL_MODE_CONTROL, reg); + if (ret) goto release; - } - ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, ®); + ret = wilc->hif_func->hif_read_reg(wilc, PWR_SEQ_MISC_CTRL, ®); + if (ret) + goto release; + + reg &= ~WILC_PWR_SEQ_ENABLE_WIFI_SLEEP; + ret = wilc->hif_func->hif_write_reg(wilc, PWR_SEQ_MISC_CTRL, reg); + if (ret) + goto release; + + ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®); if (ret) { netdev_err(vif->ndev, "Error while reading reg\n"); goto release; } - reg = BIT(0); - ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg); + ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0, + (reg | WILC_ABORT_REQ_BIT)); if (ret) { netdev_err(vif->ndev, "Error while writing reg\n"); goto release; @@ -1227,9 +1416,9 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) ret = 0; release: /* host comm is disabled - we can't issue sleep command anymore: */ - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY); - return ret; + return ret ? ret : rv; } void wilc_wlan_cleanup(struct net_device *dev) @@ -1402,19 +1591,56 @@ int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, return ret; } +int wilc_get_chipid(struct wilc *wilc) +{ + u32 chipid = 0; + u32 rfrevid = 0; + + if (wilc->chipid == 0) { + wilc->hif_func->hif_read_reg(wilc, WILC3000_CHIP_ID, &chipid); + if (!is_wilc3000(chipid)) { + wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid); + wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID, + &rfrevid); + + if (!is_wilc1000(chipid)) { + wilc->chipid = 0; + return -EINVAL; + } + if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */ + if (rfrevid != 0x1) + chipid = WILC_1000_BASE_ID_2A_REV1; + } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */ + if (rfrevid == 0x4) + chipid = WILC_1000_BASE_ID_2B_REV1; + else if (rfrevid != 0x3) + chipid = WILC_1000_BASE_ID_2B_REV2; + } + } + + wilc->chipid = chipid; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wilc_get_chipid); + static int init_chip(struct net_device *dev) { - u32 chipid; u32 reg; - int ret = 0; + int ret, rv; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; - chipid = wilc_get_chipid(wilc, true); + ret = wilc_get_chipid(wilc); + if (ret) + goto release; - if ((chipid & 0xfff) != 0xa0) { + if ((wilc->chipid & 0xfff) != 0xa0) { ret = wilc->hif_func->hif_read_reg(wilc, WILC_CORTUS_RESET_MUX_SEL, ®); @@ -1439,43 +1665,81 @@ static int init_chip(struct net_device *dev) } } + if (is_wilc3000(wilc->chipid)) { + ret = wilc->hif_func->hif_read_reg(wilc, WILC3000_BOOTROM_STATUS, ®); + if (ret) { + netdev_err(dev, "failed to read WILC3000 BootROM status register\n"); + goto release; + } + + ret = wilc->hif_func->hif_write_reg(wilc, WILC3000_CORTUS_BOOT_REGISTER_2, + WILC_CORTUS_BOOT_FROM_IRAM); + if (ret) { + netdev_err(dev, "failed to write WILC3000 Boot register\n"); + goto release; + } + } + release: - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); - return ret; + return ret ? ret : rv; } -u32 wilc_get_chipid(struct wilc *wilc, bool update) +int wilc_load_mac_from_nv(struct wilc *wl) { - u32 chipid = 0; - u32 rfrevid = 0; + int ret, rv; + unsigned int i; - if (wilc->chipid == 0 || update) { - wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid); - wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID, - &rfrevid); - if (!is_wilc1000(chipid)) { - wilc->chipid = 0; - return wilc->chipid; + ret = acquire_bus(wl, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; + + for (i = 0; i < WILC_NVMEM_MAX_NUM_BANK; i++) { + int bank_offset = get_bank_offset_from_bank_index(i); + u32 reg1, reg2; + u8 invalid; + u8 used; + + ret = wl->hif_func->hif_read_reg(wl, + WILC_NVMEM_BANK_BASE + bank_offset, + ®1); + if (ret) { + pr_err("Can not read address %d lower part", i); + break; } - if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */ - if (rfrevid != 0x1) - chipid = WILC_1000_BASE_ID_2A_REV1; - } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */ - if (rfrevid == 0x4) - chipid = WILC_1000_BASE_ID_2B_REV1; - else if (rfrevid != 0x3) - chipid = WILC_1000_BASE_ID_2B_REV2; + ret = wl->hif_func->hif_read_reg(wl, + WILC_NVMEM_BANK_BASE + bank_offset + 4, + ®2); + if (ret) { + pr_err("Can not read address %d upper part", i); + break; } - wilc->chipid = chipid; + used = FIELD_GET(WILC_NVMEM_IS_BANK_USED, reg1); + invalid = FIELD_GET(WILC_NVMEM_IS_BANK_INVALID, reg1); + if (!used || invalid) + continue; + + wl->nv_mac_address[0] = FIELD_GET(GENMASK(23, 16), reg1); + wl->nv_mac_address[1] = FIELD_GET(GENMASK(15, 8), reg1); + wl->nv_mac_address[2] = FIELD_GET(GENMASK(7, 0), reg1); + wl->nv_mac_address[3] = FIELD_GET(GENMASK(31, 24), reg2); + wl->nv_mac_address[4] = FIELD_GET(GENMASK(23, 16), reg2); + wl->nv_mac_address[5] = FIELD_GET(GENMASK(15, 8), reg2); + + ret = 0; + break; } - return wilc->chipid; + + rv = release_bus(wl, WILC_BUS_RELEASE_ALLOW_SLEEP); + return ret ? ret : rv; } +EXPORT_SYMBOL_GPL(wilc_load_mac_from_nv); int wilc_wlan_init(struct net_device *dev) { - int ret = 0; + int ret = 0, rv; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc; @@ -1484,11 +1748,26 @@ int wilc_wlan_init(struct net_device *dev) wilc->quit = 0; if (!wilc->hif_func->hif_is_init(wilc)) { - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + if (ret) + return ret; + ret = wilc->hif_func->hif_init(wilc, false); - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + if (!ret) + ret = wilc_get_chipid(wilc); + rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY); + if (!ret && rv) + ret = rv; if (ret) goto fail; + + if (!is_wilc1000(wilc->chipid) && !is_wilc3000(wilc->chipid)) { + netdev_err(dev, "Unsupported chipid: %x\n", wilc->chipid); + ret = -EINVAL; + goto fail; + } + + netdev_dbg(dev, "chipid (%08x)\n", wilc->chipid); } if (!wilc->vmm_table) diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h index a72cd5cac81d..b9e7f9222ead 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan.h @@ -56,7 +56,6 @@ #define WILC_HOST_RX_CTRL (WILC_PERIPH_REG_BASE + 0x80) #define WILC_HOST_RX_EXTRA_SIZE (WILC_PERIPH_REG_BASE + 0x84) #define WILC_HOST_TX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x88) -#define WILC_MISC (WILC_PERIPH_REG_BASE + 0x428) #define WILC_INTR_REG_BASE (WILC_PERIPH_REG_BASE + 0xa00) #define WILC_INTR_ENABLE WILC_INTR_REG_BASE #define WILC_INTR2_ENABLE (WILC_INTR_REG_BASE + 4) @@ -97,8 +96,14 @@ #define WILC_SPI_WAKEUP_REG 0x1 #define WILC_SPI_WAKEUP_BIT BIT(1) -#define WILC_SPI_CLK_STATUS_REG 0x0f -#define WILC_SPI_CLK_STATUS_BIT BIT(2) +/* WILC1000 specific */ +#define WILC1000_SPI_CLK_STATUS_REG 0x0f +#define WILC1000_SPI_CLK_STATUS_BIT BIT(2) + +/* WILC3000 specific */ +#define WILC3000_SPI_CLK_STATUS_REG 0x13 +#define WILC3000_SPI_CLK_STATUS_BIT BIT(2) + #define WILC_SPI_HOST_TO_FW_REG 0x0b #define WILC_SPI_HOST_TO_FW_BIT BIT(0) @@ -124,14 +129,24 @@ #define WILC_SDIO_WAKEUP_REG 0xf0 #define WILC_SDIO_WAKEUP_BIT BIT(0) -#define WILC_SDIO_CLK_STATUS_REG 0xf1 -#define WILC_SDIO_CLK_STATUS_BIT BIT(0) +/* WILC1000 */ +#define WILC1000_SDIO_CLK_STATUS_REG 0xf1 +#define WILC1000_SDIO_CLK_STATUS_BIT BIT(0) + +#define WILC1000_SDIO_IRQ_FLAG_REG 0xf7 +#define WILC1000_SDIO_IRQ_CLEAR_FLAG_REG 0xf8 +/* WILC3000 specific */ +#define WILC3000_SDIO_CLK_STATUS_REG 0xf0 /* clk & wakeup are on same reg */ +#define WILC3000_SDIO_CLK_STATUS_BIT BIT(4) + +#define WILC3000_SDIO_VMM_TBL_CTRL_REG 0xf1 +#define WILC3000_SDIO_IRQ_FLAG_REG 0xfe + +/* Common vendor specific CCCR register */ #define WILC_SDIO_INTERRUPT_DATA_SZ_REG 0xf2 /* Read size (2 bytes) */ #define WILC_SDIO_VMM_TBL_CTRL_REG 0xf6 -#define WILC_SDIO_IRQ_FLAG_REG 0xf7 -#define WILC_SDIO_IRQ_CLEAR_FLAG_REG 0xf8 #define WILC_SDIO_HOST_TO_FW_REG 0xfa #define WILC_SDIO_HOST_TO_FW_BIT BIT(0) @@ -156,6 +171,12 @@ #define WILC_GP_REG_0 0x149c #define WILC_GP_REG_1 0x14a0 +#define GLOBAL_MODE_CONTROL 0x1614 +#define PWR_SEQ_MISC_CTRL 0x3008 + +#define WILC_GLOBAL_MODE_ENABLE_WIFI BIT(0) +#define WILC_PWR_SEQ_ENABLE_WIFI_SLEEP BIT(28) + #define WILC_HAVE_SDIO_IRQ_GPIO BIT(0) #define WILC_HAVE_USE_PMU BIT(1) #define WILC_HAVE_SLEEP_CLK_SRC_RTC BIT(2) @@ -167,8 +188,11 @@ #define WILC_HAVE_USE_IRQ_AS_HOST_WAKE BIT(8) #define WILC_CORTUS_INTERRUPT_BASE 0x10A8 -#define WILC_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4) -#define WILC_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8) +#define WILC1000_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4) +#define WILC3000_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x14) + +#define WILC1000_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8) +#define WILC3000_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x18) /* tx control register 1 to 4 for RX */ #define WILC_REG_4_TO_1_RX 0x1e1c @@ -178,6 +202,9 @@ #define WILC_CORTUS_RESET_MUX_SEL 0x1118 #define WILC_CORTUS_BOOT_REGISTER 0xc0000 +#define WILC3000_BOOTROM_STATUS 0x207ac +#define WILC3000_CORTUS_BOOT_REGISTER_2 0x4f0000 +#define WILC3000_CHIP_ID 0x3b0000 #define WILC_CORTUS_BOOT_FROM_IRAM 0x71 @@ -190,6 +217,8 @@ #define WILC_1000_BASE_ID_2B_REV1 (WILC_1000_BASE_ID_2B + 1) #define WILC_1000_BASE_ID_2B_REV2 (WILC_1000_BASE_ID_2B + 2) +#define WILC_3000_BASE_ID 0x300000 + #define WILC_CHIP_REV_FIELD GENMASK(11, 0) /******************************************** @@ -403,6 +432,16 @@ struct wilc_cfg_rsp { struct wilc_vif; +static inline bool is_wilc1000(u32 id) +{ + return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID; +} + +static inline bool is_wilc3000(u32 id) +{ + return (id & (~WILC_CHIP_REV_FIELD)) == WILC_3000_BASE_ID; +} + int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u32 buffer_size); int wilc_wlan_start(struct wilc *wilc); @@ -426,12 +465,11 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev); void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size); bool wilc_wfi_mgmt_frame_rx(struct wilc_vif *vif, u8 *buff, u32 size); -void host_wakeup_notify(struct wilc *wilc); -void host_sleep_notify(struct wilc *wilc); -void chip_allow_sleep(struct wilc *wilc); -void chip_wakeup(struct wilc *wilc); +int host_wakeup_notify(struct wilc *wilc); +int host_sleep_notify(struct wilc *wilc); int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, u32 count); int wilc_wlan_init(struct net_device *dev); -u32 wilc_get_chipid(struct wilc *wilc, bool update); +int wilc_get_chipid(struct wilc *wilc); +int wilc_load_mac_from_nv(struct wilc *wilc); #endif |