Loading drivers/net/wireless/ath/wil6210/Kconfig +12 −0 Original line number Diff line number Diff line Loading @@ -27,3 +27,15 @@ config WIL6210_ISR_COR self-clear when accessed for debug purposes, it makes such monitoring impossible. Say y unless you debug interrupts config WIL6210_TRACING bool "wil6210 tracing support" depends on WIL6210 depends on EVENT_TRACING default y ---help--- Say Y here to enable tracepoints for the wil6210 driver using the kernel tracing infrastructure. Select this option if you are interested in debugging the driver. If unsure, say Y to make it easier to debug problems. drivers/net/wireless/ath/wil6210/Makefile +14 −11 Original line number Diff line number Diff line obj-$(CONFIG_WIL6210) += wil6210.o wil6210-objs := main.o wil6210-objs += netdev.o wil6210-objs += cfg80211.o wil6210-objs += pcie_bus.o wil6210-objs += debugfs.o wil6210-objs += wmi.o wil6210-objs += interrupt.o wil6210-objs += txrx.o wil6210-y := main.o wil6210-y += netdev.o wil6210-y += cfg80211.o wil6210-y += pcie_bus.o wil6210-y += debugfs.o wil6210-y += wmi.o wil6210-y += interrupt.o wil6210-y += txrx.o wil6210-y += debug.o wil6210-y += rx_reorder.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) subdir-ccflags-y += -Werror endif subdir-ccflags-y += -D__CHECK_ENDIAN__ drivers/net/wireless/ath/wil6210/cfg80211.c +249 −31 Original line number Diff line number Diff line Loading @@ -104,41 +104,125 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type) return -EOPNOTSUPP; } static int wil_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, u8 *mac, struct station_info *sinfo) static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, struct station_info *sinfo) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; struct wmi_notify_req_cmd cmd = { .cid = 0, .cid = cid, .interval_usec = 0, }; struct { struct wil6210_mbox_hdr_wmi wmi; struct wmi_notify_req_done_event evt; } __packed reply; struct wil_net_stats *stats = &wil->sta[cid].stats; int rc; if (memcmp(mac, wil->dst_addr[0], ETH_ALEN)) return -ENOENT; /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20); if (rc) return rc; wil_dbg_wmi(wil, "Link status for CID %d: {\n" " MCS %d TSF 0x%016llx\n" " BF status 0x%08x SNR 0x%08x SQI %d%%\n" " Tx Tpt %d goodput %d Rx goodput %d\n" " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", cid, le16_to_cpu(reply.evt.bf_mcs), le64_to_cpu(reply.evt.tsf), reply.evt.status, le32_to_cpu(reply.evt.snr_val), reply.evt.sqi, le32_to_cpu(reply.evt.tx_tpt), le32_to_cpu(reply.evt.tx_goodput), le32_to_cpu(reply.evt.rx_goodput), 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)); sinfo->generation = wil->sinfo_gen; sinfo->filled |= STATION_INFO_TX_BITRATE; sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS | STATION_INFO_RX_BITRATE | STATION_INFO_TX_BITRATE | STATION_INFO_RX_DROP_MISC | STATION_INFO_TX_FAILED; sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; sinfo->txrate.mcs = wil->stats.bf_mcs; sinfo->filled |= STATION_INFO_RX_BITRATE; sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; sinfo->rxrate.mcs = wil->stats.last_mcs_rx; sinfo->rxrate.mcs = stats->last_mcs_rx; sinfo->rx_bytes = stats->rx_bytes; sinfo->rx_packets = stats->rx_packets; sinfo->rx_dropped_misc = stats->rx_dropped; sinfo->tx_bytes = stats->tx_bytes; sinfo->tx_packets = stats->tx_packets; sinfo->tx_failed = stats->tx_errors; if (test_bit(wil_status_fwconnected, &wil->status)) { sinfo->filled |= STATION_INFO_SIGNAL; sinfo->signal = 12; /* TODO: provide real value */ sinfo->signal = reply.evt.sqi; } return 0; return rc; } static int wil_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, u8 *mac, struct station_info *sinfo) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; int cid = wil_find_cid(wil, mac); wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); if (cid < 0) return cid; rc = wil_cid_fill_sinfo(wil, cid, sinfo); return rc; } /* * Find @idx-th active STA for station dump. */ static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx) { int i; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { if (wil->sta[i].status == wil_sta_unused) continue; if (idx == 0) return i; idx--; } return -ENOENT; } static int wil_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; int cid = wil_find_cid_by_idx(wil, idx); if (cid < 0) return -ENOENT; memcpy(mac, wil->sta[cid].addr, ETH_ALEN); wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); rc = wil_cid_fill_sinfo(wil, cid, sinfo); return rc; } static int wil_cfg80211_change_iface(struct wiphy *wiphy, Loading Loading @@ -181,6 +265,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, u16 chnl[4]; } __packed cmd; uint i, n; int rc; if (wil->scan_request) { wil_err(wil, "Already scanning\n"); Loading @@ -198,11 +283,12 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, /* FW don't support scan after connection attempt */ if (test_bit(wil_status_dontscan, &wil->status)) { wil_err(wil, "Scan after connect attempt not supported\n"); wil_err(wil, "Can't scan now\n"); return -EBUSY; } wil->scan_request = request; mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); memset(&cmd, 0, sizeof(cmd)); cmd.cmd.num_channels = 0; Loading @@ -221,8 +307,13 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, request->channels[i]->center_freq); } return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); if (rc) wil->scan_request = NULL; return rc; } static int wil_cfg80211_connect(struct wiphy *wiphy, Loading @@ -237,6 +328,10 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int ch; int rc = 0; if (test_bit(wil_status_fwconnecting, &wil->status) || test_bit(wil_status_fwconnected, &wil->status)) return -EALREADY; bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); Loading Loading @@ -316,18 +411,18 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, } conn.channel = ch - 1; memcpy(conn.bssid, bss->bssid, 6); memcpy(conn.dst_mac, bss->bssid, 6); /* * FW don't support scan after connection attempt */ set_bit(wil_status_dontscan, &wil->status); memcpy(conn.bssid, bss->bssid, ETH_ALEN); memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); set_bit(wil_status_fwconnecting, &wil->status); rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); if (rc == 0) { /* Connect can take lots of time */ mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); } else { clear_bit(wil_status_fwconnecting, &wil->status); } out: Loading @@ -348,6 +443,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, return rc; } static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; struct ieee80211_mgmt *mgmt_frame = (void *)buf; struct wmi_sw_tx_req_cmd *cmd; struct { struct wil6210_mbox_hdr_wmi wmi; struct wmi_sw_tx_complete_event evt; } __packed evt; cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); if (!cmd) return -ENOMEM; memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); cmd->len = cpu_to_le16(len); memcpy(cmd->payload, buf, len); rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); if (rc == 0) rc = evt.evt.status; kfree(cmd); return rc; } static int wil_cfg80211_set_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef) { Loading Loading @@ -398,6 +527,65 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy, return 0; } static int wil_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, unsigned int duration, u64 *cookie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; /* TODO: handle duration */ wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration); rc = wmi_set_channel(wil, chan->hw_value); if (rc) return rc; rc = wmi_rxon(wil, true); return rc; } static int wil_cancel_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; wil_info(wil, "%s()\n", __func__); rc = wmi_rxon(wil, false); return rc; } static int wil_fix_bcon(struct wil6210_priv *wil, struct cfg80211_beacon_data *bcon) { struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); int rc = 0; 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; rc = 1; } return rc; } static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *info) Loading @@ -419,13 +607,23 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, info->ssid, info->ssid_len); if (wil_fix_bcon(wil, bcon)) wil_dbg_misc(wil, "Fixed bcon\n"); mutex_lock(&wil->mutex); rc = wil_reset(wil); if (rc) return rc; goto out; /* Rx VRING. */ rc = wil_rx_init(wil); if (rc) goto out; rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); if (rc) return rc; goto out; /* MAC address - pre-requisite for other commands */ wmi_set_mac_address(wil, ndev->dev_addr); Loading @@ -449,13 +647,13 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) return rc; goto out; /* Rx VRING. After MAC and beacon */ rc = wil_rx_init(wil); netif_carrier_on(ndev); out: mutex_unlock(&wil->mutex); return rc; } Loading @@ -465,17 +663,36 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, int rc = 0; struct wil6210_priv *wil = wiphy_to_wil(wiphy); mutex_lock(&wil->mutex); rc = wmi_pcp_stop(wil); mutex_unlock(&wil->mutex); return rc; } static int wil_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); mutex_lock(&wil->mutex); wil6210_disconnect(wil, mac); mutex_unlock(&wil->mutex); return 0; } static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, .disconnect = wil_cfg80211_disconnect, .change_virtual_intf = wil_cfg80211_change_iface, .get_station = wil_cfg80211_get_station, .dump_station = wil_cfg80211_dump_station, .remain_on_channel = wil_remain_on_channel, .cancel_remain_on_channel = wil_cancel_remain_on_channel, .mgmt_tx = wil_cfg80211_mgmt_tx, .set_monitor_channel = wil_cfg80211_set_channel, .add_key = wil_cfg80211_add_key, .del_key = wil_cfg80211_del_key, Loading @@ -483,6 +700,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { /* AP mode */ .start_ap = wil_cfg80211_start_ap, .stop_ap = wil_cfg80211_stop_ap, .del_station = wil_cfg80211_del_station, }; static void wil_wiphy_init(struct wiphy *wiphy) Loading @@ -508,7 +726,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz; /* TODO: figure this out */ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; wiphy->cipher_suites = wil_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); Loading drivers/net/wireless/ath/wil6210/debug.c 0 → 100644 +69 −0 Original line number Diff line number Diff line /* * Copyright (c) 2013 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 * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "wil6210.h" #include "trace.h" int wil_err(struct wil6210_priv *wil, const char *fmt, ...) { struct net_device *ndev = wil_to_ndev(wil); struct va_format vaf = { .fmt = fmt, }; va_list args; int ret; va_start(args, fmt); vaf.va = &args; ret = netdev_err(ndev, "%pV", &vaf); trace_wil6210_log_err(&vaf); va_end(args); return ret; } int wil_info(struct wil6210_priv *wil, const char *fmt, ...) { struct net_device *ndev = wil_to_ndev(wil); struct va_format vaf = { .fmt = fmt, }; va_list args; int ret; va_start(args, fmt); vaf.va = &args; ret = netdev_info(ndev, "%pV", &vaf); trace_wil6210_log_info(&vaf); va_end(args); return ret; } int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, }; va_list args; va_start(args, fmt); vaf.va = &args; trace_wil6210_log_dbg(&vaf); va_end(args); return 0; } drivers/net/wireless/ath/wil6210/debugfs.c +151 −36 Original line number Diff line number Diff line Loading @@ -26,14 +26,16 @@ /* Nasty hack. Better have per device instances */ static u32 mem_addr; static u32 dbg_txdesc_index; static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, const char *name, struct vring *vring) const char *name, struct vring *vring, char _s, char _h) { void __iomem *x = wmi_addr(wil, vring->hwtail); seq_printf(s, "VRING %s = {\n", name); seq_printf(s, " pa = 0x%016llx\n", (unsigned long long)vring->pa); seq_printf(s, " pa = %pad\n", &vring->pa); seq_printf(s, " va = 0x%p\n", vring->va); seq_printf(s, " size = %d\n", vring->size); seq_printf(s, " swtail = %d\n", vring->swtail); Loading @@ -50,8 +52,8 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, volatile struct vring_tx_desc *d = &vring->va[i].tx; if ((i % 64) == 0 && (i != 0)) seq_printf(s, "\n"); seq_printf(s, "%s", (d->dma.status & BIT(0)) ? "S" : (vring->ctx[i] ? "H" : "h")); seq_printf(s, "%c", (d->dma.status & BIT(0)) ? _s : (vring->ctx[i].skb ? _h : 'h')); } seq_printf(s, "\n"); } Loading @@ -63,14 +65,19 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) uint i; struct wil6210_priv *wil = s->private; wil_print_vring(s, wil, "rx", &wil->vring_rx); wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_'); for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { struct vring *vring = &(wil->vring_tx[i]); if (vring->va) { int cid = wil->vring2cid_tid[i][0]; int tid = wil->vring2cid_tid[i][1]; char name[10]; snprintf(name, sizeof(name), "tx_%2d", i); wil_print_vring(s, wil, name, vring); seq_printf(s, "\n%pM CID %d TID %d\n", wil->sta[cid].addr, cid, tid); wil_print_vring(s, wil, name, vring, '_', 'H'); } } Loading Loading @@ -390,56 +397,97 @@ static const struct file_operations fops_reset = { .write = wil_write_file_reset, .open = simple_open, }; /*---------Tx descriptor------------*/ static void wil_seq_hexdump(struct seq_file *s, void *p, int len, const char *prefix) { char printbuf[16 * 3 + 2]; int i = 0; while (i < len) { int l = min(len - i, 16); hex_dump_to_buffer(p + i, l, 16, 1, printbuf, sizeof(printbuf), false); seq_printf(s, "%s%s\n", prefix, printbuf); i += l; } } static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) { int i = 0; int len = skb_headlen(skb); void *p = skb->data; int nr_frags = skb_shinfo(skb)->nr_frags; seq_printf(s, " len = %d\n", len); wil_seq_hexdump(s, p, len, " : "); if (nr_frags) { seq_printf(s, " nr_frags = %d\n", nr_frags); for (i = 0; i < nr_frags; i++) { const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; len = skb_frag_size(frag); p = skb_frag_address_safe(frag); seq_printf(s, " [%2d] : len = %d\n", i, len); wil_seq_hexdump(s, p, len, " : "); } } } /*---------Tx/Rx descriptor------------*/ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; struct vring *vring = &(wil->vring_tx[0]); struct vring *vring; bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS); if (tx) vring = &(wil->vring_tx[dbg_vring_index]); else vring = &wil->vring_rx; if (!vring->va) { seq_printf(s, "No Tx VRING\n"); if (tx) seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index); else seq_puts(s, "No Rx VRING\n"); return 0; } if (dbg_txdesc_index < vring->size) { /* use struct vring_tx_desc for Rx as well, * only field used, .dma.length, is the same */ volatile struct vring_tx_desc *d = &(vring->va[dbg_txdesc_index].tx); volatile u32 *u = (volatile u32 *)d; struct sk_buff *skb = vring->ctx[dbg_txdesc_index]; struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); if (tx) seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index, dbg_txdesc_index); else seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index); seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", u[0], u[1], u[2], u[3]); seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", u[4], u[5], u[6], u[7]); seq_printf(s, " SKB = %p\n", skb); seq_printf(s, " SKB = 0x%p\n", skb); if (skb) { char printbuf[16 * 3 + 2]; int i = 0; int len = le16_to_cpu(d->dma.length); void *p = skb->data; if (len != skb_headlen(skb)) { seq_printf(s, "!!! len: desc = %d skb = %d\n", len, skb_headlen(skb)); len = min_t(int, len, skb_headlen(skb)); } seq_printf(s, " len = %d\n", len); while (i < len) { int l = min(len - i, 16); hex_dump_to_buffer(p + i, l, 16, 1, printbuf, sizeof(printbuf), false); seq_printf(s, " : %s\n", printbuf); i += l; } skb_get(skb); wil_seq_print_skb(s, skb); kfree_skb(skb); } seq_printf(s, "}\n"); } else { seq_printf(s, "TxDesc index (%d) >= size (%d)\n", if (tx) seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", dbg_vring_index, dbg_txdesc_index, vring->size); else seq_printf(s, "RxDesc index (%d) >= size (%d)\n", dbg_txdesc_index, vring->size); } Loading Loading @@ -570,6 +618,69 @@ static const struct file_operations fops_temp = { .llseek = seq_lseek, }; /*---------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; seq_printf(s, "0x%03x [", 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_puts(s, "]\n"); } static int wil_sta_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; int i, tid; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; char *status = "unknown"; 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; } seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, (p->data_port_open ? " data_port_open" : "")); if (p->status == wil_sta_connected) { for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; if (r) { seq_printf(s, "[%2d] ", tid); wil_print_rxtid(s, r); } } } } return 0; } static int wil_sta_seq_open(struct inode *inode, struct file *file) { return single_open(file, wil_sta_debugfs_show, inode->i_private); } static const struct file_operations fops_sta = { .open = wil_sta_seq_open, .release = single_release, .read = seq_read, .llseek = seq_lseek, }; /*----------------*/ int wil6210_debugfs_init(struct wil6210_priv *wil) { Loading @@ -581,9 +692,13 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc); debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg, debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta); debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc); debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg, &dbg_txdesc_index); debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg, &dbg_vring_index); debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf); debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, Loading Loading
drivers/net/wireless/ath/wil6210/Kconfig +12 −0 Original line number Diff line number Diff line Loading @@ -27,3 +27,15 @@ config WIL6210_ISR_COR self-clear when accessed for debug purposes, it makes such monitoring impossible. Say y unless you debug interrupts config WIL6210_TRACING bool "wil6210 tracing support" depends on WIL6210 depends on EVENT_TRACING default y ---help--- Say Y here to enable tracepoints for the wil6210 driver using the kernel tracing infrastructure. Select this option if you are interested in debugging the driver. If unsure, say Y to make it easier to debug problems.
drivers/net/wireless/ath/wil6210/Makefile +14 −11 Original line number Diff line number Diff line obj-$(CONFIG_WIL6210) += wil6210.o wil6210-objs := main.o wil6210-objs += netdev.o wil6210-objs += cfg80211.o wil6210-objs += pcie_bus.o wil6210-objs += debugfs.o wil6210-objs += wmi.o wil6210-objs += interrupt.o wil6210-objs += txrx.o wil6210-y := main.o wil6210-y += netdev.o wil6210-y += cfg80211.o wil6210-y += pcie_bus.o wil6210-y += debugfs.o wil6210-y += wmi.o wil6210-y += interrupt.o wil6210-y += txrx.o wil6210-y += debug.o wil6210-y += rx_reorder.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) subdir-ccflags-y += -Werror endif subdir-ccflags-y += -D__CHECK_ENDIAN__
drivers/net/wireless/ath/wil6210/cfg80211.c +249 −31 Original line number Diff line number Diff line Loading @@ -104,41 +104,125 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type) return -EOPNOTSUPP; } static int wil_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, u8 *mac, struct station_info *sinfo) static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, struct station_info *sinfo) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; struct wmi_notify_req_cmd cmd = { .cid = 0, .cid = cid, .interval_usec = 0, }; struct { struct wil6210_mbox_hdr_wmi wmi; struct wmi_notify_req_done_event evt; } __packed reply; struct wil_net_stats *stats = &wil->sta[cid].stats; int rc; if (memcmp(mac, wil->dst_addr[0], ETH_ALEN)) return -ENOENT; /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */ rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20); WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20); if (rc) return rc; wil_dbg_wmi(wil, "Link status for CID %d: {\n" " MCS %d TSF 0x%016llx\n" " BF status 0x%08x SNR 0x%08x SQI %d%%\n" " Tx Tpt %d goodput %d Rx goodput %d\n" " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", cid, le16_to_cpu(reply.evt.bf_mcs), le64_to_cpu(reply.evt.tsf), reply.evt.status, le32_to_cpu(reply.evt.snr_val), reply.evt.sqi, le32_to_cpu(reply.evt.tx_tpt), le32_to_cpu(reply.evt.tx_goodput), le32_to_cpu(reply.evt.rx_goodput), 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)); sinfo->generation = wil->sinfo_gen; sinfo->filled |= STATION_INFO_TX_BITRATE; sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS | STATION_INFO_RX_BITRATE | STATION_INFO_TX_BITRATE | STATION_INFO_RX_DROP_MISC | STATION_INFO_TX_FAILED; sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; sinfo->txrate.mcs = wil->stats.bf_mcs; sinfo->filled |= STATION_INFO_RX_BITRATE; sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; sinfo->rxrate.mcs = wil->stats.last_mcs_rx; sinfo->rxrate.mcs = stats->last_mcs_rx; sinfo->rx_bytes = stats->rx_bytes; sinfo->rx_packets = stats->rx_packets; sinfo->rx_dropped_misc = stats->rx_dropped; sinfo->tx_bytes = stats->tx_bytes; sinfo->tx_packets = stats->tx_packets; sinfo->tx_failed = stats->tx_errors; if (test_bit(wil_status_fwconnected, &wil->status)) { sinfo->filled |= STATION_INFO_SIGNAL; sinfo->signal = 12; /* TODO: provide real value */ sinfo->signal = reply.evt.sqi; } return 0; return rc; } static int wil_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, u8 *mac, struct station_info *sinfo) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; int cid = wil_find_cid(wil, mac); wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); if (cid < 0) return cid; rc = wil_cid_fill_sinfo(wil, cid, sinfo); return rc; } /* * Find @idx-th active STA for station dump. */ static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx) { int i; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { if (wil->sta[i].status == wil_sta_unused) continue; if (idx == 0) return i; idx--; } return -ENOENT; } static int wil_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; int cid = wil_find_cid_by_idx(wil, idx); if (cid < 0) return -ENOENT; memcpy(mac, wil->sta[cid].addr, ETH_ALEN); wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); rc = wil_cid_fill_sinfo(wil, cid, sinfo); return rc; } static int wil_cfg80211_change_iface(struct wiphy *wiphy, Loading Loading @@ -181,6 +265,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, u16 chnl[4]; } __packed cmd; uint i, n; int rc; if (wil->scan_request) { wil_err(wil, "Already scanning\n"); Loading @@ -198,11 +283,12 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, /* FW don't support scan after connection attempt */ if (test_bit(wil_status_dontscan, &wil->status)) { wil_err(wil, "Scan after connect attempt not supported\n"); wil_err(wil, "Can't scan now\n"); return -EBUSY; } wil->scan_request = request; mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); memset(&cmd, 0, sizeof(cmd)); cmd.cmd.num_channels = 0; Loading @@ -221,8 +307,13 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, request->channels[i]->center_freq); } return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); if (rc) wil->scan_request = NULL; return rc; } static int wil_cfg80211_connect(struct wiphy *wiphy, Loading @@ -237,6 +328,10 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int ch; int rc = 0; if (test_bit(wil_status_fwconnecting, &wil->status) || test_bit(wil_status_fwconnected, &wil->status)) return -EALREADY; bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, sme->ssid_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); Loading Loading @@ -316,18 +411,18 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, } conn.channel = ch - 1; memcpy(conn.bssid, bss->bssid, 6); memcpy(conn.dst_mac, bss->bssid, 6); /* * FW don't support scan after connection attempt */ set_bit(wil_status_dontscan, &wil->status); memcpy(conn.bssid, bss->bssid, ETH_ALEN); memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); set_bit(wil_status_fwconnecting, &wil->status); rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); if (rc == 0) { /* Connect can take lots of time */ mod_timer(&wil->connect_timer, jiffies + msecs_to_jiffies(2000)); } else { clear_bit(wil_status_fwconnecting, &wil->status); } out: Loading @@ -348,6 +443,40 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, return rc; } static int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; struct ieee80211_mgmt *mgmt_frame = (void *)buf; struct wmi_sw_tx_req_cmd *cmd; struct { struct wil6210_mbox_hdr_wmi wmi; struct wmi_sw_tx_complete_event evt; } __packed evt; cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); if (!cmd) return -ENOMEM; memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN); cmd->len = cpu_to_le16(len); memcpy(cmd->payload, buf, len); rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len, WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); if (rc == 0) rc = evt.evt.status; kfree(cmd); return rc; } static int wil_cfg80211_set_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef) { Loading Loading @@ -398,6 +527,65 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy, return 0; } static int wil_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, unsigned int duration, u64 *cookie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; /* TODO: handle duration */ wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration); rc = wmi_set_channel(wil, chan->hw_value); if (rc) return rc; rc = wmi_rxon(wil, true); return rc; } static int wil_cancel_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; wil_info(wil, "%s()\n", __func__); rc = wmi_rxon(wil, false); return rc; } static int wil_fix_bcon(struct wil6210_priv *wil, struct cfg80211_beacon_data *bcon) { struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); int rc = 0; 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; rc = 1; } return rc; } static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *info) Loading @@ -419,13 +607,23 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, info->ssid, info->ssid_len); if (wil_fix_bcon(wil, bcon)) wil_dbg_misc(wil, "Fixed bcon\n"); mutex_lock(&wil->mutex); rc = wil_reset(wil); if (rc) return rc; goto out; /* Rx VRING. */ rc = wil_rx_init(wil); if (rc) goto out; rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); if (rc) return rc; goto out; /* MAC address - pre-requisite for other commands */ wmi_set_mac_address(wil, ndev->dev_addr); Loading @@ -449,13 +647,13 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) return rc; goto out; /* Rx VRING. After MAC and beacon */ rc = wil_rx_init(wil); netif_carrier_on(ndev); out: mutex_unlock(&wil->mutex); return rc; } Loading @@ -465,17 +663,36 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, int rc = 0; struct wil6210_priv *wil = wiphy_to_wil(wiphy); mutex_lock(&wil->mutex); rc = wmi_pcp_stop(wil); mutex_unlock(&wil->mutex); return rc; } static int wil_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); mutex_lock(&wil->mutex); wil6210_disconnect(wil, mac); mutex_unlock(&wil->mutex); return 0; } static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, .disconnect = wil_cfg80211_disconnect, .change_virtual_intf = wil_cfg80211_change_iface, .get_station = wil_cfg80211_get_station, .dump_station = wil_cfg80211_dump_station, .remain_on_channel = wil_remain_on_channel, .cancel_remain_on_channel = wil_cancel_remain_on_channel, .mgmt_tx = wil_cfg80211_mgmt_tx, .set_monitor_channel = wil_cfg80211_set_channel, .add_key = wil_cfg80211_add_key, .del_key = wil_cfg80211_del_key, Loading @@ -483,6 +700,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { /* AP mode */ .start_ap = wil_cfg80211_start_ap, .stop_ap = wil_cfg80211_stop_ap, .del_station = wil_cfg80211_del_station, }; static void wil_wiphy_init(struct wiphy *wiphy) Loading @@ -508,7 +726,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz; /* TODO: figure this out */ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; wiphy->cipher_suites = wil_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); Loading
drivers/net/wireless/ath/wil6210/debug.c 0 → 100644 +69 −0 Original line number Diff line number Diff line /* * Copyright (c) 2013 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 * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "wil6210.h" #include "trace.h" int wil_err(struct wil6210_priv *wil, const char *fmt, ...) { struct net_device *ndev = wil_to_ndev(wil); struct va_format vaf = { .fmt = fmt, }; va_list args; int ret; va_start(args, fmt); vaf.va = &args; ret = netdev_err(ndev, "%pV", &vaf); trace_wil6210_log_err(&vaf); va_end(args); return ret; } int wil_info(struct wil6210_priv *wil, const char *fmt, ...) { struct net_device *ndev = wil_to_ndev(wil); struct va_format vaf = { .fmt = fmt, }; va_list args; int ret; va_start(args, fmt); vaf.va = &args; ret = netdev_info(ndev, "%pV", &vaf); trace_wil6210_log_info(&vaf); va_end(args); return ret; } int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, }; va_list args; va_start(args, fmt); vaf.va = &args; trace_wil6210_log_dbg(&vaf); va_end(args); return 0; }
drivers/net/wireless/ath/wil6210/debugfs.c +151 −36 Original line number Diff line number Diff line Loading @@ -26,14 +26,16 @@ /* Nasty hack. Better have per device instances */ static u32 mem_addr; static u32 dbg_txdesc_index; static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, const char *name, struct vring *vring) const char *name, struct vring *vring, char _s, char _h) { void __iomem *x = wmi_addr(wil, vring->hwtail); seq_printf(s, "VRING %s = {\n", name); seq_printf(s, " pa = 0x%016llx\n", (unsigned long long)vring->pa); seq_printf(s, " pa = %pad\n", &vring->pa); seq_printf(s, " va = 0x%p\n", vring->va); seq_printf(s, " size = %d\n", vring->size); seq_printf(s, " swtail = %d\n", vring->swtail); Loading @@ -50,8 +52,8 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, volatile struct vring_tx_desc *d = &vring->va[i].tx; if ((i % 64) == 0 && (i != 0)) seq_printf(s, "\n"); seq_printf(s, "%s", (d->dma.status & BIT(0)) ? "S" : (vring->ctx[i] ? "H" : "h")); seq_printf(s, "%c", (d->dma.status & BIT(0)) ? _s : (vring->ctx[i].skb ? _h : 'h')); } seq_printf(s, "\n"); } Loading @@ -63,14 +65,19 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) uint i; struct wil6210_priv *wil = s->private; wil_print_vring(s, wil, "rx", &wil->vring_rx); wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_'); for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { struct vring *vring = &(wil->vring_tx[i]); if (vring->va) { int cid = wil->vring2cid_tid[i][0]; int tid = wil->vring2cid_tid[i][1]; char name[10]; snprintf(name, sizeof(name), "tx_%2d", i); wil_print_vring(s, wil, name, vring); seq_printf(s, "\n%pM CID %d TID %d\n", wil->sta[cid].addr, cid, tid); wil_print_vring(s, wil, name, vring, '_', 'H'); } } Loading Loading @@ -390,56 +397,97 @@ static const struct file_operations fops_reset = { .write = wil_write_file_reset, .open = simple_open, }; /*---------Tx descriptor------------*/ static void wil_seq_hexdump(struct seq_file *s, void *p, int len, const char *prefix) { char printbuf[16 * 3 + 2]; int i = 0; while (i < len) { int l = min(len - i, 16); hex_dump_to_buffer(p + i, l, 16, 1, printbuf, sizeof(printbuf), false); seq_printf(s, "%s%s\n", prefix, printbuf); i += l; } } static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) { int i = 0; int len = skb_headlen(skb); void *p = skb->data; int nr_frags = skb_shinfo(skb)->nr_frags; seq_printf(s, " len = %d\n", len); wil_seq_hexdump(s, p, len, " : "); if (nr_frags) { seq_printf(s, " nr_frags = %d\n", nr_frags); for (i = 0; i < nr_frags; i++) { const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; len = skb_frag_size(frag); p = skb_frag_address_safe(frag); seq_printf(s, " [%2d] : len = %d\n", i, len); wil_seq_hexdump(s, p, len, " : "); } } } /*---------Tx/Rx descriptor------------*/ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; struct vring *vring = &(wil->vring_tx[0]); struct vring *vring; bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS); if (tx) vring = &(wil->vring_tx[dbg_vring_index]); else vring = &wil->vring_rx; if (!vring->va) { seq_printf(s, "No Tx VRING\n"); if (tx) seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index); else seq_puts(s, "No Rx VRING\n"); return 0; } if (dbg_txdesc_index < vring->size) { /* use struct vring_tx_desc for Rx as well, * only field used, .dma.length, is the same */ volatile struct vring_tx_desc *d = &(vring->va[dbg_txdesc_index].tx); volatile u32 *u = (volatile u32 *)d; struct sk_buff *skb = vring->ctx[dbg_txdesc_index]; struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index); if (tx) seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index, dbg_txdesc_index); else seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index); seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", u[0], u[1], u[2], u[3]); seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", u[4], u[5], u[6], u[7]); seq_printf(s, " SKB = %p\n", skb); seq_printf(s, " SKB = 0x%p\n", skb); if (skb) { char printbuf[16 * 3 + 2]; int i = 0; int len = le16_to_cpu(d->dma.length); void *p = skb->data; if (len != skb_headlen(skb)) { seq_printf(s, "!!! len: desc = %d skb = %d\n", len, skb_headlen(skb)); len = min_t(int, len, skb_headlen(skb)); } seq_printf(s, " len = %d\n", len); while (i < len) { int l = min(len - i, 16); hex_dump_to_buffer(p + i, l, 16, 1, printbuf, sizeof(printbuf), false); seq_printf(s, " : %s\n", printbuf); i += l; } skb_get(skb); wil_seq_print_skb(s, skb); kfree_skb(skb); } seq_printf(s, "}\n"); } else { seq_printf(s, "TxDesc index (%d) >= size (%d)\n", if (tx) seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", dbg_vring_index, dbg_txdesc_index, vring->size); else seq_printf(s, "RxDesc index (%d) >= size (%d)\n", dbg_txdesc_index, vring->size); } Loading Loading @@ -570,6 +618,69 @@ static const struct file_operations fops_temp = { .llseek = seq_lseek, }; /*---------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; seq_printf(s, "0x%03x [", 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_puts(s, "]\n"); } static int wil_sta_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; int i, tid; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; char *status = "unknown"; 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; } seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, (p->data_port_open ? " data_port_open" : "")); if (p->status == wil_sta_connected) { for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; if (r) { seq_printf(s, "[%2d] ", tid); wil_print_rxtid(s, r); } } } } return 0; } static int wil_sta_seq_open(struct inode *inode, struct file *file) { return single_open(file, wil_sta_debugfs_show, inode->i_private); } static const struct file_operations fops_sta = { .open = wil_sta_seq_open, .release = single_release, .read = seq_read, .llseek = seq_lseek, }; /*----------------*/ int wil6210_debugfs_init(struct wil6210_priv *wil) { Loading @@ -581,9 +692,13 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox); debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring); debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc); debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg, debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta); debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc); debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg, &dbg_txdesc_index); debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg, &dbg_vring_index); debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf); debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, Loading