diff options
Diffstat (limited to 'ath.patch')
-rw-r--r-- | ath.patch | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/ath.patch b/ath.patch new file mode 100644 index 000000000000..559820938c9a --- /dev/null +++ b/ath.patch @@ -0,0 +1,476 @@ +diff --git i/drivers/net/wireless/ath/ath9k/htc.h w/drivers/net/wireless/ath/ath9k/htc.h +index 16dff4b89a86..63eea0bc6097 100644 +--- i/drivers/net/wireless/ath/ath9k/htc.h ++++ w/drivers/net/wireless/ath/ath9k/htc.h +@@ -604,6 +604,9 @@ void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); + + struct base_eep_header *ath9k_htc_get_eeprom_base(struct ath9k_htc_priv *priv); + ++// TODO make more generic: any argument instead of just 2 int32s ++int dbg_firmware_cmd(struct ath9k_htc_priv *priv, u8 cmd_id, u32 arguments[2]); ++ + #ifdef CONFIG_MAC80211_LEDS + void ath9k_configure_leds(struct ath9k_htc_priv *priv); + void ath9k_init_leds(struct ath9k_htc_priv *priv); +diff --git i/drivers/net/wireless/ath/ath9k/htc_drv_debug.c w/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +index dc79afd7e151..3e0d1a35ef6f 100644 +--- i/drivers/net/wireless/ath/ath9k/htc_drv_debug.c ++++ w/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +@@ -14,6 +14,7 @@ + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + ++#include <net/genetlink.h> + #include "htc.h" + + static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, +@@ -479,13 +480,298 @@ void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, + WARN_ON(i != ATH9K_HTC_SSTATS_LEN); + } + ++struct ath9k_htc_priv *genl_ath9k_priv = NULL; ++ ++enum { ++ ATH9K_HTC_A_UNSPEC, ++ ATH9K_HTC_A_STR, ++ ATH9K_HTC_A_REG, ++ ATH9K_HTC_A_VAL, ++ ATH9K_HTC_A_MAX, ++}; ++ ++enum { ++ ATH9K_HTC_C_UNSPEC, ++ ATH9K_C_ECHO, ++ ATH9K_C_SET, ++ ATH9K_C_RATE, ++ ATH9K_C_RESET, ++ ATH9K_C_MAX, ++}; ++ ++/* attribute policy: defines which attribute has which type (e.g int, char * etc) ++ * possible values defined in net/netlink.h ++ */ ++static struct nla_policy ath9k_htc_genl_policy[ATH9K_HTC_A_MAX] = { ++ [ATH9K_HTC_A_STR] = { .type = NLA_NUL_STRING }, ++ [ATH9K_HTC_A_REG] = { .type = NLA_U32 }, ++ [ATH9K_HTC_A_VAL] = { .type = NLA_U32 }, ++}; ++ ++static struct genl_family ath9k_htc_gnl_family = { ++ .id = GENL_ID_GENERATE, ++ .hdrsize = 0, ++ .name = "ATH9K_HTC", ++ .version = 1, ++ .maxattr = ATH9K_HTC_A_MAX-1, ++}; ++ ++static int ath9k_echo(struct sk_buff *iskb, struct genl_info *info) { ++ struct nlattr *received_str_attr; ++ char *received_str; ++ struct sk_buff *skb; ++ int errc; ++ void *msg_head; ++ ++ if (info == NULL) ++ goto out; ++ ++ received_str_attr = info->attrs[ATH9K_HTC_A_STR]; ++ if (received_str_attr) { ++ received_str = (char *)nla_data(received_str_attr); ++ if (received_str != NULL) ++ printk("ath9k_htc: got %s\n", received_str); ++ else ++ printk(KERN_ERR "error while receiving data\n"); ++ } else { ++ printk(KERN_ERR "attribute %i not present\n", ATH9K_HTC_A_STR); ++ } ++ ++ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (skb == NULL) ++ goto out; ++ ++ msg_head = genlmsg_put(skb, 0, info->snd_seq + 1, &ath9k_htc_gnl_family, 0, ATH9K_C_ECHO); ++ if (msg_head == NULL) { ++ errc = -ENOMEM; ++ goto out; ++ } ++ ++ errc = nla_put_string(skb, ATH9K_HTC_A_STR, "pong"); ++ if (errc != 0) ++ goto out; ++ ++ genlmsg_end(skb, msg_head); ++ ++ errc = genlmsg_unicast(genl_info_net(info), skb, info->snd_portid); ++ if (errc != 0) ++ goto out; ++ ++ return 0; ++ ++out: ++ printk(KERN_ERR "an error occured in ath9k_echo:\n"); ++ ++ return 1; ++} ++ ++static int ath9k_set_reg(struct sk_buff *iskb, struct genl_info *info) { ++ struct nlattr *received_int_attr; ++ u32 *received_reg = NULL; ++ u32 *received_val = NULL; ++ struct sk_buff *skb; ++ int errc; ++ void *msg_head; ++ u32 vals[2]; ++ ++ if (info == NULL) ++ goto out; ++ ++ // TODO repeated code... simplify ++ received_int_attr = info->attrs[ATH9K_HTC_A_REG]; ++ if (received_int_attr) { ++ received_reg = (u32*)nla_data(received_int_attr); ++ if(received_reg) ++ printk("ath9k_htc: reg %08x\n", *received_reg); ++ } else { ++ printk(KERN_ERR "attribute %i not present\n", ATH9K_HTC_A_REG); ++ } ++ ++ received_int_attr = info->attrs[ATH9K_HTC_A_VAL]; ++ if (received_int_attr) { ++ received_val = (u32*)nla_data(received_int_attr); ++ if(received_val) ++ printk("ath9k_htc: val %08x\n", *received_val); ++ } else { ++ printk(KERN_ERR "attribute %i not present\n", ATH9K_HTC_A_VAL); ++ } ++ ++ if(received_reg) ++ vals[0] = *received_reg; ++ ++ if(received_val) ++ vals[1] = *received_val; ++ ++ dbg_firmware_cmd(genl_ath9k_priv, DBG_CMD_SET_REG, vals); ++ ++ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (skb == NULL) ++ goto out; ++ ++ msg_head = genlmsg_put(skb, 0, info->snd_seq + 1, &ath9k_htc_gnl_family, 0, ATH9K_C_SET); ++ if (msg_head == NULL) { ++ errc = -ENOMEM; ++ goto out; ++ } ++ ++ errc = nla_put_string(skb, ATH9K_HTC_A_STR, "reg set successfully"); ++ if (errc != 0) ++ goto out; ++ ++ genlmsg_end(skb, msg_head); ++ ++ errc = genlmsg_unicast(genl_info_net(info), skb, info->snd_portid); ++ if (errc != 0) ++ goto out; ++ ++ return 0; ++ ++out: ++ printk(KERN_ERR "an error occured\n"); ++ ++ return 1; ++} ++ ++static int ath9k_set_rate(struct sk_buff *iskb, struct genl_info *info) { ++ struct nlattr *received_int_attr; ++ u32 *received_val = NULL; ++ struct sk_buff *skb; ++ int errc; ++ void *msg_head; ++ u32 vals[2]; ++ ++ if (info == NULL) ++ goto out; ++ ++ // TODO repeated code... simplify ++ received_int_attr = info->attrs[ATH9K_HTC_A_VAL]; ++ if (received_int_attr) { ++ received_val = (u32*)nla_data(received_int_attr); ++ if(received_val) ++ printk("ath9k_htc: val %08x\n", *received_val); ++ } else { ++ printk(KERN_ERR "attribute %i not present\n", ATH9K_HTC_A_VAL); ++ } ++ ++ if(received_val) ++ vals[0] = *received_val; ++ ++ dbg_firmware_cmd(genl_ath9k_priv, DBG_CMD_SET_RATE, vals); ++ ++ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (skb == NULL) ++ goto out; ++ ++ msg_head = genlmsg_put(skb, 0, info->snd_seq + 1, &ath9k_htc_gnl_family, 0, ATH9K_C_RATE); ++ if (msg_head == NULL) { ++ errc = -ENOMEM; ++ goto out; ++ } ++ ++ errc = nla_put_string(skb, ATH9K_HTC_A_STR, "rate set successfully"); ++ if (errc != 0) ++ goto out; ++ ++ genlmsg_end(skb, msg_head); ++ ++ errc = genlmsg_unicast(genl_info_net(info), skb, info->snd_portid); ++ if (errc != 0) ++ goto out; ++ ++ return 0; ++ ++out: ++ printk(KERN_ERR "an error occured\n"); ++ ++ return 1; ++} ++ ++static int ath9k_reset(struct sk_buff *iskb, struct genl_info *info) { ++ struct sk_buff *skb; ++ int errc; ++ void *msg_head; ++ u32 vals[2]; ++ ++ if (info == NULL) ++ goto out; ++ ++ dbg_firmware_cmd(genl_ath9k_priv, DBG_CMD_RESET, vals); ++ ++ // TODO repeated code... simplify ++ skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); ++ if (skb == NULL) ++ goto out; ++ ++ msg_head = genlmsg_put(skb, 0, info->snd_seq + 1, &ath9k_htc_gnl_family, 0, ATH9K_C_RESET); ++ if (msg_head == NULL) { ++ errc = -ENOMEM; ++ goto out; ++ } ++ ++ errc = nla_put_string(skb, ATH9K_HTC_A_STR, "reset counters"); ++ if (errc != 0) ++ goto out; ++ ++ genlmsg_end(skb, msg_head); ++ ++ errc = genlmsg_unicast(genl_info_net(info), skb, info->snd_portid); ++ if (errc != 0) ++ goto out; ++ ++ return 0; ++ ++out: ++ printk(KERN_ERR "an error occured\n"); ++ ++ return 1; ++} ++ ++static struct genl_ops ath9k_htc_gnl_ops[] = { ++ { ++ .cmd = ATH9K_C_ECHO, ++ .flags = 0, ++ .policy = ath9k_htc_genl_policy, ++ .doit = ath9k_echo, ++ .dumpit = NULL, ++ }, ++ { ++ .cmd = ATH9K_C_SET, ++ .flags = 0, ++ .policy = ath9k_htc_genl_policy, ++ .doit = ath9k_set_reg, ++ .dumpit = NULL, ++ }, ++ { ++ .cmd = ATH9K_C_RATE, ++ .flags = 0, ++ .policy = ath9k_htc_genl_policy, ++ .doit = ath9k_set_rate, ++ .dumpit = NULL, ++ }, ++ { ++ .cmd = ATH9K_C_RESET, ++ .flags = 0, ++ .policy = ath9k_htc_genl_policy, ++ .doit = ath9k_reset, ++ .dumpit = NULL, ++ }, ++}; ++ ++ + void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) + { ++ int errc; + ath9k_cmn_spectral_deinit_debug(&priv->spec_priv); ++ ++ errc = genl_unregister_family(&ath9k_htc_gnl_family); ++ if(errc != 0){ ++ printk(KERN_ERR "unregister family %i\n", errc); ++ } + } + + int ath9k_htc_init_debug(struct ath_hw *ah) + { ++ int errc; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + +@@ -520,5 +806,14 @@ int ath9k_htc_init_debug(struct ath_hw *ah) + ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); + ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah); + ++ /* ath9k_htc netlink interface */ ++ // TODO only works with one interface at the same time! ++ genl_ath9k_priv = priv; ++ errc = genl_register_family_with_ops(&ath9k_htc_gnl_family, ath9k_htc_gnl_ops); ++ if (errc != 0) { ++ printk("genl_register_family_with_ops error\n"); ++ return 1; ++ } ++ + return 0; + } +diff --git i/drivers/net/wireless/ath/ath9k/htc_drv_init.c w/drivers/net/wireless/ath/ath9k/htc_drv_init.c +index defacc6c9c99..df7ddfde9423 100644 +--- i/drivers/net/wireless/ath/ath9k/htc_drv_init.c ++++ w/drivers/net/wireless/ath/ath9k/htc_drv_init.c +@@ -231,6 +231,59 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, + ath9k_hw_regulatory(priv->ah)); + } + ++static void fancy_printk(u8* buffer, u8 id, u8 len) { ++ u8 temp[400]; ++ int i; ++ int counth = 0; ++ int countc = 0; ++ ++ for(i = 0; i < len; i++) { ++ sprintf(temp + (counth * 3), "%02x ", buffer[i]); ++ counth++; ++ } ++ ++ sprintf(temp + (counth * 3), "| "); ++ ++ for(i = 0; i < len; i++) { ++ if((buffer[i] > '!' && buffer[i] < '~') || buffer[i] == ' ') { ++ sprintf(temp + (counth * 3) + 2 + countc, "%c", buffer[i]); ++ } else { ++ sprintf(temp + (counth * 3) + 2 + countc, "%c", '.'); ++ } ++ countc++; ++ } ++ printk(KERN_ERR "firmware: %s (cmd %d)\n", temp, id); ++} ++ ++int dbg_firmware_cmd(struct ath9k_htc_priv *priv, u8 cmd_id, u32 arguments[2]) ++{ ++ struct dbg_cmd_request cmd; ++ struct dbg_cmd_response cmd_rsp; ++ int ret; ++ ++ // Prepare command ++ memset(&cmd, 0, sizeof(cmd)); ++ cmd.id = cmd_id; ++ if(arguments != NULL) { ++ cmd.args[0] = cpu_to_be32(arguments[0]); ++ cmd.args[1] = cpu_to_be32(arguments[1]); ++ } ++ ++ // Prepare response ++ memset(&cmd_rsp, 0, sizeof(cmd_rsp)); ++ ++ do { ++ ret = ath9k_wmi_cmd(priv->wmi, WMI_DBGCMD_CMDID, (u8 *)&cmd, sizeof(cmd), (u8 *)&cmd_rsp, sizeof(cmd_rsp), HZ*2); ++ if (ret) ++ return -EINVAL; ++ ++ if(cmd_rsp.length > 0) ++ fancy_printk(cmd_rsp.buffer, cmd_id, cmd_rsp.length); ++ } while(cmd_rsp.length != 0); ++ ++ return 0; ++} ++ + static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) + { + struct ath_hw *ah = (struct ath_hw *) hw_priv; +@@ -249,6 +302,9 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) + return -EIO; + } + ++ // Piggyback reading of firmware print buffer ++ dbg_firmware_cmd(priv, DBG_CMD_READ_MEMORY, NULL); ++ + return be32_to_cpu(val); + } + +diff --git i/drivers/net/wireless/ath/ath9k/wmi.c w/drivers/net/wireless/ath/ath9k/wmi.c +index 64a354fa78ab..f34e0d6007a5 100644 +--- i/drivers/net/wireless/ath/ath9k/wmi.c ++++ w/drivers/net/wireless/ath/ath9k/wmi.c +@@ -83,6 +83,11 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) + return "WMI_RX_STATS_CMDID"; + case WMI_BITRATE_MASK_CMDID: + return "WMI_BITRATE_MASK_CMDID"; ++ case WMI_REG_RMW_CMDID: ++ return "WMI_REG_RMW_CMDID"; // Bugfix ++ // New stuff ++ case WMI_DBGCMD_CMDID: ++ return "WMI_DBGCMD_CMDID"; + } + + return "Bogus"; +@@ -334,6 +339,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, + if (!time_left) { + ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n", + wmi_cmd_to_name(cmd_id)); ++ printk(KERN_ERR "ath9k_htc: Timeout waiting for command %s", wmi_cmd_to_name(cmd_id)); + mutex_unlock(&wmi->op_mutex); + return -ETIMEDOUT; + } +diff --git i/drivers/net/wireless/ath/ath9k/wmi.h w/drivers/net/wireless/ath/ath9k/wmi.h +index 380175d5ecd7..0f9518b3ea1c 100644 +--- i/drivers/net/wireless/ath/ath9k/wmi.h ++++ w/drivers/net/wireless/ath/ath9k/wmi.h +@@ -41,6 +41,25 @@ struct wmi_event_swba { + u8 beacon_pending; + } __packed; + ++// New stuff ++typedef enum { ++ DBG_CMD_READ_MEMORY, ++ DBG_CMD_TEST, ++ DBG_CMD_SET_REG, ++ DBG_CMD_SET_RATE, ++ DBG_CMD_RESET ++} DBG_CMD_ID; ++ ++struct dbg_cmd_request { ++ u8 id; ++ __be32 args[2]; ++} __packed; ++ ++struct dbg_cmd_response { ++ u8 length; ++ u8 buffer[33]; // WMI does not allow big packets ++} __packed; ++ + /* + * 64 - HTC header - WMI header - 1 / txstatus + * And some other hdr. space is also accounted for. +@@ -113,6 +132,7 @@ enum wmi_cmd_id { + WMI_RX_STATS_CMDID, + WMI_BITRATE_MASK_CMDID, + WMI_REG_RMW_CMDID, ++ WMI_DBGCMD_CMDID, + }; + + enum wmi_event_id { |