1607 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * This file contains the handling of command.4 * It prepares command and sends it to firmware when it is ready.5 */6 7#include <linux/hardirq.h>8#include <linux/kfifo.h>9#include <linux/sched.h>10#include <linux/slab.h>11#include <linux/if_arp.h>12#include <linux/export.h>13 14#include "decl.h"15#include "cfg.h"16#include "cmd.h"17 18#define CAL_NF(nf) ((s32)(-(s32)(nf)))19#define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf)))20 21/**22 * lbs_cmd_copyback - Simple callback that copies response back into command23 *24 * @priv: A pointer to &struct lbs_private structure25 * @extra: A pointer to the original command structure for which26 * 'resp' is a response27 * @resp: A pointer to the command response28 *29 * returns: 0 on success, error on failure30 */31int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,32 struct cmd_header *resp)33{34 struct cmd_header *buf = (void *)extra;35 uint16_t copy_len;36 37 copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));38 memcpy(buf, resp, copy_len);39 return 0;40}41EXPORT_SYMBOL_GPL(lbs_cmd_copyback);42 43/**44 * lbs_cmd_async_callback - Simple callback that ignores the result.45 * Use this if you just want to send a command to the hardware, but don't46 * care for the result.47 *48 * @priv: ignored49 * @extra: ignored50 * @resp: ignored51 *52 * returns: 0 for success53 */54static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,55 struct cmd_header *resp)56{57 return 0;58}59 60 61/**62 * is_command_allowed_in_ps - tests if a command is allowed in Power Save mode63 *64 * @cmd: the command ID65 *66 * returns: 1 if allowed, 0 if not allowed67 */68static u8 is_command_allowed_in_ps(u16 cmd)69{70 switch (cmd) {71 case CMD_802_11_RSSI:72 return 1;73 case CMD_802_11_HOST_SLEEP_CFG:74 return 1;75 default:76 break;77 }78 return 0;79}80 81/**82 * lbs_update_hw_spec - Updates the hardware details like MAC address83 * and regulatory region84 *85 * @priv: A pointer to &struct lbs_private structure86 *87 * returns: 0 on success, error on failure88 */89int lbs_update_hw_spec(struct lbs_private *priv)90{91 struct cmd_ds_get_hw_spec cmd;92 int ret = -1;93 u32 i;94 95 memset(&cmd, 0, sizeof(cmd));96 cmd.hdr.size = cpu_to_le16(sizeof(cmd));97 memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);98 ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);99 if (ret)100 goto out;101 102 priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);103 104 /* The firmware release is in an interesting format: the patch105 * level is in the most significant nibble ... so fix that: */106 priv->fwrelease = le32_to_cpu(cmd.fwrelease);107 priv->fwrelease = (priv->fwrelease << 8) |108 (priv->fwrelease >> 24 & 0xff);109 110 /* Some firmware capabilities:111 * CF card firmware 5.0.16p0: cap 0x00000303112 * USB dongle firmware 5.110.17p2: cap 0x00000303113 */114 netdev_info(priv->dev, "%pM, fw %u.%u.%up%u, cap 0x%08x\n",115 cmd.permanentaddr,116 priv->fwrelease >> 24 & 0xff,117 priv->fwrelease >> 16 & 0xff,118 priv->fwrelease >> 8 & 0xff,119 priv->fwrelease & 0xff,120 priv->fwcapinfo);121 lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",122 cmd.hwifversion, cmd.version);123 124 /* Clamp region code to 8-bit since FW spec indicates that it should125 * only ever be 8-bit, even though the field size is 16-bit. Some firmware126 * returns non-zero high 8 bits here.127 *128 * Firmware version 4.0.102 used in CF8381 has region code shifted. We129 * need to check for this problem and handle it properly.130 */131 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)132 priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;133 else134 priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;135 136 for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {137 /* use the region code to search for the index */138 if (priv->regioncode == lbs_region_code_to_index[i])139 break;140 }141 142 /* if it's unidentified region code, use the default (USA) */143 if (i >= MRVDRV_MAX_REGION_CODE) {144 priv->regioncode = 0x10;145 netdev_info(priv->dev,146 "unidentified region code; using the default (USA)\n");147 }148 149 if (priv->current_addr[0] == 0xff)150 memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);151 152 if (!priv->copied_hwaddr) {153 eth_hw_addr_set(priv->dev, priv->current_addr);154 if (priv->mesh_dev)155 eth_hw_addr_set(priv->mesh_dev, priv->current_addr);156 priv->copied_hwaddr = 1;157 }158 159out:160 return ret;161}162 163static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,164 struct cmd_header *resp)165{166 if (priv->is_host_sleep_activated) {167 priv->is_host_sleep_configured = 0;168 if (priv->psstate == PS_STATE_FULL_POWER) {169 priv->is_host_sleep_activated = 0;170 wake_up_interruptible(&priv->host_sleep_q);171 }172 } else {173 priv->is_host_sleep_configured = 1;174 }175 176 return 0;177}178 179int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,180 struct wol_config *p_wol_config)181{182 struct cmd_ds_host_sleep cmd_config;183 int ret;184 185 /*186 * Certain firmware versions do not support EHS_REMOVE_WAKEUP command187 * and the card will return a failure. Since we need to be188 * able to reset the mask, in those cases we set a 0 mask instead.189 */190 if (criteria == EHS_REMOVE_WAKEUP && !priv->ehs_remove_supported)191 criteria = 0;192 193 cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));194 cmd_config.criteria = cpu_to_le32(criteria);195 cmd_config.gpio = priv->wol_gpio;196 cmd_config.gap = priv->wol_gap;197 198 if (p_wol_config != NULL)199 memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config,200 sizeof(struct wol_config));201 else202 cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;203 204 ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,205 le16_to_cpu(cmd_config.hdr.size),206 lbs_ret_host_sleep_cfg, 0);207 if (!ret) {208 if (p_wol_config)209 memcpy((uint8_t *) p_wol_config,210 (uint8_t *)&cmd_config.wol_conf,211 sizeof(struct wol_config));212 } else {213 netdev_info(priv->dev, "HOST_SLEEP_CFG failed %d\n", ret);214 }215 216 return ret;217}218EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);219 220/**221 * lbs_set_ps_mode - Sets the Power Save mode222 *223 * @priv: A pointer to &struct lbs_private structure224 * @cmd_action: The Power Save operation (PS_MODE_ACTION_ENTER_PS or225 * PS_MODE_ACTION_EXIT_PS)226 * @block: Whether to block on a response or not227 *228 * returns: 0 on success, error on failure229 */230int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)231{232 struct cmd_ds_802_11_ps_mode cmd;233 int ret = 0;234 235 memset(&cmd, 0, sizeof(cmd));236 cmd.hdr.size = cpu_to_le16(sizeof(cmd));237 cmd.action = cpu_to_le16(cmd_action);238 239 if (cmd_action == PS_MODE_ACTION_ENTER_PS) {240 lbs_deb_cmd("PS_MODE: action ENTER_PS\n");241 cmd.multipledtim = cpu_to_le16(1); /* Default DTIM multiple */242 } else if (cmd_action == PS_MODE_ACTION_EXIT_PS) {243 lbs_deb_cmd("PS_MODE: action EXIT_PS\n");244 } else {245 /* We don't handle CONFIRM_SLEEP here because it needs to246 * be fastpathed to the firmware.247 */248 lbs_deb_cmd("PS_MODE: unknown action 0x%X\n", cmd_action);249 ret = -EOPNOTSUPP;250 goto out;251 }252 253 if (block)254 ret = lbs_cmd_with_response(priv, CMD_802_11_PS_MODE, &cmd);255 else256 lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));257 258out:259 return ret;260}261 262int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,263 struct sleep_params *sp)264{265 struct cmd_ds_802_11_sleep_params cmd;266 int ret;267 268 if (cmd_action == CMD_ACT_GET) {269 memset(&cmd, 0, sizeof(cmd));270 } else {271 cmd.error = cpu_to_le16(sp->sp_error);272 cmd.offset = cpu_to_le16(sp->sp_offset);273 cmd.stabletime = cpu_to_le16(sp->sp_stabletime);274 cmd.calcontrol = sp->sp_calcontrol;275 cmd.externalsleepclk = sp->sp_extsleepclk;276 cmd.reserved = cpu_to_le16(sp->sp_reserved);277 }278 cmd.hdr.size = cpu_to_le16(sizeof(cmd));279 cmd.action = cpu_to_le16(cmd_action);280 281 ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd);282 283 if (!ret) {284 lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, "285 "calcontrol 0x%x extsleepclk 0x%x\n",286 le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset),287 le16_to_cpu(cmd.stabletime), cmd.calcontrol,288 cmd.externalsleepclk);289 290 sp->sp_error = le16_to_cpu(cmd.error);291 sp->sp_offset = le16_to_cpu(cmd.offset);292 sp->sp_stabletime = le16_to_cpu(cmd.stabletime);293 sp->sp_calcontrol = cmd.calcontrol;294 sp->sp_extsleepclk = cmd.externalsleepclk;295 sp->sp_reserved = le16_to_cpu(cmd.reserved);296 }297 298 return ret;299}300 301static int lbs_wait_for_ds_awake(struct lbs_private *priv)302{303 int ret = 0;304 305 if (priv->is_deep_sleep) {306 if (!wait_event_interruptible_timeout(priv->ds_awake_q,307 !priv->is_deep_sleep, (10 * HZ))) {308 netdev_err(priv->dev, "ds_awake_q: timer expired\n");309 ret = -1;310 }311 }312 313 return ret;314}315 316int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)317{318 int ret = 0;319 320 if (deep_sleep) {321 if (priv->is_deep_sleep != 1) {322 lbs_deb_cmd("deep sleep: sleep\n");323 BUG_ON(!priv->enter_deep_sleep);324 ret = priv->enter_deep_sleep(priv);325 if (!ret) {326 netif_stop_queue(priv->dev);327 netif_carrier_off(priv->dev);328 }329 } else {330 netdev_err(priv->dev, "deep sleep: already enabled\n");331 }332 } else {333 if (priv->is_deep_sleep) {334 lbs_deb_cmd("deep sleep: wakeup\n");335 BUG_ON(!priv->exit_deep_sleep);336 ret = priv->exit_deep_sleep(priv);337 if (!ret) {338 ret = lbs_wait_for_ds_awake(priv);339 if (ret)340 netdev_err(priv->dev,341 "deep sleep: wakeup failed\n");342 }343 }344 }345 346 return ret;347}348 349static int lbs_ret_host_sleep_activate(struct lbs_private *priv,350 unsigned long dummy,351 struct cmd_header *cmd)352{353 priv->is_host_sleep_activated = 1;354 wake_up_interruptible(&priv->host_sleep_q);355 356 return 0;357}358 359int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)360{361 struct cmd_header cmd;362 int ret = 0;363 uint32_t criteria = EHS_REMOVE_WAKEUP;364 365 if (host_sleep) {366 if (priv->is_host_sleep_activated != 1) {367 memset(&cmd, 0, sizeof(cmd));368 ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,369 (struct wol_config *)NULL);370 if (ret) {371 netdev_info(priv->dev,372 "Host sleep configuration failed: %d\n",373 ret);374 return ret;375 }376 if (priv->psstate == PS_STATE_FULL_POWER) {377 ret = __lbs_cmd(priv,378 CMD_802_11_HOST_SLEEP_ACTIVATE,379 &cmd,380 sizeof(cmd),381 lbs_ret_host_sleep_activate, 0);382 if (ret)383 netdev_info(priv->dev,384 "HOST_SLEEP_ACTIVATE failed: %d\n",385 ret);386 }387 388 if (!wait_event_interruptible_timeout(389 priv->host_sleep_q,390 priv->is_host_sleep_activated,391 (10 * HZ))) {392 netdev_err(priv->dev,393 "host_sleep_q: timer expired\n");394 ret = -1;395 }396 } else {397 netdev_err(priv->dev, "host sleep: already enabled\n");398 }399 } else {400 if (priv->is_host_sleep_activated)401 ret = lbs_host_sleep_cfg(priv, criteria,402 (struct wol_config *)NULL);403 }404 405 return ret;406}407 408/**409 * lbs_set_snmp_mib - Set an SNMP MIB value410 *411 * @priv: A pointer to &struct lbs_private structure412 * @oid: The OID to set in the firmware413 * @val: Value to set the OID to414 *415 * returns: 0 on success, error on failure416 */417int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)418{419 struct cmd_ds_802_11_snmp_mib cmd;420 int ret;421 422 memset(&cmd, 0, sizeof (cmd));423 cmd.hdr.size = cpu_to_le16(sizeof(cmd));424 cmd.action = cpu_to_le16(CMD_ACT_SET);425 cmd.oid = cpu_to_le16((u16) oid);426 427 switch (oid) {428 case SNMP_MIB_OID_BSS_TYPE:429 cmd.bufsize = cpu_to_le16(sizeof(u8));430 cmd.value[0] = val;431 break;432 case SNMP_MIB_OID_11D_ENABLE:433 case SNMP_MIB_OID_FRAG_THRESHOLD:434 case SNMP_MIB_OID_RTS_THRESHOLD:435 case SNMP_MIB_OID_SHORT_RETRY_LIMIT:436 case SNMP_MIB_OID_LONG_RETRY_LIMIT:437 cmd.bufsize = cpu_to_le16(sizeof(u16));438 *((__le16 *)(&cmd.value)) = cpu_to_le16(val);439 break;440 default:441 lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);442 ret = -EINVAL;443 goto out;444 }445 446 lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n",447 le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val);448 449 ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);450 451out:452 return ret;453}454 455/**456 * lbs_get_snmp_mib - Get an SNMP MIB value457 *458 * @priv: A pointer to &struct lbs_private structure459 * @oid: The OID to retrieve from the firmware460 * @out_val: Location for the returned value461 *462 * returns: 0 on success, error on failure463 */464int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)465{466 struct cmd_ds_802_11_snmp_mib cmd;467 int ret;468 469 memset(&cmd, 0, sizeof (cmd));470 cmd.hdr.size = cpu_to_le16(sizeof(cmd));471 cmd.action = cpu_to_le16(CMD_ACT_GET);472 cmd.oid = cpu_to_le16(oid);473 474 ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);475 if (ret)476 goto out;477 478 switch (le16_to_cpu(cmd.bufsize)) {479 case sizeof(u8):480 *out_val = cmd.value[0];481 break;482 case sizeof(u16):483 *out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));484 break;485 default:486 lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",487 oid, le16_to_cpu(cmd.bufsize));488 break;489 }490 491out:492 return ret;493}494 495/**496 * lbs_get_tx_power - Get the min, max, and current TX power497 *498 * @priv: A pointer to &struct lbs_private structure499 * @curlevel: Current power level in dBm500 * @minlevel: Minimum supported power level in dBm (optional)501 * @maxlevel: Maximum supported power level in dBm (optional)502 *503 * returns: 0 on success, error on failure504 */505int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,506 s16 *maxlevel)507{508 struct cmd_ds_802_11_rf_tx_power cmd;509 int ret;510 511 memset(&cmd, 0, sizeof(cmd));512 cmd.hdr.size = cpu_to_le16(sizeof(cmd));513 cmd.action = cpu_to_le16(CMD_ACT_GET);514 515 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);516 if (ret == 0) {517 *curlevel = le16_to_cpu(cmd.curlevel);518 if (minlevel)519 *minlevel = cmd.minlevel;520 if (maxlevel)521 *maxlevel = cmd.maxlevel;522 }523 524 return ret;525}526 527/**528 * lbs_set_tx_power - Set the TX power529 *530 * @priv: A pointer to &struct lbs_private structure531 * @dbm: The desired power level in dBm532 *533 * returns: 0 on success, error on failure534 */535int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)536{537 struct cmd_ds_802_11_rf_tx_power cmd;538 int ret;539 540 memset(&cmd, 0, sizeof(cmd));541 cmd.hdr.size = cpu_to_le16(sizeof(cmd));542 cmd.action = cpu_to_le16(CMD_ACT_SET);543 cmd.curlevel = cpu_to_le16(dbm);544 545 lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);546 547 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);548 549 return ret;550}551 552/**553 * lbs_set_monitor_mode - Enable or disable monitor mode554 * (only implemented on OLPC usb8388 FW)555 *556 * @priv: A pointer to &struct lbs_private structure557 * @enable: 1 to enable monitor mode, 0 to disable558 *559 * returns: 0 on success, error on failure560 */561int lbs_set_monitor_mode(struct lbs_private *priv, int enable)562{563 struct cmd_ds_802_11_monitor_mode cmd;564 int ret;565 566 memset(&cmd, 0, sizeof(cmd));567 cmd.hdr.size = cpu_to_le16(sizeof(cmd));568 cmd.action = cpu_to_le16(CMD_ACT_SET);569 if (enable)570 cmd.mode = cpu_to_le16(0x1);571 572 lbs_deb_cmd("SET_MONITOR_MODE: %d\n", enable);573 574 ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);575 if (ret == 0) {576 priv->dev->type = enable ? ARPHRD_IEEE80211_RADIOTAP :577 ARPHRD_ETHER;578 }579 580 return ret;581}582 583/**584 * lbs_get_channel - Get the radio channel585 *586 * @priv: A pointer to &struct lbs_private structure587 *588 * returns: The channel on success, error on failure589 */590static int lbs_get_channel(struct lbs_private *priv)591{592 struct cmd_ds_802_11_rf_channel cmd;593 int ret = 0;594 595 memset(&cmd, 0, sizeof(cmd));596 cmd.hdr.size = cpu_to_le16(sizeof(cmd));597 cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);598 599 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);600 if (ret)601 goto out;602 603 ret = le16_to_cpu(cmd.channel);604 lbs_deb_cmd("current radio channel is %d\n", ret);605 606out:607 return ret;608}609 610int lbs_update_channel(struct lbs_private *priv)611{612 int ret;613 614 /* the channel in f/w could be out of sync; get the current channel */615 ret = lbs_get_channel(priv);616 if (ret > 0) {617 priv->channel = ret;618 ret = 0;619 }620 621 return ret;622}623 624/**625 * lbs_set_channel - Set the radio channel626 *627 * @priv: A pointer to &struct lbs_private structure628 * @channel: The desired channel, or 0 to clear a locked channel629 *630 * returns: 0 on success, error on failure631 */632int lbs_set_channel(struct lbs_private *priv, u8 channel)633{634 struct cmd_ds_802_11_rf_channel cmd;635#ifdef DEBUG636 u8 old_channel = priv->channel;637#endif638 int ret = 0;639 640 memset(&cmd, 0, sizeof(cmd));641 cmd.hdr.size = cpu_to_le16(sizeof(cmd));642 cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);643 cmd.channel = cpu_to_le16(channel);644 645 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);646 if (ret)647 goto out;648 649 priv->channel = (uint8_t) le16_to_cpu(cmd.channel);650 lbs_deb_cmd("channel switch from %d to %d\n", old_channel,651 priv->channel);652 653out:654 return ret;655}656 657/**658 * lbs_get_rssi - Get current RSSI and noise floor659 *660 * @priv: A pointer to &struct lbs_private structure661 * @rssi: On successful return, signal level in mBm662 * @nf: On successful return, Noise floor663 *664 * returns: The channel on success, error on failure665 */666int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)667{668 struct cmd_ds_802_11_rssi cmd;669 int ret = 0;670 671 BUG_ON(rssi == NULL);672 BUG_ON(nf == NULL);673 674 memset(&cmd, 0, sizeof(cmd));675 cmd.hdr.size = cpu_to_le16(sizeof(cmd));676 /* Average SNR over last 8 beacons */677 cmd.n_or_snr = cpu_to_le16(8);678 679 ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);680 if (ret == 0) {681 *nf = CAL_NF(le16_to_cpu(cmd.nf));682 *rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf));683 }684 685 return ret;686}687 688/**689 * lbs_set_11d_domain_info - Send regulatory and 802.11d domain information690 * to the firmware691 *692 * @priv: pointer to &struct lbs_private693 *694 * returns: 0 on success, error code on failure695*/696int lbs_set_11d_domain_info(struct lbs_private *priv)697{698 struct wiphy *wiphy = priv->wdev->wiphy;699 struct ieee80211_supported_band **bands = wiphy->bands;700 struct cmd_ds_802_11d_domain_info cmd;701 struct mrvl_ie_domain_param_set *domain = &cmd.domain;702 struct ieee80211_country_ie_triplet *t;703 enum nl80211_band band;704 struct ieee80211_channel *ch;705 u8 num_triplet = 0;706 u8 num_parsed_chan = 0;707 u8 first_channel = 0, next_chan = 0, max_pwr = 0;708 u8 i, flag = 0;709 size_t triplet_size;710 int ret = 0;711 712 if (!priv->country_code[0])713 goto out;714 715 memset(&cmd, 0, sizeof(cmd));716 cmd.action = cpu_to_le16(CMD_ACT_SET);717 718 lbs_deb_11d("Setting country code '%c%c'\n",719 priv->country_code[0], priv->country_code[1]);720 721 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);722 723 /* Set country code */724 domain->country_code[0] = priv->country_code[0];725 domain->country_code[1] = priv->country_code[1];726 domain->country_code[2] = ' ';727 728 /* Now set up the channel triplets; firmware is somewhat picky here729 * and doesn't validate channel numbers and spans; hence it would730 * interpret a triplet of (36, 4, 20) as channels 36, 37, 38, 39. Since731 * the last 3 aren't valid channels, the driver is responsible for732 * splitting that up into 4 triplet pairs of (36, 1, 20) + (40, 1, 20)733 * etc.734 */735 for (band = 0;736 (band < NUM_NL80211_BANDS) && (num_triplet < MAX_11D_TRIPLETS);737 band++) {738 739 if (!bands[band])740 continue;741 742 for (i = 0;743 (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);744 i++) {745 ch = &bands[band]->channels[i];746 if (ch->flags & IEEE80211_CHAN_DISABLED)747 continue;748 749 if (!flag) {750 flag = 1;751 next_chan = first_channel = (u32) ch->hw_value;752 max_pwr = ch->max_power;753 num_parsed_chan = 1;754 continue;755 }756 757 if ((ch->hw_value == next_chan + 1) &&758 (ch->max_power == max_pwr)) {759 /* Consolidate adjacent channels */760 next_chan++;761 num_parsed_chan++;762 } else {763 /* Add this triplet */764 lbs_deb_11d("11D triplet (%d, %d, %d)\n",765 first_channel, num_parsed_chan,766 max_pwr);767 t = &domain->triplet[num_triplet];768 t->chans.first_channel = first_channel;769 t->chans.num_channels = num_parsed_chan;770 t->chans.max_power = max_pwr;771 num_triplet++;772 flag = 0;773 }774 }775 776 if (flag) {777 /* Add last triplet */778 lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,779 num_parsed_chan, max_pwr);780 t = &domain->triplet[num_triplet];781 t->chans.first_channel = first_channel;782 t->chans.num_channels = num_parsed_chan;783 t->chans.max_power = max_pwr;784 num_triplet++;785 }786 }787 788 lbs_deb_11d("# triplets %d\n", num_triplet);789 790 /* Set command header sizes */791 triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);792 domain->header.len = cpu_to_le16(sizeof(domain->country_code) +793 triplet_size);794 795 lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",796 (u8 *) &cmd.domain.country_code,797 le16_to_cpu(domain->header.len));798 799 cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +800 sizeof(cmd.action) +801 sizeof(cmd.domain.header) +802 sizeof(cmd.domain.country_code) +803 triplet_size);804 805 ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);806 807out:808 return ret;809}810 811/**812 * lbs_get_reg - Read a MAC, Baseband, or RF register813 *814 * @priv: pointer to &struct lbs_private815 * @reg: register command, one of CMD_MAC_REG_ACCESS,816 * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS817 * @offset: byte offset of the register to get818 * @value: on success, the value of the register at 'offset'819 *820 * returns: 0 on success, error code on failure821*/822int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)823{824 struct cmd_ds_reg_access cmd;825 int ret = 0;826 827 BUG_ON(value == NULL);828 829 memset(&cmd, 0, sizeof(cmd));830 cmd.hdr.size = cpu_to_le16(sizeof(cmd));831 cmd.action = cpu_to_le16(CMD_ACT_GET);832 cmd.offset = cpu_to_le16(offset);833 834 if (reg != CMD_MAC_REG_ACCESS &&835 reg != CMD_BBP_REG_ACCESS &&836 reg != CMD_RF_REG_ACCESS) {837 ret = -EINVAL;838 goto out;839 }840 841 ret = lbs_cmd_with_response(priv, reg, &cmd);842 if (!ret) {843 if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)844 *value = cmd.value.bbp_rf;845 else if (reg == CMD_MAC_REG_ACCESS)846 *value = le32_to_cpu(cmd.value.mac);847 }848 849out:850 return ret;851}852 853/**854 * lbs_set_reg - Write a MAC, Baseband, or RF register855 *856 * @priv: pointer to &struct lbs_private857 * @reg: register command, one of CMD_MAC_REG_ACCESS,858 * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS859 * @offset: byte offset of the register to set860 * @value: the value to write to the register at 'offset'861 *862 * returns: 0 on success, error code on failure863*/864int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)865{866 struct cmd_ds_reg_access cmd;867 int ret = 0;868 869 memset(&cmd, 0, sizeof(cmd));870 cmd.hdr.size = cpu_to_le16(sizeof(cmd));871 cmd.action = cpu_to_le16(CMD_ACT_SET);872 cmd.offset = cpu_to_le16(offset);873 874 if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)875 cmd.value.bbp_rf = (u8) (value & 0xFF);876 else if (reg == CMD_MAC_REG_ACCESS)877 cmd.value.mac = cpu_to_le32(value);878 else {879 ret = -EINVAL;880 goto out;881 }882 883 ret = lbs_cmd_with_response(priv, reg, &cmd);884 885out:886 return ret;887}888 889static void lbs_queue_cmd(struct lbs_private *priv,890 struct cmd_ctrl_node *cmdnode)891{892 unsigned long flags;893 int addtail = 1;894 895 if (!cmdnode) {896 lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");897 return;898 }899 if (!cmdnode->cmdbuf->size) {900 lbs_deb_host("DNLD_CMD: cmd size is zero\n");901 return;902 }903 cmdnode->result = 0;904 905 /* Exit_PS command needs to be queued in the header always. */906 if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {907 struct cmd_ds_802_11_ps_mode *psm = (void *)cmdnode->cmdbuf;908 909 if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {910 if (priv->psstate != PS_STATE_FULL_POWER)911 addtail = 0;912 }913 }914 915 if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_WAKEUP_CONFIRM)916 addtail = 0;917 918 spin_lock_irqsave(&priv->driver_lock, flags);919 920 if (addtail)921 list_add_tail(&cmdnode->list, &priv->cmdpendingq);922 else923 list_add(&cmdnode->list, &priv->cmdpendingq);924 925 spin_unlock_irqrestore(&priv->driver_lock, flags);926 927 lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",928 le16_to_cpu(cmdnode->cmdbuf->command));929}930 931static void lbs_submit_command(struct lbs_private *priv,932 struct cmd_ctrl_node *cmdnode)933{934 unsigned long flags;935 struct cmd_header *cmd;936 uint16_t cmdsize;937 uint16_t command;938 int timeo = 3 * HZ;939 int ret;940 941 cmd = cmdnode->cmdbuf;942 943 spin_lock_irqsave(&priv->driver_lock, flags);944 priv->seqnum++;945 cmd->seqnum = cpu_to_le16(priv->seqnum);946 priv->cur_cmd = cmdnode;947 spin_unlock_irqrestore(&priv->driver_lock, flags);948 949 cmdsize = le16_to_cpu(cmd->size);950 command = le16_to_cpu(cmd->command);951 952 /* These commands take longer */953 if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)954 timeo = 5 * HZ;955 956 lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",957 command, le16_to_cpu(cmd->seqnum), cmdsize);958 lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);959 960 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);961 962 if (ret) {963 netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n",964 ret);965 /* Reset dnld state machine, report failure */966 priv->dnld_sent = DNLD_RES_RECEIVED;967 lbs_complete_command(priv, cmdnode, ret);968 }969 970 if (command == CMD_802_11_DEEP_SLEEP) {971 if (priv->is_auto_deep_sleep_enabled) {972 priv->wakeup_dev_required = 1;973 priv->dnld_sent = 0;974 }975 priv->is_deep_sleep = 1;976 lbs_complete_command(priv, cmdnode, 0);977 } else {978 /* Setup the timer after transmit command */979 mod_timer(&priv->command_timer, jiffies + timeo);980 }981}982 983/*984 * This function inserts command node to cmdfreeq985 * after cleans it. Requires priv->driver_lock held.986 */987static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,988 struct cmd_ctrl_node *cmdnode)989{990 if (!cmdnode)991 return;992 993 cmdnode->callback = NULL;994 cmdnode->callback_arg = 0;995 996 memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);997 998 list_add_tail(&cmdnode->list, &priv->cmdfreeq);999}1000 1001static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,1002 struct cmd_ctrl_node *ptempcmd)1003{1004 unsigned long flags;1005 1006 spin_lock_irqsave(&priv->driver_lock, flags);1007 __lbs_cleanup_and_insert_cmd(priv, ptempcmd);1008 spin_unlock_irqrestore(&priv->driver_lock, flags);1009}1010 1011void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,1012 int result)1013{1014 /*1015 * Normally, commands are removed from cmdpendingq before being1016 * submitted. However, we can arrive here on alternative codepaths1017 * where the command is still pending. Make sure the command really1018 * isn't part of a list at this point.1019 */1020 list_del_init(&cmd->list);1021 1022 cmd->result = result;1023 cmd->cmdwaitqwoken = 1;1024 wake_up(&cmd->cmdwait_q);1025 1026 if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)1027 __lbs_cleanup_and_insert_cmd(priv, cmd);1028 priv->cur_cmd = NULL;1029 wake_up(&priv->waitq);1030}1031 1032void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,1033 int result)1034{1035 unsigned long flags;1036 spin_lock_irqsave(&priv->driver_lock, flags);1037 __lbs_complete_command(priv, cmd, result);1038 spin_unlock_irqrestore(&priv->driver_lock, flags);1039}1040 1041int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)1042{1043 struct cmd_ds_802_11_radio_control cmd;1044 int ret = -EINVAL;1045 1046 cmd.hdr.size = cpu_to_le16(sizeof(cmd));1047 cmd.action = cpu_to_le16(CMD_ACT_SET);1048 cmd.control = 0;1049 1050 /* Only v8 and below support setting the preamble */1051 if (priv->fwrelease < 0x09000000) {1052 switch (preamble) {1053 case RADIO_PREAMBLE_SHORT:1054 case RADIO_PREAMBLE_AUTO:1055 case RADIO_PREAMBLE_LONG:1056 cmd.control = cpu_to_le16(preamble);1057 break;1058 default:1059 goto out;1060 }1061 }1062 1063 if (radio_on)1064 cmd.control |= cpu_to_le16(0x1);1065 else {1066 cmd.control &= cpu_to_le16(~0x1);1067 priv->txpower_cur = 0;1068 }1069 1070 lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",1071 radio_on ? "ON" : "OFF", preamble);1072 1073 priv->radio_on = radio_on;1074 1075 ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);1076 1077out:1078 return ret;1079}1080 1081void lbs_set_mac_control(struct lbs_private *priv)1082{1083 struct cmd_ds_mac_control cmd;1084 1085 cmd.hdr.size = cpu_to_le16(sizeof(cmd));1086 cmd.action = cpu_to_le16(priv->mac_control);1087 cmd.reserved = 0;1088 1089 lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));1090}1091 1092int lbs_set_mac_control_sync(struct lbs_private *priv)1093{1094 struct cmd_ds_mac_control cmd;1095 int ret = 0;1096 1097 cmd.hdr.size = cpu_to_le16(sizeof(cmd));1098 cmd.action = cpu_to_le16(priv->mac_control);1099 cmd.reserved = 0;1100 ret = lbs_cmd_with_response(priv, CMD_MAC_CONTROL, &cmd);1101 1102 return ret;1103}1104 1105/**1106 * lbs_allocate_cmd_buffer - allocates the command buffer and links1107 * it to command free queue1108 *1109 * @priv: A pointer to &struct lbs_private structure1110 *1111 * returns: 0 for success or -1 on error1112 */1113int lbs_allocate_cmd_buffer(struct lbs_private *priv)1114{1115 int ret = 0;1116 u32 bufsize;1117 u32 i;1118 struct cmd_ctrl_node *cmdarray;1119 1120 /* Allocate and initialize the command array */1121 bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;1122 if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {1123 lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");1124 ret = -1;1125 goto done;1126 }1127 priv->cmd_array = cmdarray;1128 1129 /* Allocate and initialize each command buffer in the command array */1130 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {1131 cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);1132 if (!cmdarray[i].cmdbuf) {1133 lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");1134 ret = -1;1135 goto free_cmd_array;1136 }1137 }1138 1139 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {1140 init_waitqueue_head(&cmdarray[i].cmdwait_q);1141 lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);1142 }1143 return 0;1144 1145free_cmd_array:1146 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {1147 if (cmdarray[i].cmdbuf) {1148 kfree(cmdarray[i].cmdbuf);1149 cmdarray[i].cmdbuf = NULL;1150 }1151 }1152 kfree(priv->cmd_array);1153 priv->cmd_array = NULL;1154done:1155 return ret;1156}1157 1158/**1159 * lbs_free_cmd_buffer - free the command buffer1160 *1161 * @priv: A pointer to &struct lbs_private structure1162 *1163 * returns: 0 for success1164 */1165int lbs_free_cmd_buffer(struct lbs_private *priv)1166{1167 struct cmd_ctrl_node *cmdarray;1168 unsigned int i;1169 1170 /* need to check if cmd array is allocated or not */1171 if (priv->cmd_array == NULL) {1172 lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");1173 goto done;1174 }1175 1176 cmdarray = priv->cmd_array;1177 1178 /* Release shared memory buffers */1179 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {1180 if (cmdarray[i].cmdbuf) {1181 kfree(cmdarray[i].cmdbuf);1182 cmdarray[i].cmdbuf = NULL;1183 }1184 }1185 1186 /* Release cmd_ctrl_node */1187 if (priv->cmd_array) {1188 kfree(priv->cmd_array);1189 priv->cmd_array = NULL;1190 }1191 1192done:1193 return 0;1194}1195 1196/**1197 * lbs_get_free_cmd_node - gets a free command node if available in1198 * command free queue1199 *1200 * @priv: A pointer to &struct lbs_private structure1201 *1202 * returns: A pointer to &cmd_ctrl_node structure on success1203 * or %NULL on error1204 */1205static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)1206{1207 struct cmd_ctrl_node *tempnode;1208 unsigned long flags;1209 1210 if (!priv)1211 return NULL;1212 1213 spin_lock_irqsave(&priv->driver_lock, flags);1214 1215 if (!list_empty(&priv->cmdfreeq)) {1216 tempnode = list_first_entry(&priv->cmdfreeq,1217 struct cmd_ctrl_node, list);1218 list_del_init(&tempnode->list);1219 } else {1220 lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");1221 tempnode = NULL;1222 }1223 1224 spin_unlock_irqrestore(&priv->driver_lock, flags);1225 1226 return tempnode;1227}1228 1229/**1230 * lbs_execute_next_command - execute next command in command1231 * pending queue. Will put firmware back to PS mode if applicable.1232 *1233 * @priv: A pointer to &struct lbs_private structure1234 *1235 * returns: 0 on success or -1 on error1236 */1237int lbs_execute_next_command(struct lbs_private *priv)1238{1239 struct cmd_ctrl_node *cmdnode = NULL;1240 struct cmd_header *cmd;1241 unsigned long flags;1242 int ret = 0;1243 1244 /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the1245 * only caller to us is lbs_thread() and we get even when a1246 * data packet is received */1247 spin_lock_irqsave(&priv->driver_lock, flags);1248 1249 if (priv->cur_cmd) {1250 netdev_alert(priv->dev,1251 "EXEC_NEXT_CMD: already processing command!\n");1252 spin_unlock_irqrestore(&priv->driver_lock, flags);1253 ret = -1;1254 goto done;1255 }1256 1257 if (!list_empty(&priv->cmdpendingq)) {1258 cmdnode = list_first_entry(&priv->cmdpendingq,1259 struct cmd_ctrl_node, list);1260 }1261 1262 spin_unlock_irqrestore(&priv->driver_lock, flags);1263 1264 if (cmdnode) {1265 cmd = cmdnode->cmdbuf;1266 1267 if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {1268 if ((priv->psstate == PS_STATE_SLEEP) ||1269 (priv->psstate == PS_STATE_PRE_SLEEP)) {1270 lbs_deb_host(1271 "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",1272 le16_to_cpu(cmd->command),1273 priv->psstate);1274 ret = -1;1275 goto done;1276 }1277 lbs_deb_host("EXEC_NEXT_CMD: OK to send command "1278 "0x%04x in psstate %d\n",1279 le16_to_cpu(cmd->command), priv->psstate);1280 } else if (priv->psstate != PS_STATE_FULL_POWER) {1281 /*1282 * 1. Non-PS command:1283 * Queue it. set needtowakeup to TRUE if current state1284 * is SLEEP, otherwise call send EXIT_PS.1285 * 2. PS command but not EXIT_PS:1286 * Ignore it.1287 * 3. PS command EXIT_PS:1288 * Set needtowakeup to TRUE if current state is SLEEP,1289 * otherwise send this command down to firmware1290 * immediately.1291 */1292 if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {1293 /* Prepare to send Exit PS,1294 * this non PS command will be sent later */1295 if ((priv->psstate == PS_STATE_SLEEP)1296 || (priv->psstate == PS_STATE_PRE_SLEEP)1297 ) {1298 /* w/ new scheme, it will not reach here.1299 since it is blocked in main_thread. */1300 priv->needtowakeup = 1;1301 } else {1302 lbs_set_ps_mode(priv,1303 PS_MODE_ACTION_EXIT_PS,1304 false);1305 }1306 1307 ret = 0;1308 goto done;1309 } else {1310 /*1311 * PS command. Ignore it if it is not Exit_PS.1312 * otherwise send it down immediately.1313 */1314 struct cmd_ds_802_11_ps_mode *psm = (void *)cmd;1315 1316 lbs_deb_host(1317 "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",1318 psm->action);1319 if (psm->action !=1320 cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {1321 lbs_deb_host(1322 "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");1323 lbs_complete_command(priv, cmdnode, 0);1324 1325 ret = 0;1326 goto done;1327 }1328 1329 if ((priv->psstate == PS_STATE_SLEEP) ||1330 (priv->psstate == PS_STATE_PRE_SLEEP)) {1331 lbs_deb_host(1332 "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");1333 lbs_complete_command(priv, cmdnode, 0);1334 priv->needtowakeup = 1;1335 1336 ret = 0;1337 goto done;1338 }1339 1340 lbs_deb_host(1341 "EXEC_NEXT_CMD: sending EXIT_PS\n");1342 }1343 }1344 spin_lock_irqsave(&priv->driver_lock, flags);1345 list_del_init(&cmdnode->list);1346 spin_unlock_irqrestore(&priv->driver_lock, flags);1347 lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",1348 le16_to_cpu(cmd->command));1349 lbs_submit_command(priv, cmdnode);1350 } else {1351 /*1352 * check if in power save mode, if yes, put the device back1353 * to PS mode1354 */1355 if ((priv->psmode != LBS802_11POWERMODECAM) &&1356 (priv->psstate == PS_STATE_FULL_POWER) &&1357 (priv->connect_status == LBS_CONNECTED)) {1358 lbs_deb_host(1359 "EXEC_NEXT_CMD: cmdpendingq empty, go back to PS_SLEEP");1360 lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,1361 false);1362 }1363 }1364 1365 ret = 0;1366done:1367 return ret;1368}1369 1370static void lbs_send_confirmsleep(struct lbs_private *priv)1371{1372 unsigned long flags;1373 int ret;1374 1375 lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,1376 sizeof(confirm_sleep));1377 1378 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,1379 sizeof(confirm_sleep));1380 if (ret) {1381 netdev_alert(priv->dev, "confirm_sleep failed\n");1382 return;1383 }1384 1385 spin_lock_irqsave(&priv->driver_lock, flags);1386 1387 /* We don't get a response on the sleep-confirmation */1388 priv->dnld_sent = DNLD_RES_RECEIVED;1389 1390 if (priv->is_host_sleep_configured) {1391 priv->is_host_sleep_activated = 1;1392 wake_up_interruptible(&priv->host_sleep_q);1393 }1394 1395 /* If nothing to do, go back to sleep (?) */1396 if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])1397 priv->psstate = PS_STATE_SLEEP;1398 1399 spin_unlock_irqrestore(&priv->driver_lock, flags);1400}1401 1402/**1403 * lbs_ps_confirm_sleep - checks condition and prepares to1404 * send sleep confirm command to firmware if ok1405 *1406 * @priv: A pointer to &struct lbs_private structure1407 *1408 * returns: n/a1409 */1410void lbs_ps_confirm_sleep(struct lbs_private *priv)1411{1412 unsigned long flags =0;1413 int allowed = 1;1414 1415 spin_lock_irqsave(&priv->driver_lock, flags);1416 if (priv->dnld_sent) {1417 allowed = 0;1418 lbs_deb_host("dnld_sent was set\n");1419 }1420 1421 /* In-progress command? */1422 if (priv->cur_cmd) {1423 allowed = 0;1424 lbs_deb_host("cur_cmd was set\n");1425 }1426 1427 /* Pending events or command responses? */1428 if (kfifo_len(&priv->event_fifo) || priv->resp_len[priv->resp_idx]) {1429 allowed = 0;1430 lbs_deb_host("pending events or command responses\n");1431 }1432 spin_unlock_irqrestore(&priv->driver_lock, flags);1433 1434 if (allowed) {1435 lbs_deb_host("sending lbs_ps_confirm_sleep\n");1436 lbs_send_confirmsleep(priv);1437 } else {1438 lbs_deb_host("sleep confirm has been delayed\n");1439 }1440}1441 1442 1443/**1444 * lbs_set_tpc_cfg - Configures the transmission power control functionality1445 *1446 * @priv: A pointer to &struct lbs_private structure1447 * @enable: Transmission power control enable1448 * @p0: Power level when link quality is good (dBm).1449 * @p1: Power level when link quality is fair (dBm).1450 * @p2: Power level when link quality is poor (dBm).1451 * @usesnr: Use Signal to Noise Ratio in TPC1452 *1453 * returns: 0 on success1454 */1455int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,1456 int8_t p2, int usesnr)1457{1458 struct cmd_ds_802_11_tpc_cfg cmd;1459 int ret;1460 1461 memset(&cmd, 0, sizeof(cmd));1462 cmd.hdr.size = cpu_to_le16(sizeof(cmd));1463 cmd.action = cpu_to_le16(CMD_ACT_SET);1464 cmd.enable = !!enable;1465 cmd.usesnr = !!usesnr;1466 cmd.P0 = p0;1467 cmd.P1 = p1;1468 cmd.P2 = p2;1469 1470 ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd);1471 1472 return ret;1473}1474 1475/**1476 * lbs_set_power_adapt_cfg - Configures the power adaptation settings1477 *1478 * @priv: A pointer to &struct lbs_private structure1479 * @enable: Power adaptation enable1480 * @p0: Power level for 1, 2, 5.5 and 11 Mbps (dBm).1481 * @p1: Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).1482 * @p2: Power level for 48 and 54 Mbps (dBm).1483 *1484 * returns: 0 on Success1485 */1486 1487int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,1488 int8_t p1, int8_t p2)1489{1490 struct cmd_ds_802_11_pa_cfg cmd;1491 int ret;1492 1493 memset(&cmd, 0, sizeof(cmd));1494 cmd.hdr.size = cpu_to_le16(sizeof(cmd));1495 cmd.action = cpu_to_le16(CMD_ACT_SET);1496 cmd.enable = !!enable;1497 cmd.P0 = p0;1498 cmd.P1 = p1;1499 cmd.P2 = p2;1500 1501 ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd);1502 1503 return ret;1504}1505 1506 1507struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,1508 uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,1509 int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),1510 unsigned long callback_arg)1511{1512 struct cmd_ctrl_node *cmdnode;1513 1514 if (priv->surpriseremoved) {1515 lbs_deb_host("PREP_CMD: card removed\n");1516 cmdnode = ERR_PTR(-ENOENT);1517 goto done;1518 }1519 1520 /* No commands are allowed in Deep Sleep until we toggle the GPIO1521 * to wake up the card and it has signaled that it's ready.1522 */1523 if (!priv->is_auto_deep_sleep_enabled) {1524 if (priv->is_deep_sleep) {1525 lbs_deb_cmd("command not allowed in deep sleep\n");1526 cmdnode = ERR_PTR(-EBUSY);1527 goto done;1528 }1529 }1530 1531 cmdnode = lbs_get_free_cmd_node(priv);1532 if (cmdnode == NULL) {1533 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");1534 1535 /* Wake up main thread to execute next command */1536 wake_up(&priv->waitq);1537 cmdnode = ERR_PTR(-ENOBUFS);1538 goto done;1539 }1540 1541 cmdnode->callback = callback;1542 cmdnode->callback_arg = callback_arg;1543 1544 /* Copy the incoming command to the buffer */1545 memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);1546 1547 /* Set command, clean result, move to buffer */1548 cmdnode->cmdbuf->command = cpu_to_le16(command);1549 cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size);1550 cmdnode->cmdbuf->result = 0;1551 1552 lbs_deb_host("PREP_CMD: command 0x%04x\n", command);1553 1554 cmdnode->cmdwaitqwoken = 0;1555 lbs_queue_cmd(priv, cmdnode);1556 wake_up(&priv->waitq);1557 1558 done:1559 return cmdnode;1560}1561 1562void lbs_cmd_async(struct lbs_private *priv, uint16_t command,1563 struct cmd_header *in_cmd, int in_cmd_size)1564{1565 __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,1566 lbs_cmd_async_callback, 0);1567}1568 1569int __lbs_cmd(struct lbs_private *priv, uint16_t command,1570 struct cmd_header *in_cmd, int in_cmd_size,1571 int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),1572 unsigned long callback_arg)1573{1574 struct cmd_ctrl_node *cmdnode;1575 unsigned long flags;1576 int ret = 0;1577 1578 cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,1579 callback, callback_arg);1580 if (IS_ERR(cmdnode)) {1581 ret = PTR_ERR(cmdnode);1582 goto done;1583 }1584 1585 might_sleep();1586 1587 /*1588 * Be careful with signals here. A signal may be received as the system1589 * goes into suspend or resume. We do not want this to interrupt the1590 * command, so we perform an uninterruptible sleep.1591 */1592 wait_event(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);1593 1594 spin_lock_irqsave(&priv->driver_lock, flags);1595 ret = cmdnode->result;1596 if (ret)1597 netdev_info(priv->dev, "PREP_CMD: command 0x%04x failed: %d\n",1598 command, ret);1599 1600 __lbs_cleanup_and_insert_cmd(priv, cmdnode);1601 spin_unlock_irqrestore(&priv->driver_lock, flags);1602 1603done:1604 return ret;1605}1606EXPORT_SYMBOL_GPL(__lbs_cmd);1607