Loading drivers/net/wireless/ath/wil6210/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ wil6210-y += debug.o wil6210-y += rx_reorder.o wil6210-y += ioctl.o wil6210-y += fw.o wil6210-y += pmc.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o wil6210-y += wil_platform.o wil6210-y += ethtool.o Loading drivers/net/wireless/ath/wil6210/cfg80211.c +165 −43 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/etherdevice.h> #include "wil6210.h" #include "wmi.h" Loading Loading @@ -217,7 +218,7 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy, if (cid < 0) return -ENOENT; memcpy(mac, wil->sta[cid].addr, ETH_ALEN); ether_addr_copy(mac, wil->sta[cid].addr); wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); rc = wil_cid_fill_sinfo(wil, cid, sinfo); Loading Loading @@ -288,6 +289,26 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, } wil_dbg_misc(wil, "Start scan_request 0x%p\n", request); wil_dbg_misc(wil, "SSID count: %d", request->n_ssids); for (i = 0; i < request->n_ssids; i++) { wil_dbg_misc(wil, "SSID[%d]", i); print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, request->ssids[i].ssid, request->ssids[i].ssid_len); } if (request->n_ssids) rc = wmi_set_ssid(wil, request->ssids[0].ssid_len, request->ssids[0].ssid); else rc = wmi_set_ssid(wil, 0, NULL); if (rc) { wil_err(wil, "set SSID for scan request failed: %d\n", rc); return rc; } wil->scan_request = request; mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); Loading Loading @@ -401,11 +422,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rsn_eid = sme->ie ? cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : NULL; if (sme->privacy && !rsn_eid) { wil_err(wil, "Missing RSN IE for secure connection\n"); return -EINVAL; } if (sme->privacy && !rsn_eid) wil_info(wil, "WSC connection\n"); bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, Loading @@ -424,10 +442,17 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, wil->privacy = sme->privacy; if (wil->privacy) { /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */ rc = wmi_del_cipher_key(wil, 0, bss->bssid); /* For secure assoc, remove old keys */ rc = wmi_del_cipher_key(wil, 0, bss->bssid, WMI_KEY_USE_PAIRWISE); if (rc) { wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n"); goto out; } rc = wmi_del_cipher_key(wil, 0, bss->bssid, WMI_KEY_USE_RX_GROUP); if (rc) { wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n"); wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n"); goto out; } } Loading Loading @@ -457,11 +482,18 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, goto out; } if (wil->privacy) { if (rsn_eid) { /* regular secure connection */ conn.dot11_auth_mode = WMI_AUTH11_SHARED; conn.auth_mode = WMI_AUTH_WPA2_PSK; conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP; conn.pairwise_crypto_len = 16; } else { conn.group_crypto_type = WMI_CRYPT_AES_GCMP; conn.group_crypto_len = 16; } else { /* WSC */ conn.dot11_auth_mode = WMI_AUTH11_WSC; conn.auth_mode = WMI_AUTH_NONE; } } else { /* insecure connection */ conn.dot11_auth_mode = WMI_AUTH11_OPEN; conn.auth_mode = WMI_AUTH_NONE; } Loading @@ -478,8 +510,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, } conn.channel = ch - 1; memcpy(conn.bssid, bss->bssid, ETH_ALEN); memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); ether_addr_copy(conn.bssid, bss->bssid); ether_addr_copy(conn.dst_mac, bss->bssid); set_bit(wil_status_fwconnecting, wil->status); Loading @@ -506,6 +538,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, int rc; struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code); rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); return rc; Loading Loading @@ -560,6 +594,39 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy, return 0; } static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil, bool pairwise) { struct wireless_dev *wdev = wil->wdev; enum wmi_key_usage rc; static const char * const key_usage_str[] = { [WMI_KEY_USE_PAIRWISE] = "WMI_KEY_USE_PAIRWISE", [WMI_KEY_USE_RX_GROUP] = "WMI_KEY_USE_RX_GROUP", [WMI_KEY_USE_TX_GROUP] = "WMI_KEY_USE_TX_GROUP", }; if (pairwise) { rc = WMI_KEY_USE_PAIRWISE; } else { switch (wdev->iftype) { case NL80211_IFTYPE_STATION: rc = WMI_KEY_USE_RX_GROUP; break; case NL80211_IFTYPE_AP: rc = WMI_KEY_USE_TX_GROUP; break; default: /* TODO: Rx GTK or Tx GTK? */ wil_err(wil, "Can't determine GTK type\n"); rc = WMI_KEY_USE_RX_GROUP; break; } } wil_dbg_misc(wil, "%s() -> %s\n", __func__, key_usage_str[rc]); return rc; } static int wil_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, Loading @@ -567,13 +634,13 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, struct key_params *params) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise); /* group key is not used */ if (!pairwise) return 0; wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index, pairwise ? "PTK" : "GTK"); return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len, params->key); return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len, params->key, key_usage); } static int wil_cfg80211_del_key(struct wiphy *wiphy, Loading @@ -582,12 +649,12 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy, const u8 *mac_addr) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise); /* group key is not used */ if (!pairwise) return 0; wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index, pairwise ? "PTK" : "GTK"); return wmi_del_cipher_key(wil, key_index, mac_addr); return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage); } /* Need to be present or wiphy_new() will WARN */ Loading Loading @@ -660,11 +727,6 @@ static int wil_fix_bcon(struct wil6210_priv *wil, if (bcon->probe_resp_len <= hlen) return 0; if (!bcon->proberesp_ies) { bcon->proberesp_ies = f->u.probe_resp.variable; bcon->proberesp_ies_len = bcon->probe_resp_len - hlen; rc = 1; } if (!bcon->assocresp_ies) { bcon->assocresp_ies = f->u.probe_resp.variable; bcon->assocresp_ies_len = bcon->probe_resp_len - hlen; Loading @@ -679,9 +741,19 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, struct cfg80211_beacon_data *bcon) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); const u8 *pr_ies = NULL; size_t pr_ies_len = 0; int rc; wil_dbg_misc(wil, "%s()\n", __func__); wil_print_bcon_data(bcon); if (bcon->probe_resp_len > hlen) { pr_ies = f->u.probe_resp.variable; pr_ies_len = bcon->probe_resp_len - hlen; } if (wil_fix_bcon(wil, bcon)) { wil_dbg_misc(wil, "Fixed bcon\n"); Loading @@ -694,9 +766,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, * bcon->beacon_ies); */ rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, bcon->proberesp_ies); rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); if (rc) { wil_err(wil, "set_ie(PROBE_RESP) failed\n"); return rc; Loading Loading @@ -724,6 +794,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct cfg80211_beacon_data *bcon = &info->beacon; struct cfg80211_crypto_settings *crypto = &info->crypto; u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); const u8 *pr_ies = NULL; size_t pr_ies_len = 0; u8 hidden_ssid; wil_dbg_misc(wil, "%s()\n", __func__); Loading @@ -736,6 +811,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, channel->center_freq, info->privacy ? "secure" : "open"); wil_dbg_misc(wil, "Privacy: %d auth_type %d\n", info->privacy, info->auth_type); wil_dbg_misc(wil, "Hidden SSID mode: %d\n", info->hidden_ssid); wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval, info->dtim_period); print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, Loading @@ -743,6 +820,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_print_bcon_data(bcon); wil_print_crypto(wil, crypto); if (bcon->probe_resp_len > hlen) { pr_ies = f->u.probe_resp.variable; pr_ies_len = bcon->probe_resp_len - hlen; } if (wil_fix_bcon(wil, bcon)) { wil_dbg_misc(wil, "Fixed bcon\n"); wil_print_bcon_data(bcon); Loading Loading @@ -770,20 +852,46 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, * bcon->beacon_ies); */ wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, bcon->proberesp_ies); wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, bcon->assocresp_ies); wil->privacy = info->privacy; switch (info->hidden_ssid) { case NL80211_HIDDEN_SSID_NOT_IN_USE: hidden_ssid = WMI_HIDDEN_SSID_DISABLED; break; case NL80211_HIDDEN_SSID_ZERO_LEN: hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY; break; case NL80211_HIDDEN_SSID_ZERO_CONTENTS: hidden_ssid = WMI_HIDDEN_SSID_CLEAR; break; default: rc = -EOPNOTSUPP; goto out; } netif_carrier_on(ndev); rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); channel->hw_value, hidden_ssid); if (rc) netif_carrier_off(ndev); goto err_pcp_start; rc = wil_bcast_init(wil); if (rc) goto err_bcast; goto out; /* success */ err_bcast: wmi_pcp_stop(wil); err_pcp_start: netif_carrier_off(ndev); out: mutex_unlock(&wil->mutex); return rc; Loading @@ -804,13 +912,9 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wmi_pcp_stop(wil); __wil_down(wil); __wil_up(wil); mutex_unlock(&wil->mutex); /* some functions above might fail (e.g. __wil_up). Nevertheless, we * return success because AP has stopped */ return 0; } Loading @@ -819,6 +923,9 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy, { struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s(%pM, reason=%d)\n", __func__, mac, WLAN_REASON_UNSPECIFIED); mutex_lock(&wil->mutex); wil6210_disconnect(wil, mac, WLAN_REASON_UNSPECIFIED, false); mutex_unlock(&wil->mutex); Loading Loading @@ -916,6 +1023,21 @@ static int wil_cfg80211_probe_client(struct wiphy *wiphy, return 0; } static int wil_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); if (params->ap_isolate >= 0) { wil_dbg_misc(wil, "%s(ap_isolate %d => %d)\n", __func__, wil->ap_isolate, params->ap_isolate); wil->ap_isolate = params->ap_isolate; } return 0; } static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, Loading @@ -936,12 +1058,12 @@ static struct cfg80211_ops wil_cfg80211_ops = { .stop_ap = wil_cfg80211_stop_ap, .del_station = wil_cfg80211_del_station, .probe_client = wil_cfg80211_probe_client, .change_bss = wil_cfg80211_change_bss, }; static void wil_wiphy_init(struct wiphy *wiphy) { /* TODO: set real value */ wiphy->max_scan_ssids = 10; wiphy->max_scan_ssids = 1; wiphy->max_scan_ie_len = WMI_MAX_IE_LEN; wiphy->max_num_pmkids = 0 /* TODO: */; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | Loading drivers/net/wireless/ath/wil6210/debugfs.c +119 −13 Original line number Diff line number Diff line /* * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading @@ -24,6 +24,7 @@ #include "wil6210.h" #include "wmi.h" #include "txrx.h" #include "pmc.h" /* Nasty hack. Better have per device instances */ static u32 mem_addr; Loading Loading @@ -121,12 +122,20 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) snprintf(name, sizeof(name), "tx_%2d", i); if (cid < WIL6210_MAX_CID) seq_printf(s, "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %s\n", "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n", wil->sta[cid].addr, cid, tid, txdata->agg_wsize, txdata->agg_timeout, txdata->dot1x_open ? "+" : "-", txdata->agg_wsize, txdata->agg_timeout, txdata->agg_amsdu ? "+" : "-", used, avail, sidle); else seq_printf(s, "\nBroadcast 1x%s [%3d|%3d] idle %s\n", txdata->dot1x_open ? "+" : "-", used, avail, sidle); wil_print_vring(s, wil, name, vring, '_', 'H'); } Loading Loading @@ -626,7 +635,7 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf, struct wil6210_priv *wil = file->private_data; int rc; char *kbuf = kmalloc(len + 1, GFP_KERNEL); char cmd[8]; char cmd[9]; int p1, p2, p3; if (!kbuf) Loading Loading @@ -696,6 +705,89 @@ static const struct file_operations fops_back = { .open = simple_open, }; /* pmc control, write: * - "alloc <num descriptors> <descriptor_size>" to allocate PMC * - "free" to release memory allocated for PMC */ static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; int rc; char *kbuf = kmalloc(len + 1, GFP_KERNEL); char cmd[9]; int num_descs, desc_size; if (!kbuf) return -ENOMEM; rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); if (rc != len) { kfree(kbuf); return rc >= 0 ? -EIO : rc; } kbuf[len] = '\0'; rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size); kfree(kbuf); if (rc < 0) return rc; if (rc < 1) { wil_err(wil, "pmccfg: no params given\n"); return -EINVAL; } if (0 == strcmp(cmd, "alloc")) { if (rc != 3) { wil_err(wil, "pmccfg: alloc requires 2 params\n"); return -EINVAL; } wil_pmc_alloc(wil, num_descs, desc_size); } else if (0 == strcmp(cmd, "free")) { if (rc != 1) { wil_err(wil, "pmccfg: free does not have any params\n"); return -EINVAL; } wil_pmc_free(wil, true); } else { wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd); return -EINVAL; } return len; } static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; char text[256]; char help[] = "pmc control, write:\n" " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n" " - \"free\" to free memory allocated for pmc\n"; sprintf(text, "Last command status: %d\n\n%s", wil_pmc_last_cmd_status(wil), help); return simple_read_from_buffer(user_buf, count, ppos, text, strlen(text) + 1); } static const struct file_operations fops_pmccfg = { .read = wil_read_pmccfg, .write = wil_write_pmccfg, .open = simple_open, }; static const struct file_operations fops_pmcdata = { .open = simple_open, .read = wil_pmc_read, .llseek = wil_pmc_llseek, }; /*---tx_mgmt---*/ /* Write mgmt frame to this file to send it */ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, Loading Loading @@ -1105,8 +1197,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) status = "connected"; break; } seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, (p->data_port_open ? " data_port_open" : "")); seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); if (p->status == wil_sta_connected) { rc = wil_cid_fill_sinfo(wil, i, &sinfo); Loading Loading @@ -1269,7 +1360,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) { struct wil6210_priv *wil = s->private; int i, tid; int i, tid, mcs; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; Loading @@ -1286,8 +1377,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) status = "connected"; break; } seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, (p->data_port_open ? " data_port_open" : "")); seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); if (p->status == wil_sta_connected) { spin_lock_bh(&p->tid_rx_lock); Loading @@ -1300,6 +1390,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) } } spin_unlock_bh(&p->tid_rx_lock); seq_puts(s, "Rx/MCS:"); for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs); mcs++) seq_printf(s, " %lld", p->stats.rx_per_mcs[mcs]); seq_puts(s, "\n"); } } Loading Loading @@ -1357,6 +1453,8 @@ static const struct { {"tx_mgmt", S_IWUSR, &fops_txmgmt}, {"wmi_send", S_IWUSR, &fops_wmi}, {"back", S_IRUGO | S_IWUSR, &fops_back}, {"pmccfg", S_IRUGO | S_IWUSR, &fops_pmccfg}, {"pmcdata", S_IRUGO, &fops_pmcdata}, {"temp", S_IRUGO, &fops_temp}, {"freq", S_IRUGO, &fops_freq}, {"link", S_IRUGO, &fops_link}, Loading Loading @@ -1405,6 +1503,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(fw_version, S_IRUGO, doff_u32), WIL_FIELD(hw_version, S_IRUGO, doff_x32), WIL_FIELD(recovery_count, S_IRUGO, doff_u32), WIL_FIELD(ap_isolate, S_IRUGO, doff_u32), {}, }; Loading Loading @@ -1433,6 +1532,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) if (IS_ERR_OR_NULL(dbg)) return -ENODEV; wil_pmc_init(wil); wil6210_debugfs_init_files(wil, dbg); wil6210_debugfs_init_isr(wil, dbg); wil6210_debugfs_init_blobs(wil, dbg); Loading @@ -1452,4 +1553,9 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil) { debugfs_remove_recursive(wil->debug); wil->debug = NULL; /* free pmc memory without sending command to fw, as it will * be reset on the way down anyway */ wil_pmc_free(wil, false); } drivers/net/wireless/ath/wil6210/main.c +60 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,10 @@ #define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000 #define WAIT_FOR_DISCONNECT_INTERVAL_MS 10 bool debug_fw; /* = false; */ module_param(debug_fw, bool, S_IRUGO); MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug"); bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery"); Loading Loading @@ -68,6 +72,7 @@ MODULE_PARM_DESC(mtu_max, " Max MTU value."); static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT; static int ring_order_set(const char *val, const struct kernel_param *kp) { Loading Loading @@ -95,6 +100,8 @@ module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO); MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order"); module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO); MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order"); module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, S_IRUGO); MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order"); #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ Loading Loading @@ -145,7 +152,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid, sta->status); sta->data_port_open = false; if (sta->status != wil_sta_unused) { if (!from_event) wmi_disconnect_sta(wil, sta->addr, reason_code); Loading Loading @@ -216,6 +222,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: wil_bcast_fini(wil); netif_tx_stop_all_queues(ndev); netif_carrier_off(ndev); Loading Loading @@ -360,6 +367,36 @@ static int wil_find_free_vring(struct wil6210_priv *wil) return -EINVAL; } int wil_bcast_init(struct wil6210_priv *wil) { int ri = wil->bcast_vring, rc; if ((ri >= 0) && wil->vring_tx[ri].va) return 0; ri = wil_find_free_vring(wil); if (ri < 0) return ri; wil->bcast_vring = ri; rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order); if (rc) wil->bcast_vring = -1; return rc; } void wil_bcast_fini(struct wil6210_priv *wil) { int ri = wil->bcast_vring; if (ri < 0) return; wil->bcast_vring = -1; wil_vring_fini_tx(wil, ri); } static void wil_connect_worker(struct work_struct *work) { int rc; Loading Loading @@ -407,6 +444,7 @@ int wil_priv_init(struct wil6210_priv *wil) init_completion(&wil->wmi_call); wil->pending_connect_cid = -1; wil->bcast_vring = -1; setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil); Loading Loading @@ -515,7 +553,7 @@ static inline void wil_release_cpu(struct wil6210_priv *wil) static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; u32 x; u32 x, x1 = 0; wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); Loading Loading @@ -570,12 +608,16 @@ static int wil_target_reset(struct wil6210_priv *wil) do { msleep(RST_DELAY); x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready)); if (x1 != x) { wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x); x1 = x; } if (delay++ > RST_COUNT) { wil_err(wil, "Reset not completed, bl.ready 0x%08x\n", x); return -ETIME; } } while (!(x & BIT_BL_READY)); } while (x != BIT_BL_READY); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); Loading Loading @@ -654,8 +696,20 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) WARN_ON(!mutex_is_locked(&wil->mutex)); WARN_ON(test_bit(wil_status_napi_en, wil->status)); if (debug_fw) { static const u8 mac[ETH_ALEN] = { 0x00, 0xde, 0xad, 0x12, 0x34, 0x56, }; struct net_device *ndev = wil_to_ndev(wil); ether_addr_copy(ndev->perm_addr, mac); ether_addr_copy(ndev->dev_addr, ndev->perm_addr); return 0; } cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); wil_bcast_fini(wil); /* prevent NAPI from being scheduled */ bitmap_zero(wil->status, wil_status_last); Loading Loading @@ -714,6 +768,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* init after reset */ wil->pending_connect_cid = -1; wil->ap_isolate = 0; reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_call); Loading @@ -723,6 +778,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* we just started MAC, wait for FW ready */ rc = wil_wait_for_fw_ready(wil); if (rc == 0) /* check FW is responsive */ rc = wmi_echo(wil); } return rc; Loading drivers/net/wireless/ath/wil6210/netdev.c +7 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,11 @@ static int wil_open(struct net_device *ndev) wil_dbg_misc(wil, "%s()\n", __func__); if (debug_fw) { wil_err(wil, "%s() while in debug_fw mode\n", __func__); return -EINVAL; } return wil_up(wil); } Loading Loading @@ -82,7 +87,7 @@ static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) wil_rx_handle(wil, "a); done = budget - quota; if (done <= 1) { /* burst ends - only one packet processed */ if (done < budget) { napi_complete(napi); wil6210_unmask_irq_rx(wil); wil_dbg_txrx(wil, "NAPI RX complete\n"); Loading Loading @@ -110,7 +115,7 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) tx_done += wil_tx_complete(wil, i); } if (tx_done <= 1) { /* burst ends - only one packet processed */ if (tx_done < budget) { napi_complete(napi); wil6210_unmask_irq_tx(wil); wil_dbg_txrx(wil, "NAPI TX complete\n"); Loading Loading
drivers/net/wireless/ath/wil6210/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ wil6210-y += debug.o wil6210-y += rx_reorder.o wil6210-y += ioctl.o wil6210-y += fw.o wil6210-y += pmc.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o wil6210-y += wil_platform.o wil6210-y += ethtool.o Loading
drivers/net/wireless/ath/wil6210/cfg80211.c +165 −43 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/etherdevice.h> #include "wil6210.h" #include "wmi.h" Loading Loading @@ -217,7 +218,7 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy, if (cid < 0) return -ENOENT; memcpy(mac, wil->sta[cid].addr, ETH_ALEN); ether_addr_copy(mac, wil->sta[cid].addr); wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); rc = wil_cid_fill_sinfo(wil, cid, sinfo); Loading Loading @@ -288,6 +289,26 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, } wil_dbg_misc(wil, "Start scan_request 0x%p\n", request); wil_dbg_misc(wil, "SSID count: %d", request->n_ssids); for (i = 0; i < request->n_ssids; i++) { wil_dbg_misc(wil, "SSID[%d]", i); print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, request->ssids[i].ssid, request->ssids[i].ssid_len); } if (request->n_ssids) rc = wmi_set_ssid(wil, request->ssids[0].ssid_len, request->ssids[0].ssid); else rc = wmi_set_ssid(wil, 0, NULL); if (rc) { wil_err(wil, "set SSID for scan request failed: %d\n", rc); return rc; } wil->scan_request = request; mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); Loading Loading @@ -401,11 +422,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rsn_eid = sme->ie ? cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : NULL; if (sme->privacy && !rsn_eid) { wil_err(wil, "Missing RSN IE for secure connection\n"); return -EINVAL; } if (sme->privacy && !rsn_eid) wil_info(wil, "WSC connection\n"); bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, Loading @@ -424,10 +442,17 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, wil->privacy = sme->privacy; if (wil->privacy) { /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */ rc = wmi_del_cipher_key(wil, 0, bss->bssid); /* For secure assoc, remove old keys */ rc = wmi_del_cipher_key(wil, 0, bss->bssid, WMI_KEY_USE_PAIRWISE); if (rc) { wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n"); goto out; } rc = wmi_del_cipher_key(wil, 0, bss->bssid, WMI_KEY_USE_RX_GROUP); if (rc) { wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n"); wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n"); goto out; } } Loading Loading @@ -457,11 +482,18 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, goto out; } if (wil->privacy) { if (rsn_eid) { /* regular secure connection */ conn.dot11_auth_mode = WMI_AUTH11_SHARED; conn.auth_mode = WMI_AUTH_WPA2_PSK; conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP; conn.pairwise_crypto_len = 16; } else { conn.group_crypto_type = WMI_CRYPT_AES_GCMP; conn.group_crypto_len = 16; } else { /* WSC */ conn.dot11_auth_mode = WMI_AUTH11_WSC; conn.auth_mode = WMI_AUTH_NONE; } } else { /* insecure connection */ conn.dot11_auth_mode = WMI_AUTH11_OPEN; conn.auth_mode = WMI_AUTH_NONE; } Loading @@ -478,8 +510,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, } conn.channel = ch - 1; memcpy(conn.bssid, bss->bssid, ETH_ALEN); memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); ether_addr_copy(conn.bssid, bss->bssid); ether_addr_copy(conn.dst_mac, bss->bssid); set_bit(wil_status_fwconnecting, wil->status); Loading @@ -506,6 +538,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, int rc; struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code); rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0); return rc; Loading Loading @@ -560,6 +594,39 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy, return 0; } static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil, bool pairwise) { struct wireless_dev *wdev = wil->wdev; enum wmi_key_usage rc; static const char * const key_usage_str[] = { [WMI_KEY_USE_PAIRWISE] = "WMI_KEY_USE_PAIRWISE", [WMI_KEY_USE_RX_GROUP] = "WMI_KEY_USE_RX_GROUP", [WMI_KEY_USE_TX_GROUP] = "WMI_KEY_USE_TX_GROUP", }; if (pairwise) { rc = WMI_KEY_USE_PAIRWISE; } else { switch (wdev->iftype) { case NL80211_IFTYPE_STATION: rc = WMI_KEY_USE_RX_GROUP; break; case NL80211_IFTYPE_AP: rc = WMI_KEY_USE_TX_GROUP; break; default: /* TODO: Rx GTK or Tx GTK? */ wil_err(wil, "Can't determine GTK type\n"); rc = WMI_KEY_USE_RX_GROUP; break; } } wil_dbg_misc(wil, "%s() -> %s\n", __func__, key_usage_str[rc]); return rc; } static int wil_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, Loading @@ -567,13 +634,13 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, struct key_params *params) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise); /* group key is not used */ if (!pairwise) return 0; wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index, pairwise ? "PTK" : "GTK"); return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len, params->key); return wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len, params->key, key_usage); } static int wil_cfg80211_del_key(struct wiphy *wiphy, Loading @@ -582,12 +649,12 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy, const u8 *mac_addr) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise); /* group key is not used */ if (!pairwise) return 0; wil_dbg_misc(wil, "%s(%pM[%d] %s)\n", __func__, mac_addr, key_index, pairwise ? "PTK" : "GTK"); return wmi_del_cipher_key(wil, key_index, mac_addr); return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage); } /* Need to be present or wiphy_new() will WARN */ Loading Loading @@ -660,11 +727,6 @@ static int wil_fix_bcon(struct wil6210_priv *wil, if (bcon->probe_resp_len <= hlen) return 0; if (!bcon->proberesp_ies) { bcon->proberesp_ies = f->u.probe_resp.variable; bcon->proberesp_ies_len = bcon->probe_resp_len - hlen; rc = 1; } if (!bcon->assocresp_ies) { bcon->assocresp_ies = f->u.probe_resp.variable; bcon->assocresp_ies_len = bcon->probe_resp_len - hlen; Loading @@ -679,9 +741,19 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, struct cfg80211_beacon_data *bcon) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); const u8 *pr_ies = NULL; size_t pr_ies_len = 0; int rc; wil_dbg_misc(wil, "%s()\n", __func__); wil_print_bcon_data(bcon); if (bcon->probe_resp_len > hlen) { pr_ies = f->u.probe_resp.variable; pr_ies_len = bcon->probe_resp_len - hlen; } if (wil_fix_bcon(wil, bcon)) { wil_dbg_misc(wil, "Fixed bcon\n"); Loading @@ -694,9 +766,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, * bcon->beacon_ies); */ rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, bcon->proberesp_ies); rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); if (rc) { wil_err(wil, "set_ie(PROBE_RESP) failed\n"); return rc; Loading Loading @@ -724,6 +794,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct cfg80211_beacon_data *bcon = &info->beacon; struct cfg80211_crypto_settings *crypto = &info->crypto; u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); const u8 *pr_ies = NULL; size_t pr_ies_len = 0; u8 hidden_ssid; wil_dbg_misc(wil, "%s()\n", __func__); Loading @@ -736,6 +811,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, channel->center_freq, info->privacy ? "secure" : "open"); wil_dbg_misc(wil, "Privacy: %d auth_type %d\n", info->privacy, info->auth_type); wil_dbg_misc(wil, "Hidden SSID mode: %d\n", info->hidden_ssid); wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval, info->dtim_period); print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, Loading @@ -743,6 +820,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_print_bcon_data(bcon); wil_print_crypto(wil, crypto); if (bcon->probe_resp_len > hlen) { pr_ies = f->u.probe_resp.variable; pr_ies_len = bcon->probe_resp_len - hlen; } if (wil_fix_bcon(wil, bcon)) { wil_dbg_misc(wil, "Fixed bcon\n"); wil_print_bcon_data(bcon); Loading Loading @@ -770,20 +852,46 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, * bcon->beacon_ies); */ wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, bcon->proberesp_ies); wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, bcon->assocresp_ies); wil->privacy = info->privacy; switch (info->hidden_ssid) { case NL80211_HIDDEN_SSID_NOT_IN_USE: hidden_ssid = WMI_HIDDEN_SSID_DISABLED; break; case NL80211_HIDDEN_SSID_ZERO_LEN: hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY; break; case NL80211_HIDDEN_SSID_ZERO_CONTENTS: hidden_ssid = WMI_HIDDEN_SSID_CLEAR; break; default: rc = -EOPNOTSUPP; goto out; } netif_carrier_on(ndev); rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); channel->hw_value, hidden_ssid); if (rc) netif_carrier_off(ndev); goto err_pcp_start; rc = wil_bcast_init(wil); if (rc) goto err_bcast; goto out; /* success */ err_bcast: wmi_pcp_stop(wil); err_pcp_start: netif_carrier_off(ndev); out: mutex_unlock(&wil->mutex); return rc; Loading @@ -804,13 +912,9 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wmi_pcp_stop(wil); __wil_down(wil); __wil_up(wil); mutex_unlock(&wil->mutex); /* some functions above might fail (e.g. __wil_up). Nevertheless, we * return success because AP has stopped */ return 0; } Loading @@ -819,6 +923,9 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy, { struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s(%pM, reason=%d)\n", __func__, mac, WLAN_REASON_UNSPECIFIED); mutex_lock(&wil->mutex); wil6210_disconnect(wil, mac, WLAN_REASON_UNSPECIFIED, false); mutex_unlock(&wil->mutex); Loading Loading @@ -916,6 +1023,21 @@ static int wil_cfg80211_probe_client(struct wiphy *wiphy, return 0; } static int wil_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); if (params->ap_isolate >= 0) { wil_dbg_misc(wil, "%s(ap_isolate %d => %d)\n", __func__, wil->ap_isolate, params->ap_isolate); wil->ap_isolate = params->ap_isolate; } return 0; } static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, Loading @@ -936,12 +1058,12 @@ static struct cfg80211_ops wil_cfg80211_ops = { .stop_ap = wil_cfg80211_stop_ap, .del_station = wil_cfg80211_del_station, .probe_client = wil_cfg80211_probe_client, .change_bss = wil_cfg80211_change_bss, }; static void wil_wiphy_init(struct wiphy *wiphy) { /* TODO: set real value */ wiphy->max_scan_ssids = 10; wiphy->max_scan_ssids = 1; wiphy->max_scan_ie_len = WMI_MAX_IE_LEN; wiphy->max_num_pmkids = 0 /* TODO: */; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | Loading
drivers/net/wireless/ath/wil6210/debugfs.c +119 −13 Original line number Diff line number Diff line /* * Copyright (c) 2012-2014 Qualcomm Atheros, Inc. * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above Loading @@ -24,6 +24,7 @@ #include "wil6210.h" #include "wmi.h" #include "txrx.h" #include "pmc.h" /* Nasty hack. Better have per device instances */ static u32 mem_addr; Loading Loading @@ -121,12 +122,20 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) snprintf(name, sizeof(name), "tx_%2d", i); if (cid < WIL6210_MAX_CID) seq_printf(s, "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %s\n", "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n", wil->sta[cid].addr, cid, tid, txdata->agg_wsize, txdata->agg_timeout, txdata->dot1x_open ? "+" : "-", txdata->agg_wsize, txdata->agg_timeout, txdata->agg_amsdu ? "+" : "-", used, avail, sidle); else seq_printf(s, "\nBroadcast 1x%s [%3d|%3d] idle %s\n", txdata->dot1x_open ? "+" : "-", used, avail, sidle); wil_print_vring(s, wil, name, vring, '_', 'H'); } Loading Loading @@ -626,7 +635,7 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf, struct wil6210_priv *wil = file->private_data; int rc; char *kbuf = kmalloc(len + 1, GFP_KERNEL); char cmd[8]; char cmd[9]; int p1, p2, p3; if (!kbuf) Loading Loading @@ -696,6 +705,89 @@ static const struct file_operations fops_back = { .open = simple_open, }; /* pmc control, write: * - "alloc <num descriptors> <descriptor_size>" to allocate PMC * - "free" to release memory allocated for PMC */ static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; int rc; char *kbuf = kmalloc(len + 1, GFP_KERNEL); char cmd[9]; int num_descs, desc_size; if (!kbuf) return -ENOMEM; rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); if (rc != len) { kfree(kbuf); return rc >= 0 ? -EIO : rc; } kbuf[len] = '\0'; rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size); kfree(kbuf); if (rc < 0) return rc; if (rc < 1) { wil_err(wil, "pmccfg: no params given\n"); return -EINVAL; } if (0 == strcmp(cmd, "alloc")) { if (rc != 3) { wil_err(wil, "pmccfg: alloc requires 2 params\n"); return -EINVAL; } wil_pmc_alloc(wil, num_descs, desc_size); } else if (0 == strcmp(cmd, "free")) { if (rc != 1) { wil_err(wil, "pmccfg: free does not have any params\n"); return -EINVAL; } wil_pmc_free(wil, true); } else { wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd); return -EINVAL; } return len; } static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; char text[256]; char help[] = "pmc control, write:\n" " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n" " - \"free\" to free memory allocated for pmc\n"; sprintf(text, "Last command status: %d\n\n%s", wil_pmc_last_cmd_status(wil), help); return simple_read_from_buffer(user_buf, count, ppos, text, strlen(text) + 1); } static const struct file_operations fops_pmccfg = { .read = wil_read_pmccfg, .write = wil_write_pmccfg, .open = simple_open, }; static const struct file_operations fops_pmcdata = { .open = simple_open, .read = wil_pmc_read, .llseek = wil_pmc_llseek, }; /*---tx_mgmt---*/ /* Write mgmt frame to this file to send it */ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, Loading Loading @@ -1105,8 +1197,7 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) status = "connected"; break; } seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, (p->data_port_open ? " data_port_open" : "")); seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); if (p->status == wil_sta_connected) { rc = wil_cid_fill_sinfo(wil, i, &sinfo); Loading Loading @@ -1269,7 +1360,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data) __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) { struct wil6210_priv *wil = s->private; int i, tid; int i, tid, mcs; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; Loading @@ -1286,8 +1377,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) status = "connected"; break; } seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, (p->data_port_open ? " data_port_open" : "")); seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); if (p->status == wil_sta_connected) { spin_lock_bh(&p->tid_rx_lock); Loading @@ -1300,6 +1390,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) } } spin_unlock_bh(&p->tid_rx_lock); seq_puts(s, "Rx/MCS:"); for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs); mcs++) seq_printf(s, " %lld", p->stats.rx_per_mcs[mcs]); seq_puts(s, "\n"); } } Loading Loading @@ -1357,6 +1453,8 @@ static const struct { {"tx_mgmt", S_IWUSR, &fops_txmgmt}, {"wmi_send", S_IWUSR, &fops_wmi}, {"back", S_IRUGO | S_IWUSR, &fops_back}, {"pmccfg", S_IRUGO | S_IWUSR, &fops_pmccfg}, {"pmcdata", S_IRUGO, &fops_pmcdata}, {"temp", S_IRUGO, &fops_temp}, {"freq", S_IRUGO, &fops_freq}, {"link", S_IRUGO, &fops_link}, Loading Loading @@ -1405,6 +1503,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(fw_version, S_IRUGO, doff_u32), WIL_FIELD(hw_version, S_IRUGO, doff_x32), WIL_FIELD(recovery_count, S_IRUGO, doff_u32), WIL_FIELD(ap_isolate, S_IRUGO, doff_u32), {}, }; Loading Loading @@ -1433,6 +1532,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) if (IS_ERR_OR_NULL(dbg)) return -ENODEV; wil_pmc_init(wil); wil6210_debugfs_init_files(wil, dbg); wil6210_debugfs_init_isr(wil, dbg); wil6210_debugfs_init_blobs(wil, dbg); Loading @@ -1452,4 +1553,9 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil) { debugfs_remove_recursive(wil->debug); wil->debug = NULL; /* free pmc memory without sending command to fw, as it will * be reset on the way down anyway */ wil_pmc_free(wil, false); }
drivers/net/wireless/ath/wil6210/main.c +60 −3 Original line number Diff line number Diff line Loading @@ -25,6 +25,10 @@ #define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000 #define WAIT_FOR_DISCONNECT_INTERVAL_MS 10 bool debug_fw; /* = false; */ module_param(debug_fw, bool, S_IRUGO); MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug"); bool no_fw_recovery; module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery"); Loading Loading @@ -68,6 +72,7 @@ MODULE_PARM_DESC(mtu_max, " Max MTU value."); static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT; static int ring_order_set(const char *val, const struct kernel_param *kp) { Loading Loading @@ -95,6 +100,8 @@ module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, S_IRUGO); MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order"); module_param_cb(tx_ring_order, &ring_order_ops, &tx_ring_order, S_IRUGO); MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order"); module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, S_IRUGO); MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order"); #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ Loading Loading @@ -145,7 +152,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid, sta->status); sta->data_port_open = false; if (sta->status != wil_sta_unused) { if (!from_event) wmi_disconnect_sta(wil, sta->addr, reason_code); Loading Loading @@ -216,6 +222,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: wil_bcast_fini(wil); netif_tx_stop_all_queues(ndev); netif_carrier_off(ndev); Loading Loading @@ -360,6 +367,36 @@ static int wil_find_free_vring(struct wil6210_priv *wil) return -EINVAL; } int wil_bcast_init(struct wil6210_priv *wil) { int ri = wil->bcast_vring, rc; if ((ri >= 0) && wil->vring_tx[ri].va) return 0; ri = wil_find_free_vring(wil); if (ri < 0) return ri; wil->bcast_vring = ri; rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order); if (rc) wil->bcast_vring = -1; return rc; } void wil_bcast_fini(struct wil6210_priv *wil) { int ri = wil->bcast_vring; if (ri < 0) return; wil->bcast_vring = -1; wil_vring_fini_tx(wil, ri); } static void wil_connect_worker(struct work_struct *work) { int rc; Loading Loading @@ -407,6 +444,7 @@ int wil_priv_init(struct wil6210_priv *wil) init_completion(&wil->wmi_call); wil->pending_connect_cid = -1; wil->bcast_vring = -1; setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil); Loading Loading @@ -515,7 +553,7 @@ static inline void wil_release_cpu(struct wil6210_priv *wil) static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; u32 x; u32 x, x1 = 0; wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); Loading Loading @@ -570,12 +608,16 @@ static int wil_target_reset(struct wil6210_priv *wil) do { msleep(RST_DELAY); x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready)); if (x1 != x) { wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x); x1 = x; } if (delay++ > RST_COUNT) { wil_err(wil, "Reset not completed, bl.ready 0x%08x\n", x); return -ETIME; } } while (!(x & BIT_BL_READY)); } while (x != BIT_BL_READY); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); Loading Loading @@ -654,8 +696,20 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) WARN_ON(!mutex_is_locked(&wil->mutex)); WARN_ON(test_bit(wil_status_napi_en, wil->status)); if (debug_fw) { static const u8 mac[ETH_ALEN] = { 0x00, 0xde, 0xad, 0x12, 0x34, 0x56, }; struct net_device *ndev = wil_to_ndev(wil); ether_addr_copy(ndev->perm_addr, mac); ether_addr_copy(ndev->dev_addr, ndev->perm_addr); return 0; } cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); wil_bcast_fini(wil); /* prevent NAPI from being scheduled */ bitmap_zero(wil->status, wil_status_last); Loading Loading @@ -714,6 +768,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* init after reset */ wil->pending_connect_cid = -1; wil->ap_isolate = 0; reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_call); Loading @@ -723,6 +778,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* we just started MAC, wait for FW ready */ rc = wil_wait_for_fw_ready(wil); if (rc == 0) /* check FW is responsive */ rc = wmi_echo(wil); } return rc; Loading
drivers/net/wireless/ath/wil6210/netdev.c +7 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,11 @@ static int wil_open(struct net_device *ndev) wil_dbg_misc(wil, "%s()\n", __func__); if (debug_fw) { wil_err(wil, "%s() while in debug_fw mode\n", __func__); return -EINVAL; } return wil_up(wil); } Loading Loading @@ -82,7 +87,7 @@ static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) wil_rx_handle(wil, "a); done = budget - quota; if (done <= 1) { /* burst ends - only one packet processed */ if (done < budget) { napi_complete(napi); wil6210_unmask_irq_rx(wil); wil_dbg_txrx(wil, "NAPI RX complete\n"); Loading Loading @@ -110,7 +115,7 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) tx_done += wil_tx_complete(wil, i); } if (tx_done <= 1) { /* burst ends - only one packet processed */ if (tx_done < budget) { napi_complete(napi); wil6210_unmask_irq_tx(wil); wil_dbg_txrx(wil, "NAPI TX complete\n"); Loading