Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
  3. * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
  4. * Copyright (c) 2007-2008 Matthew W. S. Bell <mentor@madwifi.org>
  5. * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
  6. * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
  7. * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
  8. *
  9. * Lightly modified for gPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
  10. *
  11. * Permission to use, copy, modify, and distribute this software for any
  12. * purpose with or without fee is hereby granted, provided that the above
  13. * copyright notice and this permission notice appear in all copies.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  16. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  17. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  18. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  21. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22. *
  23. */
  24. FILE_LICENCE ( MIT );
  25. /*********************************\
  26. * Protocol Control Unit Functions *
  27. \*********************************/
  28. #include "ath5k.h"
  29. #include "reg.h"
  30. #include "base.h"
  31. /*******************\
  32. * Generic functions *
  33. \*******************/
  34. /**
  35. * ath5k_hw_set_opmode - Set PCU operating mode
  36. *
  37. * @ah: The &struct ath5k_hw
  38. *
  39. * Initialize PCU for the various operating modes (AP/STA etc)
  40. *
  41. * For gPXE we always assume STA mode.
  42. */
  43. int ath5k_hw_set_opmode(struct ath5k_hw *ah)
  44. {
  45. u32 pcu_reg, beacon_reg, low_id, high_id;
  46. /* Preserve rest settings */
  47. pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
  48. pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
  49. | AR5K_STA_ID1_KEYSRCH_MODE
  50. | (ah->ah_version == AR5K_AR5210 ?
  51. (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
  52. beacon_reg = 0;
  53. pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
  54. | (ah->ah_version == AR5K_AR5210 ?
  55. AR5K_STA_ID1_PWR_SV : 0);
  56. /*
  57. * Set PCU registers
  58. */
  59. low_id = AR5K_LOW_ID(ah->ah_sta_id);
  60. high_id = AR5K_HIGH_ID(ah->ah_sta_id);
  61. ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
  62. ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
  63. /*
  64. * Set Beacon Control Register on 5210
  65. */
  66. if (ah->ah_version == AR5K_AR5210)
  67. ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
  68. return 0;
  69. }
  70. /**
  71. * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
  72. *
  73. * @ah: The &struct ath5k_hw
  74. * @high: Flag to determine if we want to use high transmition rate
  75. * for ACKs or not
  76. *
  77. * If high flag is set, we tell hw to use a set of control rates based on
  78. * the current transmition rate (check out control_rates array inside reset.c).
  79. * If not hw just uses the lowest rate available for the current modulation
  80. * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
  81. */
  82. void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, int high)
  83. {
  84. if (ah->ah_version != AR5K_AR5212)
  85. return;
  86. else {
  87. u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
  88. if (high)
  89. AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
  90. else
  91. AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
  92. }
  93. }
  94. /******************\
  95. * ACK/CTS Timeouts *
  96. \******************/
  97. /**
  98. * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec
  99. *
  100. * @ah: The &struct ath5k_hw
  101. */
  102. unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
  103. {
  104. return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
  105. AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
  106. }
  107. /**
  108. * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
  109. *
  110. * @ah: The &struct ath5k_hw
  111. * @timeout: Timeout in usec
  112. */
  113. int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
  114. {
  115. if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
  116. ah->ah_turbo) <= timeout)
  117. return -EINVAL;
  118. AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
  119. ath5k_hw_htoclock(timeout, ah->ah_turbo));
  120. return 0;
  121. }
  122. /**
  123. * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec
  124. *
  125. * @ah: The &struct ath5k_hw
  126. */
  127. unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
  128. {
  129. return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
  130. AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
  131. }
  132. /**
  133. * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
  134. *
  135. * @ah: The &struct ath5k_hw
  136. * @timeout: Timeout in usec
  137. */
  138. int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
  139. {
  140. if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
  141. ah->ah_turbo) <= timeout)
  142. return -EINVAL;
  143. AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
  144. ath5k_hw_htoclock(timeout, ah->ah_turbo));
  145. return 0;
  146. }
  147. /****************\
  148. * BSSID handling *
  149. \****************/
  150. /**
  151. * ath5k_hw_get_lladdr - Get station id
  152. *
  153. * @ah: The &struct ath5k_hw
  154. * @mac: The card's mac address
  155. *
  156. * Initialize ah->ah_sta_id using the mac address provided
  157. * (just a memcpy).
  158. *
  159. * TODO: Remove it once we merge ath5k_softc and ath5k_hw
  160. */
  161. void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
  162. {
  163. memcpy(mac, ah->ah_sta_id, ETH_ALEN);
  164. }
  165. /**
  166. * ath5k_hw_set_lladdr - Set station id
  167. *
  168. * @ah: The &struct ath5k_hw
  169. * @mac: The card's mac address
  170. *
  171. * Set station id on hw using the provided mac address
  172. */
  173. int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
  174. {
  175. u32 low_id, high_id;
  176. u32 pcu_reg;
  177. /* Set new station ID */
  178. memcpy(ah->ah_sta_id, mac, ETH_ALEN);
  179. pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
  180. low_id = AR5K_LOW_ID(mac);
  181. high_id = AR5K_HIGH_ID(mac);
  182. ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
  183. ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
  184. return 0;
  185. }
  186. /**
  187. * ath5k_hw_set_associd - Set BSSID for association
  188. *
  189. * @ah: The &struct ath5k_hw
  190. * @bssid: BSSID
  191. * @assoc_id: Assoc id
  192. *
  193. * Sets the BSSID which trigers the "SME Join" operation
  194. */
  195. void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
  196. {
  197. u32 low_id, high_id;
  198. /*
  199. * Set simple BSSID mask on 5212
  200. */
  201. if (ah->ah_version == AR5K_AR5212) {
  202. ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
  203. AR5K_BSS_IDM0);
  204. ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
  205. AR5K_BSS_IDM1);
  206. }
  207. /*
  208. * Set BSSID which triggers the "SME Join" operation
  209. */
  210. low_id = AR5K_LOW_ID(bssid);
  211. high_id = AR5K_HIGH_ID(bssid);
  212. ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
  213. ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
  214. AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
  215. }
  216. /**
  217. * ath5k_hw_set_bssid_mask - filter out bssids we listen
  218. *
  219. * @ah: the &struct ath5k_hw
  220. * @mask: the bssid_mask, a u8 array of size ETH_ALEN
  221. *
  222. * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
  223. * which bits of the interface's MAC address should be looked at when trying
  224. * to decide which packets to ACK. In station mode and AP mode with a single
  225. * BSS every bit matters since we lock to only one BSS. In AP mode with
  226. * multiple BSSes (virtual interfaces) not every bit matters because hw must
  227. * accept frames for all BSSes and so we tweak some bits of our mac address
  228. * in order to have multiple BSSes.
  229. *
  230. * NOTE: This is a simple filter and does *not* filter out all
  231. * relevant frames. Some frames that are not for us might get ACKed from us
  232. * by PCU because they just match the mask.
  233. *
  234. * When handling multiple BSSes you can get the BSSID mask by computing the
  235. * set of ~ ( MAC XOR BSSID ) for all bssids we handle.
  236. *
  237. * When you do this you are essentially computing the common bits of all your
  238. * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
  239. * the MAC address to obtain the relevant bits and compare the result with
  240. * (frame's BSSID & mask) to see if they match.
  241. */
  242. /*
  243. * Simple example: on your card you have have two BSSes you have created with
  244. * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
  245. * There is another BSSID-03 but you are not part of it. For simplicity's sake,
  246. * assuming only 4 bits for a mac address and for BSSIDs you can then have:
  247. *
  248. * \
  249. * MAC: 0001 |
  250. * BSSID-01: 0100 | --> Belongs to us
  251. * BSSID-02: 1001 |
  252. * /
  253. * -------------------
  254. * BSSID-03: 0110 | --> External
  255. * -------------------
  256. *
  257. * Our bssid_mask would then be:
  258. *
  259. * On loop iteration for BSSID-01:
  260. * ~(0001 ^ 0100) -> ~(0101)
  261. * -> 1010
  262. * bssid_mask = 1010
  263. *
  264. * On loop iteration for BSSID-02:
  265. * bssid_mask &= ~(0001 ^ 1001)
  266. * bssid_mask = (1010) & ~(0001 ^ 1001)
  267. * bssid_mask = (1010) & ~(1001)
  268. * bssid_mask = (1010) & (0110)
  269. * bssid_mask = 0010
  270. *
  271. * A bssid_mask of 0010 means "only pay attention to the second least
  272. * significant bit". This is because its the only bit common
  273. * amongst the MAC and all BSSIDs we support. To findout what the real
  274. * common bit is we can simply "&" the bssid_mask now with any BSSID we have
  275. * or our MAC address (we assume the hardware uses the MAC address).
  276. *
  277. * Now, suppose there's an incoming frame for BSSID-03:
  278. *
  279. * IFRAME-01: 0110
  280. *
  281. * An easy eye-inspeciton of this already should tell you that this frame
  282. * will not pass our check. This is beacuse the bssid_mask tells the
  283. * hardware to only look at the second least significant bit and the
  284. * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
  285. * as 1, which does not match 0.
  286. *
  287. * So with IFRAME-01 we *assume* the hardware will do:
  288. *
  289. * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
  290. * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
  291. * --> allow = (0010) == 0000 ? 1 : 0;
  292. * --> allow = 0
  293. *
  294. * Lets now test a frame that should work:
  295. *
  296. * IFRAME-02: 0001 (we should allow)
  297. *
  298. * allow = (0001 & 1010) == 1010
  299. *
  300. * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
  301. * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0;
  302. * --> allow = (0010) == (0010)
  303. * --> allow = 1
  304. *
  305. * Other examples:
  306. *
  307. * IFRAME-03: 0100 --> allowed
  308. * IFRAME-04: 1001 --> allowed
  309. * IFRAME-05: 1101 --> allowed but its not for us!!!
  310. *
  311. */
  312. int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
  313. {
  314. u32 low_id, high_id;
  315. /* Cache bssid mask so that we can restore it
  316. * on reset */
  317. memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
  318. if (ah->ah_version == AR5K_AR5212) {
  319. low_id = AR5K_LOW_ID(mask);
  320. high_id = AR5K_HIGH_ID(mask);
  321. ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
  322. ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
  323. return 0;
  324. }
  325. return -EIO;
  326. }
  327. /************\
  328. * RX Control *
  329. \************/
  330. /**
  331. * ath5k_hw_start_rx_pcu - Start RX engine
  332. *
  333. * @ah: The &struct ath5k_hw
  334. *
  335. * Starts RX engine on PCU so that hw can process RXed frames
  336. * (ACK etc).
  337. *
  338. * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
  339. * TODO: Init ANI here
  340. */
  341. void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
  342. {
  343. AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
  344. }
  345. /**
  346. * at5k_hw_stop_rx_pcu - Stop RX engine
  347. *
  348. * @ah: The &struct ath5k_hw
  349. *
  350. * Stops RX engine on PCU
  351. *
  352. * TODO: Detach ANI here
  353. */
  354. void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
  355. {
  356. AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
  357. }
  358. /*
  359. * Set multicast filter
  360. */
  361. void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
  362. {
  363. /* Set the multicat filter */
  364. ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
  365. ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
  366. }
  367. /**
  368. * ath5k_hw_get_rx_filter - Get current rx filter
  369. *
  370. * @ah: The &struct ath5k_hw
  371. *
  372. * Returns the RX filter by reading rx filter and
  373. * phy error filter registers. RX filter is used
  374. * to set the allowed frame types that PCU will accept
  375. * and pass to the driver. For a list of frame types
  376. * check out reg.h.
  377. */
  378. u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
  379. {
  380. u32 data, filter = 0;
  381. filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
  382. /*Radar detection for 5212*/
  383. if (ah->ah_version == AR5K_AR5212) {
  384. data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
  385. if (data & AR5K_PHY_ERR_FIL_RADAR)
  386. filter |= AR5K_RX_FILTER_RADARERR;
  387. if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
  388. filter |= AR5K_RX_FILTER_PHYERR;
  389. }
  390. return filter;
  391. }
  392. /**
  393. * ath5k_hw_set_rx_filter - Set rx filter
  394. *
  395. * @ah: The &struct ath5k_hw
  396. * @filter: RX filter mask (see reg.h)
  397. *
  398. * Sets RX filter register and also handles PHY error filter
  399. * register on 5212 and newer chips so that we have proper PHY
  400. * error reporting.
  401. */
  402. void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
  403. {
  404. u32 data = 0;
  405. /* Set PHY error filter register on 5212*/
  406. if (ah->ah_version == AR5K_AR5212) {
  407. if (filter & AR5K_RX_FILTER_RADARERR)
  408. data |= AR5K_PHY_ERR_FIL_RADAR;
  409. if (filter & AR5K_RX_FILTER_PHYERR)
  410. data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
  411. }
  412. /*
  413. * The AR5210 uses promiscous mode to detect radar activity
  414. */
  415. if (ah->ah_version == AR5K_AR5210 &&
  416. (filter & AR5K_RX_FILTER_RADARERR)) {
  417. filter &= ~AR5K_RX_FILTER_RADARERR;
  418. filter |= AR5K_RX_FILTER_PROM;
  419. }
  420. /*Zero length DMA (phy error reporting) */
  421. if (data)
  422. AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
  423. else
  424. AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
  425. /*Write RX Filter register*/
  426. ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
  427. /*Write PHY error filter register on 5212*/
  428. if (ah->ah_version == AR5K_AR5212)
  429. ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
  430. }
  431. /*********************\
  432. * Key table functions *
  433. \*********************/
  434. /*
  435. * Reset a key entry on the table
  436. */
  437. int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
  438. {
  439. unsigned int i, type;
  440. u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
  441. type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
  442. for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
  443. ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
  444. /* Reset associated MIC entry if TKIP
  445. * is enabled located at offset (entry + 64) */
  446. if (type == AR5K_KEYTABLE_TYPE_TKIP) {
  447. for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
  448. ath5k_hw_reg_write(ah, 0,
  449. AR5K_KEYTABLE_OFF(micentry, i));
  450. }
  451. /*
  452. * Set NULL encryption on AR5212+
  453. *
  454. * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
  455. * AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
  456. *
  457. * Note2: Windows driver (ndiswrapper) sets this to
  458. * 0x00000714 instead of 0x00000007
  459. */
  460. if (ah->ah_version > AR5K_AR5211) {
  461. ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
  462. AR5K_KEYTABLE_TYPE(entry));
  463. if (type == AR5K_KEYTABLE_TYPE_TKIP) {
  464. ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
  465. AR5K_KEYTABLE_TYPE(micentry));
  466. }
  467. }
  468. return 0;
  469. }