cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cmd.c (5779B)


      1/*
      2 * Atheros CARL9170 driver
      3 *
      4 * Basic HW register/memory/command access functions
      5 *
      6 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
      7 *
      8 * This program is free software; you can redistribute it and/or modify
      9 * it under the terms of the GNU General Public License as published by
     10 * the Free Software Foundation; either version 2 of the License, or
     11 * (at your option) any later version.
     12 *
     13 * This program is distributed in the hope that it will be useful,
     14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 * GNU General Public License for more details.
     17 *
     18 * You should have received a copy of the GNU General Public License
     19 * along with this program; see the file COPYING.  If not, see
     20 * http://www.gnu.org/licenses/.
     21 *
     22 * This file incorporates work covered by the following copyright and
     23 * permission notice:
     24 *    Copyright (c) 2007-2008 Atheros Communications, Inc.
     25 *
     26 *    Permission to use, copy, modify, and/or distribute this software for any
     27 *    purpose with or without fee is hereby granted, provided that the above
     28 *    copyright notice and this permission notice appear in all copies.
     29 *
     30 *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     31 *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     32 *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     33 *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     34 *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     35 *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     36 *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     37 */
     38
     39#include <asm/div64.h>
     40#include "carl9170.h"
     41#include "cmd.h"
     42
     43int carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
     44{
     45	const __le32 buf[2] = {
     46		cpu_to_le32(reg),
     47		cpu_to_le32(val),
     48	};
     49	int err;
     50
     51	err = carl9170_exec_cmd(ar, CARL9170_CMD_WREG, sizeof(buf),
     52				(u8 *) buf, 0, NULL);
     53	if (err) {
     54		if (net_ratelimit()) {
     55			wiphy_err(ar->hw->wiphy, "writing reg %#x "
     56				"(val %#x) failed (%d)\n", reg, val, err);
     57		}
     58	}
     59	return err;
     60}
     61
     62int carl9170_read_mreg(struct ar9170 *ar, const int nregs,
     63		       const u32 *regs, u32 *out)
     64{
     65	int i, err;
     66	__le32 *offs, *res;
     67
     68	/* abuse "out" for the register offsets, must be same length */
     69	offs = (__le32 *)out;
     70	for (i = 0; i < nregs; i++)
     71		offs[i] = cpu_to_le32(regs[i]);
     72
     73	/* also use the same buffer for the input */
     74	res = (__le32 *)out;
     75
     76	err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
     77				4 * nregs, (u8 *)offs,
     78				4 * nregs, (u8 *)res);
     79	if (err) {
     80		if (net_ratelimit()) {
     81			wiphy_err(ar->hw->wiphy, "reading regs failed (%d)\n",
     82				  err);
     83		}
     84		return err;
     85	}
     86
     87	/* convert result to cpu endian */
     88	for (i = 0; i < nregs; i++)
     89		out[i] = le32_to_cpu(res[i]);
     90
     91	return 0;
     92}
     93
     94int carl9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val)
     95{
     96	return carl9170_read_mreg(ar, 1, &reg, val);
     97}
     98
     99int carl9170_echo_test(struct ar9170 *ar, const u32 v)
    100{
    101	u32 echores;
    102	int err;
    103
    104	err = carl9170_exec_cmd(ar, CARL9170_CMD_ECHO,
    105				4, (u8 *)&v,
    106				4, (u8 *)&echores);
    107	if (err)
    108		return err;
    109
    110	if (v != echores) {
    111		wiphy_info(ar->hw->wiphy, "wrong echo %x != %x", v, echores);
    112		return -EINVAL;
    113	}
    114
    115	return 0;
    116}
    117
    118struct carl9170_cmd *carl9170_cmd_buf(struct ar9170 *ar,
    119	const enum carl9170_cmd_oids cmd, const unsigned int len)
    120{
    121	struct carl9170_cmd *tmp;
    122
    123	tmp = kzalloc(sizeof(struct carl9170_cmd_head) + len, GFP_ATOMIC);
    124	if (tmp) {
    125		tmp->hdr.cmd = cmd;
    126		tmp->hdr.len = len;
    127	}
    128
    129	return tmp;
    130}
    131
    132int carl9170_reboot(struct ar9170 *ar)
    133{
    134	struct carl9170_cmd *cmd;
    135	int err;
    136
    137	cmd = carl9170_cmd_buf(ar, CARL9170_CMD_REBOOT_ASYNC, 0);
    138	if (!cmd)
    139		return -ENOMEM;
    140
    141	err = __carl9170_exec_cmd(ar, cmd, true);
    142	return err;
    143}
    144
    145int carl9170_mac_reset(struct ar9170 *ar)
    146{
    147	return carl9170_exec_cmd(ar, CARL9170_CMD_SWRST,
    148				 0, NULL, 0, NULL);
    149}
    150
    151int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
    152		       const u32 mode, const u32 addr, const u32 len)
    153{
    154	struct carl9170_cmd *cmd;
    155
    156	cmd = carl9170_cmd_buf(ar, CARL9170_CMD_BCN_CTRL_ASYNC,
    157			       sizeof(struct carl9170_bcn_ctrl_cmd));
    158	if (!cmd)
    159		return -ENOMEM;
    160
    161	cmd->bcn_ctrl.vif_id = cpu_to_le32(vif_id);
    162	cmd->bcn_ctrl.mode = cpu_to_le32(mode);
    163	cmd->bcn_ctrl.bcn_addr = cpu_to_le32(addr);
    164	cmd->bcn_ctrl.bcn_len = cpu_to_le32(len);
    165
    166	return __carl9170_exec_cmd(ar, cmd, true);
    167}
    168
    169int carl9170_collect_tally(struct ar9170 *ar)
    170{
    171	struct carl9170_tally_rsp tally;
    172	struct survey_info *info;
    173	unsigned int tick;
    174	int err;
    175
    176	err = carl9170_exec_cmd(ar, CARL9170_CMD_TALLY, 0, NULL,
    177				sizeof(tally), (u8 *)&tally);
    178	if (err)
    179		return err;
    180
    181	tick = le32_to_cpu(tally.tick);
    182	if (tick) {
    183		ar->tally.active += le32_to_cpu(tally.active) / tick;
    184		ar->tally.cca += le32_to_cpu(tally.cca) / tick;
    185		ar->tally.tx_time += le32_to_cpu(tally.tx_time) / tick;
    186		ar->tally.rx_total += le32_to_cpu(tally.rx_total);
    187		ar->tally.rx_overrun += le32_to_cpu(tally.rx_overrun);
    188
    189		if (ar->channel) {
    190			info = &ar->survey[ar->channel->hw_value];
    191			info->time = ar->tally.active;
    192			info->time_busy = ar->tally.cca;
    193			info->time_tx = ar->tally.tx_time;
    194			do_div(info->time, 1000);
    195			do_div(info->time_busy, 1000);
    196			do_div(info->time_tx, 1000);
    197		}
    198	}
    199	return 0;
    200}
    201
    202int carl9170_powersave(struct ar9170 *ar, const bool ps)
    203{
    204	struct carl9170_cmd *cmd;
    205	u32 state;
    206
    207	cmd = carl9170_cmd_buf(ar, CARL9170_CMD_PSM_ASYNC,
    208			       sizeof(struct carl9170_psm));
    209	if (!cmd)
    210		return -ENOMEM;
    211
    212	if (ps) {
    213		/* Sleep until next TBTT */
    214		state = CARL9170_PSM_SLEEP | 1;
    215	} else {
    216		/* wake up immediately */
    217		state = 1;
    218	}
    219
    220	cmd->psm.state = cpu_to_le32(state);
    221	return __carl9170_exec_cmd(ar, cmd, true);
    222}