Created
December 21, 2017 10:33
-
-
Save dev-zzo/e5d4aa57aa80318020ef57749c2ebf8e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -Naur backports-4.4.2-1/defconfigs/ath9k-debug backports-4.4.2-1-modwifi/defconfigs/ath9k-debug | |
--- backports-4.4.2-1/defconfigs/ath9k-debug 2016-02-18 22:41:34.000000000 +0100 | |
+++ backports-4.4.2-1-modwifi/defconfigs/ath9k-debug 2016-04-03 13:28:53.000000000 +0200 | |
@@ -17,3 +17,4 @@ | |
CPTCFG_ATH9K_HTC=m | |
CPTCFG_ATH_DEBUG=y | |
CPTCFG_ATH9K_DEBUGFS=y | |
+CPTCFG_ATH9K_HTC_DEBUGFS=y | |
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_debug.c backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_debug.c | |
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_debug.c 2016-02-18 22:41:35.000000000 +0100 | |
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_debug.c 2016-04-03 13:28:54.000000000 +0200 | |
@@ -15,6 +15,61 @@ | |
*/ | |
#include "htc.h" | |
+#include "hw.h" | |
+ | |
+typedef u32 (*GetTimeFunc)(struct ath_hw *ah); | |
+typedef void (*SetTimeFunc)(struct ath_hw *ah, u32 us); | |
+ | |
+struct time_func { | |
+ const char *name; | |
+ GetTimeFunc getter; | |
+ SetTimeFunc setter; | |
+ const char *comments; | |
+}; | |
+ | |
+struct time_func_context { | |
+ struct time_func *timefunc; | |
+ struct ath9k_htc_priv *htcpriv; | |
+}; | |
+ | |
+struct time_func timefunctions[] = | |
+{ | |
+ {"time_sifs", ath9k_hw_get_sifs_time, ath9k_hw_set_sifs_time, | |
+ "SIFS time in microseconds (us) = Rx/Tx time = required time to wait after Rx."}, | |
+ {"time_slottime", ath9k_hw_getslottime, ath9k_hw_setslottime, | |
+ "Slot time (aSlotTime) in microseconds (us) = slot time as used in backoff algo."}, | |
+ {"time_ack_timeout", ath9k_hw_get_ack_timeout, ath9k_hw_set_ack_timeout, | |
+ "ACK timeout in microseconds (us)"}, | |
+ {"time_cts_timeout", ath9k_hw_get_cts_timeout, ath9k_hw_set_cts_timeout, | |
+ "CTS timeout in microseconds (us)"}, | |
+ {"time_eifs", ath9k_hw_get_eifs_timeout, ath9k_hw_set_eifs_timeout, | |
+ "EIFS time in microseconds (us)"} | |
+}; | |
+ | |
+struct reg_ops registers[] = { | |
+ // Backoff parameters | |
+ {"ifs_cwmin_queue0", AR_DLCL_IFS(0), AR_D_LCL_IFS_CWMIN, | |
+ "Backoff behaviour (queue 0): CW_MIN is the minimum number of time slots to wait."}, | |
+ {"ifs_cwmax_queue0", AR_DLCL_IFS(0), AR_D_LCL_IFS_CWMAX, | |
+ "Backoff behaviour (queue 0): CW_MAX is the maximum number of time slots to wait."}, | |
+ {"ifs_aifs_queue0", AR_DLCL_IFS(0), AR_D_LCL_IFS_AIFS, | |
+ "AIFS (in number of aSlotTime's) for queue 0."}, | |
+ // Disable backoff | |
+ {"ifs_ignore_backoff", AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF, | |
+ "Ignore backoff (perhaps you also want to disable waiting for ACKs - see inject_noack)."}, | |
+ // Virtual and physical carrier sense | |
+ {"ignore_virt_cs", AR_DIAG_SW, AR_DIAG_IGNORE_VIRT_CS, | |
+ "Disables virtual carrier (cts/rts) sense when set."}, | |
+ {"force_channel_idle", AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH, | |
+ "Disables physical carrier sense (air clear) when set."}, | |
+ {"diag_rx_disable", AR_DIAG_SW, AR_DIAG_RX_DIS, | |
+ "Block incoming frames from being sent to the firmware."}, | |
+ // Other | |
+ {"diag_corrupt_fcs", AR_DIAG_SW, AR_DIAG_CORR_FCS, | |
+ "If set, every transmitted packet is given an incorrect FCS."}, | |
+ {"cpu_freq_pll", 0x00056000, -1, | |
+ "Value = frequency * 4 + 5 (Setting of the Phase Locked Loop)."}, | |
+}; | |
static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, | |
size_t count, loff_t *ppos) | |
@@ -398,6 +453,633 @@ | |
.llseek = default_llseek, | |
}; | |
+static ssize_t read_file_reg_ops(struct file *file, char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct reg_ops_instance *instance = file->private_data; | |
+ struct ath9k_htc_priv *priv = instance->owner; | |
+ struct reg_ops *regops = instance->regops; | |
+ char buf[512]; | |
+ unsigned int len; | |
+ unsigned int regval, mask; | |
+ | |
+ ath9k_htc_ps_wakeup(priv); | |
+ regval = REG_READ(priv->ah, regops->address); | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ // apply mask, and shift according to mask | |
+ regval &= regops->mask; | |
+ mask = regops->mask; | |
+ while ( (mask & 1) == 0) { | |
+ mask >>= 1; | |
+ regval >>= 1; | |
+ } | |
+ | |
+ len = snprintf(buf, sizeof(buf), "%s: %s\nValue: 0x%08X = %d (forced: %d)\n", | |
+ regops->name, regops->description, regval, regval, | |
+ !!(instance->valueset)); | |
+ | |
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len); | |
+} | |
+ | |
+static ssize_t write_file_reg_ops(struct file *file, const char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct reg_ops_instance *instance = file->private_data; | |
+ struct ath9k_htc_priv *priv = instance->owner; | |
+ struct reg_ops *regops = instance->regops; | |
+ unsigned long val; | |
+ char buf[32]; | |
+ ssize_t len; | |
+ unsigned int mask, regval; | |
+ | |
+ len = min(count, sizeof(buf) - 1); | |
+ if (copy_from_user(buf, user_buf, len)) | |
+ return -EINVAL; | |
+ | |
+ buf[len] = '\0'; | |
+ if (kstrtoul(buf, 0, &val)) | |
+ return -EINVAL; | |
+ | |
+ // shift according to mask | |
+ mask = regops->mask; | |
+ while ( (mask & 1) == 0) { | |
+ mask >>= 1; | |
+ val <<= 1; | |
+ } | |
+ | |
+ // apply mask to assure we're not overwriting anything else | |
+ val &= regops->mask; | |
+ | |
+ ath9k_htc_ps_wakeup(priv); | |
+ regval = REG_READ(priv->ah, regops->address); | |
+ regval = (regval & ~regops->mask) | val; | |
+ REG_WRITE(priv->ah, regops->address, regval); | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ instance->valueset = 1; | |
+ instance->value = val; | |
+ | |
+ return count; | |
+} | |
+ | |
+static const struct file_operations fops_reg_ops = { | |
+ .read = read_file_reg_ops, | |
+ .write = write_file_reg_ops, | |
+ .open = simple_open, | |
+ .owner = THIS_MODULE, | |
+ .llseek = default_llseek, | |
+}; | |
+ | |
+static ssize_t read_file_dmesg(struct file *file, char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ struct wmi_debugmsg_cmd cmd; | |
+ struct wmi_debugmsg_resp cmd_rsp; | |
+ /** ppos is the amount of data already read (maintained by caller) */ | |
+ int offset = *ppos; | |
+ int ret; | |
+ | |
+ /** Note: don't need to wake the WiFi MAC chip to get debug messages! */ | |
+ memset(&cmd, 0, sizeof(cmd)); | |
+ cmd.offset = cpu_to_be16(offset); | |
+ | |
+ memset(&cmd_rsp, 0, sizeof(cmd_rsp)); | |
+ ret = ath9k_wmi_cmd(priv->wmi, WMI_DEBUGMSG_CMDID, | |
+ (u8*)&cmd, sizeof(cmd), | |
+ (u8*)&cmd_rsp, sizeof(cmd_rsp), | |
+ HZ*2); | |
+ if (ret) { | |
+ printk("ath9k_htc %s: Something went wrong reading firmware dmesg (ret: %d, len: %d)\n", | |
+ __FUNCTION__, ret, cmd_rsp.length); | |
+ return -EIO; | |
+ } | |
+ | |
+ // Don't overflow user_buf | |
+ if (count < cmd_rsp.length) | |
+ cmd_rsp.length = count; | |
+ | |
+ // Length of zero signifies EOF | |
+ if (cmd_rsp.length != 0) { | |
+ // Returns number of bytes that could not be copied | |
+ if (copy_to_user(user_buf, cmd_rsp.buffer, cmd_rsp.length) != 0) | |
+ return -EFAULT; | |
+ } | |
+ | |
+ *ppos += cmd_rsp.length; | |
+ return cmd_rsp.length; | |
+} | |
+ | |
+static const struct file_operations fops_dmesg = { | |
+ .read = read_file_dmesg, | |
+ .open = simple_open, | |
+ .owner = THIS_MODULE, | |
+ .llseek = default_llseek, | |
+}; | |
+ | |
+static ssize_t read_file_reactivejam(struct file *file, char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ char output[] = "Jam beacons and probe responses by writing the bssid and" | |
+ "duration (in msecs) to this file as 'XX:XX:XX:XX:XX:XX,10000'.\n" | |
+ "Duration of 0 means an infinite jam (device becomes unresponsive).\n"; | |
+ return simple_read_from_buffer(user_buf, count, ppos, output, sizeof(output)); | |
+} | |
+ | |
+static ssize_t write_file_reactivejam(struct file *file, const char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ struct wmi_reactivejam_cmd cmd; | |
+ char buf[32] = {0}, reply[128] = {0}; | |
+ unsigned int intmac[6]; | |
+ unsigned int duration; | |
+ int rval, len, i; | |
+ | |
+ if (*ppos != 0) return 0; | |
+ | |
+ // copy over input | |
+ len = min(count, sizeof(buf) - 1); | |
+ if (unlikely(copy_from_user(buf, user_buf, len))) { | |
+ printk("ath9k_htc %s: copy_from_user failed\n", __FUNCTION__); | |
+ return -EFAULT; | |
+ } | |
+ buf[sizeof(buf) - 1] = 0; | |
+ | |
+ // parse input | |
+ if ( 7 != sscanf(buf, "%x:%x:%x:%x:%x:%x,%u", &intmac[0], &intmac[1], &intmac[2], | |
+ &intmac[3], &intmac[4], &intmac[5], &duration) ) { | |
+ printk("ath9k_htc %s: invalid format\n", __FUNCTION__); | |
+ return -EINVAL; | |
+ } | |
+ | |
+ // save input to command | |
+ for (i = 0; i < 6; ++i) | |
+ cmd.bssid[i] = intmac[i]; | |
+ cmd.mduration = cpu_to_be32(duration); | |
+ | |
+ printk("ath9k_htc: Reactively jamming %x:%x:%x:%x:%x:%x ", cmd.bssid[0], cmd.bssid[1], | |
+ cmd.bssid[2], cmd.bssid[3], cmd.bssid[4], cmd.bssid[5]); | |
+ if (cmd.mduration == 0) | |
+ printk("indefinitely (device will be unresponsive)\n"); | |
+ else | |
+ printk("for %u miliseconds\n", duration); | |
+ | |
+ // Blocking call! Wait for duration + 4 seconds. Response is an ASCII string. If the duration | |
+ // is zero, firmware instantly replies, but will then become unresponsive (infinite jam). | |
+ ath9k_htc_ps_wakeup(priv); | |
+ rval = ath9k_wmi_cmd(priv->wmi, WMI_REACTIVEJAM_CMDID, | |
+ (u8*)&cmd, sizeof(cmd), | |
+ (u8*)reply, sizeof(reply), | |
+ HZ * (duration / 1000 + 4)); | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ if (unlikely(rval) && cmd.mduration != 0) { | |
+ printk("ath9k_htc %s: WMI_REACTIVEJAM_CMD failed with %d\n", __FUNCTION__, rval); | |
+ return -EBUSY; | |
+ } | |
+ | |
+ // Reset radio settings | |
+ ath9k_hw_init_global_settings(priv->ah); | |
+ | |
+ return count; | |
+} | |
+ | |
+static const struct file_operations fops_reactivejam = { | |
+ .read = read_file_reactivejam, | |
+ .write = write_file_reactivejam, | |
+ .open = simple_open, | |
+ .owner = THIS_MODULE, | |
+ .llseek = default_llseek, | |
+}; | |
+ | |
+static ssize_t read_file_constantjam(struct file *file, char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ struct wmi_constantjam_resp cmd_rsp; | |
+ struct wmi_constantjam_cmd cmd; | |
+ char buf[128]; | |
+ unsigned int len; | |
+ int rval; | |
+ | |
+ if (*ppos != 0) return 0; | |
+ | |
+ memset(&cmd, 0, sizeof(cmd)); | |
+ cmd.request = CONSTJAM_STATUS; | |
+ | |
+ // Send command to firmware | |
+ rval = ath9k_wmi_cmd(priv->wmi, WMI_CONSTANTJAM_CMDID, | |
+ (u8 *)&cmd, sizeof(cmd), | |
+ (u8 *)&cmd_rsp, sizeof(cmd_rsp), | |
+ HZ*2); | |
+ | |
+ if (unlikely(rval)) { | |
+ printk(">>>> WMI_CONSTANTJAM_CMD failed: %d\n", rval); | |
+ return -EIO; | |
+ } | |
+ | |
+ len = snprintf(buf, sizeof(buf), "Constant jammer running: %d\n", cmd_rsp.status); | |
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len); | |
+} | |
+ | |
+static ssize_t write_file_constantjam(struct file *file, const char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ struct wmi_constantjam_resp cmd_rsp; | |
+ struct wmi_constantjam_cmd cmd; | |
+ unsigned long val; | |
+ char buf[32]; | |
+ ssize_t len; | |
+ int rval = 0; | |
+ | |
+ if (*ppos != 0) return 0; | |
+ | |
+ // parse input | |
+ len = min(count, sizeof(buf) - 1); | |
+ if (copy_from_user(buf, user_buf, len)) | |
+ return -EINVAL; | |
+ | |
+ buf[len] = '\0'; | |
+ if (kstrtoul(buf, 0, &val)) | |
+ return -EINVAL; | |
+ | |
+ memset(&cmd, 0, sizeof(cmd)); | |
+ // should we start or stop | |
+ cmd.request = val == 0 ? CONSTJAM_STOP : CONSTJAM_START; | |
+ // full continuous jamming (disable carrier sense, no timeouts between packets) | |
+ cmd.conf_radio = 1; | |
+ // length of packet used for jamming (pick a small one to avoid memory issues) | |
+ cmd.len = cpu_to_be16(50); | |
+ | |
+ // Send command to firmware | |
+ ath9k_htc_ps_wakeup(priv); | |
+ rval = ath9k_wmi_cmd(priv->wmi, WMI_CONSTANTJAM_CMDID, | |
+ (u8 *)&cmd, sizeof(cmd), | |
+ (u8 *)&cmd_rsp, sizeof(cmd_rsp), | |
+ HZ*2); | |
+ | |
+ if (unlikely(rval)) { | |
+ printk(">>>> WMI_CONSTANTJAM_CMD failed: %d\n", rval); | |
+ return -EIO; | |
+ } | |
+ | |
+ if (cmd.request == CONSTJAM_STOP) | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ return count; | |
+} | |
+ | |
+static const struct file_operations fops_constantjam = { | |
+ .read = read_file_constantjam, | |
+ .write = write_file_constantjam, | |
+ .open = simple_open, | |
+ .owner = THIS_MODULE, | |
+ .llseek = default_llseek, | |
+}; | |
+ | |
+static ssize_t read_file_macaddr(struct file *file, char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ char buf[512]; | |
+ unsigned int len; | |
+ unsigned int low, upper; | |
+ | |
+ ath9k_htc_ps_wakeup(priv); | |
+ low = REG_READ(priv->ah, AR_STA_ID0); | |
+ upper = REG_READ(priv->ah, AR_STA_ID1) & AR_STA_ID1_SADH_MASK; | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ len = snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X\n", | |
+ low & 0xFF, (low >> 8) & 0xFF, (low >> 16) & 0xFF, | |
+ (low >> 24) & 0xFF, upper & 0xFF, (upper >> 8) & 0xFF); | |
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len); | |
+} | |
+ | |
+static ssize_t write_file_macaddr(struct file *file, const char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ char buf[32]; | |
+ unsigned int mac[6]; | |
+ unsigned int low, upper; | |
+ ssize_t len; | |
+ | |
+ len = min(count, sizeof(buf) - 1); | |
+ if (copy_from_user(buf, user_buf, len)) | |
+ return -EFAULT; | |
+ buf[sizeof(buf) - 1] = 0; | |
+ | |
+ if ( 6 != sscanf(buf, "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) ) | |
+ return -EINVAL; | |
+ | |
+ low = mac[0] | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24); | |
+ upper = mac[4] | (mac[5] << 8); | |
+ | |
+ ath9k_htc_ps_wakeup(priv); | |
+ REG_WRITE(priv->ah, AR_STA_ID0, low); | |
+ REG_WRITE(priv->ah, AR_STA_ID1, upper & AR_STA_ID1_SADH_MASK); | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ return count; | |
+} | |
+ | |
+static const struct file_operations fops_macaddr = { | |
+ .read = read_file_macaddr, | |
+ .write = write_file_macaddr, | |
+ .open = simple_open, | |
+ .owner = THIS_MODULE, | |
+ .llseek = default_llseek, | |
+}; | |
+ | |
+static ssize_t read_file_bssidmask(struct file *file, char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ char buf[512]; | |
+ unsigned int len; | |
+ unsigned int low, upper; | |
+ | |
+ ath9k_htc_ps_wakeup(priv); | |
+ low = REG_READ(priv->ah, AR_BSSMSKL); | |
+ upper = REG_READ(priv->ah, AR_BSSMSKU); | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ len = snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X\n", | |
+ low & 0xFF, (low >> 8) & 0xFF, (low >> 16) & 0xFF, | |
+ (low >> 24) & 0xFF, upper & 0xFF, (upper >> 8) & 0xFF); | |
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len); | |
+} | |
+ | |
+static ssize_t write_file_bssidmask(struct file *file, const char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ char buf[32]; | |
+ unsigned int mask[6]; | |
+ unsigned int low, upper; | |
+ ssize_t len; | |
+ | |
+ len = min(count, sizeof(buf) - 1); | |
+ if (copy_from_user(buf, user_buf, len)) | |
+ return -EFAULT; | |
+ buf[sizeof(buf) - 1] = 0; | |
+ | |
+ if ( 6 != sscanf(buf, "%x:%x:%x:%x:%x:%x", &mask[0], &mask[1], &mask[2], &mask[3], &mask[4], &mask[5]) ) | |
+ return -EINVAL; | |
+ | |
+ low = mask[0] | (mask[1] << 8) | (mask[2] << 16) | (mask[3] << 24); | |
+ upper = mask[4] | (mask[5] << 8); | |
+ | |
+ ath9k_htc_ps_wakeup(priv); | |
+ REG_WRITE(priv->ah, AR_BSSMSKL, low); | |
+ REG_WRITE(priv->ah, AR_BSSMSKU, upper & AR_BSS_ID1_U16); | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ return count; | |
+} | |
+ | |
+static const struct file_operations fops_bssidmask = { | |
+ .read = read_file_bssidmask, | |
+ .write = write_file_bssidmask, | |
+ .open = simple_open, | |
+ .owner = THIS_MODULE, | |
+ .llseek = default_llseek, | |
+}; | |
+ | |
+static ssize_t read_file_inject_noack(struct file *file, char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ char buf[64]; | |
+ int len; | |
+ | |
+ len = snprintf(buf, sizeof(buf), "%d\n", priv->inject_noack); | |
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len); | |
+} | |
+ | |
+static ssize_t write_file_inject_noack(struct file *file, const char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ char buf[32]; | |
+ unsigned long val; | |
+ int len; | |
+ | |
+ len = min(count, sizeof(buf) - 1); | |
+ if (copy_from_user(buf, user_buf, len)) | |
+ return -EFAULT; | |
+ | |
+ buf[len] = '\0'; | |
+ if (kstrtoul(buf, 0, &val)) | |
+ return -EINVAL; | |
+ | |
+ priv->inject_noack = val; | |
+ | |
+ return count; | |
+} | |
+ | |
+static const struct file_operations fops_inject_noack = { | |
+ .read = read_file_inject_noack, | |
+ .write = write_file_inject_noack, | |
+ .open = simple_open, | |
+ .owner = THIS_MODULE, | |
+ .llseek = default_llseek, | |
+}; | |
+ | |
+static ssize_t read_file_fastreply_packet(struct file *file, char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ char buf[128] = "Write the reply packet used in fastreply_start to this file.\n"; | |
+ return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); | |
+} | |
+ | |
+static ssize_t write_file_fastreply_packet(struct file *file, | |
+ const char __user *user_buf, size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ struct wmi_fastreply_cmd cmd; | |
+ uint8_t buff[256]; | |
+ unsigned int offset; | |
+ int reply, rval; | |
+ | |
+ if (*ppos != 0) return 0; | |
+ | |
+ // | |
+ // 1. copy input | |
+ // | |
+ | |
+ if (count > 256) { | |
+ printk("fastreply_packet: packet is too long (%zu)\n", count); | |
+ return -EMSGSIZE; | |
+ } | |
+ | |
+ if (copy_from_user(buff, user_buf, count)) | |
+ return -EFAULT; | |
+ | |
+ // | |
+ // 2. send the buffer to the firmware | |
+ // | |
+ | |
+ cmd.type = FASTREPLY_PKT; | |
+ cmd.pkt.length = count; | |
+ | |
+ ath9k_htc_ps_wakeup(priv); | |
+ | |
+ for (offset = 0; offset < count; offset += sizeof(cmd.pkt.data)) | |
+ { | |
+ cmd.pkt.offset = offset; | |
+ cmd.pkt.datalen = min(40U, (unsigned int)(count - offset)); | |
+ memcpy(cmd.pkt.data, &buff[offset], cmd.pkt.datalen); | |
+ | |
+ rval = ath9k_wmi_cmd(priv->wmi, WMI_FASTREPLY_CMDID, | |
+ (u8*)&cmd, sizeof(cmd), | |
+ (u8*)&reply, sizeof(reply), | |
+ 2*HZ); | |
+ | |
+ if (unlikely(rval)) { | |
+ printk("ath9k_htc %s: WMI_FASTREPLY_CMDID failed with %d\n", __FUNCTION__, rval); | |
+ ath9k_htc_ps_restore(priv); | |
+ return -EIO; | |
+ } | |
+ } | |
+ | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ return count; | |
+} | |
+ | |
+ | |
+static const struct file_operations fops_fastreply_packet = { | |
+ .read = read_file_fastreply_packet, | |
+ .write = write_file_fastreply_packet, | |
+ .open = simple_open, | |
+ .owner = THIS_MODULE, | |
+ .llseek = default_llseek, | |
+}; | |
+ | |
+static ssize_t read_file_fastreply_start(struct file *file, char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ char buf[128] = "Write the source MAC and duration ( 90:18:7c:6e:6b:20,10000 ) to this file.\n" | |
+ "Set the reply packet using fastreply_packet.\n"; | |
+ return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf)); | |
+} | |
+ | |
+static ssize_t write_file_fastreply_start(struct file *file, | |
+ const char __user *user_buf, size_t count, loff_t *ppos) | |
+{ | |
+ struct ath9k_htc_priv *priv = file->private_data; | |
+ struct wmi_fastreply_cmd cmd; | |
+ char input[256]; | |
+ int mac[6]; | |
+ unsigned int duration; | |
+ int len, reply, rval, i; | |
+ | |
+ if (*ppos != 0) return 0; | |
+ | |
+ // 1. parse input | |
+ | |
+ len = min(count, sizeof(input) - 1); | |
+ if (copy_from_user(input, user_buf, len)) | |
+ return -EFAULT; | |
+ input[len] = '\0'; | |
+ | |
+ if (sscanf(input, "%x:%x:%x:%x:%x:%x,%u", &mac[0], &mac[1], &mac[2], | |
+ &mac[3], &mac[4], &mac[5], &duration) != 7) { | |
+ printk("%s: sscanf parsing failed\n", __FUNCTION__); | |
+ return -EINVAL; | |
+ } | |
+ | |
+ // 2. send the start command | |
+ | |
+ cmd.type = FASTREPLY_START; | |
+ cmd.start.mduration = cpu_to_be32(duration); | |
+ for (i = 0; i < 6; ++i) | |
+ cmd.start.source[i] = mac[i]; | |
+ | |
+ ath9k_htc_ps_wakeup(priv); | |
+ | |
+ rval = ath9k_wmi_cmd(priv->wmi, WMI_FASTREPLY_CMDID, | |
+ (u8*)&cmd, sizeof(cmd), | |
+ (u8*)&reply, sizeof(reply), | |
+ HZ * (duration / 1000 + 4)); | |
+ | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ if (unlikely(rval)) { | |
+ printk("ath9k_htc %s: WMI_FASTREPLY_CMDID failed with %d\n", __FUNCTION__, rval); | |
+ return -EBUSY; | |
+ } | |
+ | |
+ return count; | |
+} | |
+ | |
+static const struct file_operations fops_fastreply_start = { | |
+ .read = read_file_fastreply_start, | |
+ .write = write_file_fastreply_start, | |
+ .open = simple_open, | |
+ .owner = THIS_MODULE, | |
+ .llseek = default_llseek, | |
+}; | |
+ | |
+ | |
+static ssize_t read_file_timefunc(struct file *file, char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct time_func_context *context = file->private_data; | |
+ struct time_func *timefunc = context->timefunc; | |
+ struct ath9k_htc_priv *priv = context->htcpriv; | |
+ char buf[512]; | |
+ unsigned int len, val; | |
+ | |
+ // FIXME: Is the wakeup/restore call needed? | |
+ ath9k_htc_ps_wakeup(priv); | |
+ val = timefunc->getter(priv->ah); | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ len = snprintf(buf, sizeof(buf), "%s: %s\nValue: 0x%08X = %d\n", | |
+ timefunc->name, timefunc->comments, val, val); | |
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len); | |
+} | |
+ | |
+static ssize_t write_file_timefunc(struct file *file, const char __user *user_buf, | |
+ size_t count, loff_t *ppos) | |
+{ | |
+ struct time_func_context *context = file->private_data; | |
+ struct time_func *timefunc = context->timefunc; | |
+ struct ath9k_htc_priv *priv = context->htcpriv; | |
+ unsigned long val; | |
+ char buf[32]; | |
+ ssize_t len; | |
+ | |
+ len = min(count, sizeof(buf) - 1); | |
+ if (copy_from_user(buf, user_buf, len)) | |
+ return -EINVAL; | |
+ | |
+ buf[len] = '\0'; | |
+ if (kstrtoul(buf, 0, &val)) | |
+ return -EINVAL; | |
+ | |
+ // FIXME: Is the wakeup/restore call needed? | |
+ ath9k_htc_ps_wakeup(priv); | |
+ timefunc->setter(priv->ah, (u32)val); | |
+ ath9k_htc_ps_restore(priv); | |
+ | |
+ return count; | |
+} | |
+ | |
+static const struct file_operations fops_timefunc = { | |
+ .read = read_file_timefunc, | |
+ .write = write_file_timefunc, | |
+ .open = simple_open, | |
+ .owner = THIS_MODULE, | |
+ .llseek = default_llseek, | |
+}; | |
+ | |
/* Ethtool support for get-stats */ | |
#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" | |
static const char ath9k_htc_gstrings_stats[][ETH_GSTRING_LEN] = { | |
@@ -488,6 +1170,8 @@ | |
{ | |
struct ath_common *common = ath9k_hw_common(ah); | |
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; | |
+ struct reg_ops_instance *previnstance; | |
+ int i; | |
priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, | |
priv->hw->wiphy->debugfsdir); | |
@@ -516,9 +1200,79 @@ | |
priv, &fops_queue); | |
debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, | |
priv, &fops_debug); | |
+ debugfs_create_file("dmesg", S_IRUSR, priv->debug.debugfs_phy, | |
+ priv, &fops_dmesg); | |
+ debugfs_create_file("reactivejam", S_IRUSR, priv->debug.debugfs_phy, | |
+ priv, &fops_reactivejam); | |
+ debugfs_create_file("constantjam", S_IRUSR, priv->debug.debugfs_phy, | |
+ priv, &fops_constantjam); | |
+ debugfs_create_file("fastreply_packet", S_IRUSR | S_IWUSR, | |
+ priv->debug.debugfs_phy, priv, &fops_fastreply_packet); | |
+ debugfs_create_file("fastreply_start", S_IRUSR | S_IWUSR, | |
+ priv->debug.debugfs_phy, priv, &fops_fastreply_start); | |
+ debugfs_create_file("macaddr", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, | |
+ priv, &fops_macaddr); | |
+ debugfs_create_file("bssidmask", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, | |
+ priv, &fops_bssidmask); | |
+ debugfs_create_file("inject_noack", S_IRUSR | S_IWUSR, | |
+ priv->debug.debugfs_phy, priv, &fops_inject_noack); | |
ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); | |
ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah); | |
+ // | |
+ // Read/write access to registers | |
+ // | |
+ | |
+ priv->debug.debugfs_phy_regs = debugfs_create_dir("registers", priv->debug.debugfs_phy); | |
+ if (!priv->debug.debugfs_phy_regs) | |
+ return -ENOMEM; | |
+ | |
+ previnstance = NULL; | |
+ for (i = 0; i < sizeof(registers) / sizeof(registers[0]); ++i) | |
+ { | |
+ struct reg_ops *regops = ®isters[i]; | |
+ struct reg_ops_instance *instance; | |
+ | |
+ // Allocated linked list is freed in ath9k_hw_deinit | |
+ instance = kzalloc(sizeof(struct reg_ops_instance), GFP_KERNEL); | |
+ if (!instance) return -ENOMEM; | |
+ | |
+ instance->regops = regops; | |
+ instance->owner = priv; | |
+ | |
+ instance->valueset = 0; | |
+ instance->value = 0; | |
+ instance->next = previnstance; | |
+ | |
+ // Read/write access using general functions | |
+ debugfs_create_file(regops->name, S_IRUSR|S_IWUSR, | |
+ priv->debug.debugfs_phy_regs, instance, &fops_reg_ops); | |
+ | |
+ previnstance = instance; | |
+ } | |
+ | |
+ priv->ah->modified_registers = previnstance; | |
+ | |
+ | |
+ // | |
+ // Time functions | |
+ // | |
+ | |
+ for (i = 0; i < sizeof(timefunctions) / sizeof(timefunctions[0]); ++i) | |
+ { | |
+ // Allocate a context | |
+ struct time_func_context *context; | |
+ context = devm_kzalloc(priv->dev, sizeof(struct time_func_context), GFP_KERNEL); | |
+ if (!context) return -ENOMEM; | |
+ | |
+ context->timefunc = &timefunctions[i]; | |
+ context->htcpriv = priv; | |
+ | |
+ // Read/write access using general functions | |
+ debugfs_create_file(context->timefunc->name, S_IRUSR|S_IWUSR, | |
+ priv->debug.debugfs_phy, context, &fops_timefunc); | |
+ } | |
+ | |
return 0; | |
} | |
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_init.c backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_init.c 2016-02-18 22:41:35.000000000 +0100 | |
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_init.c 2016-04-03 13:28:54.000000000 +0200 | |
@@ -99,6 +99,18 @@ | |
static void ath9k_deinit_priv(struct ath9k_htc_priv *priv) | |
{ | |
+ if (priv->debug.debugfs_phy_regs) | |
+ debugfs_remove(priv->debug.debugfs_phy_regs); | |
+ priv->debug.debugfs_phy_regs = NULL; | |
+ | |
+ if (priv->debug.debugfs_phy) | |
+ debugfs_remove(priv->debug.debugfs_phy); | |
+ priv->debug.debugfs_phy = NULL; | |
+ | |
+ if (priv->hw->wiphy->debugfsdir) | |
+ debugfs_remove(priv->hw->wiphy->debugfsdir); | |
+ priv->hw->wiphy->debugfsdir = NULL; | |
+ | |
ath9k_hw_deinit(priv->ah); | |
kfree(priv->ah); | |
priv->ah = NULL; | |
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c 2016-02-18 22:41:36.000000000 +0100 | |
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c 2016-04-03 13:28:54.000000000 +0200 | |
@@ -211,6 +211,7 @@ | |
return error; | |
} | |
+/** Used to handle management and injected frames */ | |
static void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv, | |
struct ath9k_htc_vif *avp, | |
struct sk_buff *skb, | |
@@ -222,6 +223,7 @@ | |
struct tx_mgmt_hdr mgmt_hdr; | |
struct ath9k_htc_tx_ctl *tx_ctl; | |
u8 *tx_fhdr; | |
+ u8 flags = 0; | |
tx_ctl = HTC_SKB_CB(skb); | |
hdr = (struct ieee80211_hdr *) skb->data; | |
@@ -238,12 +240,19 @@ | |
mgmt->u.probe_resp.timestamp = avp->tsfadjust; | |
} | |
+ /* Should firmware assign sequence number */ | |
+ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) | |
+ flags |= ATH9K_HTC_TX_ASSIGN_SEQ; | |
+ /* Don't retransmit injected packets if requested so */ | |
+ if (unlikely(priv->inject_noack && (tx_info->flags & IEEE80211_TX_CTL_INJECTED))) | |
+ flags |= ATH9K_HTC_TX_NO_ACK; | |
+ | |
tx_ctl->type = ATH9K_HTC_MGMT; | |
mgmt_hdr.node_idx = sta_idx; | |
mgmt_hdr.vif_idx = vif_idx; | |
mgmt_hdr.tidno = 0; | |
- mgmt_hdr.flags = 0; | |
+ mgmt_hdr.flags = flags; | |
mgmt_hdr.cookie = slot; | |
mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); | |
@@ -302,6 +311,13 @@ | |
tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | |
} | |
+ /* Should firmware assign sequence number */ | |
+ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) | |
+ flags |= ATH9K_HTC_TX_ASSIGN_SEQ; | |
+ /* Don't retransmit injected packets if requested so */ | |
+ if (unlikely(priv->inject_noack && (tx_info->flags & IEEE80211_TX_CTL_INJECTED))) | |
+ flags |= ATH9K_HTC_TX_NO_ACK; | |
+ | |
/* Check for RTS protection */ | |
if (priv->hw->wiphy->rts_threshold != (u32) -1) | |
if (skb->len > priv->hw->wiphy->rts_threshold) | |
@@ -373,12 +389,11 @@ | |
sta_idx = priv->vif_sta_pos[vif_idx]; | |
} | |
- if (ieee80211_is_data(hdr->frame_control)) | |
- ath9k_htc_tx_data(priv, vif, skb, | |
- sta_idx, vif_idx, slot, is_cab); | |
+ /** Treat injected frames as management frames to avoid modifications to them */ | |
+ if (ieee80211_is_data(hdr->frame_control) && !(tx_info->flags & IEEE80211_TX_CTL_INJECTED)) | |
+ ath9k_htc_tx_data(priv, vif, skb, sta_idx, vif_idx, slot, is_cab); | |
else | |
- ath9k_htc_tx_mgmt(priv, avp, skb, | |
- sta_idx, vif_idx, slot); | |
+ ath9k_htc_tx_mgmt(priv, avp, skb, sta_idx, vif_idx, slot); | |
return htc_send(priv->htc, skb); | |
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc.h backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc.h | |
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc.h 2016-02-18 22:41:35.000000000 +0100 | |
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc.h 2016-04-03 13:28:54.000000000 +0200 | |
@@ -69,6 +69,8 @@ | |
#define ATH9K_HTC_TX_CTSONLY 0x1 | |
#define ATH9K_HTC_TX_RTSCTS 0x2 | |
+#define ATH9K_HTC_TX_ASSIGN_SEQ 0x10 | |
+#define ATH9K_HTC_TX_NO_ACK 0x20 | |
struct tx_frame_hdr { | |
u8 data_type; | |
@@ -357,6 +359,7 @@ | |
struct ath9k_debug { | |
struct dentry *debugfs_phy; | |
+ struct dentry *debugfs_phy_regs; | |
struct ath_tx_stats tx_stats; | |
struct ath_rx_stats rx_stats; | |
struct ath_skbrx_stats skbrx_stats; | |
@@ -510,6 +513,9 @@ | |
bool ps_enabled; | |
bool ps_idle; | |
+ /** If set, injected packets are never retransmitted (not waiting for ACK) */ | |
+ u8 inject_noack; | |
+ | |
#ifdef CPTCFG_MAC80211_LEDS | |
enum led_brightness brightness; | |
bool led_registered; | |
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/hw.c backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/hw.c | |
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/hw.c 2016-02-18 22:41:36.000000000 +0100 | |
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/hw.c 2016-04-03 13:28:54.000000000 +0200 | |
@@ -67,6 +67,7 @@ | |
common->clockrate = clockrate; | |
} | |
+/** This is the clockrate of the wireless chip (not the chip running the firmware for ath9k_htc) */ | |
static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) | |
{ | |
struct ath_common *common = ath9k_hw_common(ah); | |
@@ -74,6 +75,17 @@ | |
return usecs * common->clockrate; | |
} | |
+/** This is the clockrate of the wireless chip (not the chip running the firmware for ath9k_htc) */ | |
+static u32 ath9k_hw_mac_to_usecs(struct ath_hw *ah, u32 clks) | |
+{ | |
+ struct ath_common *common = ath9k_hw_common(ah); | |
+ | |
+ if (common->clockrate == 0) | |
+ return 0xFFFFFFFF; | |
+ | |
+ return clks / common->clockrate; | |
+} | |
+ | |
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) | |
{ | |
int i; | |
@@ -246,6 +258,24 @@ | |
centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT); | |
} | |
+static void ath9k_restore_registers(struct ath_hw *ah) | |
+{ | |
+ struct reg_ops_instance *saved_reg = ah->modified_registers; | |
+ int regval; | |
+ | |
+ while (saved_reg != NULL) | |
+ { | |
+ if (saved_reg->valueset) | |
+ { | |
+ regval = REG_READ(ah, saved_reg->regops->address); | |
+ regval = (regval & ~saved_reg->regops->mask) | saved_reg->value; | |
+ REG_WRITE(ah, saved_reg->regops->address, regval); | |
+ } | |
+ | |
+ saved_reg = saved_reg->next; | |
+ } | |
+} | |
+ | |
/******************/ | |
/* Chip Revisions */ | |
/******************/ | |
@@ -972,33 +1002,78 @@ | |
} | |
} | |
-static void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us) | |
+void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us) | |
{ | |
u32 val = ath9k_hw_mac_to_clks(ah, us - 2); | |
- val = min(val, (u32) 0xFFFF); | |
+ val &= AR_D_GBL_IFS_SIFS_M; | |
REG_WRITE(ah, AR_D_GBL_IFS_SIFS, val); | |
} | |
+EXPORT_SYMBOL(ath9k_hw_set_sifs_time); | |
void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) | |
{ | |
u32 val = ath9k_hw_mac_to_clks(ah, us); | |
- val = min(val, (u32) 0xFFFF); | |
+ val &= AR_D_GBL_IFS_SLOT_M; | |
REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val); | |
} | |
+EXPORT_SYMBOL(ath9k_hw_setslottime); | |
void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) | |
{ | |
u32 val = ath9k_hw_mac_to_clks(ah, us); | |
- val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK)); | |
REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val); | |
} | |
+EXPORT_SYMBOL(ath9k_hw_set_ack_timeout); | |
void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) | |
{ | |
u32 val = ath9k_hw_mac_to_clks(ah, us); | |
- val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS)); | |
REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, val); | |
} | |
+EXPORT_SYMBOL(ath9k_hw_set_cts_timeout); | |
+ | |
+void ath9k_hw_set_eifs_timeout(struct ath_hw *ah, u32 us) | |
+{ | |
+ u32 val = ath9k_hw_mac_to_clks(ah, us); | |
+ val &= AR_D_GBL_IFS_EIFS; | |
+ REG_WRITE(ah, AR_D_GBL_IFS_EIFS, val); | |
+} | |
+EXPORT_SYMBOL(ath9k_hw_set_eifs_timeout); | |
+ | |
+u32 ath9k_hw_get_sifs_time(struct ath_hw *ah) | |
+{ | |
+ u32 val = REG_READ(ah, AR_D_GBL_IFS_SIFS) & AR_D_GBL_IFS_SIFS_M; | |
+ return ath9k_hw_mac_to_usecs(ah, val) + 2; | |
+} | |
+EXPORT_SYMBOL(ath9k_hw_get_sifs_time); | |
+ | |
+u32 ath9k_hw_getslottime(struct ath_hw *ah) | |
+{ | |
+ u32 val = REG_READ(ah, AR_D_GBL_IFS_SLOT) & AR_D_GBL_IFS_SLOT_M; | |
+ return ath9k_hw_mac_to_usecs(ah, val); | |
+} | |
+EXPORT_SYMBOL(ath9k_hw_getslottime); | |
+ | |
+u32 ath9k_hw_get_ack_timeout(struct ath_hw *ah) | |
+{ | |
+ u32 val = MS(REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); | |
+ return ath9k_hw_mac_to_usecs(ah, val); | |
+} | |
+EXPORT_SYMBOL(ath9k_hw_get_ack_timeout); | |
+ | |
+u32 ath9k_hw_get_cts_timeout(struct ath_hw *ah) | |
+{ | |
+ u32 val = MS(REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); | |
+ return ath9k_hw_mac_to_usecs(ah, val); | |
+} | |
+EXPORT_SYMBOL(ath9k_hw_get_cts_timeout); | |
+ | |
+u32 ath9k_hw_get_eifs_timeout(struct ath_hw *ah) | |
+{ | |
+ u32 val = REG_READ(ah, AR_D_GBL_IFS_EIFS) & AR_D_GBL_IFS_EIFS_M; | |
+ return ath9k_hw_mac_to_usecs(ah, val); | |
+} | |
+EXPORT_SYMBOL(ath9k_hw_get_eifs_timeout); | |
static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) | |
{ | |
@@ -2025,6 +2100,8 @@ | |
if (AR_SREV_9565(ah) && common->bt_ant_diversity) | |
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); | |
+ ath9k_restore_registers(ah); | |
+ | |
if (ah->hw->conf.radar_enabled) { | |
/* set HW specific DFS configuration */ | |
ah->radar_conf.ext_channel = IS_CHAN_HT40(chan); | |
@@ -2173,6 +2250,8 @@ | |
REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); | |
+ ath9k_restore_registers(ah); | |
+ | |
return true; | |
} | |
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/hw.h backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/hw.h | |
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/hw.h 2016-02-18 22:41:36.000000000 +0100 | |
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/hw.h 2016-04-03 13:28:54.000000000 +0200 | |
@@ -761,6 +761,40 @@ | |
TX_CL_CAL = BIT(2), | |
}; | |
+/** | |
+ * reg_ops - describes one specific functionality of a particular register | |
+ * | |
+ * @name: name of the register as used in debugfs | |
+ * @address: memory address of the register | |
+ * @mask: mask for the specific functionality we are exposing. One single addresses | |
+ * may have multiple reg_ops, one for each mask/functionality. | |
+ * @description: human readable description of the functionality | |
+ */ | |
+struct reg_ops { | |
+ const char *name; | |
+ unsigned int address; | |
+ unsigned int mask; | |
+ const char *description; | |
+}; | |
+ | |
+/** | |
+ * reg_ops_instance - describes a specific configuration of a reg_ops register | |
+ * | |
+ * @regops: the register functionality we are referencing | |
+ * @valueset: did the user write a custom value to this register? | |
+ * @value: the value the user wrote to the register | |
+ * @owner: the interface on which the custom value was set | |
+ * | |
+ * @next: pointer to next reg_ops_instance, to create linked lists | |
+ */ | |
+struct reg_ops_instance { | |
+ struct reg_ops *regops; | |
+ char valueset; | |
+ unsigned int value; | |
+ struct ath9k_htc_priv *owner; | |
+ struct reg_ops_instance *next; | |
+}; | |
+ | |
/* ah_flags */ | |
#define AH_USE_EEPROM 0x1 | |
#define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ | |
@@ -972,6 +1006,9 @@ | |
struct ath_dynack dynack; | |
+ /** Linked list of (possibly) manually overwritten registers */ | |
+ struct reg_ops_instance *modified_registers; | |
+ | |
bool tpc_enabled; | |
u8 tx_power[Ar5416RateSize]; | |
u8 tx_power_stbc[Ar5416RateSize]; | |
@@ -1066,6 +1103,18 @@ | |
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); | |
+void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us); | |
+void ath9k_hw_setslottime(struct ath_hw *ah, u32 us); | |
+void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us); | |
+void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us); | |
+void ath9k_hw_set_eifs_timeout(struct ath_hw *ah, u32 us); | |
+ | |
+u32 ath9k_hw_get_sifs_time(struct ath_hw *ah); | |
+u32 ath9k_hw_getslottime(struct ath_hw *ah); | |
+u32 ath9k_hw_get_ack_timeout(struct ath_hw *ah); | |
+u32 ath9k_hw_get_cts_timeout(struct ath_hw *ah); | |
+u32 ath9k_hw_get_eifs_timeout(struct ath_hw *ah); | |
+ | |
/* Generic hw timer primitives */ | |
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, | |
void (*trigger)(void *), | |
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/Kconfig backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/Kconfig | |
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/Kconfig 2016-02-18 22:41:36.000000000 +0100 | |
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/Kconfig 2016-04-03 13:28:55.000000000 +0200 | |
@@ -167,6 +167,7 @@ | |
select BPAUTO_LEDS_CLASS | |
select BPAUTO_NEW_LEDS | |
select ATH9K_COMMON | |
+ select ATH9K_HTC_DEBUGFS | |
---help--- | |
Support for Atheros HTC based cards. | |
Chipsets supported: AR9271 | |
@@ -177,6 +178,6 @@ | |
config ATH9K_HTC_DEBUGFS | |
bool "Atheros ath9k_htc debugging" | |
- depends on ATH9K_HTC && DEBUG_FS | |
+ depends on DEBUG_FS | |
---help--- | |
Say Y, if you need access to ath9k_htc's statistics. | |
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/wmi.c backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/wmi.c | |
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/wmi.c 2016-02-18 22:41:35.000000000 +0100 | |
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/wmi.c 2016-04-03 13:28:54.000000000 +0200 | |
@@ -83,6 +83,14 @@ | |
return "WMI_RX_STATS_CMDID"; | |
case WMI_BITRATE_MASK_CMDID: | |
return "WMI_BITRATE_MASK_CMDID"; | |
+ case WMI_DEBUGMSG_CMDID: | |
+ return "WMI_DEBUGMSG_CMDID"; | |
+ case WMI_REACTIVEJAM_CMDID: | |
+ return "WMI_REACTIVEJAM_CMDID"; | |
+ case WMI_FASTREPLY_CMDID: | |
+ return "WMI_FASTREPLY_CMDID"; | |
+ case WMI_CONSTANTJAM_CMDID: | |
+ return "WMI_CONSTANTJAM_CMDID"; | |
} | |
return "Bogus"; | |
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/wmi.h backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/wmi.h | |
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/wmi.h 2016-02-18 22:41:36.000000000 +0100 | |
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/wmi.h 2016-04-03 13:28:54.000000000 +0200 | |
@@ -113,6 +113,12 @@ | |
WMI_RX_STATS_CMDID, | |
WMI_BITRATE_MASK_CMDID, | |
WMI_REG_RMW_CMDID, | |
+ | |
+ /* Custom commands added */ | |
+ WMI_DEBUGMSG_CMDID = 0x0080, | |
+ WMI_REACTIVEJAM_CMDID, | |
+ WMI_FASTREPLY_CMDID, | |
+ WMI_CONSTANTJAM_CMDID, | |
}; | |
enum wmi_event_id { | |
@@ -145,6 +151,65 @@ | |
struct list_head list; | |
}; | |
+struct wmi_debugmsg_cmd { | |
+ __be16 offset; | |
+} __packed; | |
+ | |
+struct wmi_debugmsg_resp { | |
+ /** Length of zero signifies that no more data is available */ | |
+ u8 length; | |
+ /** Debug message(s) **/ | |
+ u8 buffer[40]; | |
+} __packed; | |
+ | |
+struct wmi_reactivejam_cmd { | |
+ u8 bssid[6]; | |
+ u32 mduration; | |
+} __packed; | |
+ | |
+struct wmi_constantjam_cmd { | |
+ /** A value from CONSTJAM_REQUEST to denote the request */ | |
+ u8 request; | |
+ /** Set to 1 to disable CS and inter-frame-timeouts */ | |
+ u8 conf_radio; | |
+ /** Length of the packet which is continuously transmitted */ | |
+ u16 len; | |
+} __packed; | |
+ | |
+struct wmi_constantjam_resp { | |
+ /** Is 1 when jammer is running, 0 otherwise */ | |
+ u8 status; | |
+} __packed; | |
+ | |
+enum CONSTJAM_REQUEST { | |
+ CONSTJAM_START, | |
+ CONSTJAM_STOP, | |
+ CONSTJAM_STATUS | |
+}; | |
+ | |
+struct wmi_fastreply_cmd { | |
+ u8 type; | |
+ union { | |
+ // transmit response packet in multiple commands | |
+ struct { | |
+ u8 length; | |
+ u8 offset; | |
+ u8 datalen; | |
+ u8 data[40]; | |
+ } pkt; | |
+ // command to start monitoring | |
+ struct { | |
+ u32 mduration; | |
+ u8 source[6]; | |
+ } start; | |
+ }; | |
+} __packed; | |
+ | |
+enum FASTREPLY_TYPE { | |
+ FASTREPLY_PKT, | |
+ FASTREPLY_START | |
+}; | |
+ | |
struct wmi { | |
struct ath9k_htc_priv *drv_priv; | |
struct htc_target *htc; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment