Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
0004  * DebugFS code
0005  *
0006  * Copyright (c) 2010, ST-Ericsson
0007  * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/debugfs.h>
0012 #include <linux/seq_file.h>
0013 #include "cw1200.h"
0014 #include "debug.h"
0015 #include "fwio.h"
0016 
0017 /* join_status */
0018 static const char * const cw1200_debug_join_status[] = {
0019     "passive",
0020     "monitor",
0021     "station (joining)",
0022     "station (not authenticated yet)",
0023     "station",
0024     "adhoc",
0025     "access point",
0026 };
0027 
0028 /* WSM_JOIN_PREAMBLE_... */
0029 static const char * const cw1200_debug_preamble[] = {
0030     "long",
0031     "short",
0032     "long on 1 and 2 Mbps",
0033 };
0034 
0035 
0036 static const char * const cw1200_debug_link_id[] = {
0037     "OFF",
0038     "REQ",
0039     "SOFT",
0040     "HARD",
0041     "RESET",
0042     "RESET_REMAP",
0043 };
0044 
0045 static const char *cw1200_debug_mode(int mode)
0046 {
0047     switch (mode) {
0048     case NL80211_IFTYPE_UNSPECIFIED:
0049         return "unspecified";
0050     case NL80211_IFTYPE_MONITOR:
0051         return "monitor";
0052     case NL80211_IFTYPE_STATION:
0053         return "station";
0054     case NL80211_IFTYPE_ADHOC:
0055         return "adhoc";
0056     case NL80211_IFTYPE_MESH_POINT:
0057         return "mesh point";
0058     case NL80211_IFTYPE_AP:
0059         return "access point";
0060     case NL80211_IFTYPE_P2P_CLIENT:
0061         return "p2p client";
0062     case NL80211_IFTYPE_P2P_GO:
0063         return "p2p go";
0064     default:
0065         return "unsupported";
0066     }
0067 }
0068 
0069 static void cw1200_queue_status_show(struct seq_file *seq,
0070                      struct cw1200_queue *q)
0071 {
0072     int i;
0073     seq_printf(seq, "Queue       %d:\n", q->queue_id);
0074     seq_printf(seq, "  capacity: %zu\n", q->capacity);
0075     seq_printf(seq, "  queued:   %zu\n", q->num_queued);
0076     seq_printf(seq, "  pending:  %zu\n", q->num_pending);
0077     seq_printf(seq, "  sent:     %zu\n", q->num_sent);
0078     seq_printf(seq, "  locked:   %s\n", q->tx_locked_cnt ? "yes" : "no");
0079     seq_printf(seq, "  overfull: %s\n", q->overfull ? "yes" : "no");
0080     seq_puts(seq,   "  link map: 0-> ");
0081     for (i = 0; i < q->stats->map_capacity; ++i)
0082         seq_printf(seq, "%.2d ", q->link_map_cache[i]);
0083     seq_printf(seq, "<-%zu\n", q->stats->map_capacity);
0084 }
0085 
0086 static void cw1200_debug_print_map(struct seq_file *seq,
0087                    struct cw1200_common *priv,
0088                    const char *label,
0089                    u32 map)
0090 {
0091     int i;
0092     seq_printf(seq, "%s0-> ", label);
0093     for (i = 0; i < priv->tx_queue_stats.map_capacity; ++i)
0094         seq_printf(seq, "%s ", (map & BIT(i)) ? "**" : "..");
0095     seq_printf(seq, "<-%zu\n", priv->tx_queue_stats.map_capacity - 1);
0096 }
0097 
0098 static int cw1200_status_show(struct seq_file *seq, void *v)
0099 {
0100     int i;
0101     struct list_head *item;
0102     struct cw1200_common *priv = seq->private;
0103     struct cw1200_debug_priv *d = priv->debug;
0104 
0105     seq_puts(seq,   "CW1200 Wireless LAN driver status\n");
0106     seq_printf(seq, "Hardware:   %d.%d\n",
0107            priv->wsm_caps.hw_id,
0108            priv->wsm_caps.hw_subid);
0109     seq_printf(seq, "Firmware:   %s %d.%d\n",
0110            cw1200_fw_types[priv->wsm_caps.fw_type],
0111            priv->wsm_caps.fw_ver,
0112            priv->wsm_caps.fw_build);
0113     seq_printf(seq, "FW API:     %d\n",
0114            priv->wsm_caps.fw_api);
0115     seq_printf(seq, "FW caps:    0x%.4X\n",
0116            priv->wsm_caps.fw_cap);
0117     seq_printf(seq, "FW label:  '%s'\n",
0118            priv->wsm_caps.fw_label);
0119     seq_printf(seq, "Mode:       %s%s\n",
0120            cw1200_debug_mode(priv->mode),
0121            priv->listening ? " (listening)" : "");
0122     seq_printf(seq, "Join state: %s\n",
0123            cw1200_debug_join_status[priv->join_status]);
0124     if (priv->channel)
0125         seq_printf(seq, "Channel:    %d%s\n",
0126                priv->channel->hw_value,
0127                priv->channel_switch_in_progress ?
0128                " (switching)" : "");
0129     if (priv->rx_filter.promiscuous)
0130         seq_puts(seq,   "Filter:     promisc\n");
0131     else if (priv->rx_filter.fcs)
0132         seq_puts(seq,   "Filter:     fcs\n");
0133     if (priv->rx_filter.bssid)
0134         seq_puts(seq,   "Filter:     bssid\n");
0135     if (!priv->disable_beacon_filter)
0136         seq_puts(seq,   "Filter:     beacons\n");
0137 
0138     if (priv->enable_beacon ||
0139         priv->mode == NL80211_IFTYPE_AP ||
0140         priv->mode == NL80211_IFTYPE_ADHOC ||
0141         priv->mode == NL80211_IFTYPE_MESH_POINT ||
0142         priv->mode == NL80211_IFTYPE_P2P_GO)
0143         seq_printf(seq, "Beaconing:  %s\n",
0144                priv->enable_beacon ?
0145                "enabled" : "disabled");
0146 
0147     for (i = 0; i < 4; ++i)
0148         seq_printf(seq, "EDCA(%d):    %d, %d, %d, %d, %d\n", i,
0149                priv->edca.params[i].cwmin,
0150                priv->edca.params[i].cwmax,
0151                priv->edca.params[i].aifns,
0152                priv->edca.params[i].txop_limit,
0153                priv->edca.params[i].max_rx_lifetime);
0154 
0155     if (priv->join_status == CW1200_JOIN_STATUS_STA) {
0156         static const char *pm_mode = "unknown";
0157         switch (priv->powersave_mode.mode) {
0158         case WSM_PSM_ACTIVE:
0159             pm_mode = "off";
0160             break;
0161         case WSM_PSM_PS:
0162             pm_mode = "on";
0163             break;
0164         case WSM_PSM_FAST_PS:
0165             pm_mode = "dynamic";
0166             break;
0167         }
0168         seq_printf(seq, "Preamble:   %s\n",
0169                cw1200_debug_preamble[priv->association_mode.preamble]);
0170         seq_printf(seq, "AMPDU spcn: %d\n",
0171                priv->association_mode.mpdu_start_spacing);
0172         seq_printf(seq, "Basic rate: 0x%.8X\n",
0173                le32_to_cpu(priv->association_mode.basic_rate_set));
0174         seq_printf(seq, "Bss lost:   %d beacons\n",
0175                priv->bss_params.beacon_lost_count);
0176         seq_printf(seq, "AID:        %d\n",
0177                priv->bss_params.aid);
0178         seq_printf(seq, "Rates:      0x%.8X\n",
0179                priv->bss_params.operational_rate_set);
0180         seq_printf(seq, "Powersave:  %s\n", pm_mode);
0181     }
0182     seq_printf(seq, "HT:         %s\n",
0183            cw1200_is_ht(&priv->ht_info) ? "on" : "off");
0184     if (cw1200_is_ht(&priv->ht_info)) {
0185         seq_printf(seq, "Greenfield: %s\n",
0186                cw1200_ht_greenfield(&priv->ht_info) ? "yes" : "no");
0187         seq_printf(seq, "AMPDU dens: %d\n",
0188                cw1200_ht_ampdu_density(&priv->ht_info));
0189     }
0190     seq_printf(seq, "RSSI thold: %d\n",
0191            priv->cqm_rssi_thold);
0192     seq_printf(seq, "RSSI hyst:  %d\n",
0193            priv->cqm_rssi_hyst);
0194     seq_printf(seq, "Long retr:  %d\n",
0195            priv->long_frame_max_tx_count);
0196     seq_printf(seq, "Short retr: %d\n",
0197            priv->short_frame_max_tx_count);
0198     spin_lock_bh(&priv->tx_policy_cache.lock);
0199     i = 0;
0200     list_for_each(item, &priv->tx_policy_cache.used)
0201         ++i;
0202     spin_unlock_bh(&priv->tx_policy_cache.lock);
0203     seq_printf(seq, "RC in use:  %d\n", i);
0204 
0205     seq_puts(seq, "\n");
0206     for (i = 0; i < 4; ++i) {
0207         cw1200_queue_status_show(seq, &priv->tx_queue[i]);
0208         seq_puts(seq, "\n");
0209     }
0210 
0211     cw1200_debug_print_map(seq, priv, "Link map:   ",
0212                    priv->link_id_map);
0213     cw1200_debug_print_map(seq, priv, "Asleep map: ",
0214                    priv->sta_asleep_mask);
0215     cw1200_debug_print_map(seq, priv, "PSPOLL map: ",
0216                    priv->pspoll_mask);
0217 
0218     seq_puts(seq, "\n");
0219 
0220     for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) {
0221         if (priv->link_id_db[i].status) {
0222             seq_printf(seq, "Link %d:     %s, %pM\n",
0223                    i + 1,
0224                    cw1200_debug_link_id[priv->link_id_db[i].status],
0225                    priv->link_id_db[i].mac);
0226         }
0227     }
0228 
0229     seq_puts(seq, "\n");
0230 
0231     seq_printf(seq, "BH status:  %s\n",
0232            atomic_read(&priv->bh_term) ? "terminated" : "alive");
0233     seq_printf(seq, "Pending RX: %d\n",
0234            atomic_read(&priv->bh_rx));
0235     seq_printf(seq, "Pending TX: %d\n",
0236            atomic_read(&priv->bh_tx));
0237     if (priv->bh_error)
0238         seq_printf(seq, "BH errcode: %d\n",
0239                priv->bh_error);
0240     seq_printf(seq, "TX bufs:    %d x %d bytes\n",
0241            priv->wsm_caps.input_buffers,
0242            priv->wsm_caps.input_buffer_size);
0243     seq_printf(seq, "Used bufs:  %d\n",
0244            priv->hw_bufs_used);
0245     seq_printf(seq, "Powermgmt:  %s\n",
0246            priv->powersave_enabled ? "on" : "off");
0247     seq_printf(seq, "Device:     %s\n",
0248            priv->device_can_sleep ? "asleep" : "awake");
0249 
0250     spin_lock(&priv->wsm_cmd.lock);
0251     seq_printf(seq, "WSM status: %s\n",
0252            priv->wsm_cmd.done ? "idle" : "active");
0253     seq_printf(seq, "WSM cmd:    0x%.4X (%td bytes)\n",
0254            priv->wsm_cmd.cmd, priv->wsm_cmd.len);
0255     seq_printf(seq, "WSM retval: %d\n",
0256            priv->wsm_cmd.ret);
0257     spin_unlock(&priv->wsm_cmd.lock);
0258 
0259     seq_printf(seq, "Datapath:   %s\n",
0260            atomic_read(&priv->tx_lock) ? "locked" : "unlocked");
0261     if (atomic_read(&priv->tx_lock))
0262         seq_printf(seq, "TXlock cnt: %d\n",
0263                atomic_read(&priv->tx_lock));
0264 
0265     seq_printf(seq, "TXed:       %d\n",
0266            d->tx);
0267     seq_printf(seq, "AGG TXed:   %d\n",
0268            d->tx_agg);
0269     seq_printf(seq, "MULTI TXed: %d (%d)\n",
0270            d->tx_multi, d->tx_multi_frames);
0271     seq_printf(seq, "RXed:       %d\n",
0272            d->rx);
0273     seq_printf(seq, "AGG RXed:   %d\n",
0274            d->rx_agg);
0275     seq_printf(seq, "TX miss:    %d\n",
0276            d->tx_cache_miss);
0277     seq_printf(seq, "TX align:   %d\n",
0278            d->tx_align);
0279     seq_printf(seq, "TX burst:   %d\n",
0280            d->tx_burst);
0281     seq_printf(seq, "TX TTL:     %d\n",
0282            d->tx_ttl);
0283     seq_printf(seq, "Scan:       %s\n",
0284            atomic_read(&priv->scan.in_progress) ? "active" : "idle");
0285 
0286     return 0;
0287 }
0288 
0289 DEFINE_SHOW_ATTRIBUTE(cw1200_status);
0290 
0291 static int cw1200_counters_show(struct seq_file *seq, void *v)
0292 {
0293     int ret;
0294     struct cw1200_common *priv = seq->private;
0295     struct wsm_mib_counters_table counters;
0296 
0297     ret = wsm_get_counters_table(priv, &counters);
0298     if (ret)
0299         return ret;
0300 
0301 #define PUT_COUNTER(tab, name) \
0302     seq_printf(seq, "%s:" tab "%d\n", #name, \
0303         __le32_to_cpu(counters.name))
0304 
0305     PUT_COUNTER("\t\t", plcp_errors);
0306     PUT_COUNTER("\t\t", fcs_errors);
0307     PUT_COUNTER("\t\t", tx_packets);
0308     PUT_COUNTER("\t\t", rx_packets);
0309     PUT_COUNTER("\t\t", rx_packet_errors);
0310     PUT_COUNTER("\t",   rx_decryption_failures);
0311     PUT_COUNTER("\t\t", rx_mic_failures);
0312     PUT_COUNTER("\t",   rx_no_key_failures);
0313     PUT_COUNTER("\t",   tx_multicast_frames);
0314     PUT_COUNTER("\t",   tx_frames_success);
0315     PUT_COUNTER("\t",   tx_frame_failures);
0316     PUT_COUNTER("\t",   tx_frames_retried);
0317     PUT_COUNTER("\t",   tx_frames_multi_retried);
0318     PUT_COUNTER("\t",   rx_frame_duplicates);
0319     PUT_COUNTER("\t\t", rts_success);
0320     PUT_COUNTER("\t\t", rts_failures);
0321     PUT_COUNTER("\t\t", ack_failures);
0322     PUT_COUNTER("\t",   rx_multicast_frames);
0323     PUT_COUNTER("\t",   rx_frames_success);
0324     PUT_COUNTER("\t",   rx_cmac_icv_errors);
0325     PUT_COUNTER("\t\t", rx_cmac_replays);
0326     PUT_COUNTER("\t",   rx_mgmt_ccmp_replays);
0327 
0328 #undef PUT_COUNTER
0329 
0330     return 0;
0331 }
0332 
0333 DEFINE_SHOW_ATTRIBUTE(cw1200_counters);
0334 
0335 static ssize_t cw1200_wsm_dumps(struct file *file,
0336     const char __user *user_buf, size_t count, loff_t *ppos)
0337 {
0338     struct cw1200_common *priv = file->private_data;
0339     char buf[1];
0340 
0341     if (!count)
0342         return -EINVAL;
0343     if (copy_from_user(buf, user_buf, 1))
0344         return -EFAULT;
0345 
0346     if (buf[0] == '1')
0347         priv->wsm_enable_wsm_dumps = 1;
0348     else
0349         priv->wsm_enable_wsm_dumps = 0;
0350 
0351     return count;
0352 }
0353 
0354 static const struct file_operations fops_wsm_dumps = {
0355     .open = simple_open,
0356     .write = cw1200_wsm_dumps,
0357     .llseek = default_llseek,
0358 };
0359 
0360 int cw1200_debug_init(struct cw1200_common *priv)
0361 {
0362     int ret = -ENOMEM;
0363     struct cw1200_debug_priv *d = kzalloc(sizeof(struct cw1200_debug_priv),
0364             GFP_KERNEL);
0365     priv->debug = d;
0366     if (!d)
0367         return ret;
0368 
0369     d->debugfs_phy = debugfs_create_dir("cw1200",
0370                         priv->hw->wiphy->debugfsdir);
0371     debugfs_create_file("status", 0400, d->debugfs_phy, priv,
0372                 &cw1200_status_fops);
0373     debugfs_create_file("counters", 0400, d->debugfs_phy, priv,
0374                 &cw1200_counters_fops);
0375     debugfs_create_file("wsm_dumps", 0200, d->debugfs_phy, priv,
0376                 &fops_wsm_dumps);
0377 
0378     return 0;
0379 }
0380 
0381 void cw1200_debug_release(struct cw1200_common *priv)
0382 {
0383     struct cw1200_debug_priv *d = priv->debug;
0384     if (d) {
0385         debugfs_remove_recursive(d->debugfs_phy);
0386         priv->debug = NULL;
0387         kfree(d);
0388     }
0389 }