Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
/*---------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";
		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) {
			rc = wil_cid_fill_sinfo(wil, 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);
		}
	}

	return 0;
}
Exemplo n.º 3
0
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);
}
Exemplo n.º 4
0
static int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
                              struct station_info *sinfo)
{
    struct wmi_notify_req_cmd cmd = {
        .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;

    rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
                  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_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 = le16_to_cpu(reply.evt.bf_mcs);
    sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
    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 = reply.evt.sqi;
    }

    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;
}