diff options
author | Brian Cavagnolo <brian@cozybit.com> | 2010-11-12 20:23:49 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-11-16 16:37:02 -0500 |
commit | 3cc7772c0a3cc193fa9873816168bd34d4f16837 (patch) | |
tree | 1c87d998fd922f0f18d2694759513b2fcc454ed5 /drivers/net/wireless/mwl8k.c | |
parent | 41fdf0974d9eb81215cb578211a6d8f8a022a9eb (diff) |
mwl8k: factor out firmware loading and hw init code
This is in preparation for supporting different fw images for
different interface types, and for supporting asynchronous
firmware loading.
Based on a patch from Pradeep Nemavat <pnemavat@marvell.com>
and Yogesh Powar <yogeshp@marvell.com>
Signed-off-by: Brian Cavagnolo <brian@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 345 |
1 files changed, 214 insertions, 131 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index cfda87a595e3..7bd861586983 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -3942,73 +3942,10 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { | |||
3942 | }; | 3942 | }; |
3943 | MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); | 3943 | MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); |
3944 | 3944 | ||
3945 | static int __devinit mwl8k_probe(struct pci_dev *pdev, | 3945 | static int mwl8k_init_firmware(struct ieee80211_hw *hw) |
3946 | const struct pci_device_id *id) | ||
3947 | { | 3946 | { |
3948 | static int printed_version = 0; | 3947 | struct mwl8k_priv *priv = hw->priv; |
3949 | struct ieee80211_hw *hw; | ||
3950 | struct mwl8k_priv *priv; | ||
3951 | int rc; | 3948 | int rc; |
3952 | int i; | ||
3953 | |||
3954 | if (!printed_version) { | ||
3955 | printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); | ||
3956 | printed_version = 1; | ||
3957 | } | ||
3958 | |||
3959 | |||
3960 | rc = pci_enable_device(pdev); | ||
3961 | if (rc) { | ||
3962 | printk(KERN_ERR "%s: Cannot enable new PCI device\n", | ||
3963 | MWL8K_NAME); | ||
3964 | return rc; | ||
3965 | } | ||
3966 | |||
3967 | rc = pci_request_regions(pdev, MWL8K_NAME); | ||
3968 | if (rc) { | ||
3969 | printk(KERN_ERR "%s: Cannot obtain PCI resources\n", | ||
3970 | MWL8K_NAME); | ||
3971 | goto err_disable_device; | ||
3972 | } | ||
3973 | |||
3974 | pci_set_master(pdev); | ||
3975 | |||
3976 | |||
3977 | hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); | ||
3978 | if (hw == NULL) { | ||
3979 | printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); | ||
3980 | rc = -ENOMEM; | ||
3981 | goto err_free_reg; | ||
3982 | } | ||
3983 | |||
3984 | SET_IEEE80211_DEV(hw, &pdev->dev); | ||
3985 | pci_set_drvdata(pdev, hw); | ||
3986 | |||
3987 | priv = hw->priv; | ||
3988 | priv->hw = hw; | ||
3989 | priv->pdev = pdev; | ||
3990 | priv->device_info = &mwl8k_info_tbl[id->driver_data]; | ||
3991 | |||
3992 | |||
3993 | priv->sram = pci_iomap(pdev, 0, 0x10000); | ||
3994 | if (priv->sram == NULL) { | ||
3995 | wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); | ||
3996 | goto err_iounmap; | ||
3997 | } | ||
3998 | |||
3999 | /* | ||
4000 | * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. | ||
4001 | * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. | ||
4002 | */ | ||
4003 | priv->regs = pci_iomap(pdev, 1, 0x10000); | ||
4004 | if (priv->regs == NULL) { | ||
4005 | priv->regs = pci_iomap(pdev, 2, 0x10000); | ||
4006 | if (priv->regs == NULL) { | ||
4007 | wiphy_err(hw->wiphy, "Cannot map device registers\n"); | ||
4008 | goto err_iounmap; | ||
4009 | } | ||
4010 | } | ||
4011 | |||
4012 | 3949 | ||
4013 | /* Reset firmware and hardware */ | 3950 | /* Reset firmware and hardware */ |
4014 | mwl8k_hw_reset(priv); | 3951 | mwl8k_hw_reset(priv); |
@@ -4017,19 +3954,26 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4017 | rc = mwl8k_request_firmware(priv); | 3954 | rc = mwl8k_request_firmware(priv); |
4018 | if (rc) { | 3955 | if (rc) { |
4019 | wiphy_err(hw->wiphy, "Firmware files not found\n"); | 3956 | wiphy_err(hw->wiphy, "Firmware files not found\n"); |
4020 | goto err_stop_firmware; | 3957 | return rc; |
4021 | } | 3958 | } |
4022 | 3959 | ||
4023 | /* Load firmware into hardware */ | 3960 | /* Load firmware into hardware */ |
4024 | rc = mwl8k_load_firmware(hw); | 3961 | rc = mwl8k_load_firmware(hw); |
4025 | if (rc) { | 3962 | if (rc) |
4026 | wiphy_err(hw->wiphy, "Cannot start firmware\n"); | 3963 | wiphy_err(hw->wiphy, "Cannot start firmware\n"); |
4027 | goto err_stop_firmware; | ||
4028 | } | ||
4029 | 3964 | ||
4030 | /* Reclaim memory once firmware is successfully loaded */ | 3965 | /* Reclaim memory once firmware is successfully loaded */ |
4031 | mwl8k_release_firmware(priv); | 3966 | mwl8k_release_firmware(priv); |
4032 | 3967 | ||
3968 | return rc; | ||
3969 | } | ||
3970 | |||
3971 | /* initialize hw after successfully loading a firmware image */ | ||
3972 | static int mwl8k_probe_hw(struct ieee80211_hw *hw) | ||
3973 | { | ||
3974 | struct mwl8k_priv *priv = hw->priv; | ||
3975 | int rc = 0; | ||
3976 | int i; | ||
4033 | 3977 | ||
4034 | if (priv->ap_fw) { | 3978 | if (priv->ap_fw) { |
4035 | priv->rxd_ops = priv->device_info->ap_rxd_ops; | 3979 | priv->rxd_ops = priv->device_info->ap_rxd_ops; |
@@ -4046,58 +3990,11 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4046 | priv->wmm_enabled = false; | 3990 | priv->wmm_enabled = false; |
4047 | priv->pending_tx_pkts = 0; | 3991 | priv->pending_tx_pkts = 0; |
4048 | 3992 | ||
4049 | |||
4050 | /* | ||
4051 | * Extra headroom is the size of the required DMA header | ||
4052 | * minus the size of the smallest 802.11 frame (CTS frame). | ||
4053 | */ | ||
4054 | hw->extra_tx_headroom = | ||
4055 | sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); | ||
4056 | |||
4057 | hw->channel_change_time = 10; | ||
4058 | |||
4059 | hw->queues = MWL8K_TX_QUEUES; | ||
4060 | |||
4061 | /* Set rssi values to dBm */ | ||
4062 | hw->flags |= IEEE80211_HW_SIGNAL_DBM; | ||
4063 | hw->vif_data_size = sizeof(struct mwl8k_vif); | ||
4064 | hw->sta_data_size = sizeof(struct mwl8k_sta); | ||
4065 | |||
4066 | priv->macids_used = 0; | ||
4067 | INIT_LIST_HEAD(&priv->vif_list); | ||
4068 | |||
4069 | /* Set default radio state and preamble */ | ||
4070 | priv->radio_on = 0; | ||
4071 | priv->radio_short_preamble = 0; | ||
4072 | |||
4073 | /* Finalize join worker */ | ||
4074 | INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); | ||
4075 | |||
4076 | /* TX reclaim and RX tasklets. */ | ||
4077 | tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); | ||
4078 | tasklet_disable(&priv->poll_tx_task); | ||
4079 | tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); | ||
4080 | tasklet_disable(&priv->poll_rx_task); | ||
4081 | |||
4082 | /* Power management cookie */ | ||
4083 | priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); | ||
4084 | if (priv->cookie == NULL) | ||
4085 | goto err_stop_firmware; | ||
4086 | |||
4087 | rc = mwl8k_rxq_init(hw, 0); | 3993 | rc = mwl8k_rxq_init(hw, 0); |
4088 | if (rc) | 3994 | if (rc) |
4089 | goto err_free_cookie; | 3995 | goto err_stop_firmware; |
4090 | rxq_refill(hw, 0, INT_MAX); | 3996 | rxq_refill(hw, 0, INT_MAX); |
4091 | 3997 | ||
4092 | mutex_init(&priv->fw_mutex); | ||
4093 | priv->fw_mutex_owner = NULL; | ||
4094 | priv->fw_mutex_depth = 0; | ||
4095 | priv->hostcmd_wait = NULL; | ||
4096 | |||
4097 | spin_lock_init(&priv->tx_lock); | ||
4098 | |||
4099 | priv->tx_wait = NULL; | ||
4100 | |||
4101 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | 3998 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { |
4102 | rc = mwl8k_txq_init(hw, i); | 3999 | rc = mwl8k_txq_init(hw, i); |
4103 | if (rc) | 4000 | if (rc) |
@@ -4137,13 +4034,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4137 | goto err_free_irq; | 4034 | goto err_free_irq; |
4138 | } | 4035 | } |
4139 | 4036 | ||
4140 | hw->wiphy->interface_modes = 0; | ||
4141 | if (priv->ap_macids_supported) | ||
4142 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); | ||
4143 | if (priv->sta_macids_supported) | ||
4144 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); | ||
4145 | |||
4146 | |||
4147 | /* Turn radio off */ | 4037 | /* Turn radio off */ |
4148 | rc = mwl8k_cmd_radio_disable(hw); | 4038 | rc = mwl8k_cmd_radio_disable(hw); |
4149 | if (rc) { | 4039 | if (rc) { |
@@ -4162,12 +4052,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4162 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 4052 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
4163 | free_irq(priv->pdev->irq, hw); | 4053 | free_irq(priv->pdev->irq, hw); |
4164 | 4054 | ||
4165 | rc = ieee80211_register_hw(hw); | ||
4166 | if (rc) { | ||
4167 | wiphy_err(hw->wiphy, "Cannot register device\n"); | ||
4168 | goto err_free_queues; | ||
4169 | } | ||
4170 | |||
4171 | wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n", | 4055 | wiphy_info(hw->wiphy, "%s v%d, %pm, %s firmware %u.%u.%u.%u\n", |
4172 | priv->device_info->part_name, | 4056 | priv->device_info->part_name, |
4173 | priv->hw_rev, hw->wiphy->perm_addr, | 4057 | priv->hw_rev, hw->wiphy->perm_addr, |
@@ -4186,14 +4070,213 @@ err_free_queues: | |||
4186 | mwl8k_txq_deinit(hw, i); | 4070 | mwl8k_txq_deinit(hw, i); |
4187 | mwl8k_rxq_deinit(hw, 0); | 4071 | mwl8k_rxq_deinit(hw, 0); |
4188 | 4072 | ||
4073 | err_stop_firmware: | ||
4074 | mwl8k_hw_reset(priv); | ||
4075 | |||
4076 | return rc; | ||
4077 | } | ||
4078 | |||
4079 | /* | ||
4080 | * invoke mwl8k_reload_firmware to change the firmware image after the device | ||
4081 | * has already been registered | ||
4082 | */ | ||
4083 | static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) | ||
4084 | { | ||
4085 | int i, rc = 0; | ||
4086 | struct mwl8k_priv *priv = hw->priv; | ||
4087 | |||
4088 | mwl8k_stop(hw); | ||
4089 | mwl8k_rxq_deinit(hw, 0); | ||
4090 | |||
4091 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | ||
4092 | mwl8k_txq_deinit(hw, i); | ||
4093 | |||
4094 | rc = mwl8k_init_firmware(hw, fw_image); | ||
4095 | if (rc) | ||
4096 | goto fail; | ||
4097 | |||
4098 | rc = mwl8k_probe_hw(hw); | ||
4099 | if (rc) | ||
4100 | goto fail; | ||
4101 | |||
4102 | rc = mwl8k_start(hw); | ||
4103 | if (rc) | ||
4104 | goto fail; | ||
4105 | |||
4106 | rc = mwl8k_config(hw, ~0); | ||
4107 | if (rc) | ||
4108 | goto fail; | ||
4109 | |||
4110 | for (i = 0; i < MWL8K_TX_QUEUES; i++) { | ||
4111 | rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); | ||
4112 | if (rc) | ||
4113 | goto fail; | ||
4114 | } | ||
4115 | |||
4116 | return rc; | ||
4117 | |||
4118 | fail: | ||
4119 | printk(KERN_WARNING "mwl8k: Failed to reload firmware image.\n"); | ||
4120 | return rc; | ||
4121 | } | ||
4122 | |||
4123 | static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) | ||
4124 | { | ||
4125 | struct ieee80211_hw *hw = priv->hw; | ||
4126 | int i, rc; | ||
4127 | |||
4128 | /* | ||
4129 | * Extra headroom is the size of the required DMA header | ||
4130 | * minus the size of the smallest 802.11 frame (CTS frame). | ||
4131 | */ | ||
4132 | hw->extra_tx_headroom = | ||
4133 | sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); | ||
4134 | |||
4135 | hw->channel_change_time = 10; | ||
4136 | |||
4137 | hw->queues = MWL8K_TX_QUEUES; | ||
4138 | |||
4139 | /* Set rssi values to dBm */ | ||
4140 | hw->flags |= IEEE80211_HW_SIGNAL_DBM; | ||
4141 | hw->vif_data_size = sizeof(struct mwl8k_vif); | ||
4142 | hw->sta_data_size = sizeof(struct mwl8k_sta); | ||
4143 | |||
4144 | priv->macids_used = 0; | ||
4145 | INIT_LIST_HEAD(&priv->vif_list); | ||
4146 | |||
4147 | /* Set default radio state and preamble */ | ||
4148 | priv->radio_on = 0; | ||
4149 | priv->radio_short_preamble = 0; | ||
4150 | |||
4151 | /* Finalize join worker */ | ||
4152 | INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); | ||
4153 | |||
4154 | /* TX reclaim and RX tasklets. */ | ||
4155 | tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); | ||
4156 | tasklet_disable(&priv->poll_tx_task); | ||
4157 | tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); | ||
4158 | tasklet_disable(&priv->poll_rx_task); | ||
4159 | |||
4160 | /* Power management cookie */ | ||
4161 | priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); | ||
4162 | if (priv->cookie == NULL) | ||
4163 | return -ENOMEM; | ||
4164 | |||
4165 | mutex_init(&priv->fw_mutex); | ||
4166 | priv->fw_mutex_owner = NULL; | ||
4167 | priv->fw_mutex_depth = 0; | ||
4168 | priv->hostcmd_wait = NULL; | ||
4169 | |||
4170 | spin_lock_init(&priv->tx_lock); | ||
4171 | |||
4172 | priv->tx_wait = NULL; | ||
4173 | |||
4174 | rc = mwl8k_probe_hw(hw); | ||
4175 | if (rc) | ||
4176 | goto err_free_cookie; | ||
4177 | |||
4178 | hw->wiphy->interface_modes = 0; | ||
4179 | if (priv->ap_macids_supported || priv->device_info->fw_image_ap) | ||
4180 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); | ||
4181 | if (priv->sta_macids_supported || priv->device_info->fw_image_sta) | ||
4182 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); | ||
4183 | |||
4184 | rc = ieee80211_register_hw(hw); | ||
4185 | if (rc) { | ||
4186 | wiphy_err(hw->wiphy, "Cannot register device\n"); | ||
4187 | goto err_unprobe_hw; | ||
4188 | } | ||
4189 | |||
4190 | return 0; | ||
4191 | |||
4192 | err_unprobe_hw: | ||
4193 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | ||
4194 | mwl8k_txq_deinit(hw, i); | ||
4195 | mwl8k_rxq_deinit(hw, 0); | ||
4196 | |||
4189 | err_free_cookie: | 4197 | err_free_cookie: |
4190 | if (priv->cookie != NULL) | 4198 | if (priv->cookie != NULL) |
4191 | pci_free_consistent(priv->pdev, 4, | 4199 | pci_free_consistent(priv->pdev, 4, |
4192 | priv->cookie, priv->cookie_dma); | 4200 | priv->cookie, priv->cookie_dma); |
4193 | 4201 | ||
4202 | return rc; | ||
4203 | } | ||
4204 | static int __devinit mwl8k_probe(struct pci_dev *pdev, | ||
4205 | const struct pci_device_id *id) | ||
4206 | { | ||
4207 | static int printed_version; | ||
4208 | struct ieee80211_hw *hw; | ||
4209 | struct mwl8k_priv *priv; | ||
4210 | int rc; | ||
4211 | |||
4212 | if (!printed_version) { | ||
4213 | printk(KERN_INFO "%s version %s\n", MWL8K_DESC, MWL8K_VERSION); | ||
4214 | printed_version = 1; | ||
4215 | } | ||
4216 | |||
4217 | |||
4218 | rc = pci_enable_device(pdev); | ||
4219 | if (rc) { | ||
4220 | printk(KERN_ERR "%s: Cannot enable new PCI device\n", | ||
4221 | MWL8K_NAME); | ||
4222 | return rc; | ||
4223 | } | ||
4224 | |||
4225 | rc = pci_request_regions(pdev, MWL8K_NAME); | ||
4226 | if (rc) { | ||
4227 | printk(KERN_ERR "%s: Cannot obtain PCI resources\n", | ||
4228 | MWL8K_NAME); | ||
4229 | goto err_disable_device; | ||
4230 | } | ||
4231 | |||
4232 | pci_set_master(pdev); | ||
4233 | |||
4234 | |||
4235 | hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops); | ||
4236 | if (hw == NULL) { | ||
4237 | printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME); | ||
4238 | rc = -ENOMEM; | ||
4239 | goto err_free_reg; | ||
4240 | } | ||
4241 | |||
4242 | SET_IEEE80211_DEV(hw, &pdev->dev); | ||
4243 | pci_set_drvdata(pdev, hw); | ||
4244 | |||
4245 | priv = hw->priv; | ||
4246 | priv->hw = hw; | ||
4247 | priv->pdev = pdev; | ||
4248 | priv->device_info = &mwl8k_info_tbl[id->driver_data]; | ||
4249 | |||
4250 | |||
4251 | priv->sram = pci_iomap(pdev, 0, 0x10000); | ||
4252 | if (priv->sram == NULL) { | ||
4253 | wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); | ||
4254 | goto err_iounmap; | ||
4255 | } | ||
4256 | |||
4257 | /* | ||
4258 | * If BAR0 is a 32 bit BAR, the register BAR will be BAR1. | ||
4259 | * If BAR0 is a 64 bit BAR, the register BAR will be BAR2. | ||
4260 | */ | ||
4261 | priv->regs = pci_iomap(pdev, 1, 0x10000); | ||
4262 | if (priv->regs == NULL) { | ||
4263 | priv->regs = pci_iomap(pdev, 2, 0x10000); | ||
4264 | if (priv->regs == NULL) { | ||
4265 | wiphy_err(hw->wiphy, "Cannot map device registers\n"); | ||
4266 | goto err_iounmap; | ||
4267 | } | ||
4268 | } | ||
4269 | |||
4270 | rc = mwl8k_init_firmware(hw); | ||
4271 | if (rc) | ||
4272 | goto err_stop_firmware; | ||
4273 | |||
4274 | rc = mwl8k_firmware_load_success(priv); | ||
4275 | if (!rc) | ||
4276 | return rc; | ||
4277 | |||
4194 | err_stop_firmware: | 4278 | err_stop_firmware: |
4195 | mwl8k_hw_reset(priv); | 4279 | mwl8k_hw_reset(priv); |
4196 | mwl8k_release_firmware(priv); | ||
4197 | 4280 | ||
4198 | err_iounmap: | 4281 | err_iounmap: |
4199 | if (priv->regs != NULL) | 4282 | if (priv->regs != NULL) |