223 lines · c
1/*2 * Atheros CARL9170 driver3 *4 * Basic HW register/memory/command access functions5 *6 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>7 *8 * This program is free software; you can redistribute it and/or modify9 * it under the terms of the GNU General Public License as published by10 * the Free Software Foundation; either version 2 of the License, or11 * (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 of15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16 * GNU General Public License for more details.17 *18 * You should have received a copy of the GNU General Public License19 * along with this program; see the file COPYING. If not, see20 * http://www.gnu.org/licenses/.21 *22 * This file incorporates work covered by the following copyright and23 * permission notice:24 * Copyright (c) 2007-2008 Atheros Communications, Inc.25 *26 * Permission to use, copy, modify, and/or distribute this software for any27 * purpose with or without fee is hereby granted, provided that the above28 * copyright notice and this permission notice appear in all copies.29 *30 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES31 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF32 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR33 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES34 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN35 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF36 * 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, ®, 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(*tmp), 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}223