.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2008, cozybit Inc. |
---|
3 | 4 | * Copyright (C) 2003-2006, Marvell International Ltd. |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify |
---|
6 | | - * it under the terms of the GNU General Public License as published by |
---|
7 | | - * the Free Software Foundation; either version 2 of the License, or (at |
---|
8 | | - * your option) any later version. |
---|
9 | 5 | */ |
---|
10 | 6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
11 | 7 | |
---|
.. | .. |
---|
19 | 15 | /* thinfirm version: 5.132.X.pX */ |
---|
20 | 16 | #define LBTF_FW_VER_MIN 0x05840300 |
---|
21 | 17 | #define LBTF_FW_VER_MAX 0x0584ffff |
---|
22 | | -#define QOS_CONTROL_LEN 2 |
---|
23 | 18 | |
---|
24 | 19 | /* Module parameters */ |
---|
25 | 20 | unsigned int lbtf_debug; |
---|
.. | .. |
---|
118 | 113 | priv->cmd_timed_out = 0; |
---|
119 | 114 | spin_unlock_irq(&priv->driver_lock); |
---|
120 | 115 | |
---|
121 | | - if (!priv->fw_ready) { |
---|
122 | | - lbtf_deb_leave_args(LBTF_DEB_CMD, "fw not ready"); |
---|
123 | | - return; |
---|
124 | | - } |
---|
125 | | - |
---|
126 | 116 | /* Execute the next command */ |
---|
127 | 117 | if (!priv->cur_cmd) |
---|
128 | 118 | lbtf_execute_next_command(priv); |
---|
.. | .. |
---|
130 | 120 | lbtf_deb_leave(LBTF_DEB_CMD); |
---|
131 | 121 | } |
---|
132 | 122 | |
---|
133 | | -/** |
---|
134 | | - * lbtf_setup_firmware: initialize firmware. |
---|
135 | | - * |
---|
136 | | - * @priv A pointer to struct lbtf_private structure |
---|
137 | | - * |
---|
138 | | - * Returns: 0 on success. |
---|
139 | | - */ |
---|
140 | | -static int lbtf_setup_firmware(struct lbtf_private *priv) |
---|
141 | | -{ |
---|
142 | | - int ret = -1; |
---|
143 | | - |
---|
144 | | - lbtf_deb_enter(LBTF_DEB_FW); |
---|
145 | | - /* |
---|
146 | | - * Read priv address from HW |
---|
147 | | - */ |
---|
148 | | - eth_broadcast_addr(priv->current_addr); |
---|
149 | | - ret = lbtf_update_hw_spec(priv); |
---|
150 | | - if (ret) { |
---|
151 | | - ret = -1; |
---|
152 | | - goto done; |
---|
153 | | - } |
---|
154 | | - |
---|
155 | | - lbtf_set_mac_control(priv); |
---|
156 | | - lbtf_set_radio_control(priv); |
---|
157 | | - |
---|
158 | | - ret = 0; |
---|
159 | | -done: |
---|
160 | | - lbtf_deb_leave_args(LBTF_DEB_FW, "ret: %d", ret); |
---|
161 | | - return ret; |
---|
162 | | -} |
---|
163 | | - |
---|
164 | | -/** |
---|
| 123 | +/* |
---|
165 | 124 | * This function handles the timeout of command sending. |
---|
166 | 125 | * It will re-send the same command again. |
---|
167 | 126 | */ |
---|
.. | .. |
---|
281 | 240 | BUG_ON(priv->tx_skb); |
---|
282 | 241 | spin_lock_irq(&priv->driver_lock); |
---|
283 | 242 | priv->tx_skb = skb; |
---|
284 | | - err = priv->hw_host_to_card(priv, MVMS_DAT, skb->data, skb->len); |
---|
| 243 | + err = priv->ops->hw_host_to_card(priv, MVMS_DAT, skb->data, skb->len); |
---|
285 | 244 | spin_unlock_irq(&priv->driver_lock); |
---|
286 | 245 | if (err) { |
---|
287 | 246 | dev_kfree_skb_any(skb); |
---|
.. | .. |
---|
294 | 253 | static int lbtf_op_start(struct ieee80211_hw *hw) |
---|
295 | 254 | { |
---|
296 | 255 | struct lbtf_private *priv = hw->priv; |
---|
297 | | - void *card = priv->card; |
---|
298 | | - int ret = -1; |
---|
299 | 256 | |
---|
300 | 257 | lbtf_deb_enter(LBTF_DEB_MACOPS); |
---|
301 | 258 | |
---|
302 | | - if (!priv->fw_ready) |
---|
303 | | - /* Upload firmware */ |
---|
304 | | - if (priv->hw_prog_firmware(card)) |
---|
305 | | - goto err_prog_firmware; |
---|
306 | | - |
---|
307 | | - /* poke the firmware */ |
---|
308 | 259 | priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; |
---|
309 | 260 | priv->radioon = RADIO_ON; |
---|
310 | 261 | priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; |
---|
311 | | - ret = lbtf_setup_firmware(priv); |
---|
312 | | - if (ret) |
---|
313 | | - goto err_prog_firmware; |
---|
| 262 | + lbtf_set_mac_control(priv); |
---|
| 263 | + lbtf_set_radio_control(priv); |
---|
314 | 264 | |
---|
315 | | - if ((priv->fwrelease < LBTF_FW_VER_MIN) || |
---|
316 | | - (priv->fwrelease > LBTF_FW_VER_MAX)) { |
---|
317 | | - ret = -1; |
---|
318 | | - goto err_prog_firmware; |
---|
319 | | - } |
---|
320 | | - |
---|
321 | | - printk(KERN_INFO "libertastf: Marvell WLAN 802.11 thinfirm adapter\n"); |
---|
322 | 265 | lbtf_deb_leave(LBTF_DEB_MACOPS); |
---|
323 | 266 | return 0; |
---|
324 | | - |
---|
325 | | -err_prog_firmware: |
---|
326 | | - priv->hw_reset_device(card); |
---|
327 | | - lbtf_deb_leave_args(LBTF_DEB_MACOPS, "error programming fw; ret=%d", ret); |
---|
328 | | - return ret; |
---|
329 | 267 | } |
---|
330 | 268 | |
---|
331 | 269 | static void lbtf_op_stop(struct ieee80211_hw *hw) |
---|
.. | .. |
---|
551 | 489 | struct ieee80211_rx_status stats; |
---|
552 | 490 | struct rxpd *prxpd; |
---|
553 | 491 | int need_padding; |
---|
554 | | - unsigned int flags; |
---|
555 | 492 | struct ieee80211_hdr *hdr; |
---|
556 | 493 | |
---|
557 | 494 | lbtf_deb_enter(LBTF_DEB_RX); |
---|
| 495 | + |
---|
| 496 | + if (priv->radioon != RADIO_ON) { |
---|
| 497 | + lbtf_deb_rx("rx before we turned on the radio"); |
---|
| 498 | + goto done; |
---|
| 499 | + } |
---|
558 | 500 | |
---|
559 | 501 | prxpd = (struct rxpd *) skb->data; |
---|
560 | 502 | |
---|
.. | .. |
---|
563 | 505 | stats.flag |= RX_FLAG_FAILED_FCS_CRC; |
---|
564 | 506 | stats.freq = priv->cur_freq; |
---|
565 | 507 | stats.band = NL80211_BAND_2GHZ; |
---|
566 | | - stats.signal = prxpd->snr; |
---|
| 508 | + stats.signal = prxpd->snr - prxpd->nf; |
---|
567 | 509 | priv->noise = prxpd->nf; |
---|
568 | 510 | /* Marvell rate index has a hole at value 4 */ |
---|
569 | 511 | if (prxpd->rx_rate > 4) |
---|
.. | .. |
---|
572 | 514 | skb_pull(skb, sizeof(struct rxpd)); |
---|
573 | 515 | |
---|
574 | 516 | hdr = (struct ieee80211_hdr *)skb->data; |
---|
575 | | - flags = le32_to_cpu(*(__le32 *)(skb->data + 4)); |
---|
576 | 517 | |
---|
577 | 518 | need_padding = ieee80211_is_data_qos(hdr->frame_control); |
---|
578 | 519 | need_padding ^= ieee80211_has_a4(hdr->frame_control); |
---|
.. | .. |
---|
594 | 535 | |
---|
595 | 536 | ieee80211_rx_irqsafe(priv->hw, skb); |
---|
596 | 537 | |
---|
| 538 | +done: |
---|
597 | 539 | lbtf_deb_leave(LBTF_DEB_RX); |
---|
598 | 540 | return 0; |
---|
599 | 541 | } |
---|
600 | 542 | EXPORT_SYMBOL_GPL(lbtf_rx); |
---|
601 | 543 | |
---|
602 | | -/** |
---|
603 | | - * lbtf_add_card: Add and initialize the card, no fw upload yet. |
---|
604 | | - * |
---|
605 | | - * @card A pointer to card |
---|
| 544 | +/* |
---|
| 545 | + * lbtf_add_card: Add and initialize the card. |
---|
606 | 546 | * |
---|
607 | 547 | * Returns: pointer to struct lbtf_priv. |
---|
608 | 548 | */ |
---|
609 | | -struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev) |
---|
| 549 | +struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev, |
---|
| 550 | + const struct lbtf_ops *ops) |
---|
610 | 551 | { |
---|
611 | 552 | struct ieee80211_hw *hw; |
---|
612 | 553 | struct lbtf_private *priv = NULL; |
---|
.. | .. |
---|
623 | 564 | |
---|
624 | 565 | priv->hw = hw; |
---|
625 | 566 | priv->card = card; |
---|
| 567 | + priv->ops = ops; |
---|
626 | 568 | priv->tx_skb = NULL; |
---|
| 569 | + priv->radioon = RADIO_OFF; |
---|
627 | 570 | |
---|
628 | 571 | hw->queues = 1; |
---|
629 | 572 | ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); |
---|
| 573 | + ieee80211_hw_set(hw, SIGNAL_DBM); |
---|
630 | 574 | hw->extra_tx_headroom = sizeof(struct txpd); |
---|
631 | 575 | memcpy(priv->channels, lbtf_channels, sizeof(lbtf_channels)); |
---|
632 | 576 | memcpy(priv->rates, lbtf_rates, sizeof(lbtf_rates)); |
---|
.. | .. |
---|
646 | 590 | |
---|
647 | 591 | INIT_WORK(&priv->cmd_work, lbtf_cmd_work); |
---|
648 | 592 | INIT_WORK(&priv->tx_work, lbtf_tx_work); |
---|
| 593 | + |
---|
| 594 | + if (priv->ops->hw_prog_firmware(priv)) { |
---|
| 595 | + lbtf_deb_usbd(dmdev, "Error programming the firmware\n"); |
---|
| 596 | + priv->ops->hw_reset_device(priv); |
---|
| 597 | + goto err_init_adapter; |
---|
| 598 | + } |
---|
| 599 | + |
---|
| 600 | + eth_broadcast_addr(priv->current_addr); |
---|
| 601 | + if (lbtf_update_hw_spec(priv)) |
---|
| 602 | + goto err_init_adapter; |
---|
| 603 | + |
---|
| 604 | + if (priv->fwrelease < LBTF_FW_VER_MIN || |
---|
| 605 | + priv->fwrelease > LBTF_FW_VER_MAX) { |
---|
| 606 | + goto err_init_adapter; |
---|
| 607 | + } |
---|
| 608 | + |
---|
| 609 | + /* The firmware seems to start with the radio enabled. Turn it |
---|
| 610 | + * off before an actual mac80211 start callback is invoked. |
---|
| 611 | + */ |
---|
| 612 | + lbtf_set_radio_control(priv); |
---|
| 613 | + |
---|
649 | 614 | if (ieee80211_register_hw(hw)) |
---|
650 | 615 | goto err_init_adapter; |
---|
651 | 616 | |
---|
| 617 | + dev_info(dmdev, "libertastf: Marvell WLAN 802.11 thinfirm adapter\n"); |
---|
652 | 618 | goto done; |
---|
653 | 619 | |
---|
654 | 620 | err_init_adapter: |
---|
.. | .. |
---|
676 | 642 | ieee80211_unregister_hw(hw); |
---|
677 | 643 | ieee80211_free_hw(hw); |
---|
678 | 644 | |
---|
679 | | - lbtf_deb_leave(LBTF_DEB_MAIN); |
---|
| 645 | + lbtf_deb_leave(LBTF_DEB_MAIN); |
---|
680 | 646 | return 0; |
---|
681 | 647 | } |
---|
682 | 648 | EXPORT_SYMBOL_GPL(lbtf_remove_card); |
---|