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 43 int 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 62 int 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 94 int carl9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val) 95 { 96 return carl9170_read_mreg(ar, 1, ®, val); 97 } 98 99 int 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 118 struct 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 132 int 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 145 int carl9170_mac_reset(struct ar9170 *ar) 146 { 147 return carl9170_exec_cmd(ar, CARL9170_CMD_SWRST, 148 0, NULL, 0, NULL); 149 } 150 151 int 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 169 int 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->channel_time = ar->tally.active; 192 info->channel_time_busy = ar->tally.cca; 193 info->channel_time_tx = ar->tally.tx_time; 194 do_div(info->channel_time, 1000); 195 do_div(info->channel_time_busy, 1000); 196 do_div(info->channel_time_tx, 1000); 197 } 198 } 199 return 0; 200 } 201 202 int 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