/* Write WMI command (w/o mbox header) to this file to send it * WMI starts from wil6210_mbox_hdr_wmi header */ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wmi_cmd_hdr *wmi; void *cmd; int cmdlen = len - sizeof(struct wmi_cmd_hdr); u16 cmdid; int rc, rc1; if (cmdlen < 0) return -EINVAL; wmi = kmalloc(len, GFP_KERNEL); if (!wmi) return -ENOMEM; rc = simple_write_to_buffer(wmi, len, ppos, buf, len); if (rc < 0) { kfree(wmi); return rc; } cmd = (cmdlen > 0) ? &wmi[1] : NULL; cmdid = le16_to_cpu(wmi->command_id); rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen); kfree(wmi); wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1); return rc; }
int marlin_priv_cmd(struct net_device *ndev, struct ifreq *ifr) { struct wlan_vif_t *vif; struct android_wifi_priv_cmd priv_cmd; char *command = NULL; u8 addr[ETH_ALEN] = {0}; int bytes_written = 0; int ret = 0; vif = ndev_to_vif(ndev); if (!ifr->ifr_data) return -EINVAL; if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(struct android_wifi_priv_cmd))) return -EFAULT; command = kmalloc(priv_cmd.total_len, GFP_KERNEL); if (!command) { printke("%s: Failed to allocate command!\n", __func__); return -ENOMEM; } if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) { ret = -EFAULT; goto exit; } if (strnicmp(command, CMD_BLACKLIST_ENABLE, strlen(CMD_BLACKLIST_ENABLE)) == 0) { int skip = strlen(CMD_BLACKLIST_ENABLE) + 1; printke("%s, Received regular blacklist enable command\n", __func__); sscanf(command + skip, "" MACSTR "", STR2MAC(addr)); bytes_written = wlan_cmd_add_blacklist(vif, addr); } else if (strnicmp(command, CMD_BLACKLIST_DISABLE, strlen(CMD_BLACKLIST_DISABLE)) == 0) { int skip = strlen(CMD_BLACKLIST_DISABLE) + 1; printke("%s, Received regular blacklist disable command\n", __func__); sscanf(command + skip, "" MACSTR "", STR2MAC(addr)); bytes_written = wlan_cmd_del_blacklist(vif, addr); } if (bytes_written < 0) ret = bytes_written; exit: kfree(command); return ret; }
static void wlan_tx_timeout(struct net_device *dev) { wlan_vif_t *vif; printke("%s tx timeout\n", dev->name); vif = ndev_to_vif(dev); if (!netif_carrier_ok(dev)) netif_carrier_on(dev); dev->trans_start = jiffies; wake_net(vif->id); core_up(); return; }
static int wlan_xmit(struct sk_buff *skb, struct net_device *dev) { wlan_vif_t *vif; tx_msg_t msg = { 0 }; msg_q_t *msg_q; int ret, addr_len = 0; struct sk_buff *wapi_skb; vif = ndev_to_vif(dev); msg_q = wlan_tcpack_q(vif, skb->data, skb->len); if (vif->cfg80211.cipher_type == WAPI && vif->cfg80211.connect_status == ITM_CONNECTED && vif->cfg80211.key_len[PAIRWISE][vif->cfg80211. key_index[PAIRWISE]] != 0 && (*(u16 *) ((u8 *) skb->data + ETH_PKT_TYPE_OFFSET) != 0xb488)) { wapi_skb = dev_alloc_skb(skb->len + 100 + NET_IP_ALIGN); skb_reserve(wapi_skb, NET_IP_ALIGN); memcpy(wapi_skb->data, skb->data, ETHERNET_HDR_LEN); addr_len = wlan_tx_wapi_encryption(vif, skb->data, (skb->len - ETHERNET_HDR_LEN), ((unsigned char *)(wapi_skb->data) + ETHERNET_HDR_LEN)); addr_len = addr_len + ETHERNET_HDR_LEN; skb_put(wapi_skb, addr_len); dev_kfree_skb(skb); skb = wapi_skb; } msg.p = (void *)skb; msg.slice[0].data = skb->data; msg.slice[0].len = skb->len; msg.hdr.mode = vif->id; msg.hdr.type = HOST_SC2331_PKT; msg.hdr.subtype = 0; msg.hdr.len = skb->len; ret = msg_q_in(msg_q, &msg); if (OK != ret) { printkd("L-PKT\n"); dev_kfree_skb(skb); return NETDEV_TX_OK; } vif->ndev->stats.tx_bytes += skb->len; vif->ndev->stats.tx_packets++; dev->trans_start = jiffies; g_wlan.wlan_core.need_tx++; core_up(); return NETDEV_TX_OK; }
static int wil_bf_debugfs_show(struct seq_file *s, void *data) { int rc; int i; struct wil6210_priv *wil = s->private; struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wmi_notify_req_cmd cmd = { .interval_usec = 0, }; struct { struct wmi_cmd_hdr wmi; struct wmi_notify_req_done_event evt; } __packed reply; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { u32 status; cmd.cid = i; rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20); /* if reply is all-0, ignore this CID */ if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt))) continue; status = le32_to_cpu(reply.evt.status); seq_printf(s, "CID %d {\n" " TSF = 0x%016llx\n" " TxMCS = %2d TxTpt = %4d\n" " SQI = %4d\n" " RSSI = %4d\n" " Status = 0x%08x %s\n" " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n" " Goodput(rx:tx) %4d:%4d\n" "}\n", i, le64_to_cpu(reply.evt.tsf), le16_to_cpu(reply.evt.bf_mcs), le32_to_cpu(reply.evt.tx_tpt), reply.evt.sqi, reply.evt.rssi, status, wil_bfstatus_str(status), le16_to_cpu(reply.evt.my_rx_sector), le16_to_cpu(reply.evt.my_tx_sector), le16_to_cpu(reply.evt.other_rx_sector), le16_to_cpu(reply.evt.other_tx_sector), le32_to_cpu(reply.evt.rx_goodput), le32_to_cpu(reply.evt.tx_goodput)); } return 0; } static int wil_bf_seq_open(struct inode *inode, struct file *file) { return single_open(file, wil_bf_debugfs_show, inode->i_private); } static const struct file_operations fops_bf = { .open = wil_bf_seq_open, .release = single_release, .read = seq_read, .llseek = seq_lseek, }; /*---------temp------------*/ static void print_temp(struct seq_file *s, const char *prefix, u32 t) { switch (t) { case 0: case ~(u32)0: seq_printf(s, "%s N/A\n", prefix); break; default: seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000); break; } } static int wil_temp_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; u32 t_m, t_r; int rc = wmi_get_temperature(wil, &t_m, &t_r); if (rc) { seq_puts(s, "Failed\n"); return 0; } print_temp(s, "T_mac =", t_m); print_temp(s, "T_radio =", t_r); return 0; } static int wil_temp_seq_open(struct inode *inode, struct file *file) { return single_open(file, wil_temp_debugfs_show, inode->i_private); } static const struct file_operations fops_temp = { .open = wil_temp_seq_open, .release = single_release, .read = seq_read, .llseek = seq_lseek, }; /*---------freq------------*/ static int wil_freq_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; seq_printf(s, "Freq = %d\n", freq); return 0; } static int wil_freq_seq_open(struct inode *inode, struct file *file) { return single_open(file, wil_freq_debugfs_show, inode->i_private); } static const struct file_operations fops_freq = { .open = wil_freq_seq_open, .release = single_release, .read = seq_read, .llseek = seq_lseek, }; /*---------link------------*/ static int wil_link_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; struct station_info sinfo; int i, rc; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; char *status = "unknown"; struct wil6210_vif *vif; u8 mid; switch (p->status) { case wil_sta_unused: status = "unused "; break; case wil_sta_conn_pending: status = "pending "; break; case wil_sta_connected: status = "connected"; break; } mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; seq_printf(s, "[%d][MID %d] %pM %s\n", i, mid, p->addr, status); if (p->status != wil_sta_connected) continue; vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL; if (vif) { rc = wil_cid_fill_sinfo(vif, i, &sinfo); if (rc) return rc; seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs); seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs); seq_printf(s, " SQ = %d\n", sinfo.signal); } else { seq_puts(s, " INVALID MID\n"); } } return 0; } static int wil_link_seq_open(struct inode *inode, struct file *file) { return single_open(file, wil_link_debugfs_show, inode->i_private); } static const struct file_operations fops_link = { .open = wil_link_seq_open, .release = single_release, .read = seq_read, .llseek = seq_lseek, }; /*---------info------------*/ static int wil_info_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; struct net_device *ndev = wil->main_ndev; int is_ac = power_supply_is_system_supplied(); int rx = atomic_xchg(&wil->isr_count_rx, 0); int tx = atomic_xchg(&wil->isr_count_tx, 0); static ulong rxf_old, txf_old; ulong rxf = ndev->stats.rx_packets; ulong txf = ndev->stats.tx_packets; unsigned int i; /* >0 : AC; 0 : battery; <0 : error */ seq_printf(s, "AC powered : %d\n", is_ac); seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old); seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old); rxf_old = rxf; txf_old = txf; #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \ " " __stringify(x) : "" for (i = 0; i < ndev->num_tx_queues; i++) { struct netdev_queue *txq = netdev_get_tx_queue(ndev, i); unsigned long state = txq->state; seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state, CHECK_QSTATE(DRV_XOFF), CHECK_QSTATE(STACK_XOFF), CHECK_QSTATE(FROZEN) ); } #undef CHECK_QSTATE return 0; } static int wil_info_seq_open(struct inode *inode, struct file *file) { return single_open(file, wil_info_debugfs_show, inode->i_private); } static const struct file_operations fops_info = { .open = wil_info_seq_open, .release = single_release, .read = seq_read, .llseek = seq_lseek, }; /*---------recovery------------*/ /* mode = [manual|auto] * state = [idle|pending|running] */ static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; char buf[80]; int n; static const char * const sstate[] = {"idle", "pending", "running"}; n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n", no_fw_recovery ? "manual" : "auto", sstate[wil->recovery_state]); n = min_t(int, n, sizeof(buf)); return simple_read_from_buffer(user_buf, count, ppos, buf, n); } static ssize_t wil_write_file_recovery(struct file *file, const char __user *buf_, size_t count, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; static const char run_command[] = "run"; char buf[sizeof(run_command) + 1]; /* to detect "runx" */ ssize_t rc; if (wil->recovery_state != fw_recovery_pending) { wil_err(wil, "No recovery pending\n"); return -EINVAL; } if (*ppos != 0) { wil_err(wil, "Offset [%d]\n", (int)*ppos); return -EINVAL; } if (count > sizeof(buf)) { wil_err(wil, "Input too long, len = %d\n", (int)count); return -EINVAL; } rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count); if (rc < 0) return rc; buf[rc] = '\0'; if (0 == strcmp(buf, run_command)) wil_set_recovery_state(wil, fw_recovery_running); else wil_err(wil, "Bad recovery command \"%s\"\n", buf); return rc; } static const struct file_operations fops_recovery = { .read = wil_read_file_recovery, .write = wil_write_file_recovery, .open = simple_open, }; /*---------Station matrix------------*/ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) { int i; u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old; seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout, r->head_seq_num); for (i = 0; i < r->buf_size; i++) { if (i == index) seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); else seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); } seq_printf(s, "] total %llu drop %llu (dup %llu + old %llu) last 0x%03x\n", r->total, drop_dup + drop_old, drop_dup, drop_old, r->ssn_last_drop); }