1277b024eSKalle Valo /* 2277b024eSKalle Valo * Marvell Wireless LAN device driver: SDIO specific handling 3277b024eSKalle Valo * 4277b024eSKalle Valo * Copyright (C) 2011-2014, Marvell International Ltd. 5277b024eSKalle Valo * 6277b024eSKalle Valo * This software file (the "File") is distributed by Marvell International 7277b024eSKalle Valo * Ltd. under the terms of the GNU General Public License Version 2, June 1991 8277b024eSKalle Valo * (the "License"). You may use, redistribute and/or modify this File in 9277b024eSKalle Valo * accordance with the terms and conditions of the License, a copy of which 10277b024eSKalle Valo * is available by writing to the Free Software Foundation, Inc., 11277b024eSKalle Valo * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 12277b024eSKalle Valo * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 13277b024eSKalle Valo * 14277b024eSKalle Valo * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 15277b024eSKalle Valo * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 16277b024eSKalle Valo * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 17277b024eSKalle Valo * this warranty disclaimer. 18277b024eSKalle Valo */ 19277b024eSKalle Valo 20277b024eSKalle Valo #include <linux/firmware.h> 21277b024eSKalle Valo 22277b024eSKalle Valo #include "decl.h" 23277b024eSKalle Valo #include "ioctl.h" 24277b024eSKalle Valo #include "util.h" 25277b024eSKalle Valo #include "fw.h" 26277b024eSKalle Valo #include "main.h" 27277b024eSKalle Valo #include "wmm.h" 28277b024eSKalle Valo #include "11n.h" 29277b024eSKalle Valo #include "sdio.h" 30277b024eSKalle Valo 31277b024eSKalle Valo 32277b024eSKalle Valo #define SDIO_VERSION "1.0" 33277b024eSKalle Valo 34277b024eSKalle Valo /* The mwifiex_sdio_remove() callback function is called when 35277b024eSKalle Valo * user removes this module from kernel space or ejects 36277b024eSKalle Valo * the card from the slot. The driver handles these 2 cases 37277b024eSKalle Valo * differently. 38277b024eSKalle Valo * If the user is removing the module, the few commands (FUNC_SHUTDOWN, 39277b024eSKalle Valo * HS_CANCEL etc.) are sent to the firmware. 40277b024eSKalle Valo * If the card is removed, there is no need to send these command. 41277b024eSKalle Valo * 42277b024eSKalle Valo * The variable 'user_rmmod' is used to distinguish these two 43277b024eSKalle Valo * scenarios. This flag is initialized as FALSE in case the card 44277b024eSKalle Valo * is removed, and will be set to TRUE for module removal when 45277b024eSKalle Valo * module_exit function is called. 46277b024eSKalle Valo */ 47277b024eSKalle Valo static u8 user_rmmod; 48277b024eSKalle Valo 49277b024eSKalle Valo static struct mwifiex_if_ops sdio_ops; 50277b024eSKalle Valo static unsigned long iface_work_flags; 51277b024eSKalle Valo 52277b024eSKalle Valo static struct semaphore add_remove_card_sem; 53277b024eSKalle Valo 54277b024eSKalle Valo static struct memory_type_mapping generic_mem_type_map[] = { 55277b024eSKalle Valo {"DUMP", NULL, 0, 0xDD}, 56277b024eSKalle Valo }; 57277b024eSKalle Valo 58277b024eSKalle Valo static struct memory_type_mapping mem_type_mapping_tbl[] = { 59277b024eSKalle Valo {"ITCM", NULL, 0, 0xF0}, 60277b024eSKalle Valo {"DTCM", NULL, 0, 0xF1}, 61277b024eSKalle Valo {"SQRAM", NULL, 0, 0xF2}, 62277b024eSKalle Valo {"APU", NULL, 0, 0xF3}, 63277b024eSKalle Valo {"CIU", NULL, 0, 0xF4}, 64277b024eSKalle Valo {"ICU", NULL, 0, 0xF5}, 65277b024eSKalle Valo {"MAC", NULL, 0, 0xF6}, 66277b024eSKalle Valo {"EXT7", NULL, 0, 0xF7}, 67277b024eSKalle Valo {"EXT8", NULL, 0, 0xF8}, 68277b024eSKalle Valo {"EXT9", NULL, 0, 0xF9}, 69277b024eSKalle Valo {"EXT10", NULL, 0, 0xFA}, 70277b024eSKalle Valo {"EXT11", NULL, 0, 0xFB}, 71277b024eSKalle Valo {"EXT12", NULL, 0, 0xFC}, 72277b024eSKalle Valo {"EXT13", NULL, 0, 0xFD}, 73277b024eSKalle Valo {"EXTLAST", NULL, 0, 0xFE}, 74277b024eSKalle Valo }; 75277b024eSKalle Valo 76277b024eSKalle Valo /* 77277b024eSKalle Valo * SDIO probe. 78277b024eSKalle Valo * 79277b024eSKalle Valo * This function probes an mwifiex device and registers it. It allocates 80277b024eSKalle Valo * the card structure, enables SDIO function number and initiates the 81277b024eSKalle Valo * device registration and initialization procedure by adding a logical 82277b024eSKalle Valo * interface. 83277b024eSKalle Valo */ 84277b024eSKalle Valo static int 85277b024eSKalle Valo mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) 86277b024eSKalle Valo { 87277b024eSKalle Valo int ret; 88277b024eSKalle Valo struct sdio_mmc_card *card = NULL; 89277b024eSKalle Valo 90277b024eSKalle Valo pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", 91277b024eSKalle Valo func->vendor, func->device, func->class, func->num); 92277b024eSKalle Valo 93277b024eSKalle Valo card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL); 94277b024eSKalle Valo if (!card) 95277b024eSKalle Valo return -ENOMEM; 96277b024eSKalle Valo 97277b024eSKalle Valo card->func = func; 98277b024eSKalle Valo card->device_id = id; 99277b024eSKalle Valo 100277b024eSKalle Valo func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; 101277b024eSKalle Valo 102277b024eSKalle Valo if (id->driver_data) { 103277b024eSKalle Valo struct mwifiex_sdio_device *data = (void *)id->driver_data; 104277b024eSKalle Valo 105277b024eSKalle Valo card->firmware = data->firmware; 106277b024eSKalle Valo card->reg = data->reg; 107277b024eSKalle Valo card->max_ports = data->max_ports; 108277b024eSKalle Valo card->mp_agg_pkt_limit = data->mp_agg_pkt_limit; 109277b024eSKalle Valo card->supports_sdio_new_mode = data->supports_sdio_new_mode; 110277b024eSKalle Valo card->has_control_mask = data->has_control_mask; 111277b024eSKalle Valo card->tx_buf_size = data->tx_buf_size; 112277b024eSKalle Valo card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; 113277b024eSKalle Valo card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; 114277b024eSKalle Valo card->can_dump_fw = data->can_dump_fw; 115277b024eSKalle Valo card->fw_dump_enh = data->fw_dump_enh; 116277b024eSKalle Valo card->can_auto_tdls = data->can_auto_tdls; 117277b024eSKalle Valo card->can_ext_scan = data->can_ext_scan; 118277b024eSKalle Valo } 119277b024eSKalle Valo 120277b024eSKalle Valo sdio_claim_host(func); 121277b024eSKalle Valo ret = sdio_enable_func(func); 122277b024eSKalle Valo sdio_release_host(func); 123277b024eSKalle Valo 124277b024eSKalle Valo if (ret) { 125277b024eSKalle Valo pr_err("%s: failed to enable function\n", __func__); 126277b024eSKalle Valo kfree(card); 127277b024eSKalle Valo return -EIO; 128277b024eSKalle Valo } 129277b024eSKalle Valo 130277b024eSKalle Valo if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops, 131277b024eSKalle Valo MWIFIEX_SDIO)) { 132277b024eSKalle Valo pr_err("%s: add card failed\n", __func__); 133277b024eSKalle Valo kfree(card); 134277b024eSKalle Valo sdio_claim_host(func); 135277b024eSKalle Valo ret = sdio_disable_func(func); 136277b024eSKalle Valo sdio_release_host(func); 137277b024eSKalle Valo ret = -1; 138277b024eSKalle Valo } 139277b024eSKalle Valo 140277b024eSKalle Valo return ret; 141277b024eSKalle Valo } 142277b024eSKalle Valo 143277b024eSKalle Valo /* 144277b024eSKalle Valo * SDIO resume. 145277b024eSKalle Valo * 146277b024eSKalle Valo * Kernel needs to suspend all functions separately. Therefore all 147277b024eSKalle Valo * registered functions must have drivers with suspend and resume 148277b024eSKalle Valo * methods. Failing that the kernel simply removes the whole card. 149277b024eSKalle Valo * 150277b024eSKalle Valo * If already not resumed, this function turns on the traffic and 151277b024eSKalle Valo * sends a host sleep cancel request to the firmware. 152277b024eSKalle Valo */ 153277b024eSKalle Valo static int mwifiex_sdio_resume(struct device *dev) 154277b024eSKalle Valo { 155277b024eSKalle Valo struct sdio_func *func = dev_to_sdio_func(dev); 156277b024eSKalle Valo struct sdio_mmc_card *card; 157277b024eSKalle Valo struct mwifiex_adapter *adapter; 158277b024eSKalle Valo mmc_pm_flag_t pm_flag = 0; 159277b024eSKalle Valo 160277b024eSKalle Valo if (func) { 161277b024eSKalle Valo pm_flag = sdio_get_host_pm_caps(func); 162277b024eSKalle Valo card = sdio_get_drvdata(func); 163277b024eSKalle Valo if (!card || !card->adapter) { 164277b024eSKalle Valo pr_err("resume: invalid card or adapter\n"); 165277b024eSKalle Valo return 0; 166277b024eSKalle Valo } 167277b024eSKalle Valo } else { 168277b024eSKalle Valo pr_err("resume: sdio_func is not specified\n"); 169277b024eSKalle Valo return 0; 170277b024eSKalle Valo } 171277b024eSKalle Valo 172277b024eSKalle Valo adapter = card->adapter; 173277b024eSKalle Valo 174277b024eSKalle Valo if (!adapter->is_suspended) { 175277b024eSKalle Valo mwifiex_dbg(adapter, WARN, 176277b024eSKalle Valo "device already resumed\n"); 177277b024eSKalle Valo return 0; 178277b024eSKalle Valo } 179277b024eSKalle Valo 180277b024eSKalle Valo adapter->is_suspended = false; 181277b024eSKalle Valo 182277b024eSKalle Valo /* Disable Host Sleep */ 183277b024eSKalle Valo mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), 184277b024eSKalle Valo MWIFIEX_ASYNC_CMD); 185277b024eSKalle Valo 186277b024eSKalle Valo return 0; 187277b024eSKalle Valo } 188277b024eSKalle Valo 189277b024eSKalle Valo /* 190277b024eSKalle Valo * SDIO remove. 191277b024eSKalle Valo * 192277b024eSKalle Valo * This function removes the interface and frees up the card structure. 193277b024eSKalle Valo */ 194277b024eSKalle Valo static void 195277b024eSKalle Valo mwifiex_sdio_remove(struct sdio_func *func) 196277b024eSKalle Valo { 197277b024eSKalle Valo struct sdio_mmc_card *card; 198277b024eSKalle Valo struct mwifiex_adapter *adapter; 199277b024eSKalle Valo struct mwifiex_private *priv; 200277b024eSKalle Valo 201277b024eSKalle Valo card = sdio_get_drvdata(func); 202277b024eSKalle Valo if (!card) 203277b024eSKalle Valo return; 204277b024eSKalle Valo 205277b024eSKalle Valo adapter = card->adapter; 206277b024eSKalle Valo if (!adapter || !adapter->priv_num) 207277b024eSKalle Valo return; 208277b024eSKalle Valo 209277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num); 210277b024eSKalle Valo 211277b024eSKalle Valo if (user_rmmod) { 212277b024eSKalle Valo if (adapter->is_suspended) 213277b024eSKalle Valo mwifiex_sdio_resume(adapter->dev); 214277b024eSKalle Valo 215277b024eSKalle Valo mwifiex_deauthenticate_all(adapter); 216277b024eSKalle Valo 217277b024eSKalle Valo priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 218277b024eSKalle Valo mwifiex_disable_auto_ds(priv); 219277b024eSKalle Valo mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); 220277b024eSKalle Valo } 221277b024eSKalle Valo 222277b024eSKalle Valo mwifiex_remove_card(card->adapter, &add_remove_card_sem); 223277b024eSKalle Valo } 224277b024eSKalle Valo 225277b024eSKalle Valo /* 226277b024eSKalle Valo * SDIO suspend. 227277b024eSKalle Valo * 228277b024eSKalle Valo * Kernel needs to suspend all functions separately. Therefore all 229277b024eSKalle Valo * registered functions must have drivers with suspend and resume 230277b024eSKalle Valo * methods. Failing that the kernel simply removes the whole card. 231277b024eSKalle Valo * 232277b024eSKalle Valo * If already not suspended, this function allocates and sends a host 233277b024eSKalle Valo * sleep activate request to the firmware and turns off the traffic. 234277b024eSKalle Valo */ 235277b024eSKalle Valo static int mwifiex_sdio_suspend(struct device *dev) 236277b024eSKalle Valo { 237277b024eSKalle Valo struct sdio_func *func = dev_to_sdio_func(dev); 238277b024eSKalle Valo struct sdio_mmc_card *card; 239277b024eSKalle Valo struct mwifiex_adapter *adapter; 240277b024eSKalle Valo mmc_pm_flag_t pm_flag = 0; 241277b024eSKalle Valo int ret = 0; 242277b024eSKalle Valo 243277b024eSKalle Valo if (func) { 244277b024eSKalle Valo pm_flag = sdio_get_host_pm_caps(func); 245277b024eSKalle Valo pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", 246277b024eSKalle Valo sdio_func_id(func), pm_flag); 247277b024eSKalle Valo if (!(pm_flag & MMC_PM_KEEP_POWER)) { 248277b024eSKalle Valo pr_err("%s: cannot remain alive while host is" 249277b024eSKalle Valo " suspended\n", sdio_func_id(func)); 250277b024eSKalle Valo return -ENOSYS; 251277b024eSKalle Valo } 252277b024eSKalle Valo 253277b024eSKalle Valo card = sdio_get_drvdata(func); 254277b024eSKalle Valo if (!card || !card->adapter) { 255277b024eSKalle Valo pr_err("suspend: invalid card or adapter\n"); 256277b024eSKalle Valo return 0; 257277b024eSKalle Valo } 258277b024eSKalle Valo } else { 259277b024eSKalle Valo pr_err("suspend: sdio_func is not specified\n"); 260277b024eSKalle Valo return 0; 261277b024eSKalle Valo } 262277b024eSKalle Valo 263277b024eSKalle Valo adapter = card->adapter; 264277b024eSKalle Valo 265277b024eSKalle Valo /* Enable the Host Sleep */ 266277b024eSKalle Valo if (!mwifiex_enable_hs(adapter)) { 267277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 268277b024eSKalle Valo "cmd: failed to suspend\n"); 269277b024eSKalle Valo adapter->hs_enabling = false; 270277b024eSKalle Valo return -EFAULT; 271277b024eSKalle Valo } 272277b024eSKalle Valo 273277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 274277b024eSKalle Valo "cmd: suspend with MMC_PM_KEEP_POWER\n"); 275277b024eSKalle Valo ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 276277b024eSKalle Valo 277277b024eSKalle Valo /* Indicate device suspended */ 278277b024eSKalle Valo adapter->is_suspended = true; 279277b024eSKalle Valo adapter->hs_enabling = false; 280277b024eSKalle Valo 281277b024eSKalle Valo return ret; 282277b024eSKalle Valo } 283277b024eSKalle Valo 284277b024eSKalle Valo /* Device ID for SD8786 */ 285277b024eSKalle Valo #define SDIO_DEVICE_ID_MARVELL_8786 (0x9116) 286277b024eSKalle Valo /* Device ID for SD8787 */ 287277b024eSKalle Valo #define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) 288277b024eSKalle Valo /* Device ID for SD8797 */ 289277b024eSKalle Valo #define SDIO_DEVICE_ID_MARVELL_8797 (0x9129) 290277b024eSKalle Valo /* Device ID for SD8897 */ 291277b024eSKalle Valo #define SDIO_DEVICE_ID_MARVELL_8897 (0x912d) 292277b024eSKalle Valo /* Device ID for SD8887 */ 293277b024eSKalle Valo #define SDIO_DEVICE_ID_MARVELL_8887 (0x9135) 294277b024eSKalle Valo /* Device ID for SD8801 */ 295277b024eSKalle Valo #define SDIO_DEVICE_ID_MARVELL_8801 (0x9139) 296277b024eSKalle Valo /* Device ID for SD8997 */ 297277b024eSKalle Valo #define SDIO_DEVICE_ID_MARVELL_8997 (0x9141) 298277b024eSKalle Valo 299277b024eSKalle Valo 300277b024eSKalle Valo /* WLAN IDs */ 301277b024eSKalle Valo static const struct sdio_device_id mwifiex_ids[] = { 302277b024eSKalle Valo {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786), 303277b024eSKalle Valo .driver_data = (unsigned long) &mwifiex_sdio_sd8786}, 304277b024eSKalle Valo {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787), 305277b024eSKalle Valo .driver_data = (unsigned long) &mwifiex_sdio_sd8787}, 306277b024eSKalle Valo {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797), 307277b024eSKalle Valo .driver_data = (unsigned long) &mwifiex_sdio_sd8797}, 308277b024eSKalle Valo {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897), 309277b024eSKalle Valo .driver_data = (unsigned long) &mwifiex_sdio_sd8897}, 310277b024eSKalle Valo {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887), 311277b024eSKalle Valo .driver_data = (unsigned long)&mwifiex_sdio_sd8887}, 312277b024eSKalle Valo {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801), 313277b024eSKalle Valo .driver_data = (unsigned long)&mwifiex_sdio_sd8801}, 314277b024eSKalle Valo {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8997), 315277b024eSKalle Valo .driver_data = (unsigned long)&mwifiex_sdio_sd8997}, 316277b024eSKalle Valo {}, 317277b024eSKalle Valo }; 318277b024eSKalle Valo 319277b024eSKalle Valo MODULE_DEVICE_TABLE(sdio, mwifiex_ids); 320277b024eSKalle Valo 321277b024eSKalle Valo static const struct dev_pm_ops mwifiex_sdio_pm_ops = { 322277b024eSKalle Valo .suspend = mwifiex_sdio_suspend, 323277b024eSKalle Valo .resume = mwifiex_sdio_resume, 324277b024eSKalle Valo }; 325277b024eSKalle Valo 326277b024eSKalle Valo static struct sdio_driver mwifiex_sdio = { 327277b024eSKalle Valo .name = "mwifiex_sdio", 328277b024eSKalle Valo .id_table = mwifiex_ids, 329277b024eSKalle Valo .probe = mwifiex_sdio_probe, 330277b024eSKalle Valo .remove = mwifiex_sdio_remove, 331277b024eSKalle Valo .drv = { 332277b024eSKalle Valo .owner = THIS_MODULE, 333277b024eSKalle Valo .pm = &mwifiex_sdio_pm_ops, 334277b024eSKalle Valo } 335277b024eSKalle Valo }; 336277b024eSKalle Valo 337277b024eSKalle Valo /* Write data into SDIO card register. Caller claims SDIO device. */ 338277b024eSKalle Valo static int 339277b024eSKalle Valo mwifiex_write_reg_locked(struct sdio_func *func, u32 reg, u8 data) 340277b024eSKalle Valo { 341277b024eSKalle Valo int ret = -1; 342277b024eSKalle Valo sdio_writeb(func, data, reg, &ret); 343277b024eSKalle Valo return ret; 344277b024eSKalle Valo } 345277b024eSKalle Valo 346277b024eSKalle Valo /* 347277b024eSKalle Valo * This function writes data into SDIO card register. 348277b024eSKalle Valo */ 349277b024eSKalle Valo static int 350277b024eSKalle Valo mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u8 data) 351277b024eSKalle Valo { 352277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 353277b024eSKalle Valo int ret; 354277b024eSKalle Valo 355277b024eSKalle Valo sdio_claim_host(card->func); 356277b024eSKalle Valo ret = mwifiex_write_reg_locked(card->func, reg, data); 357277b024eSKalle Valo sdio_release_host(card->func); 358277b024eSKalle Valo 359277b024eSKalle Valo return ret; 360277b024eSKalle Valo } 361277b024eSKalle Valo 362277b024eSKalle Valo /* 363277b024eSKalle Valo * This function reads data from SDIO card register. 364277b024eSKalle Valo */ 365277b024eSKalle Valo static int 366277b024eSKalle Valo mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u8 *data) 367277b024eSKalle Valo { 368277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 369277b024eSKalle Valo int ret = -1; 370277b024eSKalle Valo u8 val; 371277b024eSKalle Valo 372277b024eSKalle Valo sdio_claim_host(card->func); 373277b024eSKalle Valo val = sdio_readb(card->func, reg, &ret); 374277b024eSKalle Valo sdio_release_host(card->func); 375277b024eSKalle Valo 376277b024eSKalle Valo *data = val; 377277b024eSKalle Valo 378277b024eSKalle Valo return ret; 379277b024eSKalle Valo } 380277b024eSKalle Valo 381277b024eSKalle Valo /* 382277b024eSKalle Valo * This function writes multiple data into SDIO card memory. 383277b024eSKalle Valo * 384277b024eSKalle Valo * This does not work in suspended mode. 385277b024eSKalle Valo */ 386277b024eSKalle Valo static int 387277b024eSKalle Valo mwifiex_write_data_sync(struct mwifiex_adapter *adapter, 388277b024eSKalle Valo u8 *buffer, u32 pkt_len, u32 port) 389277b024eSKalle Valo { 390277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 391277b024eSKalle Valo int ret; 392277b024eSKalle Valo u8 blk_mode = 393277b024eSKalle Valo (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; 394277b024eSKalle Valo u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; 395277b024eSKalle Valo u32 blk_cnt = 396277b024eSKalle Valo (blk_mode == 397277b024eSKalle Valo BLOCK_MODE) ? (pkt_len / 398277b024eSKalle Valo MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len; 399277b024eSKalle Valo u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); 400277b024eSKalle Valo 401277b024eSKalle Valo if (adapter->is_suspended) { 402277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 403277b024eSKalle Valo "%s: not allowed while suspended\n", __func__); 404277b024eSKalle Valo return -1; 405277b024eSKalle Valo } 406277b024eSKalle Valo 407277b024eSKalle Valo sdio_claim_host(card->func); 408277b024eSKalle Valo 409277b024eSKalle Valo ret = sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size); 410277b024eSKalle Valo 411277b024eSKalle Valo sdio_release_host(card->func); 412277b024eSKalle Valo 413277b024eSKalle Valo return ret; 414277b024eSKalle Valo } 415277b024eSKalle Valo 416277b024eSKalle Valo /* 417277b024eSKalle Valo * This function reads multiple data from SDIO card memory. 418277b024eSKalle Valo */ 419277b024eSKalle Valo static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, 420277b024eSKalle Valo u32 len, u32 port, u8 claim) 421277b024eSKalle Valo { 422277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 423277b024eSKalle Valo int ret; 424277b024eSKalle Valo u8 blk_mode = (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE 425277b024eSKalle Valo : BLOCK_MODE; 426277b024eSKalle Valo u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; 427277b024eSKalle Valo u32 blk_cnt = (blk_mode == BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) 428277b024eSKalle Valo : len; 429277b024eSKalle Valo u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); 430277b024eSKalle Valo 431277b024eSKalle Valo if (claim) 432277b024eSKalle Valo sdio_claim_host(card->func); 433277b024eSKalle Valo 434277b024eSKalle Valo ret = sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size); 435277b024eSKalle Valo 436277b024eSKalle Valo if (claim) 437277b024eSKalle Valo sdio_release_host(card->func); 438277b024eSKalle Valo 439277b024eSKalle Valo return ret; 440277b024eSKalle Valo } 441277b024eSKalle Valo 442277b024eSKalle Valo /* 443277b024eSKalle Valo * This function wakes up the card. 444277b024eSKalle Valo * 445277b024eSKalle Valo * A host power up command is written to the card configuration 446277b024eSKalle Valo * register to wake up the card. 447277b024eSKalle Valo */ 448277b024eSKalle Valo static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) 449277b024eSKalle Valo { 450277b024eSKalle Valo mwifiex_dbg(adapter, EVENT, 451277b024eSKalle Valo "event: wakeup device...\n"); 452277b024eSKalle Valo 453277b024eSKalle Valo return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); 454277b024eSKalle Valo } 455277b024eSKalle Valo 456277b024eSKalle Valo /* 457277b024eSKalle Valo * This function is called after the card has woken up. 458277b024eSKalle Valo * 459277b024eSKalle Valo * The card configuration register is reset. 460277b024eSKalle Valo */ 461277b024eSKalle Valo static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) 462277b024eSKalle Valo { 463277b024eSKalle Valo mwifiex_dbg(adapter, EVENT, 464277b024eSKalle Valo "cmd: wakeup device completed\n"); 465277b024eSKalle Valo 466277b024eSKalle Valo return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); 467277b024eSKalle Valo } 468277b024eSKalle Valo 469277b024eSKalle Valo /* 470277b024eSKalle Valo * This function is used to initialize IO ports for the 471277b024eSKalle Valo * chipsets supporting SDIO new mode eg SD8897. 472277b024eSKalle Valo */ 473277b024eSKalle Valo static int mwifiex_init_sdio_new_mode(struct mwifiex_adapter *adapter) 474277b024eSKalle Valo { 475277b024eSKalle Valo u8 reg; 476277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 477277b024eSKalle Valo 478277b024eSKalle Valo adapter->ioport = MEM_PORT; 479277b024eSKalle Valo 480277b024eSKalle Valo /* enable sdio new mode */ 481277b024eSKalle Valo if (mwifiex_read_reg(adapter, card->reg->card_cfg_2_1_reg, ®)) 482277b024eSKalle Valo return -1; 483277b024eSKalle Valo if (mwifiex_write_reg(adapter, card->reg->card_cfg_2_1_reg, 484277b024eSKalle Valo reg | CMD53_NEW_MODE)) 485277b024eSKalle Valo return -1; 486277b024eSKalle Valo 487277b024eSKalle Valo /* Configure cmd port and enable reading rx length from the register */ 488277b024eSKalle Valo if (mwifiex_read_reg(adapter, card->reg->cmd_cfg_0, ®)) 489277b024eSKalle Valo return -1; 490277b024eSKalle Valo if (mwifiex_write_reg(adapter, card->reg->cmd_cfg_0, 491277b024eSKalle Valo reg | CMD_PORT_RD_LEN_EN)) 492277b024eSKalle Valo return -1; 493277b024eSKalle Valo 494277b024eSKalle Valo /* Enable Dnld/Upld ready auto reset for cmd port after cmd53 is 495277b024eSKalle Valo * completed 496277b024eSKalle Valo */ 497277b024eSKalle Valo if (mwifiex_read_reg(adapter, card->reg->cmd_cfg_1, ®)) 498277b024eSKalle Valo return -1; 499277b024eSKalle Valo if (mwifiex_write_reg(adapter, card->reg->cmd_cfg_1, 500277b024eSKalle Valo reg | CMD_PORT_AUTO_EN)) 501277b024eSKalle Valo return -1; 502277b024eSKalle Valo 503277b024eSKalle Valo return 0; 504277b024eSKalle Valo } 505277b024eSKalle Valo 506277b024eSKalle Valo /* This function initializes the IO ports. 507277b024eSKalle Valo * 508277b024eSKalle Valo * The following operations are performed - 509277b024eSKalle Valo * - Read the IO ports (0, 1 and 2) 510277b024eSKalle Valo * - Set host interrupt Reset-To-Read to clear 511277b024eSKalle Valo * - Set auto re-enable interrupt 512277b024eSKalle Valo */ 513277b024eSKalle Valo static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) 514277b024eSKalle Valo { 515277b024eSKalle Valo u8 reg; 516277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 517277b024eSKalle Valo 518277b024eSKalle Valo adapter->ioport = 0; 519277b024eSKalle Valo 520277b024eSKalle Valo if (card->supports_sdio_new_mode) { 521277b024eSKalle Valo if (mwifiex_init_sdio_new_mode(adapter)) 522277b024eSKalle Valo return -1; 523277b024eSKalle Valo goto cont; 524277b024eSKalle Valo } 525277b024eSKalle Valo 526277b024eSKalle Valo /* Read the IO port */ 527277b024eSKalle Valo if (!mwifiex_read_reg(adapter, card->reg->io_port_0_reg, ®)) 528277b024eSKalle Valo adapter->ioport |= (reg & 0xff); 529277b024eSKalle Valo else 530277b024eSKalle Valo return -1; 531277b024eSKalle Valo 532277b024eSKalle Valo if (!mwifiex_read_reg(adapter, card->reg->io_port_1_reg, ®)) 533277b024eSKalle Valo adapter->ioport |= ((reg & 0xff) << 8); 534277b024eSKalle Valo else 535277b024eSKalle Valo return -1; 536277b024eSKalle Valo 537277b024eSKalle Valo if (!mwifiex_read_reg(adapter, card->reg->io_port_2_reg, ®)) 538277b024eSKalle Valo adapter->ioport |= ((reg & 0xff) << 16); 539277b024eSKalle Valo else 540277b024eSKalle Valo return -1; 541277b024eSKalle Valo cont: 542277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 543277b024eSKalle Valo "info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); 544277b024eSKalle Valo 545277b024eSKalle Valo /* Set Host interrupt reset to read to clear */ 546277b024eSKalle Valo if (!mwifiex_read_reg(adapter, card->reg->host_int_rsr_reg, ®)) 547277b024eSKalle Valo mwifiex_write_reg(adapter, card->reg->host_int_rsr_reg, 548277b024eSKalle Valo reg | card->reg->sdio_int_mask); 549277b024eSKalle Valo else 550277b024eSKalle Valo return -1; 551277b024eSKalle Valo 552277b024eSKalle Valo /* Dnld/Upld ready set to auto reset */ 553277b024eSKalle Valo if (!mwifiex_read_reg(adapter, card->reg->card_misc_cfg_reg, ®)) 554277b024eSKalle Valo mwifiex_write_reg(adapter, card->reg->card_misc_cfg_reg, 555277b024eSKalle Valo reg | AUTO_RE_ENABLE_INT); 556277b024eSKalle Valo else 557277b024eSKalle Valo return -1; 558277b024eSKalle Valo 559277b024eSKalle Valo return 0; 560277b024eSKalle Valo } 561277b024eSKalle Valo 562277b024eSKalle Valo /* 563277b024eSKalle Valo * This function sends data to the card. 564277b024eSKalle Valo */ 565277b024eSKalle Valo static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, 566277b024eSKalle Valo u8 *payload, u32 pkt_len, u32 port) 567277b024eSKalle Valo { 568277b024eSKalle Valo u32 i = 0; 569277b024eSKalle Valo int ret; 570277b024eSKalle Valo 571277b024eSKalle Valo do { 572277b024eSKalle Valo ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port); 573277b024eSKalle Valo if (ret) { 574277b024eSKalle Valo i++; 575277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 576277b024eSKalle Valo "host_to_card, write iomem\t" 577277b024eSKalle Valo "(%d) failed: %d\n", i, ret); 578277b024eSKalle Valo if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) 579277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 580277b024eSKalle Valo "write CFG reg failed\n"); 581277b024eSKalle Valo 582277b024eSKalle Valo ret = -1; 583277b024eSKalle Valo if (i > MAX_WRITE_IOMEM_RETRY) 584277b024eSKalle Valo return ret; 585277b024eSKalle Valo } 586277b024eSKalle Valo } while (ret == -1); 587277b024eSKalle Valo 588277b024eSKalle Valo return ret; 589277b024eSKalle Valo } 590277b024eSKalle Valo 591277b024eSKalle Valo /* 592277b024eSKalle Valo * This function gets the read port. 593277b024eSKalle Valo * 594277b024eSKalle Valo * If control port bit is set in MP read bitmap, the control port 595277b024eSKalle Valo * is returned, otherwise the current read port is returned and 596277b024eSKalle Valo * the value is increased (provided it does not reach the maximum 597277b024eSKalle Valo * limit, in which case it is reset to 1) 598277b024eSKalle Valo */ 599277b024eSKalle Valo static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) 600277b024eSKalle Valo { 601277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 602277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 603277b024eSKalle Valo u32 rd_bitmap = card->mp_rd_bitmap; 604277b024eSKalle Valo 605277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 606277b024eSKalle Valo "data: mp_rd_bitmap=0x%08x\n", rd_bitmap); 607277b024eSKalle Valo 608277b024eSKalle Valo if (card->supports_sdio_new_mode) { 609277b024eSKalle Valo if (!(rd_bitmap & reg->data_port_mask)) 610277b024eSKalle Valo return -1; 611277b024eSKalle Valo } else { 612277b024eSKalle Valo if (!(rd_bitmap & (CTRL_PORT_MASK | reg->data_port_mask))) 613277b024eSKalle Valo return -1; 614277b024eSKalle Valo } 615277b024eSKalle Valo 616277b024eSKalle Valo if ((card->has_control_mask) && 617277b024eSKalle Valo (card->mp_rd_bitmap & CTRL_PORT_MASK)) { 618277b024eSKalle Valo card->mp_rd_bitmap &= (u32) (~CTRL_PORT_MASK); 619277b024eSKalle Valo *port = CTRL_PORT; 620277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 621277b024eSKalle Valo "data: port=%d mp_rd_bitmap=0x%08x\n", 622277b024eSKalle Valo *port, card->mp_rd_bitmap); 623277b024eSKalle Valo return 0; 624277b024eSKalle Valo } 625277b024eSKalle Valo 626277b024eSKalle Valo if (!(card->mp_rd_bitmap & (1 << card->curr_rd_port))) 627277b024eSKalle Valo return -1; 628277b024eSKalle Valo 629277b024eSKalle Valo /* We are now handling the SDIO data ports */ 630277b024eSKalle Valo card->mp_rd_bitmap &= (u32)(~(1 << card->curr_rd_port)); 631277b024eSKalle Valo *port = card->curr_rd_port; 632277b024eSKalle Valo 633277b024eSKalle Valo if (++card->curr_rd_port == card->max_ports) 634277b024eSKalle Valo card->curr_rd_port = reg->start_rd_port; 635277b024eSKalle Valo 636277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 637277b024eSKalle Valo "data: port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n", 638277b024eSKalle Valo *port, rd_bitmap, card->mp_rd_bitmap); 639277b024eSKalle Valo 640277b024eSKalle Valo return 0; 641277b024eSKalle Valo } 642277b024eSKalle Valo 643277b024eSKalle Valo /* 644277b024eSKalle Valo * This function gets the write port for data. 645277b024eSKalle Valo * 646277b024eSKalle Valo * The current write port is returned if available and the value is 647277b024eSKalle Valo * increased (provided it does not reach the maximum limit, in which 648277b024eSKalle Valo * case it is reset to 1) 649277b024eSKalle Valo */ 650277b024eSKalle Valo static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port) 651277b024eSKalle Valo { 652277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 653277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 654277b024eSKalle Valo u32 wr_bitmap = card->mp_wr_bitmap; 655277b024eSKalle Valo 656277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 657277b024eSKalle Valo "data: mp_wr_bitmap=0x%08x\n", wr_bitmap); 658277b024eSKalle Valo 659277b024eSKalle Valo if (!(wr_bitmap & card->mp_data_port_mask)) { 660277b024eSKalle Valo adapter->data_sent = true; 661277b024eSKalle Valo return -EBUSY; 662277b024eSKalle Valo } 663277b024eSKalle Valo 664277b024eSKalle Valo if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { 665277b024eSKalle Valo card->mp_wr_bitmap &= (u32) (~(1 << card->curr_wr_port)); 666277b024eSKalle Valo *port = card->curr_wr_port; 667277b024eSKalle Valo if (++card->curr_wr_port == card->mp_end_port) 668277b024eSKalle Valo card->curr_wr_port = reg->start_wr_port; 669277b024eSKalle Valo } else { 670277b024eSKalle Valo adapter->data_sent = true; 671277b024eSKalle Valo return -EBUSY; 672277b024eSKalle Valo } 673277b024eSKalle Valo 674277b024eSKalle Valo if ((card->has_control_mask) && (*port == CTRL_PORT)) { 675277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 676277b024eSKalle Valo "invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n", 677277b024eSKalle Valo *port, card->curr_wr_port, wr_bitmap, 678277b024eSKalle Valo card->mp_wr_bitmap); 679277b024eSKalle Valo return -1; 680277b024eSKalle Valo } 681277b024eSKalle Valo 682277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 683277b024eSKalle Valo "data: port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n", 684277b024eSKalle Valo *port, wr_bitmap, card->mp_wr_bitmap); 685277b024eSKalle Valo 686277b024eSKalle Valo return 0; 687277b024eSKalle Valo } 688277b024eSKalle Valo 689277b024eSKalle Valo /* 690277b024eSKalle Valo * This function polls the card status. 691277b024eSKalle Valo */ 692277b024eSKalle Valo static int 693277b024eSKalle Valo mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) 694277b024eSKalle Valo { 695277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 696277b024eSKalle Valo u32 tries; 697277b024eSKalle Valo u8 cs; 698277b024eSKalle Valo 699277b024eSKalle Valo for (tries = 0; tries < MAX_POLL_TRIES; tries++) { 700277b024eSKalle Valo if (mwifiex_read_reg(adapter, card->reg->poll_reg, &cs)) 701277b024eSKalle Valo break; 702277b024eSKalle Valo else if ((cs & bits) == bits) 703277b024eSKalle Valo return 0; 704277b024eSKalle Valo 705277b024eSKalle Valo usleep_range(10, 20); 706277b024eSKalle Valo } 707277b024eSKalle Valo 708277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 709277b024eSKalle Valo "poll card status failed, tries = %d\n", tries); 710277b024eSKalle Valo 711277b024eSKalle Valo return -1; 712277b024eSKalle Valo } 713277b024eSKalle Valo 714277b024eSKalle Valo /* 715277b024eSKalle Valo * This function reads the firmware status. 716277b024eSKalle Valo */ 717277b024eSKalle Valo static int 718277b024eSKalle Valo mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) 719277b024eSKalle Valo { 720277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 721277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 722277b024eSKalle Valo u8 fws0, fws1; 723277b024eSKalle Valo 724277b024eSKalle Valo if (mwifiex_read_reg(adapter, reg->status_reg_0, &fws0)) 725277b024eSKalle Valo return -1; 726277b024eSKalle Valo 727277b024eSKalle Valo if (mwifiex_read_reg(adapter, reg->status_reg_1, &fws1)) 728277b024eSKalle Valo return -1; 729277b024eSKalle Valo 730277b024eSKalle Valo *dat = (u16) ((fws1 << 8) | fws0); 731277b024eSKalle Valo 732277b024eSKalle Valo return 0; 733277b024eSKalle Valo } 734277b024eSKalle Valo 735277b024eSKalle Valo /* 736277b024eSKalle Valo * This function disables the host interrupt. 737277b024eSKalle Valo * 738277b024eSKalle Valo * The host interrupt mask is read, the disable bit is reset and 739277b024eSKalle Valo * written back to the card host interrupt mask register. 740277b024eSKalle Valo */ 741277b024eSKalle Valo static void mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) 742277b024eSKalle Valo { 743277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 744277b024eSKalle Valo struct sdio_func *func = card->func; 745277b024eSKalle Valo 746277b024eSKalle Valo sdio_claim_host(func); 747277b024eSKalle Valo mwifiex_write_reg_locked(func, card->reg->host_int_mask_reg, 0); 748277b024eSKalle Valo sdio_release_irq(func); 749277b024eSKalle Valo sdio_release_host(func); 750277b024eSKalle Valo } 751277b024eSKalle Valo 752277b024eSKalle Valo /* 753277b024eSKalle Valo * This function reads the interrupt status from card. 754277b024eSKalle Valo */ 755277b024eSKalle Valo static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) 756277b024eSKalle Valo { 757277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 758277b024eSKalle Valo u8 sdio_ireg; 759277b024eSKalle Valo unsigned long flags; 760277b024eSKalle Valo 761277b024eSKalle Valo if (mwifiex_read_data_sync(adapter, card->mp_regs, 762277b024eSKalle Valo card->reg->max_mp_regs, 763277b024eSKalle Valo REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) { 764277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "read mp_regs failed\n"); 765277b024eSKalle Valo return; 766277b024eSKalle Valo } 767277b024eSKalle Valo 768277b024eSKalle Valo sdio_ireg = card->mp_regs[card->reg->host_int_status_reg]; 769277b024eSKalle Valo if (sdio_ireg) { 770277b024eSKalle Valo /* 771277b024eSKalle Valo * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS 772277b024eSKalle Valo * For SDIO new mode CMD port interrupts 773277b024eSKalle Valo * DN_LD_CMD_PORT_HOST_INT_STATUS and/or 774277b024eSKalle Valo * UP_LD_CMD_PORT_HOST_INT_STATUS 775277b024eSKalle Valo * Clear the interrupt status register 776277b024eSKalle Valo */ 777277b024eSKalle Valo mwifiex_dbg(adapter, INTR, 778277b024eSKalle Valo "int: sdio_ireg = %#x\n", sdio_ireg); 779277b024eSKalle Valo spin_lock_irqsave(&adapter->int_lock, flags); 780277b024eSKalle Valo adapter->int_status |= sdio_ireg; 781277b024eSKalle Valo spin_unlock_irqrestore(&adapter->int_lock, flags); 782277b024eSKalle Valo } 783277b024eSKalle Valo } 784277b024eSKalle Valo 785277b024eSKalle Valo /* 786277b024eSKalle Valo * SDIO interrupt handler. 787277b024eSKalle Valo * 788277b024eSKalle Valo * This function reads the interrupt status from firmware and handles 789277b024eSKalle Valo * the interrupt in current thread (ksdioirqd) right away. 790277b024eSKalle Valo */ 791277b024eSKalle Valo static void 792277b024eSKalle Valo mwifiex_sdio_interrupt(struct sdio_func *func) 793277b024eSKalle Valo { 794277b024eSKalle Valo struct mwifiex_adapter *adapter; 795277b024eSKalle Valo struct sdio_mmc_card *card; 796277b024eSKalle Valo 797277b024eSKalle Valo card = sdio_get_drvdata(func); 798277b024eSKalle Valo if (!card || !card->adapter) { 799277b024eSKalle Valo pr_debug("int: func=%p card=%p adapter=%p\n", 800277b024eSKalle Valo func, card, card ? card->adapter : NULL); 801277b024eSKalle Valo return; 802277b024eSKalle Valo } 803277b024eSKalle Valo adapter = card->adapter; 804277b024eSKalle Valo 805277b024eSKalle Valo if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) 806277b024eSKalle Valo adapter->ps_state = PS_STATE_AWAKE; 807277b024eSKalle Valo 808277b024eSKalle Valo mwifiex_interrupt_status(adapter); 809277b024eSKalle Valo mwifiex_main_process(adapter); 810277b024eSKalle Valo } 811277b024eSKalle Valo 812277b024eSKalle Valo /* 813277b024eSKalle Valo * This function enables the host interrupt. 814277b024eSKalle Valo * 815277b024eSKalle Valo * The host interrupt enable mask is written to the card 816277b024eSKalle Valo * host interrupt mask register. 817277b024eSKalle Valo */ 818277b024eSKalle Valo static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) 819277b024eSKalle Valo { 820277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 821277b024eSKalle Valo struct sdio_func *func = card->func; 822277b024eSKalle Valo int ret; 823277b024eSKalle Valo 824277b024eSKalle Valo sdio_claim_host(func); 825277b024eSKalle Valo 826277b024eSKalle Valo /* Request the SDIO IRQ */ 827277b024eSKalle Valo ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); 828277b024eSKalle Valo if (ret) { 829277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 830277b024eSKalle Valo "claim irq failed: ret=%d\n", ret); 831277b024eSKalle Valo goto out; 832277b024eSKalle Valo } 833277b024eSKalle Valo 834277b024eSKalle Valo /* Simply write the mask to the register */ 835277b024eSKalle Valo ret = mwifiex_write_reg_locked(func, card->reg->host_int_mask_reg, 836277b024eSKalle Valo card->reg->host_int_enable); 837277b024eSKalle Valo if (ret) { 838277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 839277b024eSKalle Valo "enable host interrupt failed\n"); 840277b024eSKalle Valo sdio_release_irq(func); 841277b024eSKalle Valo } 842277b024eSKalle Valo 843277b024eSKalle Valo out: 844277b024eSKalle Valo sdio_release_host(func); 845277b024eSKalle Valo return ret; 846277b024eSKalle Valo } 847277b024eSKalle Valo 848277b024eSKalle Valo /* 849277b024eSKalle Valo * This function sends a data buffer to the card. 850277b024eSKalle Valo */ 851277b024eSKalle Valo static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, 852277b024eSKalle Valo u32 *type, u8 *buffer, 853277b024eSKalle Valo u32 npayload, u32 ioport) 854277b024eSKalle Valo { 855277b024eSKalle Valo int ret; 856277b024eSKalle Valo u32 nb; 857277b024eSKalle Valo 858277b024eSKalle Valo if (!buffer) { 859277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 860277b024eSKalle Valo "%s: buffer is NULL\n", __func__); 861277b024eSKalle Valo return -1; 862277b024eSKalle Valo } 863277b024eSKalle Valo 864277b024eSKalle Valo ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1); 865277b024eSKalle Valo 866277b024eSKalle Valo if (ret) { 867277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 868277b024eSKalle Valo "%s: read iomem failed: %d\n", __func__, 869277b024eSKalle Valo ret); 870277b024eSKalle Valo return -1; 871277b024eSKalle Valo } 872277b024eSKalle Valo 873277b024eSKalle Valo nb = le16_to_cpu(*(__le16 *) (buffer)); 874277b024eSKalle Valo if (nb > npayload) { 875277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 876277b024eSKalle Valo "%s: invalid packet, nb=%d npayload=%d\n", 877277b024eSKalle Valo __func__, nb, npayload); 878277b024eSKalle Valo return -1; 879277b024eSKalle Valo } 880277b024eSKalle Valo 881277b024eSKalle Valo *type = le16_to_cpu(*(__le16 *) (buffer + 2)); 882277b024eSKalle Valo 883277b024eSKalle Valo return ret; 884277b024eSKalle Valo } 885277b024eSKalle Valo 886277b024eSKalle Valo /* 887277b024eSKalle Valo * This function downloads the firmware to the card. 888277b024eSKalle Valo * 889277b024eSKalle Valo * Firmware is downloaded to the card in blocks. Every block download 890277b024eSKalle Valo * is tested for CRC errors, and retried a number of times before 891277b024eSKalle Valo * returning failure. 892277b024eSKalle Valo */ 893277b024eSKalle Valo static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, 894277b024eSKalle Valo struct mwifiex_fw_image *fw) 895277b024eSKalle Valo { 896277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 897277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 898277b024eSKalle Valo int ret; 899277b024eSKalle Valo u8 *firmware = fw->fw_buf; 900277b024eSKalle Valo u32 firmware_len = fw->fw_len; 901277b024eSKalle Valo u32 offset = 0; 902277b024eSKalle Valo u8 base0, base1; 903277b024eSKalle Valo u8 *fwbuf; 904277b024eSKalle Valo u16 len = 0; 905277b024eSKalle Valo u32 txlen, tx_blocks = 0, tries; 906277b024eSKalle Valo u32 i = 0; 907277b024eSKalle Valo 908277b024eSKalle Valo if (!firmware_len) { 909277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 910277b024eSKalle Valo "firmware image not found! Terminating download\n"); 911277b024eSKalle Valo return -1; 912277b024eSKalle Valo } 913277b024eSKalle Valo 914277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 915277b024eSKalle Valo "info: downloading FW image (%d bytes)\n", 916277b024eSKalle Valo firmware_len); 917277b024eSKalle Valo 918277b024eSKalle Valo /* Assume that the allocated buffer is 8-byte aligned */ 919277b024eSKalle Valo fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); 920277b024eSKalle Valo if (!fwbuf) 921277b024eSKalle Valo return -ENOMEM; 922277b024eSKalle Valo 923277b024eSKalle Valo sdio_claim_host(card->func); 924277b024eSKalle Valo 925277b024eSKalle Valo /* Perform firmware data transfer */ 926277b024eSKalle Valo do { 927277b024eSKalle Valo /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY 928277b024eSKalle Valo bits */ 929277b024eSKalle Valo ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY | 930277b024eSKalle Valo DN_LD_CARD_RDY); 931277b024eSKalle Valo if (ret) { 932277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 933277b024eSKalle Valo "FW download with helper:\t" 934277b024eSKalle Valo "poll status timeout @ %d\n", offset); 935277b024eSKalle Valo goto done; 936277b024eSKalle Valo } 937277b024eSKalle Valo 938277b024eSKalle Valo /* More data? */ 939277b024eSKalle Valo if (offset >= firmware_len) 940277b024eSKalle Valo break; 941277b024eSKalle Valo 942277b024eSKalle Valo for (tries = 0; tries < MAX_POLL_TRIES; tries++) { 943277b024eSKalle Valo ret = mwifiex_read_reg(adapter, reg->base_0_reg, 944277b024eSKalle Valo &base0); 945277b024eSKalle Valo if (ret) { 946277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 947277b024eSKalle Valo "dev BASE0 register read failed:\t" 948277b024eSKalle Valo "base0=%#04X(%d). Terminating dnld\n", 949277b024eSKalle Valo base0, base0); 950277b024eSKalle Valo goto done; 951277b024eSKalle Valo } 952277b024eSKalle Valo ret = mwifiex_read_reg(adapter, reg->base_1_reg, 953277b024eSKalle Valo &base1); 954277b024eSKalle Valo if (ret) { 955277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 956277b024eSKalle Valo "dev BASE1 register read failed:\t" 957277b024eSKalle Valo "base1=%#04X(%d). Terminating dnld\n", 958277b024eSKalle Valo base1, base1); 959277b024eSKalle Valo goto done; 960277b024eSKalle Valo } 961277b024eSKalle Valo len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); 962277b024eSKalle Valo 963277b024eSKalle Valo if (len) 964277b024eSKalle Valo break; 965277b024eSKalle Valo 966277b024eSKalle Valo usleep_range(10, 20); 967277b024eSKalle Valo } 968277b024eSKalle Valo 969277b024eSKalle Valo if (!len) { 970277b024eSKalle Valo break; 971277b024eSKalle Valo } else if (len > MWIFIEX_UPLD_SIZE) { 972277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 973277b024eSKalle Valo "FW dnld failed @ %d, invalid length %d\n", 974277b024eSKalle Valo offset, len); 975277b024eSKalle Valo ret = -1; 976277b024eSKalle Valo goto done; 977277b024eSKalle Valo } 978277b024eSKalle Valo 979277b024eSKalle Valo txlen = len; 980277b024eSKalle Valo 981277b024eSKalle Valo if (len & BIT(0)) { 982277b024eSKalle Valo i++; 983277b024eSKalle Valo if (i > MAX_WRITE_IOMEM_RETRY) { 984277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 985277b024eSKalle Valo "FW dnld failed @ %d, over max retry\n", 986277b024eSKalle Valo offset); 987277b024eSKalle Valo ret = -1; 988277b024eSKalle Valo goto done; 989277b024eSKalle Valo } 990277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 991277b024eSKalle Valo "CRC indicated by the helper:\t" 992277b024eSKalle Valo "len = 0x%04X, txlen = %d\n", len, txlen); 993277b024eSKalle Valo len &= ~BIT(0); 994277b024eSKalle Valo /* Setting this to 0 to resend from same offset */ 995277b024eSKalle Valo txlen = 0; 996277b024eSKalle Valo } else { 997277b024eSKalle Valo i = 0; 998277b024eSKalle Valo 999277b024eSKalle Valo /* Set blocksize to transfer - checking for last 1000277b024eSKalle Valo block */ 1001277b024eSKalle Valo if (firmware_len - offset < txlen) 1002277b024eSKalle Valo txlen = firmware_len - offset; 1003277b024eSKalle Valo 1004277b024eSKalle Valo tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE - 1) 1005277b024eSKalle Valo / MWIFIEX_SDIO_BLOCK_SIZE; 1006277b024eSKalle Valo 1007277b024eSKalle Valo /* Copy payload to buffer */ 1008277b024eSKalle Valo memmove(fwbuf, &firmware[offset], txlen); 1009277b024eSKalle Valo } 1010277b024eSKalle Valo 1011277b024eSKalle Valo ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * 1012277b024eSKalle Valo MWIFIEX_SDIO_BLOCK_SIZE, 1013277b024eSKalle Valo adapter->ioport); 1014277b024eSKalle Valo if (ret) { 1015277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1016277b024eSKalle Valo "FW download, write iomem (%d) failed @ %d\n", 1017277b024eSKalle Valo i, offset); 1018277b024eSKalle Valo if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) 1019277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1020277b024eSKalle Valo "write CFG reg failed\n"); 1021277b024eSKalle Valo 1022277b024eSKalle Valo ret = -1; 1023277b024eSKalle Valo goto done; 1024277b024eSKalle Valo } 1025277b024eSKalle Valo 1026277b024eSKalle Valo offset += txlen; 1027277b024eSKalle Valo } while (true); 1028277b024eSKalle Valo 1029277b024eSKalle Valo sdio_release_host(card->func); 1030277b024eSKalle Valo 1031277b024eSKalle Valo mwifiex_dbg(adapter, MSG, 1032277b024eSKalle Valo "info: FW download over, size %d bytes\n", offset); 1033277b024eSKalle Valo 1034277b024eSKalle Valo ret = 0; 1035277b024eSKalle Valo done: 1036277b024eSKalle Valo kfree(fwbuf); 1037277b024eSKalle Valo return ret; 1038277b024eSKalle Valo } 1039277b024eSKalle Valo 1040277b024eSKalle Valo /* 1041277b024eSKalle Valo * This function checks the firmware status in card. 1042277b024eSKalle Valo * 1043277b024eSKalle Valo * The winner interface is also determined by this function. 1044277b024eSKalle Valo */ 1045277b024eSKalle Valo static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, 1046277b024eSKalle Valo u32 poll_num) 1047277b024eSKalle Valo { 1048277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1049277b024eSKalle Valo int ret = 0; 1050277b024eSKalle Valo u16 firmware_stat; 1051277b024eSKalle Valo u32 tries; 1052277b024eSKalle Valo u8 winner_status; 1053277b024eSKalle Valo 1054277b024eSKalle Valo /* Wait for firmware initialization event */ 1055277b024eSKalle Valo for (tries = 0; tries < poll_num; tries++) { 1056277b024eSKalle Valo ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); 1057277b024eSKalle Valo if (ret) 1058277b024eSKalle Valo continue; 1059277b024eSKalle Valo if (firmware_stat == FIRMWARE_READY_SDIO) { 1060277b024eSKalle Valo ret = 0; 1061277b024eSKalle Valo break; 1062277b024eSKalle Valo } else { 1063277b024eSKalle Valo msleep(100); 1064277b024eSKalle Valo ret = -1; 1065277b024eSKalle Valo } 1066277b024eSKalle Valo } 1067277b024eSKalle Valo 1068277b024eSKalle Valo if (ret) { 1069277b024eSKalle Valo if (mwifiex_read_reg 1070277b024eSKalle Valo (adapter, card->reg->status_reg_0, &winner_status)) 1071277b024eSKalle Valo winner_status = 0; 1072277b024eSKalle Valo 1073277b024eSKalle Valo if (winner_status) 1074277b024eSKalle Valo adapter->winner = 0; 1075277b024eSKalle Valo else 1076277b024eSKalle Valo adapter->winner = 1; 1077277b024eSKalle Valo } 1078277b024eSKalle Valo return ret; 1079277b024eSKalle Valo } 1080277b024eSKalle Valo 1081277b024eSKalle Valo /* 1082277b024eSKalle Valo * This function decode sdio aggreation pkt. 1083277b024eSKalle Valo * 1084277b024eSKalle Valo * Based on the the data block size and pkt_len, 1085277b024eSKalle Valo * skb data will be decoded to few packets. 1086277b024eSKalle Valo */ 1087277b024eSKalle Valo static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, 1088277b024eSKalle Valo struct sk_buff *skb) 1089277b024eSKalle Valo { 1090277b024eSKalle Valo u32 total_pkt_len, pkt_len; 1091277b024eSKalle Valo struct sk_buff *skb_deaggr; 1092277b024eSKalle Valo u32 pkt_type; 1093277b024eSKalle Valo u16 blk_size; 1094277b024eSKalle Valo u8 blk_num; 1095277b024eSKalle Valo u8 *data; 1096277b024eSKalle Valo 1097277b024eSKalle Valo data = skb->data; 1098277b024eSKalle Valo total_pkt_len = skb->len; 1099277b024eSKalle Valo 1100277b024eSKalle Valo while (total_pkt_len >= (SDIO_HEADER_OFFSET + INTF_HEADER_LEN)) { 1101277b024eSKalle Valo if (total_pkt_len < adapter->sdio_rx_block_size) 1102277b024eSKalle Valo break; 1103277b024eSKalle Valo blk_num = *(data + BLOCK_NUMBER_OFFSET); 1104277b024eSKalle Valo blk_size = adapter->sdio_rx_block_size * blk_num; 1105277b024eSKalle Valo if (blk_size > total_pkt_len) { 1106277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1107277b024eSKalle Valo "%s: error in blk_size,\t" 1108277b024eSKalle Valo "blk_num=%d, blk_size=%d, total_pkt_len=%d\n", 1109277b024eSKalle Valo __func__, blk_num, blk_size, total_pkt_len); 1110277b024eSKalle Valo break; 1111277b024eSKalle Valo } 1112277b024eSKalle Valo pkt_len = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET)); 1113277b024eSKalle Valo pkt_type = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET + 1114277b024eSKalle Valo 2)); 1115277b024eSKalle Valo if ((pkt_len + SDIO_HEADER_OFFSET) > blk_size) { 1116277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1117277b024eSKalle Valo "%s: error in pkt_len,\t" 1118277b024eSKalle Valo "pkt_len=%d, blk_size=%d\n", 1119277b024eSKalle Valo __func__, pkt_len, blk_size); 1120277b024eSKalle Valo break; 1121277b024eSKalle Valo } 1122277b024eSKalle Valo skb_deaggr = mwifiex_alloc_dma_align_buf(pkt_len, 1123277b024eSKalle Valo GFP_KERNEL | GFP_DMA); 1124277b024eSKalle Valo if (!skb_deaggr) 1125277b024eSKalle Valo break; 1126277b024eSKalle Valo skb_put(skb_deaggr, pkt_len); 1127277b024eSKalle Valo memcpy(skb_deaggr->data, data + SDIO_HEADER_OFFSET, pkt_len); 1128277b024eSKalle Valo skb_pull(skb_deaggr, INTF_HEADER_LEN); 1129277b024eSKalle Valo 1130277b024eSKalle Valo mwifiex_handle_rx_packet(adapter, skb_deaggr); 1131277b024eSKalle Valo data += blk_size; 1132277b024eSKalle Valo total_pkt_len -= blk_size; 1133277b024eSKalle Valo } 1134277b024eSKalle Valo } 1135277b024eSKalle Valo 1136277b024eSKalle Valo /* 1137277b024eSKalle Valo * This function decodes a received packet. 1138277b024eSKalle Valo * 1139277b024eSKalle Valo * Based on the type, the packet is treated as either a data, or 1140277b024eSKalle Valo * a command response, or an event, and the correct handler 1141277b024eSKalle Valo * function is invoked. 1142277b024eSKalle Valo */ 1143277b024eSKalle Valo static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, 1144277b024eSKalle Valo struct sk_buff *skb, u32 upld_typ) 1145277b024eSKalle Valo { 1146277b024eSKalle Valo u8 *cmd_buf; 1147277b024eSKalle Valo __le16 *curr_ptr = (__le16 *)skb->data; 1148277b024eSKalle Valo u16 pkt_len = le16_to_cpu(*curr_ptr); 1149277b024eSKalle Valo struct mwifiex_rxinfo *rx_info; 1150277b024eSKalle Valo 1151277b024eSKalle Valo if (upld_typ != MWIFIEX_TYPE_AGGR_DATA) { 1152277b024eSKalle Valo skb_trim(skb, pkt_len); 1153277b024eSKalle Valo skb_pull(skb, INTF_HEADER_LEN); 1154277b024eSKalle Valo } 1155277b024eSKalle Valo 1156277b024eSKalle Valo switch (upld_typ) { 1157277b024eSKalle Valo case MWIFIEX_TYPE_AGGR_DATA: 1158277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1159277b024eSKalle Valo "info: --- Rx: Aggr Data packet ---\n"); 1160277b024eSKalle Valo rx_info = MWIFIEX_SKB_RXCB(skb); 1161277b024eSKalle Valo rx_info->buf_type = MWIFIEX_TYPE_AGGR_DATA; 1162277b024eSKalle Valo if (adapter->rx_work_enabled) { 1163277b024eSKalle Valo skb_queue_tail(&adapter->rx_data_q, skb); 1164277b024eSKalle Valo atomic_inc(&adapter->rx_pending); 1165277b024eSKalle Valo adapter->data_received = true; 1166277b024eSKalle Valo } else { 1167277b024eSKalle Valo mwifiex_deaggr_sdio_pkt(adapter, skb); 1168277b024eSKalle Valo dev_kfree_skb_any(skb); 1169277b024eSKalle Valo } 1170277b024eSKalle Valo break; 1171277b024eSKalle Valo 1172277b024eSKalle Valo case MWIFIEX_TYPE_DATA: 1173277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1174277b024eSKalle Valo "info: --- Rx: Data packet ---\n"); 1175277b024eSKalle Valo if (adapter->rx_work_enabled) { 1176277b024eSKalle Valo skb_queue_tail(&adapter->rx_data_q, skb); 1177277b024eSKalle Valo adapter->data_received = true; 1178277b024eSKalle Valo atomic_inc(&adapter->rx_pending); 1179277b024eSKalle Valo } else { 1180277b024eSKalle Valo mwifiex_handle_rx_packet(adapter, skb); 1181277b024eSKalle Valo } 1182277b024eSKalle Valo break; 1183277b024eSKalle Valo 1184277b024eSKalle Valo case MWIFIEX_TYPE_CMD: 1185277b024eSKalle Valo mwifiex_dbg(adapter, CMD, 1186277b024eSKalle Valo "info: --- Rx: Cmd Response ---\n"); 1187277b024eSKalle Valo /* take care of curr_cmd = NULL case */ 1188277b024eSKalle Valo if (!adapter->curr_cmd) { 1189277b024eSKalle Valo cmd_buf = adapter->upld_buf; 1190277b024eSKalle Valo 1191277b024eSKalle Valo if (adapter->ps_state == PS_STATE_SLEEP_CFM) 1192277b024eSKalle Valo mwifiex_process_sleep_confirm_resp(adapter, 1193277b024eSKalle Valo skb->data, 1194277b024eSKalle Valo skb->len); 1195277b024eSKalle Valo 1196277b024eSKalle Valo memcpy(cmd_buf, skb->data, 1197277b024eSKalle Valo min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, 1198277b024eSKalle Valo skb->len)); 1199277b024eSKalle Valo 1200277b024eSKalle Valo dev_kfree_skb_any(skb); 1201277b024eSKalle Valo } else { 1202277b024eSKalle Valo adapter->cmd_resp_received = true; 1203277b024eSKalle Valo adapter->curr_cmd->resp_skb = skb; 1204277b024eSKalle Valo } 1205277b024eSKalle Valo break; 1206277b024eSKalle Valo 1207277b024eSKalle Valo case MWIFIEX_TYPE_EVENT: 1208277b024eSKalle Valo mwifiex_dbg(adapter, EVENT, 1209277b024eSKalle Valo "info: --- Rx: Event ---\n"); 1210277b024eSKalle Valo adapter->event_cause = le32_to_cpu(*(__le32 *) skb->data); 1211277b024eSKalle Valo 1212277b024eSKalle Valo if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) 1213277b024eSKalle Valo memcpy(adapter->event_body, 1214277b024eSKalle Valo skb->data + MWIFIEX_EVENT_HEADER_LEN, 1215277b024eSKalle Valo skb->len); 1216277b024eSKalle Valo 1217277b024eSKalle Valo /* event cause has been saved to adapter->event_cause */ 1218277b024eSKalle Valo adapter->event_received = true; 1219277b024eSKalle Valo adapter->event_skb = skb; 1220277b024eSKalle Valo 1221277b024eSKalle Valo break; 1222277b024eSKalle Valo 1223277b024eSKalle Valo default: 1224277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1225277b024eSKalle Valo "unknown upload type %#x\n", upld_typ); 1226277b024eSKalle Valo dev_kfree_skb_any(skb); 1227277b024eSKalle Valo break; 1228277b024eSKalle Valo } 1229277b024eSKalle Valo 1230277b024eSKalle Valo return 0; 1231277b024eSKalle Valo } 1232277b024eSKalle Valo 1233277b024eSKalle Valo /* 1234277b024eSKalle Valo * This function transfers received packets from card to driver, performing 1235277b024eSKalle Valo * aggregation if required. 1236277b024eSKalle Valo * 1237277b024eSKalle Valo * For data received on control port, or if aggregation is disabled, the 1238277b024eSKalle Valo * received buffers are uploaded as separate packets. However, if aggregation 1239277b024eSKalle Valo * is enabled and required, the buffers are copied onto an aggregation buffer, 1240277b024eSKalle Valo * provided there is space left, processed and finally uploaded. 1241277b024eSKalle Valo */ 1242277b024eSKalle Valo static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, 1243277b024eSKalle Valo u16 rx_len, u8 port) 1244277b024eSKalle Valo { 1245277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1246277b024eSKalle Valo s32 f_do_rx_aggr = 0; 1247277b024eSKalle Valo s32 f_do_rx_cur = 0; 1248277b024eSKalle Valo s32 f_aggr_cur = 0; 1249277b024eSKalle Valo s32 f_post_aggr_cur = 0; 1250277b024eSKalle Valo struct sk_buff *skb_deaggr; 1251277b024eSKalle Valo struct sk_buff *skb = NULL; 1252277b024eSKalle Valo u32 pkt_len, pkt_type, mport, pind; 1253277b024eSKalle Valo u8 *curr_ptr; 1254277b024eSKalle Valo 1255277b024eSKalle Valo if ((card->has_control_mask) && (port == CTRL_PORT)) { 1256277b024eSKalle Valo /* Read the command Resp without aggr */ 1257277b024eSKalle Valo mwifiex_dbg(adapter, CMD, 1258277b024eSKalle Valo "info: %s: no aggregation for cmd\t" 1259277b024eSKalle Valo "response\n", __func__); 1260277b024eSKalle Valo 1261277b024eSKalle Valo f_do_rx_cur = 1; 1262277b024eSKalle Valo goto rx_curr_single; 1263277b024eSKalle Valo } 1264277b024eSKalle Valo 1265277b024eSKalle Valo if (!card->mpa_rx.enabled) { 1266277b024eSKalle Valo mwifiex_dbg(adapter, WARN, 1267277b024eSKalle Valo "info: %s: rx aggregation disabled\n", 1268277b024eSKalle Valo __func__); 1269277b024eSKalle Valo 1270277b024eSKalle Valo f_do_rx_cur = 1; 1271277b024eSKalle Valo goto rx_curr_single; 1272277b024eSKalle Valo } 1273277b024eSKalle Valo 1274277b024eSKalle Valo if ((!card->has_control_mask && (card->mp_rd_bitmap & 1275277b024eSKalle Valo card->reg->data_port_mask)) || 1276277b024eSKalle Valo (card->has_control_mask && (card->mp_rd_bitmap & 1277277b024eSKalle Valo (~((u32) CTRL_PORT_MASK))))) { 1278277b024eSKalle Valo /* Some more data RX pending */ 1279277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1280277b024eSKalle Valo "info: %s: not last packet\n", __func__); 1281277b024eSKalle Valo 1282277b024eSKalle Valo if (MP_RX_AGGR_IN_PROGRESS(card)) { 1283277b024eSKalle Valo if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) { 1284277b024eSKalle Valo f_aggr_cur = 1; 1285277b024eSKalle Valo } else { 1286277b024eSKalle Valo /* No room in Aggr buf, do rx aggr now */ 1287277b024eSKalle Valo f_do_rx_aggr = 1; 1288277b024eSKalle Valo f_post_aggr_cur = 1; 1289277b024eSKalle Valo } 1290277b024eSKalle Valo } else { 1291277b024eSKalle Valo /* Rx aggr not in progress */ 1292277b024eSKalle Valo f_aggr_cur = 1; 1293277b024eSKalle Valo } 1294277b024eSKalle Valo 1295277b024eSKalle Valo } else { 1296277b024eSKalle Valo /* No more data RX pending */ 1297277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1298277b024eSKalle Valo "info: %s: last packet\n", __func__); 1299277b024eSKalle Valo 1300277b024eSKalle Valo if (MP_RX_AGGR_IN_PROGRESS(card)) { 1301277b024eSKalle Valo f_do_rx_aggr = 1; 1302277b024eSKalle Valo if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) 1303277b024eSKalle Valo f_aggr_cur = 1; 1304277b024eSKalle Valo else 1305277b024eSKalle Valo /* No room in Aggr buf, do rx aggr now */ 1306277b024eSKalle Valo f_do_rx_cur = 1; 1307277b024eSKalle Valo } else { 1308277b024eSKalle Valo f_do_rx_cur = 1; 1309277b024eSKalle Valo } 1310277b024eSKalle Valo } 1311277b024eSKalle Valo 1312277b024eSKalle Valo if (f_aggr_cur) { 1313277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1314277b024eSKalle Valo "info: current packet aggregation\n"); 1315277b024eSKalle Valo /* Curr pkt can be aggregated */ 1316277b024eSKalle Valo mp_rx_aggr_setup(card, rx_len, port); 1317277b024eSKalle Valo 1318277b024eSKalle Valo if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || 1319277b024eSKalle Valo mp_rx_aggr_port_limit_reached(card)) { 1320277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1321277b024eSKalle Valo "info: %s: aggregated packet\t" 1322277b024eSKalle Valo "limit reached\n", __func__); 1323277b024eSKalle Valo /* No more pkts allowed in Aggr buf, rx it */ 1324277b024eSKalle Valo f_do_rx_aggr = 1; 1325277b024eSKalle Valo } 1326277b024eSKalle Valo } 1327277b024eSKalle Valo 1328277b024eSKalle Valo if (f_do_rx_aggr) { 1329277b024eSKalle Valo /* do aggr RX now */ 1330277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1331277b024eSKalle Valo "info: do_rx_aggr: num of packets: %d\n", 1332277b024eSKalle Valo card->mpa_rx.pkt_cnt); 1333277b024eSKalle Valo 1334277b024eSKalle Valo if (card->supports_sdio_new_mode) { 1335277b024eSKalle Valo int i; 1336277b024eSKalle Valo u32 port_count; 1337277b024eSKalle Valo 1338277b024eSKalle Valo for (i = 0, port_count = 0; i < card->max_ports; i++) 1339277b024eSKalle Valo if (card->mpa_rx.ports & BIT(i)) 1340277b024eSKalle Valo port_count++; 1341277b024eSKalle Valo 1342277b024eSKalle Valo /* Reading data from "start_port + 0" to "start_port + 1343277b024eSKalle Valo * port_count -1", so decrease the count by 1 1344277b024eSKalle Valo */ 1345277b024eSKalle Valo port_count--; 1346277b024eSKalle Valo mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | 1347277b024eSKalle Valo (port_count << 8)) + card->mpa_rx.start_port; 1348277b024eSKalle Valo } else { 1349277b024eSKalle Valo mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | 1350277b024eSKalle Valo (card->mpa_rx.ports << 4)) + 1351277b024eSKalle Valo card->mpa_rx.start_port; 1352277b024eSKalle Valo } 1353277b024eSKalle Valo 1354277b024eSKalle Valo if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, 1355277b024eSKalle Valo card->mpa_rx.buf_len, mport, 1)) 1356277b024eSKalle Valo goto error; 1357277b024eSKalle Valo 1358277b024eSKalle Valo curr_ptr = card->mpa_rx.buf; 1359277b024eSKalle Valo 1360277b024eSKalle Valo for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { 1361277b024eSKalle Valo u32 *len_arr = card->mpa_rx.len_arr; 1362277b024eSKalle Valo 1363277b024eSKalle Valo /* get curr PKT len & type */ 1364277b024eSKalle Valo pkt_len = le16_to_cpu(*(__le16 *) &curr_ptr[0]); 1365277b024eSKalle Valo pkt_type = le16_to_cpu(*(__le16 *) &curr_ptr[2]); 1366277b024eSKalle Valo 1367277b024eSKalle Valo /* copy pkt to deaggr buf */ 1368277b024eSKalle Valo skb_deaggr = mwifiex_alloc_dma_align_buf(len_arr[pind], 1369277b024eSKalle Valo GFP_KERNEL | 1370277b024eSKalle Valo GFP_DMA); 1371277b024eSKalle Valo if (!skb_deaggr) { 1372277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "skb allocation failure\t" 1373277b024eSKalle Valo "drop pkt len=%d type=%d\n", 1374277b024eSKalle Valo pkt_len, pkt_type); 1375277b024eSKalle Valo curr_ptr += len_arr[pind]; 1376277b024eSKalle Valo continue; 1377277b024eSKalle Valo } 1378277b024eSKalle Valo 1379277b024eSKalle Valo skb_put(skb_deaggr, len_arr[pind]); 1380277b024eSKalle Valo 1381277b024eSKalle Valo if ((pkt_type == MWIFIEX_TYPE_DATA || 1382277b024eSKalle Valo (pkt_type == MWIFIEX_TYPE_AGGR_DATA && 1383277b024eSKalle Valo adapter->sdio_rx_aggr_enable)) && 1384277b024eSKalle Valo (pkt_len <= len_arr[pind])) { 1385277b024eSKalle Valo 1386277b024eSKalle Valo memcpy(skb_deaggr->data, curr_ptr, pkt_len); 1387277b024eSKalle Valo 1388277b024eSKalle Valo skb_trim(skb_deaggr, pkt_len); 1389277b024eSKalle Valo 1390277b024eSKalle Valo /* Process de-aggr packet */ 1391277b024eSKalle Valo mwifiex_decode_rx_packet(adapter, skb_deaggr, 1392277b024eSKalle Valo pkt_type); 1393277b024eSKalle Valo } else { 1394277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1395277b024eSKalle Valo "drop wrong aggr pkt:\t" 1396277b024eSKalle Valo "sdio_single_port_rx_aggr=%d\t" 1397277b024eSKalle Valo "type=%d len=%d max_len=%d\n", 1398277b024eSKalle Valo adapter->sdio_rx_aggr_enable, 1399277b024eSKalle Valo pkt_type, pkt_len, len_arr[pind]); 1400277b024eSKalle Valo dev_kfree_skb_any(skb_deaggr); 1401277b024eSKalle Valo } 1402277b024eSKalle Valo curr_ptr += len_arr[pind]; 1403277b024eSKalle Valo } 1404277b024eSKalle Valo MP_RX_AGGR_BUF_RESET(card); 1405277b024eSKalle Valo } 1406277b024eSKalle Valo 1407277b024eSKalle Valo rx_curr_single: 1408277b024eSKalle Valo if (f_do_rx_cur) { 1409277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: RX: port: %d, rx_len: %d\n", 1410277b024eSKalle Valo port, rx_len); 1411277b024eSKalle Valo 1412277b024eSKalle Valo skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA); 1413277b024eSKalle Valo if (!skb) { 1414277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1415277b024eSKalle Valo "single skb allocated fail,\t" 1416277b024eSKalle Valo "drop pkt port=%d len=%d\n", port, rx_len); 1417277b024eSKalle Valo if (mwifiex_sdio_card_to_host(adapter, &pkt_type, 1418277b024eSKalle Valo card->mpa_rx.buf, rx_len, 1419277b024eSKalle Valo adapter->ioport + port)) 1420277b024eSKalle Valo goto error; 1421277b024eSKalle Valo return 0; 1422277b024eSKalle Valo } 1423277b024eSKalle Valo 1424277b024eSKalle Valo skb_put(skb, rx_len); 1425277b024eSKalle Valo 1426277b024eSKalle Valo if (mwifiex_sdio_card_to_host(adapter, &pkt_type, 1427277b024eSKalle Valo skb->data, skb->len, 1428277b024eSKalle Valo adapter->ioport + port)) 1429277b024eSKalle Valo goto error; 1430277b024eSKalle Valo if (!adapter->sdio_rx_aggr_enable && 1431277b024eSKalle Valo pkt_type == MWIFIEX_TYPE_AGGR_DATA) { 1432277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "drop wrong pkt type %d\t" 1433277b024eSKalle Valo "current SDIO RX Aggr not enabled\n", 1434277b024eSKalle Valo pkt_type); 1435277b024eSKalle Valo dev_kfree_skb_any(skb); 1436277b024eSKalle Valo return 0; 1437277b024eSKalle Valo } 1438277b024eSKalle Valo 1439277b024eSKalle Valo mwifiex_decode_rx_packet(adapter, skb, pkt_type); 1440277b024eSKalle Valo } 1441277b024eSKalle Valo if (f_post_aggr_cur) { 1442277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1443277b024eSKalle Valo "info: current packet aggregation\n"); 1444277b024eSKalle Valo /* Curr pkt can be aggregated */ 1445277b024eSKalle Valo mp_rx_aggr_setup(card, rx_len, port); 1446277b024eSKalle Valo } 1447277b024eSKalle Valo 1448277b024eSKalle Valo return 0; 1449277b024eSKalle Valo error: 1450277b024eSKalle Valo if (MP_RX_AGGR_IN_PROGRESS(card)) 1451277b024eSKalle Valo MP_RX_AGGR_BUF_RESET(card); 1452277b024eSKalle Valo 1453277b024eSKalle Valo if (f_do_rx_cur && skb) 1454277b024eSKalle Valo /* Single transfer pending. Free curr buff also */ 1455277b024eSKalle Valo dev_kfree_skb_any(skb); 1456277b024eSKalle Valo 1457277b024eSKalle Valo return -1; 1458277b024eSKalle Valo } 1459277b024eSKalle Valo 1460277b024eSKalle Valo /* 1461277b024eSKalle Valo * This function checks the current interrupt status. 1462277b024eSKalle Valo * 1463277b024eSKalle Valo * The following interrupts are checked and handled by this function - 1464277b024eSKalle Valo * - Data sent 1465277b024eSKalle Valo * - Command sent 1466277b024eSKalle Valo * - Packets received 1467277b024eSKalle Valo * 1468277b024eSKalle Valo * Since the firmware does not generate download ready interrupt if the 1469277b024eSKalle Valo * port updated is command port only, command sent interrupt checking 1470277b024eSKalle Valo * should be done manually, and for every SDIO interrupt. 1471277b024eSKalle Valo * 1472277b024eSKalle Valo * In case of Rx packets received, the packets are uploaded from card to 1473277b024eSKalle Valo * host and processed accordingly. 1474277b024eSKalle Valo */ 1475277b024eSKalle Valo static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) 1476277b024eSKalle Valo { 1477277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1478277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 1479277b024eSKalle Valo int ret = 0; 1480277b024eSKalle Valo u8 sdio_ireg; 1481277b024eSKalle Valo struct sk_buff *skb; 1482277b024eSKalle Valo u8 port = CTRL_PORT; 1483277b024eSKalle Valo u32 len_reg_l, len_reg_u; 1484277b024eSKalle Valo u32 rx_blocks; 1485277b024eSKalle Valo u16 rx_len; 1486277b024eSKalle Valo unsigned long flags; 1487277b024eSKalle Valo u32 bitmap; 1488277b024eSKalle Valo u8 cr; 1489277b024eSKalle Valo 1490277b024eSKalle Valo spin_lock_irqsave(&adapter->int_lock, flags); 1491277b024eSKalle Valo sdio_ireg = adapter->int_status; 1492277b024eSKalle Valo adapter->int_status = 0; 1493277b024eSKalle Valo spin_unlock_irqrestore(&adapter->int_lock, flags); 1494277b024eSKalle Valo 1495277b024eSKalle Valo if (!sdio_ireg) 1496277b024eSKalle Valo return ret; 1497277b024eSKalle Valo 1498277b024eSKalle Valo /* Following interrupt is only for SDIO new mode */ 1499277b024eSKalle Valo if (sdio_ireg & DN_LD_CMD_PORT_HOST_INT_STATUS && adapter->cmd_sent) 1500277b024eSKalle Valo adapter->cmd_sent = false; 1501277b024eSKalle Valo 1502277b024eSKalle Valo /* Following interrupt is only for SDIO new mode */ 1503277b024eSKalle Valo if (sdio_ireg & UP_LD_CMD_PORT_HOST_INT_STATUS) { 1504277b024eSKalle Valo u32 pkt_type; 1505277b024eSKalle Valo 1506277b024eSKalle Valo /* read the len of control packet */ 1507277b024eSKalle Valo rx_len = card->mp_regs[reg->cmd_rd_len_1] << 8; 1508277b024eSKalle Valo rx_len |= (u16)card->mp_regs[reg->cmd_rd_len_0]; 1509277b024eSKalle Valo rx_blocks = DIV_ROUND_UP(rx_len, MWIFIEX_SDIO_BLOCK_SIZE); 1510277b024eSKalle Valo if (rx_len <= INTF_HEADER_LEN || 1511277b024eSKalle Valo (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > 1512277b024eSKalle Valo MWIFIEX_RX_DATA_BUF_SIZE) 1513277b024eSKalle Valo return -1; 1514277b024eSKalle Valo rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); 1515277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n", rx_len); 1516277b024eSKalle Valo 1517277b024eSKalle Valo skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA); 1518277b024eSKalle Valo if (!skb) 1519277b024eSKalle Valo return -1; 1520277b024eSKalle Valo 1521277b024eSKalle Valo skb_put(skb, rx_len); 1522277b024eSKalle Valo 1523277b024eSKalle Valo if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data, 1524277b024eSKalle Valo skb->len, adapter->ioport | 1525277b024eSKalle Valo CMD_PORT_SLCT)) { 1526277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1527277b024eSKalle Valo "%s: failed to card_to_host", __func__); 1528277b024eSKalle Valo dev_kfree_skb_any(skb); 1529277b024eSKalle Valo goto term_cmd; 1530277b024eSKalle Valo } 1531277b024eSKalle Valo 1532277b024eSKalle Valo if ((pkt_type != MWIFIEX_TYPE_CMD) && 1533277b024eSKalle Valo (pkt_type != MWIFIEX_TYPE_EVENT)) 1534277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1535277b024eSKalle Valo "%s:Received wrong packet on cmd port", 1536277b024eSKalle Valo __func__); 1537277b024eSKalle Valo 1538277b024eSKalle Valo mwifiex_decode_rx_packet(adapter, skb, pkt_type); 1539277b024eSKalle Valo } 1540277b024eSKalle Valo 1541277b024eSKalle Valo if (sdio_ireg & DN_LD_HOST_INT_STATUS) { 1542277b024eSKalle Valo bitmap = (u32) card->mp_regs[reg->wr_bitmap_l]; 1543277b024eSKalle Valo bitmap |= ((u32) card->mp_regs[reg->wr_bitmap_u]) << 8; 1544277b024eSKalle Valo if (card->supports_sdio_new_mode) { 1545277b024eSKalle Valo bitmap |= 1546277b024eSKalle Valo ((u32) card->mp_regs[reg->wr_bitmap_1l]) << 16; 1547277b024eSKalle Valo bitmap |= 1548277b024eSKalle Valo ((u32) card->mp_regs[reg->wr_bitmap_1u]) << 24; 1549277b024eSKalle Valo } 1550277b024eSKalle Valo card->mp_wr_bitmap = bitmap; 1551277b024eSKalle Valo 1552277b024eSKalle Valo mwifiex_dbg(adapter, INTR, 1553277b024eSKalle Valo "int: DNLD: wr_bitmap=0x%x\n", 1554277b024eSKalle Valo card->mp_wr_bitmap); 1555277b024eSKalle Valo if (adapter->data_sent && 1556277b024eSKalle Valo (card->mp_wr_bitmap & card->mp_data_port_mask)) { 1557277b024eSKalle Valo mwifiex_dbg(adapter, INTR, 1558277b024eSKalle Valo "info: <--- Tx DONE Interrupt --->\n"); 1559277b024eSKalle Valo adapter->data_sent = false; 1560277b024eSKalle Valo } 1561277b024eSKalle Valo } 1562277b024eSKalle Valo 1563277b024eSKalle Valo /* As firmware will not generate download ready interrupt if the port 1564277b024eSKalle Valo updated is command port only, cmd_sent should be done for any SDIO 1565277b024eSKalle Valo interrupt. */ 1566277b024eSKalle Valo if (card->has_control_mask && adapter->cmd_sent) { 1567277b024eSKalle Valo /* Check if firmware has attach buffer at command port and 1568277b024eSKalle Valo update just that in wr_bit_map. */ 1569277b024eSKalle Valo card->mp_wr_bitmap |= 1570277b024eSKalle Valo (u32) card->mp_regs[reg->wr_bitmap_l] & CTRL_PORT_MASK; 1571277b024eSKalle Valo if (card->mp_wr_bitmap & CTRL_PORT_MASK) 1572277b024eSKalle Valo adapter->cmd_sent = false; 1573277b024eSKalle Valo } 1574277b024eSKalle Valo 1575277b024eSKalle Valo mwifiex_dbg(adapter, INTR, "info: cmd_sent=%d data_sent=%d\n", 1576277b024eSKalle Valo adapter->cmd_sent, adapter->data_sent); 1577277b024eSKalle Valo if (sdio_ireg & UP_LD_HOST_INT_STATUS) { 1578277b024eSKalle Valo bitmap = (u32) card->mp_regs[reg->rd_bitmap_l]; 1579277b024eSKalle Valo bitmap |= ((u32) card->mp_regs[reg->rd_bitmap_u]) << 8; 1580277b024eSKalle Valo if (card->supports_sdio_new_mode) { 1581277b024eSKalle Valo bitmap |= 1582277b024eSKalle Valo ((u32) card->mp_regs[reg->rd_bitmap_1l]) << 16; 1583277b024eSKalle Valo bitmap |= 1584277b024eSKalle Valo ((u32) card->mp_regs[reg->rd_bitmap_1u]) << 24; 1585277b024eSKalle Valo } 1586277b024eSKalle Valo card->mp_rd_bitmap = bitmap; 1587277b024eSKalle Valo mwifiex_dbg(adapter, INTR, 1588277b024eSKalle Valo "int: UPLD: rd_bitmap=0x%x\n", 1589277b024eSKalle Valo card->mp_rd_bitmap); 1590277b024eSKalle Valo 1591277b024eSKalle Valo while (true) { 1592277b024eSKalle Valo ret = mwifiex_get_rd_port(adapter, &port); 1593277b024eSKalle Valo if (ret) { 1594277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1595277b024eSKalle Valo "info: no more rd_port available\n"); 1596277b024eSKalle Valo break; 1597277b024eSKalle Valo } 1598277b024eSKalle Valo len_reg_l = reg->rd_len_p0_l + (port << 1); 1599277b024eSKalle Valo len_reg_u = reg->rd_len_p0_u + (port << 1); 1600277b024eSKalle Valo rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; 1601277b024eSKalle Valo rx_len |= (u16) card->mp_regs[len_reg_l]; 1602277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1603277b024eSKalle Valo "info: RX: port=%d rx_len=%u\n", 1604277b024eSKalle Valo port, rx_len); 1605277b024eSKalle Valo rx_blocks = 1606277b024eSKalle Valo (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - 1607277b024eSKalle Valo 1) / MWIFIEX_SDIO_BLOCK_SIZE; 1608277b024eSKalle Valo if (rx_len <= INTF_HEADER_LEN || 1609277b024eSKalle Valo (card->mpa_rx.enabled && 1610277b024eSKalle Valo ((rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > 1611277b024eSKalle Valo card->mpa_rx.buf_size))) { 1612277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1613277b024eSKalle Valo "invalid rx_len=%d\n", 1614277b024eSKalle Valo rx_len); 1615277b024eSKalle Valo return -1; 1616277b024eSKalle Valo } 1617277b024eSKalle Valo 1618277b024eSKalle Valo rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); 1619277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n", 1620277b024eSKalle Valo rx_len); 1621277b024eSKalle Valo 1622277b024eSKalle Valo if (mwifiex_sdio_card_to_host_mp_aggr(adapter, rx_len, 1623277b024eSKalle Valo port)) { 1624277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1625277b024eSKalle Valo "card_to_host_mpa failed: int status=%#x\n", 1626277b024eSKalle Valo sdio_ireg); 1627277b024eSKalle Valo goto term_cmd; 1628277b024eSKalle Valo } 1629277b024eSKalle Valo } 1630277b024eSKalle Valo } 1631277b024eSKalle Valo 1632277b024eSKalle Valo return 0; 1633277b024eSKalle Valo 1634277b024eSKalle Valo term_cmd: 1635277b024eSKalle Valo /* terminate cmd */ 1636277b024eSKalle Valo if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr)) 1637277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "read CFG reg failed\n"); 1638277b024eSKalle Valo else 1639277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1640277b024eSKalle Valo "info: CFG reg val = %d\n", cr); 1641277b024eSKalle Valo 1642277b024eSKalle Valo if (mwifiex_write_reg(adapter, CONFIGURATION_REG, (cr | 0x04))) 1643277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1644277b024eSKalle Valo "write CFG reg failed\n"); 1645277b024eSKalle Valo else 1646277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: write success\n"); 1647277b024eSKalle Valo 1648277b024eSKalle Valo if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr)) 1649277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1650277b024eSKalle Valo "read CFG reg failed\n"); 1651277b024eSKalle Valo else 1652277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1653277b024eSKalle Valo "info: CFG reg val =%x\n", cr); 1654277b024eSKalle Valo 1655277b024eSKalle Valo return -1; 1656277b024eSKalle Valo } 1657277b024eSKalle Valo 1658277b024eSKalle Valo /* 1659277b024eSKalle Valo * This function aggregates transmission buffers in driver and downloads 1660277b024eSKalle Valo * the aggregated packet to card. 1661277b024eSKalle Valo * 1662277b024eSKalle Valo * The individual packets are aggregated by copying into an aggregation 1663277b024eSKalle Valo * buffer and then downloaded to the card. Previous unsent packets in the 1664277b024eSKalle Valo * aggregation buffer are pre-copied first before new packets are added. 1665277b024eSKalle Valo * Aggregation is done till there is space left in the aggregation buffer, 1666277b024eSKalle Valo * or till new packets are available. 1667277b024eSKalle Valo * 1668277b024eSKalle Valo * The function will only download the packet to the card when aggregation 1669277b024eSKalle Valo * stops, otherwise it will just aggregate the packet in aggregation buffer 1670277b024eSKalle Valo * and return. 1671277b024eSKalle Valo */ 1672277b024eSKalle Valo static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, 1673277b024eSKalle Valo u8 *payload, u32 pkt_len, u32 port, 1674277b024eSKalle Valo u32 next_pkt_len) 1675277b024eSKalle Valo { 1676277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1677277b024eSKalle Valo int ret = 0; 1678277b024eSKalle Valo s32 f_send_aggr_buf = 0; 1679277b024eSKalle Valo s32 f_send_cur_buf = 0; 1680277b024eSKalle Valo s32 f_precopy_cur_buf = 0; 1681277b024eSKalle Valo s32 f_postcopy_cur_buf = 0; 1682277b024eSKalle Valo u32 mport; 1683277b024eSKalle Valo 1684277b024eSKalle Valo if (!card->mpa_tx.enabled || 1685277b024eSKalle Valo (card->has_control_mask && (port == CTRL_PORT)) || 1686277b024eSKalle Valo (card->supports_sdio_new_mode && (port == CMD_PORT_SLCT))) { 1687277b024eSKalle Valo mwifiex_dbg(adapter, WARN, 1688277b024eSKalle Valo "info: %s: tx aggregation disabled\n", 1689277b024eSKalle Valo __func__); 1690277b024eSKalle Valo 1691277b024eSKalle Valo f_send_cur_buf = 1; 1692277b024eSKalle Valo goto tx_curr_single; 1693277b024eSKalle Valo } 1694277b024eSKalle Valo 1695277b024eSKalle Valo if (next_pkt_len) { 1696277b024eSKalle Valo /* More pkt in TX queue */ 1697277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1698277b024eSKalle Valo "info: %s: more packets in queue.\n", 1699277b024eSKalle Valo __func__); 1700277b024eSKalle Valo 1701277b024eSKalle Valo if (MP_TX_AGGR_IN_PROGRESS(card)) { 1702277b024eSKalle Valo if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { 1703277b024eSKalle Valo f_precopy_cur_buf = 1; 1704277b024eSKalle Valo 1705277b024eSKalle Valo if (!(card->mp_wr_bitmap & 1706277b024eSKalle Valo (1 << card->curr_wr_port)) || 1707277b024eSKalle Valo !MP_TX_AGGR_BUF_HAS_ROOM( 1708277b024eSKalle Valo card, pkt_len + next_pkt_len)) 1709277b024eSKalle Valo f_send_aggr_buf = 1; 1710277b024eSKalle Valo } else { 1711277b024eSKalle Valo /* No room in Aggr buf, send it */ 1712277b024eSKalle Valo f_send_aggr_buf = 1; 1713277b024eSKalle Valo 1714277b024eSKalle Valo if (!(card->mp_wr_bitmap & 1715277b024eSKalle Valo (1 << card->curr_wr_port))) 1716277b024eSKalle Valo f_send_cur_buf = 1; 1717277b024eSKalle Valo else 1718277b024eSKalle Valo f_postcopy_cur_buf = 1; 1719277b024eSKalle Valo } 1720277b024eSKalle Valo } else { 1721277b024eSKalle Valo if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len) && 1722277b024eSKalle Valo (card->mp_wr_bitmap & (1 << card->curr_wr_port))) 1723277b024eSKalle Valo f_precopy_cur_buf = 1; 1724277b024eSKalle Valo else 1725277b024eSKalle Valo f_send_cur_buf = 1; 1726277b024eSKalle Valo } 1727277b024eSKalle Valo } else { 1728277b024eSKalle Valo /* Last pkt in TX queue */ 1729277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1730277b024eSKalle Valo "info: %s: Last packet in Tx Queue.\n", 1731277b024eSKalle Valo __func__); 1732277b024eSKalle Valo 1733277b024eSKalle Valo if (MP_TX_AGGR_IN_PROGRESS(card)) { 1734277b024eSKalle Valo /* some packs in Aggr buf already */ 1735277b024eSKalle Valo f_send_aggr_buf = 1; 1736277b024eSKalle Valo 1737277b024eSKalle Valo if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) 1738277b024eSKalle Valo f_precopy_cur_buf = 1; 1739277b024eSKalle Valo else 1740277b024eSKalle Valo /* No room in Aggr buf, send it */ 1741277b024eSKalle Valo f_send_cur_buf = 1; 1742277b024eSKalle Valo } else { 1743277b024eSKalle Valo f_send_cur_buf = 1; 1744277b024eSKalle Valo } 1745277b024eSKalle Valo } 1746277b024eSKalle Valo 1747277b024eSKalle Valo if (f_precopy_cur_buf) { 1748277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1749277b024eSKalle Valo "data: %s: precopy current buffer\n", 1750277b024eSKalle Valo __func__); 1751277b024eSKalle Valo MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); 1752277b024eSKalle Valo 1753277b024eSKalle Valo if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || 1754277b024eSKalle Valo mp_tx_aggr_port_limit_reached(card)) 1755277b024eSKalle Valo /* No more pkts allowed in Aggr buf, send it */ 1756277b024eSKalle Valo f_send_aggr_buf = 1; 1757277b024eSKalle Valo } 1758277b024eSKalle Valo 1759277b024eSKalle Valo if (f_send_aggr_buf) { 1760277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1761277b024eSKalle Valo "data: %s: send aggr buffer: %d %d\n", 1762277b024eSKalle Valo __func__, card->mpa_tx.start_port, 1763277b024eSKalle Valo card->mpa_tx.ports); 1764277b024eSKalle Valo if (card->supports_sdio_new_mode) { 1765277b024eSKalle Valo u32 port_count; 1766277b024eSKalle Valo int i; 1767277b024eSKalle Valo 1768277b024eSKalle Valo for (i = 0, port_count = 0; i < card->max_ports; i++) 1769277b024eSKalle Valo if (card->mpa_tx.ports & BIT(i)) 1770277b024eSKalle Valo port_count++; 1771277b024eSKalle Valo 1772277b024eSKalle Valo /* Writing data from "start_port + 0" to "start_port + 1773277b024eSKalle Valo * port_count -1", so decrease the count by 1 1774277b024eSKalle Valo */ 1775277b024eSKalle Valo port_count--; 1776277b024eSKalle Valo mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | 1777277b024eSKalle Valo (port_count << 8)) + card->mpa_tx.start_port; 1778277b024eSKalle Valo } else { 1779277b024eSKalle Valo mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | 1780277b024eSKalle Valo (card->mpa_tx.ports << 4)) + 1781277b024eSKalle Valo card->mpa_tx.start_port; 1782277b024eSKalle Valo } 1783277b024eSKalle Valo 1784277b024eSKalle Valo ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, 1785277b024eSKalle Valo card->mpa_tx.buf_len, mport); 1786277b024eSKalle Valo 1787277b024eSKalle Valo MP_TX_AGGR_BUF_RESET(card); 1788277b024eSKalle Valo } 1789277b024eSKalle Valo 1790277b024eSKalle Valo tx_curr_single: 1791277b024eSKalle Valo if (f_send_cur_buf) { 1792277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1793277b024eSKalle Valo "data: %s: send current buffer %d\n", 1794277b024eSKalle Valo __func__, port); 1795277b024eSKalle Valo ret = mwifiex_write_data_to_card(adapter, payload, pkt_len, 1796277b024eSKalle Valo adapter->ioport + port); 1797277b024eSKalle Valo } 1798277b024eSKalle Valo 1799277b024eSKalle Valo if (f_postcopy_cur_buf) { 1800277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1801277b024eSKalle Valo "data: %s: postcopy current buffer\n", 1802277b024eSKalle Valo __func__); 1803277b024eSKalle Valo MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); 1804277b024eSKalle Valo } 1805277b024eSKalle Valo 1806277b024eSKalle Valo return ret; 1807277b024eSKalle Valo } 1808277b024eSKalle Valo 1809277b024eSKalle Valo /* 1810277b024eSKalle Valo * This function downloads data from driver to card. 1811277b024eSKalle Valo * 1812277b024eSKalle Valo * Both commands and data packets are transferred to the card by this 1813277b024eSKalle Valo * function. 1814277b024eSKalle Valo * 1815277b024eSKalle Valo * This function adds the SDIO specific header to the front of the buffer 1816277b024eSKalle Valo * before transferring. The header contains the length of the packet and 1817277b024eSKalle Valo * the type. The firmware handles the packets based upon this set type. 1818277b024eSKalle Valo */ 1819277b024eSKalle Valo static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, 1820277b024eSKalle Valo u8 type, struct sk_buff *skb, 1821277b024eSKalle Valo struct mwifiex_tx_param *tx_param) 1822277b024eSKalle Valo { 1823277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1824277b024eSKalle Valo int ret; 1825277b024eSKalle Valo u32 buf_block_len; 1826277b024eSKalle Valo u32 blk_size; 1827277b024eSKalle Valo u32 port = CTRL_PORT; 1828277b024eSKalle Valo u8 *payload = (u8 *)skb->data; 1829277b024eSKalle Valo u32 pkt_len = skb->len; 1830277b024eSKalle Valo 1831277b024eSKalle Valo /* Allocate buffer and copy payload */ 1832277b024eSKalle Valo blk_size = MWIFIEX_SDIO_BLOCK_SIZE; 1833277b024eSKalle Valo buf_block_len = (pkt_len + blk_size - 1) / blk_size; 1834277b024eSKalle Valo *(__le16 *)&payload[0] = cpu_to_le16((u16)pkt_len); 1835277b024eSKalle Valo *(__le16 *)&payload[2] = cpu_to_le16(type); 1836277b024eSKalle Valo 1837277b024eSKalle Valo /* 1838277b024eSKalle Valo * This is SDIO specific header 1839277b024eSKalle Valo * u16 length, 1840277b024eSKalle Valo * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1, 1841277b024eSKalle Valo * MWIFIEX_TYPE_EVENT = 3) 1842277b024eSKalle Valo */ 1843277b024eSKalle Valo if (type == MWIFIEX_TYPE_DATA) { 1844277b024eSKalle Valo ret = mwifiex_get_wr_port_data(adapter, &port); 1845277b024eSKalle Valo if (ret) { 1846277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1847277b024eSKalle Valo "%s: no wr_port available\n", 1848277b024eSKalle Valo __func__); 1849277b024eSKalle Valo return ret; 1850277b024eSKalle Valo } 1851277b024eSKalle Valo } else { 1852277b024eSKalle Valo adapter->cmd_sent = true; 1853277b024eSKalle Valo /* Type must be MWIFIEX_TYPE_CMD */ 1854277b024eSKalle Valo 1855277b024eSKalle Valo if (pkt_len <= INTF_HEADER_LEN || 1856277b024eSKalle Valo pkt_len > MWIFIEX_UPLD_SIZE) 1857277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1858277b024eSKalle Valo "%s: payload=%p, nb=%d\n", 1859277b024eSKalle Valo __func__, payload, pkt_len); 1860277b024eSKalle Valo 1861277b024eSKalle Valo if (card->supports_sdio_new_mode) 1862277b024eSKalle Valo port = CMD_PORT_SLCT; 1863277b024eSKalle Valo } 1864277b024eSKalle Valo 1865277b024eSKalle Valo /* Transfer data to card */ 1866277b024eSKalle Valo pkt_len = buf_block_len * blk_size; 1867277b024eSKalle Valo 1868277b024eSKalle Valo if (tx_param) 1869277b024eSKalle Valo ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, 1870277b024eSKalle Valo port, tx_param->next_pkt_len 1871277b024eSKalle Valo ); 1872277b024eSKalle Valo else 1873277b024eSKalle Valo ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, 1874277b024eSKalle Valo port, 0); 1875277b024eSKalle Valo 1876277b024eSKalle Valo if (ret) { 1877277b024eSKalle Valo if (type == MWIFIEX_TYPE_CMD) 1878277b024eSKalle Valo adapter->cmd_sent = false; 1879277b024eSKalle Valo if (type == MWIFIEX_TYPE_DATA) { 1880277b024eSKalle Valo adapter->data_sent = false; 1881277b024eSKalle Valo /* restore curr_wr_port in error cases */ 1882277b024eSKalle Valo card->curr_wr_port = port; 1883277b024eSKalle Valo card->mp_wr_bitmap |= (u32)(1 << card->curr_wr_port); 1884277b024eSKalle Valo } 1885277b024eSKalle Valo } else { 1886277b024eSKalle Valo if (type == MWIFIEX_TYPE_DATA) { 1887277b024eSKalle Valo if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) 1888277b024eSKalle Valo adapter->data_sent = true; 1889277b024eSKalle Valo else 1890277b024eSKalle Valo adapter->data_sent = false; 1891277b024eSKalle Valo } 1892277b024eSKalle Valo } 1893277b024eSKalle Valo 1894277b024eSKalle Valo return ret; 1895277b024eSKalle Valo } 1896277b024eSKalle Valo 1897277b024eSKalle Valo /* 1898277b024eSKalle Valo * This function allocates the MPA Tx and Rx buffers. 1899277b024eSKalle Valo */ 1900277b024eSKalle Valo static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, 1901277b024eSKalle Valo u32 mpa_tx_buf_size, u32 mpa_rx_buf_size) 1902277b024eSKalle Valo { 1903277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1904277b024eSKalle Valo u32 rx_buf_size; 1905277b024eSKalle Valo int ret = 0; 1906277b024eSKalle Valo 1907277b024eSKalle Valo card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); 1908277b024eSKalle Valo if (!card->mpa_tx.buf) { 1909277b024eSKalle Valo ret = -1; 1910277b024eSKalle Valo goto error; 1911277b024eSKalle Valo } 1912277b024eSKalle Valo 1913277b024eSKalle Valo card->mpa_tx.buf_size = mpa_tx_buf_size; 1914277b024eSKalle Valo 1915277b024eSKalle Valo rx_buf_size = max_t(u32, mpa_rx_buf_size, 1916277b024eSKalle Valo (u32)SDIO_MAX_AGGR_BUF_SIZE); 1917277b024eSKalle Valo card->mpa_rx.buf = kzalloc(rx_buf_size, GFP_KERNEL); 1918277b024eSKalle Valo if (!card->mpa_rx.buf) { 1919277b024eSKalle Valo ret = -1; 1920277b024eSKalle Valo goto error; 1921277b024eSKalle Valo } 1922277b024eSKalle Valo 1923277b024eSKalle Valo card->mpa_rx.buf_size = rx_buf_size; 1924277b024eSKalle Valo 1925277b024eSKalle Valo error: 1926277b024eSKalle Valo if (ret) { 1927277b024eSKalle Valo kfree(card->mpa_tx.buf); 1928277b024eSKalle Valo kfree(card->mpa_rx.buf); 1929277b024eSKalle Valo card->mpa_tx.buf_size = 0; 1930277b024eSKalle Valo card->mpa_rx.buf_size = 0; 1931277b024eSKalle Valo } 1932277b024eSKalle Valo 1933277b024eSKalle Valo return ret; 1934277b024eSKalle Valo } 1935277b024eSKalle Valo 1936277b024eSKalle Valo /* 1937277b024eSKalle Valo * This function unregisters the SDIO device. 1938277b024eSKalle Valo * 1939277b024eSKalle Valo * The SDIO IRQ is released, the function is disabled and driver 1940277b024eSKalle Valo * data is set to null. 1941277b024eSKalle Valo */ 1942277b024eSKalle Valo static void 1943277b024eSKalle Valo mwifiex_unregister_dev(struct mwifiex_adapter *adapter) 1944277b024eSKalle Valo { 1945277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1946277b024eSKalle Valo 1947277b024eSKalle Valo if (adapter->card) { 1948277b024eSKalle Valo sdio_claim_host(card->func); 1949277b024eSKalle Valo sdio_disable_func(card->func); 1950277b024eSKalle Valo sdio_release_host(card->func); 1951277b024eSKalle Valo } 1952277b024eSKalle Valo } 1953277b024eSKalle Valo 1954277b024eSKalle Valo /* 1955277b024eSKalle Valo * This function registers the SDIO device. 1956277b024eSKalle Valo * 1957277b024eSKalle Valo * SDIO IRQ is claimed, block size is set and driver data is initialized. 1958277b024eSKalle Valo */ 1959277b024eSKalle Valo static int mwifiex_register_dev(struct mwifiex_adapter *adapter) 1960277b024eSKalle Valo { 1961277b024eSKalle Valo int ret; 1962277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1963277b024eSKalle Valo struct sdio_func *func = card->func; 1964277b024eSKalle Valo 1965277b024eSKalle Valo /* save adapter pointer in card */ 1966277b024eSKalle Valo card->adapter = adapter; 1967277b024eSKalle Valo adapter->tx_buf_size = card->tx_buf_size; 1968277b024eSKalle Valo 1969277b024eSKalle Valo sdio_claim_host(func); 1970277b024eSKalle Valo 1971277b024eSKalle Valo /* Set block size */ 1972277b024eSKalle Valo ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); 1973277b024eSKalle Valo sdio_release_host(func); 1974277b024eSKalle Valo if (ret) { 1975277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1976277b024eSKalle Valo "cannot set SDIO block size\n"); 1977277b024eSKalle Valo return ret; 1978277b024eSKalle Valo } 1979277b024eSKalle Valo 1980277b024eSKalle Valo 1981277b024eSKalle Valo adapter->dev = &func->dev; 1982277b024eSKalle Valo 1983277b024eSKalle Valo strcpy(adapter->fw_name, card->firmware); 1984277b024eSKalle Valo if (card->fw_dump_enh) { 1985277b024eSKalle Valo adapter->mem_type_mapping_tbl = generic_mem_type_map; 1986277b024eSKalle Valo adapter->num_mem_types = 1; 1987277b024eSKalle Valo } else { 1988277b024eSKalle Valo adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; 1989277b024eSKalle Valo adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); 1990277b024eSKalle Valo } 1991277b024eSKalle Valo 1992277b024eSKalle Valo return 0; 1993277b024eSKalle Valo } 1994277b024eSKalle Valo 1995277b024eSKalle Valo /* 1996277b024eSKalle Valo * This function initializes the SDIO driver. 1997277b024eSKalle Valo * 1998277b024eSKalle Valo * The following initializations steps are followed - 1999277b024eSKalle Valo * - Read the Host interrupt status register to acknowledge 2000277b024eSKalle Valo * the first interrupt got from bootloader 2001277b024eSKalle Valo * - Disable host interrupt mask register 2002277b024eSKalle Valo * - Get SDIO port 2003277b024eSKalle Valo * - Initialize SDIO variables in card 2004277b024eSKalle Valo * - Allocate MP registers 2005277b024eSKalle Valo * - Allocate MPA Tx and Rx buffers 2006277b024eSKalle Valo */ 2007277b024eSKalle Valo static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) 2008277b024eSKalle Valo { 2009277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2010277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 2011277b024eSKalle Valo int ret; 2012277b024eSKalle Valo u8 sdio_ireg; 2013277b024eSKalle Valo 2014277b024eSKalle Valo sdio_set_drvdata(card->func, card); 2015277b024eSKalle Valo 2016277b024eSKalle Valo /* 2017277b024eSKalle Valo * Read the host_int_status_reg for ACK the first interrupt got 2018277b024eSKalle Valo * from the bootloader. If we don't do this we get a interrupt 2019277b024eSKalle Valo * as soon as we register the irq. 2020277b024eSKalle Valo */ 2021277b024eSKalle Valo mwifiex_read_reg(adapter, card->reg->host_int_status_reg, &sdio_ireg); 2022277b024eSKalle Valo 2023277b024eSKalle Valo /* Get SDIO ioport */ 2024277b024eSKalle Valo mwifiex_init_sdio_ioport(adapter); 2025277b024eSKalle Valo 2026277b024eSKalle Valo /* Initialize SDIO variables in card */ 2027277b024eSKalle Valo card->mp_rd_bitmap = 0; 2028277b024eSKalle Valo card->mp_wr_bitmap = 0; 2029277b024eSKalle Valo card->curr_rd_port = reg->start_rd_port; 2030277b024eSKalle Valo card->curr_wr_port = reg->start_wr_port; 2031277b024eSKalle Valo 2032277b024eSKalle Valo card->mp_data_port_mask = reg->data_port_mask; 2033277b024eSKalle Valo 2034277b024eSKalle Valo card->mpa_tx.buf_len = 0; 2035277b024eSKalle Valo card->mpa_tx.pkt_cnt = 0; 2036277b024eSKalle Valo card->mpa_tx.start_port = 0; 2037277b024eSKalle Valo 2038277b024eSKalle Valo card->mpa_tx.enabled = 1; 2039277b024eSKalle Valo card->mpa_tx.pkt_aggr_limit = card->mp_agg_pkt_limit; 2040277b024eSKalle Valo 2041277b024eSKalle Valo card->mpa_rx.buf_len = 0; 2042277b024eSKalle Valo card->mpa_rx.pkt_cnt = 0; 2043277b024eSKalle Valo card->mpa_rx.start_port = 0; 2044277b024eSKalle Valo 2045277b024eSKalle Valo card->mpa_rx.enabled = 1; 2046277b024eSKalle Valo card->mpa_rx.pkt_aggr_limit = card->mp_agg_pkt_limit; 2047277b024eSKalle Valo 2048277b024eSKalle Valo /* Allocate buffers for SDIO MP-A */ 2049277b024eSKalle Valo card->mp_regs = kzalloc(reg->max_mp_regs, GFP_KERNEL); 2050277b024eSKalle Valo if (!card->mp_regs) 2051277b024eSKalle Valo return -ENOMEM; 2052277b024eSKalle Valo 2053277b024eSKalle Valo /* Allocate skb pointer buffers */ 2054277b024eSKalle Valo card->mpa_rx.skb_arr = kzalloc((sizeof(void *)) * 2055277b024eSKalle Valo card->mp_agg_pkt_limit, GFP_KERNEL); 2056*50f85e22SInsu Yun if (!card->mpa_rx.skb_arr) { 2057*50f85e22SInsu Yun kfree(card->mp_regs); 2058*50f85e22SInsu Yun return -ENOMEM; 2059*50f85e22SInsu Yun } 2060*50f85e22SInsu Yun 2061277b024eSKalle Valo card->mpa_rx.len_arr = kzalloc(sizeof(*card->mpa_rx.len_arr) * 2062277b024eSKalle Valo card->mp_agg_pkt_limit, GFP_KERNEL); 2063*50f85e22SInsu Yun if (!card->mpa_rx.len_arr) { 2064*50f85e22SInsu Yun kfree(card->mp_regs); 2065*50f85e22SInsu Yun kfree(card->mpa_rx.skb_arr); 2066*50f85e22SInsu Yun return -ENOMEM; 2067*50f85e22SInsu Yun } 2068*50f85e22SInsu Yun 2069277b024eSKalle Valo ret = mwifiex_alloc_sdio_mpa_buffers(adapter, 2070277b024eSKalle Valo card->mp_tx_agg_buf_size, 2071277b024eSKalle Valo card->mp_rx_agg_buf_size); 2072277b024eSKalle Valo 2073277b024eSKalle Valo /* Allocate 32k MPA Tx/Rx buffers if 64k memory allocation fails */ 2074277b024eSKalle Valo if (ret && (card->mp_tx_agg_buf_size == MWIFIEX_MP_AGGR_BUF_SIZE_MAX || 2075277b024eSKalle Valo card->mp_rx_agg_buf_size == MWIFIEX_MP_AGGR_BUF_SIZE_MAX)) { 2076277b024eSKalle Valo /* Disable rx single port aggregation */ 2077277b024eSKalle Valo adapter->host_disable_sdio_rx_aggr = true; 2078277b024eSKalle Valo 2079277b024eSKalle Valo ret = mwifiex_alloc_sdio_mpa_buffers 2080277b024eSKalle Valo (adapter, MWIFIEX_MP_AGGR_BUF_SIZE_32K, 2081277b024eSKalle Valo MWIFIEX_MP_AGGR_BUF_SIZE_32K); 2082277b024eSKalle Valo if (ret) { 2083277b024eSKalle Valo /* Disable multi port aggregation */ 2084277b024eSKalle Valo card->mpa_tx.enabled = 0; 2085277b024eSKalle Valo card->mpa_rx.enabled = 0; 2086277b024eSKalle Valo } 2087277b024eSKalle Valo } 2088277b024eSKalle Valo 2089277b024eSKalle Valo adapter->auto_tdls = card->can_auto_tdls; 2090277b024eSKalle Valo adapter->ext_scan = card->can_ext_scan; 2091277b024eSKalle Valo return 0; 2092277b024eSKalle Valo } 2093277b024eSKalle Valo 2094277b024eSKalle Valo /* 2095277b024eSKalle Valo * This function resets the MPA Tx and Rx buffers. 2096277b024eSKalle Valo */ 2097277b024eSKalle Valo static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter) 2098277b024eSKalle Valo { 2099277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2100277b024eSKalle Valo 2101277b024eSKalle Valo MP_TX_AGGR_BUF_RESET(card); 2102277b024eSKalle Valo MP_RX_AGGR_BUF_RESET(card); 2103277b024eSKalle Valo } 2104277b024eSKalle Valo 2105277b024eSKalle Valo /* 2106277b024eSKalle Valo * This function cleans up the allocated card buffers. 2107277b024eSKalle Valo * 2108277b024eSKalle Valo * The following are freed by this function - 2109277b024eSKalle Valo * - MP registers 2110277b024eSKalle Valo * - MPA Tx buffer 2111277b024eSKalle Valo * - MPA Rx buffer 2112277b024eSKalle Valo */ 2113277b024eSKalle Valo static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter) 2114277b024eSKalle Valo { 2115277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2116277b024eSKalle Valo 2117277b024eSKalle Valo kfree(card->mp_regs); 2118277b024eSKalle Valo kfree(card->mpa_rx.skb_arr); 2119277b024eSKalle Valo kfree(card->mpa_rx.len_arr); 2120277b024eSKalle Valo kfree(card->mpa_tx.buf); 2121277b024eSKalle Valo kfree(card->mpa_rx.buf); 2122277b024eSKalle Valo sdio_set_drvdata(card->func, NULL); 2123277b024eSKalle Valo kfree(card); 2124277b024eSKalle Valo } 2125277b024eSKalle Valo 2126277b024eSKalle Valo /* 2127277b024eSKalle Valo * This function updates the MP end port in card. 2128277b024eSKalle Valo */ 2129277b024eSKalle Valo static void 2130277b024eSKalle Valo mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) 2131277b024eSKalle Valo { 2132277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2133277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 2134277b024eSKalle Valo int i; 2135277b024eSKalle Valo 2136277b024eSKalle Valo card->mp_end_port = port; 2137277b024eSKalle Valo 2138277b024eSKalle Valo card->mp_data_port_mask = reg->data_port_mask; 2139277b024eSKalle Valo 2140277b024eSKalle Valo if (reg->start_wr_port) { 2141277b024eSKalle Valo for (i = 1; i <= card->max_ports - card->mp_end_port; i++) 2142277b024eSKalle Valo card->mp_data_port_mask &= 2143277b024eSKalle Valo ~(1 << (card->max_ports - i)); 2144277b024eSKalle Valo } 2145277b024eSKalle Valo 2146277b024eSKalle Valo card->curr_wr_port = reg->start_wr_port; 2147277b024eSKalle Valo 2148277b024eSKalle Valo mwifiex_dbg(adapter, CMD, 2149277b024eSKalle Valo "cmd: mp_end_port %d, data port mask 0x%x\n", 2150277b024eSKalle Valo port, card->mp_data_port_mask); 2151277b024eSKalle Valo } 2152277b024eSKalle Valo 2153277b024eSKalle Valo static void mwifiex_recreate_adapter(struct sdio_mmc_card *card) 2154277b024eSKalle Valo { 2155277b024eSKalle Valo struct sdio_func *func = card->func; 2156277b024eSKalle Valo const struct sdio_device_id *device_id = card->device_id; 2157277b024eSKalle Valo 2158277b024eSKalle Valo /* TODO mmc_hw_reset does not require destroying and re-probing the 2159277b024eSKalle Valo * whole adapter. Hence there was no need to for this rube-goldberg 2160277b024eSKalle Valo * design to reload the fw from an external workqueue. If we don't 2161277b024eSKalle Valo * destroy the adapter we could reload the fw from 2162277b024eSKalle Valo * mwifiex_main_work_queue directly. 2163277b024eSKalle Valo * The real difficulty with fw reset is to restore all the user 2164277b024eSKalle Valo * settings applied through ioctl. By destroying and recreating the 2165277b024eSKalle Valo * adapter, we take the easy way out, since we rely on user space to 2166277b024eSKalle Valo * restore them. We assume that user space will treat the new 2167277b024eSKalle Valo * incarnation of the adapter(interfaces) as if they had been just 2168277b024eSKalle Valo * discovered and initializes them from scratch. 2169277b024eSKalle Valo */ 2170277b024eSKalle Valo 2171277b024eSKalle Valo mwifiex_sdio_remove(func); 2172277b024eSKalle Valo 2173277b024eSKalle Valo /* power cycle the adapter */ 2174277b024eSKalle Valo sdio_claim_host(func); 2175277b024eSKalle Valo mmc_hw_reset(func->card->host); 2176277b024eSKalle Valo sdio_release_host(func); 2177277b024eSKalle Valo 2178277b024eSKalle Valo mwifiex_sdio_probe(func, device_id); 2179277b024eSKalle Valo } 2180277b024eSKalle Valo 2181277b024eSKalle Valo static struct mwifiex_adapter *save_adapter; 2182277b024eSKalle Valo static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) 2183277b024eSKalle Valo { 2184277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2185277b024eSKalle Valo 2186277b024eSKalle Valo /* TODO card pointer is unprotected. If the adapter is removed 2187277b024eSKalle Valo * physically, sdio core might trigger mwifiex_sdio_remove, before this 2188277b024eSKalle Valo * workqueue is run, which will destroy the adapter struct. When this 2189277b024eSKalle Valo * workqueue eventually exceutes it will dereference an invalid adapter 2190277b024eSKalle Valo * pointer 2191277b024eSKalle Valo */ 2192277b024eSKalle Valo mwifiex_recreate_adapter(card); 2193277b024eSKalle Valo } 2194277b024eSKalle Valo 2195277b024eSKalle Valo /* This function read/write firmware */ 2196277b024eSKalle Valo static enum 2197277b024eSKalle Valo rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, 2198277b024eSKalle Valo u8 doneflag) 2199277b024eSKalle Valo { 2200277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2201277b024eSKalle Valo int ret, tries; 2202277b024eSKalle Valo u8 ctrl_data = 0; 2203277b024eSKalle Valo 2204277b024eSKalle Valo sdio_writeb(card->func, card->reg->fw_dump_host_ready, 2205277b024eSKalle Valo card->reg->fw_dump_ctrl, &ret); 2206277b024eSKalle Valo if (ret) { 2207277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO Write ERR\n"); 2208277b024eSKalle Valo return RDWR_STATUS_FAILURE; 2209277b024eSKalle Valo } 2210277b024eSKalle Valo for (tries = 0; tries < MAX_POLL_TRIES; tries++) { 2211277b024eSKalle Valo ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl, 2212277b024eSKalle Valo &ret); 2213277b024eSKalle Valo if (ret) { 2214277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO read err\n"); 2215277b024eSKalle Valo return RDWR_STATUS_FAILURE; 2216277b024eSKalle Valo } 2217277b024eSKalle Valo if (ctrl_data == FW_DUMP_DONE) 2218277b024eSKalle Valo break; 2219277b024eSKalle Valo if (doneflag && ctrl_data == doneflag) 2220277b024eSKalle Valo return RDWR_STATUS_DONE; 2221277b024eSKalle Valo if (ctrl_data != card->reg->fw_dump_host_ready) { 2222277b024eSKalle Valo mwifiex_dbg(adapter, WARN, 2223277b024eSKalle Valo "The ctrl reg was changed, re-try again\n"); 2224277b024eSKalle Valo sdio_writeb(card->func, card->reg->fw_dump_host_ready, 2225277b024eSKalle Valo card->reg->fw_dump_ctrl, &ret); 2226277b024eSKalle Valo if (ret) { 2227277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO write err\n"); 2228277b024eSKalle Valo return RDWR_STATUS_FAILURE; 2229277b024eSKalle Valo } 2230277b024eSKalle Valo } 2231277b024eSKalle Valo usleep_range(100, 200); 2232277b024eSKalle Valo } 2233277b024eSKalle Valo if (ctrl_data == card->reg->fw_dump_host_ready) { 2234277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2235277b024eSKalle Valo "Fail to pull ctrl_data\n"); 2236277b024eSKalle Valo return RDWR_STATUS_FAILURE; 2237277b024eSKalle Valo } 2238277b024eSKalle Valo 2239277b024eSKalle Valo return RDWR_STATUS_SUCCESS; 2240277b024eSKalle Valo } 2241277b024eSKalle Valo 2242277b024eSKalle Valo /* This function dump firmware memory to file */ 2243277b024eSKalle Valo static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter) 2244277b024eSKalle Valo { 2245277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2246277b024eSKalle Valo int ret = 0; 2247277b024eSKalle Valo unsigned int reg, reg_start, reg_end; 2248277b024eSKalle Valo u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0; 2249277b024eSKalle Valo enum rdwr_status stat; 2250277b024eSKalle Valo u32 memory_size; 2251277b024eSKalle Valo 2252277b024eSKalle Valo if (!card->can_dump_fw) 2253277b024eSKalle Valo return; 2254277b024eSKalle Valo 2255277b024eSKalle Valo for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) { 2256277b024eSKalle Valo struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; 2257277b024eSKalle Valo 2258277b024eSKalle Valo if (entry->mem_ptr) { 2259277b024eSKalle Valo vfree(entry->mem_ptr); 2260277b024eSKalle Valo entry->mem_ptr = NULL; 2261277b024eSKalle Valo } 2262277b024eSKalle Valo entry->mem_size = 0; 2263277b024eSKalle Valo } 2264277b024eSKalle Valo 2265277b024eSKalle Valo mwifiex_pm_wakeup_card(adapter); 2266277b024eSKalle Valo sdio_claim_host(card->func); 2267277b024eSKalle Valo 2268277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n"); 2269277b024eSKalle Valo 2270277b024eSKalle Valo stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); 2271277b024eSKalle Valo if (stat == RDWR_STATUS_FAILURE) 2272277b024eSKalle Valo goto done; 2273277b024eSKalle Valo 2274277b024eSKalle Valo reg = card->reg->fw_dump_start; 2275277b024eSKalle Valo /* Read the number of the memories which will dump */ 2276277b024eSKalle Valo dump_num = sdio_readb(card->func, reg, &ret); 2277277b024eSKalle Valo if (ret) { 2278277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO read memory length err\n"); 2279277b024eSKalle Valo goto done; 2280277b024eSKalle Valo } 2281277b024eSKalle Valo 2282277b024eSKalle Valo /* Read the length of every memory which will dump */ 2283277b024eSKalle Valo for (idx = 0; idx < dump_num; idx++) { 2284277b024eSKalle Valo struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; 2285277b024eSKalle Valo 2286277b024eSKalle Valo stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); 2287277b024eSKalle Valo if (stat == RDWR_STATUS_FAILURE) 2288277b024eSKalle Valo goto done; 2289277b024eSKalle Valo 2290277b024eSKalle Valo memory_size = 0; 2291277b024eSKalle Valo reg = card->reg->fw_dump_start; 2292277b024eSKalle Valo for (i = 0; i < 4; i++) { 2293277b024eSKalle Valo read_reg = sdio_readb(card->func, reg, &ret); 2294277b024eSKalle Valo if (ret) { 2295277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO read err\n"); 2296277b024eSKalle Valo goto done; 2297277b024eSKalle Valo } 2298277b024eSKalle Valo memory_size |= (read_reg << i*8); 2299277b024eSKalle Valo reg++; 2300277b024eSKalle Valo } 2301277b024eSKalle Valo 2302277b024eSKalle Valo if (memory_size == 0) { 2303277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, "Firmware dump Finished!\n"); 2304277b024eSKalle Valo ret = mwifiex_write_reg(adapter, 2305277b024eSKalle Valo card->reg->fw_dump_ctrl, 2306277b024eSKalle Valo FW_DUMP_READ_DONE); 2307277b024eSKalle Valo if (ret) { 2308277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO write err\n"); 2309277b024eSKalle Valo return; 2310277b024eSKalle Valo } 2311277b024eSKalle Valo break; 2312277b024eSKalle Valo } 2313277b024eSKalle Valo 2314277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, 2315277b024eSKalle Valo "%s_SIZE=0x%x\n", entry->mem_name, memory_size); 2316277b024eSKalle Valo entry->mem_ptr = vmalloc(memory_size + 1); 2317277b024eSKalle Valo entry->mem_size = memory_size; 2318277b024eSKalle Valo if (!entry->mem_ptr) { 2319277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "Vmalloc %s failed\n", 2320277b024eSKalle Valo entry->mem_name); 2321277b024eSKalle Valo goto done; 2322277b024eSKalle Valo } 2323277b024eSKalle Valo dbg_ptr = entry->mem_ptr; 2324277b024eSKalle Valo end_ptr = dbg_ptr + memory_size; 2325277b024eSKalle Valo 2326277b024eSKalle Valo doneflag = entry->done_flag; 2327277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, 2328277b024eSKalle Valo "Start %s output, please wait...\n", 2329277b024eSKalle Valo entry->mem_name); 2330277b024eSKalle Valo 2331277b024eSKalle Valo do { 2332277b024eSKalle Valo stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); 2333277b024eSKalle Valo if (stat == RDWR_STATUS_FAILURE) 2334277b024eSKalle Valo goto done; 2335277b024eSKalle Valo 2336277b024eSKalle Valo reg_start = card->reg->fw_dump_start; 2337277b024eSKalle Valo reg_end = card->reg->fw_dump_end; 2338277b024eSKalle Valo for (reg = reg_start; reg <= reg_end; reg++) { 2339277b024eSKalle Valo *dbg_ptr = sdio_readb(card->func, reg, &ret); 2340277b024eSKalle Valo if (ret) { 2341277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2342277b024eSKalle Valo "SDIO read err\n"); 2343277b024eSKalle Valo goto done; 2344277b024eSKalle Valo } 2345277b024eSKalle Valo if (dbg_ptr < end_ptr) 2346277b024eSKalle Valo dbg_ptr++; 2347277b024eSKalle Valo else 2348277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2349277b024eSKalle Valo "Allocated buf not enough\n"); 2350277b024eSKalle Valo } 2351277b024eSKalle Valo 2352277b024eSKalle Valo if (stat != RDWR_STATUS_DONE) 2353277b024eSKalle Valo continue; 2354277b024eSKalle Valo 2355277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, "%s done: size=0x%tx\n", 2356277b024eSKalle Valo entry->mem_name, dbg_ptr - entry->mem_ptr); 2357277b024eSKalle Valo break; 2358277b024eSKalle Valo } while (1); 2359277b024eSKalle Valo } 2360277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n"); 2361277b024eSKalle Valo 2362277b024eSKalle Valo done: 2363277b024eSKalle Valo sdio_release_host(card->func); 2364277b024eSKalle Valo } 2365277b024eSKalle Valo 2366277b024eSKalle Valo static void mwifiex_sdio_generic_fw_dump(struct mwifiex_adapter *adapter) 2367277b024eSKalle Valo { 2368277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2369277b024eSKalle Valo struct memory_type_mapping *entry = &generic_mem_type_map[0]; 2370277b024eSKalle Valo unsigned int reg, reg_start, reg_end; 2371277b024eSKalle Valo u8 start_flag = 0, done_flag = 0; 2372277b024eSKalle Valo u8 *dbg_ptr, *end_ptr; 2373277b024eSKalle Valo enum rdwr_status stat; 2374277b024eSKalle Valo int ret = -1, tries; 2375277b024eSKalle Valo 2376277b024eSKalle Valo if (!card->fw_dump_enh) 2377277b024eSKalle Valo return; 2378277b024eSKalle Valo 2379277b024eSKalle Valo if (entry->mem_ptr) { 2380277b024eSKalle Valo vfree(entry->mem_ptr); 2381277b024eSKalle Valo entry->mem_ptr = NULL; 2382277b024eSKalle Valo } 2383277b024eSKalle Valo entry->mem_size = 0; 2384277b024eSKalle Valo 2385277b024eSKalle Valo mwifiex_pm_wakeup_card(adapter); 2386277b024eSKalle Valo sdio_claim_host(card->func); 2387277b024eSKalle Valo 2388277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n"); 2389277b024eSKalle Valo 2390277b024eSKalle Valo stat = mwifiex_sdio_rdwr_firmware(adapter, done_flag); 2391277b024eSKalle Valo if (stat == RDWR_STATUS_FAILURE) 2392277b024eSKalle Valo goto done; 2393277b024eSKalle Valo 2394277b024eSKalle Valo reg_start = card->reg->fw_dump_start; 2395277b024eSKalle Valo reg_end = card->reg->fw_dump_end; 2396277b024eSKalle Valo for (reg = reg_start; reg <= reg_end; reg++) { 2397277b024eSKalle Valo for (tries = 0; tries < MAX_POLL_TRIES; tries++) { 2398277b024eSKalle Valo start_flag = sdio_readb(card->func, reg, &ret); 2399277b024eSKalle Valo if (ret) { 2400277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2401277b024eSKalle Valo "SDIO read err\n"); 2402277b024eSKalle Valo goto done; 2403277b024eSKalle Valo } 2404277b024eSKalle Valo if (start_flag == 0) 2405277b024eSKalle Valo break; 2406277b024eSKalle Valo if (tries == MAX_POLL_TRIES) { 2407277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2408277b024eSKalle Valo "FW not ready to dump\n"); 2409277b024eSKalle Valo ret = -1; 2410277b024eSKalle Valo goto done; 2411277b024eSKalle Valo } 2412277b024eSKalle Valo } 2413277b024eSKalle Valo usleep_range(100, 200); 2414277b024eSKalle Valo } 2415277b024eSKalle Valo 2416277b024eSKalle Valo entry->mem_ptr = vmalloc(0xf0000 + 1); 2417277b024eSKalle Valo if (!entry->mem_ptr) { 2418277b024eSKalle Valo ret = -1; 2419277b024eSKalle Valo goto done; 2420277b024eSKalle Valo } 2421277b024eSKalle Valo dbg_ptr = entry->mem_ptr; 2422277b024eSKalle Valo entry->mem_size = 0xf0000; 2423277b024eSKalle Valo end_ptr = dbg_ptr + entry->mem_size; 2424277b024eSKalle Valo 2425277b024eSKalle Valo done_flag = entry->done_flag; 2426277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, 2427277b024eSKalle Valo "Start %s output, please wait...\n", entry->mem_name); 2428277b024eSKalle Valo 2429277b024eSKalle Valo while (true) { 2430277b024eSKalle Valo stat = mwifiex_sdio_rdwr_firmware(adapter, done_flag); 2431277b024eSKalle Valo if (stat == RDWR_STATUS_FAILURE) 2432277b024eSKalle Valo goto done; 2433277b024eSKalle Valo for (reg = reg_start; reg <= reg_end; reg++) { 2434277b024eSKalle Valo *dbg_ptr = sdio_readb(card->func, reg, &ret); 2435277b024eSKalle Valo if (ret) { 2436277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2437277b024eSKalle Valo "SDIO read err\n"); 2438277b024eSKalle Valo goto done; 2439277b024eSKalle Valo } 2440277b024eSKalle Valo dbg_ptr++; 2441277b024eSKalle Valo if (dbg_ptr >= end_ptr) { 2442277b024eSKalle Valo u8 *tmp_ptr; 2443277b024eSKalle Valo 2444277b024eSKalle Valo tmp_ptr = vmalloc(entry->mem_size + 0x4000 + 1); 2445277b024eSKalle Valo if (!tmp_ptr) 2446277b024eSKalle Valo goto done; 2447277b024eSKalle Valo 2448277b024eSKalle Valo memcpy(tmp_ptr, entry->mem_ptr, 2449277b024eSKalle Valo entry->mem_size); 2450277b024eSKalle Valo vfree(entry->mem_ptr); 2451277b024eSKalle Valo entry->mem_ptr = tmp_ptr; 2452277b024eSKalle Valo tmp_ptr = NULL; 2453277b024eSKalle Valo dbg_ptr = entry->mem_ptr + entry->mem_size; 2454277b024eSKalle Valo entry->mem_size += 0x4000; 2455277b024eSKalle Valo end_ptr = entry->mem_ptr + entry->mem_size; 2456277b024eSKalle Valo } 2457277b024eSKalle Valo } 2458277b024eSKalle Valo if (stat == RDWR_STATUS_DONE) { 2459277b024eSKalle Valo entry->mem_size = dbg_ptr - entry->mem_ptr; 2460277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, "dump %s done size=0x%x\n", 2461277b024eSKalle Valo entry->mem_name, entry->mem_size); 2462277b024eSKalle Valo ret = 0; 2463277b024eSKalle Valo break; 2464277b024eSKalle Valo } 2465277b024eSKalle Valo } 2466277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n"); 2467277b024eSKalle Valo 2468277b024eSKalle Valo done: 2469277b024eSKalle Valo if (ret) { 2470277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "firmware dump failed\n"); 2471277b024eSKalle Valo if (entry->mem_ptr) { 2472277b024eSKalle Valo vfree(entry->mem_ptr); 2473277b024eSKalle Valo entry->mem_ptr = NULL; 2474277b024eSKalle Valo } 2475277b024eSKalle Valo entry->mem_size = 0; 2476277b024eSKalle Valo } 2477277b024eSKalle Valo sdio_release_host(card->func); 2478277b024eSKalle Valo } 2479277b024eSKalle Valo 2480277b024eSKalle Valo static void mwifiex_sdio_device_dump_work(struct mwifiex_adapter *adapter) 2481277b024eSKalle Valo { 2482277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2483277b024eSKalle Valo 2484277b024eSKalle Valo mwifiex_drv_info_dump(adapter); 2485277b024eSKalle Valo if (card->fw_dump_enh) 2486277b024eSKalle Valo mwifiex_sdio_generic_fw_dump(adapter); 2487277b024eSKalle Valo else 2488277b024eSKalle Valo mwifiex_sdio_fw_dump(adapter); 2489277b024eSKalle Valo mwifiex_upload_device_dump(adapter); 2490277b024eSKalle Valo } 2491277b024eSKalle Valo 2492277b024eSKalle Valo static void mwifiex_sdio_work(struct work_struct *work) 2493277b024eSKalle Valo { 2494277b024eSKalle Valo if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, 2495277b024eSKalle Valo &iface_work_flags)) 2496277b024eSKalle Valo mwifiex_sdio_device_dump_work(save_adapter); 2497277b024eSKalle Valo if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, 2498277b024eSKalle Valo &iface_work_flags)) 2499277b024eSKalle Valo mwifiex_sdio_card_reset_work(save_adapter); 2500277b024eSKalle Valo } 2501277b024eSKalle Valo 2502277b024eSKalle Valo static DECLARE_WORK(sdio_work, mwifiex_sdio_work); 2503277b024eSKalle Valo /* This function resets the card */ 2504277b024eSKalle Valo static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) 2505277b024eSKalle Valo { 2506277b024eSKalle Valo save_adapter = adapter; 2507277b024eSKalle Valo if (test_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &iface_work_flags)) 2508277b024eSKalle Valo return; 2509277b024eSKalle Valo 2510277b024eSKalle Valo set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &iface_work_flags); 2511277b024eSKalle Valo 2512277b024eSKalle Valo schedule_work(&sdio_work); 2513277b024eSKalle Valo } 2514277b024eSKalle Valo 2515277b024eSKalle Valo /* This function dumps FW information */ 2516277b024eSKalle Valo static void mwifiex_sdio_device_dump(struct mwifiex_adapter *adapter) 2517277b024eSKalle Valo { 2518277b024eSKalle Valo save_adapter = adapter; 2519277b024eSKalle Valo if (test_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags)) 2520277b024eSKalle Valo return; 2521277b024eSKalle Valo 2522277b024eSKalle Valo set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &iface_work_flags); 2523277b024eSKalle Valo schedule_work(&sdio_work); 2524277b024eSKalle Valo } 2525277b024eSKalle Valo 2526277b024eSKalle Valo /* Function to dump SDIO function registers and SDIO scratch registers in case 2527277b024eSKalle Valo * of FW crash 2528277b024eSKalle Valo */ 2529277b024eSKalle Valo static int 2530277b024eSKalle Valo mwifiex_sdio_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf) 2531277b024eSKalle Valo { 2532277b024eSKalle Valo char *p = drv_buf; 2533277b024eSKalle Valo struct sdio_mmc_card *cardp = adapter->card; 2534277b024eSKalle Valo int ret = 0; 2535277b024eSKalle Valo u8 count, func, data, index = 0, size = 0; 2536277b024eSKalle Valo u8 reg, reg_start, reg_end; 2537277b024eSKalle Valo char buf[256], *ptr; 2538277b024eSKalle Valo 2539277b024eSKalle Valo if (!p) 2540277b024eSKalle Valo return 0; 2541277b024eSKalle Valo 2542277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "SDIO register dump start\n"); 2543277b024eSKalle Valo 2544277b024eSKalle Valo mwifiex_pm_wakeup_card(adapter); 2545277b024eSKalle Valo 2546277b024eSKalle Valo sdio_claim_host(cardp->func); 2547277b024eSKalle Valo 2548277b024eSKalle Valo for (count = 0; count < 5; count++) { 2549277b024eSKalle Valo memset(buf, 0, sizeof(buf)); 2550277b024eSKalle Valo ptr = buf; 2551277b024eSKalle Valo 2552277b024eSKalle Valo switch (count) { 2553277b024eSKalle Valo case 0: 2554277b024eSKalle Valo /* Read the registers of SDIO function0 */ 2555277b024eSKalle Valo func = count; 2556277b024eSKalle Valo reg_start = 0; 2557277b024eSKalle Valo reg_end = 9; 2558277b024eSKalle Valo break; 2559277b024eSKalle Valo case 1: 2560277b024eSKalle Valo /* Read the registers of SDIO function1 */ 2561277b024eSKalle Valo func = count; 2562277b024eSKalle Valo reg_start = cardp->reg->func1_dump_reg_start; 2563277b024eSKalle Valo reg_end = cardp->reg->func1_dump_reg_end; 2564277b024eSKalle Valo break; 2565277b024eSKalle Valo case 2: 2566277b024eSKalle Valo index = 0; 2567277b024eSKalle Valo func = 1; 2568277b024eSKalle Valo reg_start = cardp->reg->func1_spec_reg_table[index++]; 2569277b024eSKalle Valo size = cardp->reg->func1_spec_reg_num; 2570277b024eSKalle Valo reg_end = cardp->reg->func1_spec_reg_table[size-1]; 2571277b024eSKalle Valo break; 2572277b024eSKalle Valo default: 2573277b024eSKalle Valo /* Read the scratch registers of SDIO function1 */ 2574277b024eSKalle Valo if (count == 4) 2575277b024eSKalle Valo mdelay(100); 2576277b024eSKalle Valo func = 1; 2577277b024eSKalle Valo reg_start = cardp->reg->func1_scratch_reg; 2578277b024eSKalle Valo reg_end = reg_start + MWIFIEX_SDIO_SCRATCH_SIZE; 2579277b024eSKalle Valo } 2580277b024eSKalle Valo 2581277b024eSKalle Valo if (count != 2) 2582277b024eSKalle Valo ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", 2583277b024eSKalle Valo func, reg_start, reg_end); 2584277b024eSKalle Valo else 2585277b024eSKalle Valo ptr += sprintf(ptr, "SDIO Func%d: ", func); 2586277b024eSKalle Valo 2587277b024eSKalle Valo for (reg = reg_start; reg <= reg_end;) { 2588277b024eSKalle Valo if (func == 0) 2589277b024eSKalle Valo data = sdio_f0_readb(cardp->func, reg, &ret); 2590277b024eSKalle Valo else 2591277b024eSKalle Valo data = sdio_readb(cardp->func, reg, &ret); 2592277b024eSKalle Valo 2593277b024eSKalle Valo if (count == 2) 2594277b024eSKalle Valo ptr += sprintf(ptr, "(%#x) ", reg); 2595277b024eSKalle Valo if (!ret) { 2596277b024eSKalle Valo ptr += sprintf(ptr, "%02x ", data); 2597277b024eSKalle Valo } else { 2598277b024eSKalle Valo ptr += sprintf(ptr, "ERR"); 2599277b024eSKalle Valo break; 2600277b024eSKalle Valo } 2601277b024eSKalle Valo 2602277b024eSKalle Valo if (count == 2 && reg < reg_end) 2603277b024eSKalle Valo reg = cardp->reg->func1_spec_reg_table[index++]; 2604277b024eSKalle Valo else 2605277b024eSKalle Valo reg++; 2606277b024eSKalle Valo } 2607277b024eSKalle Valo 2608277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "%s\n", buf); 2609277b024eSKalle Valo p += sprintf(p, "%s\n", buf); 2610277b024eSKalle Valo } 2611277b024eSKalle Valo 2612277b024eSKalle Valo sdio_release_host(cardp->func); 2613277b024eSKalle Valo 2614277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "SDIO register dump end\n"); 2615277b024eSKalle Valo 2616277b024eSKalle Valo return p - drv_buf; 2617277b024eSKalle Valo } 2618277b024eSKalle Valo 2619277b024eSKalle Valo static struct mwifiex_if_ops sdio_ops = { 2620277b024eSKalle Valo .init_if = mwifiex_init_sdio, 2621277b024eSKalle Valo .cleanup_if = mwifiex_cleanup_sdio, 2622277b024eSKalle Valo .check_fw_status = mwifiex_check_fw_status, 2623277b024eSKalle Valo .prog_fw = mwifiex_prog_fw_w_helper, 2624277b024eSKalle Valo .register_dev = mwifiex_register_dev, 2625277b024eSKalle Valo .unregister_dev = mwifiex_unregister_dev, 2626277b024eSKalle Valo .enable_int = mwifiex_sdio_enable_host_int, 2627277b024eSKalle Valo .disable_int = mwifiex_sdio_disable_host_int, 2628277b024eSKalle Valo .process_int_status = mwifiex_process_int_status, 2629277b024eSKalle Valo .host_to_card = mwifiex_sdio_host_to_card, 2630277b024eSKalle Valo .wakeup = mwifiex_pm_wakeup_card, 2631277b024eSKalle Valo .wakeup_complete = mwifiex_pm_wakeup_card_complete, 2632277b024eSKalle Valo 2633277b024eSKalle Valo /* SDIO specific */ 2634277b024eSKalle Valo .update_mp_end_port = mwifiex_update_mp_end_port, 2635277b024eSKalle Valo .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, 2636277b024eSKalle Valo .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete, 2637277b024eSKalle Valo .event_complete = mwifiex_sdio_event_complete, 2638277b024eSKalle Valo .card_reset = mwifiex_sdio_card_reset, 2639277b024eSKalle Valo .reg_dump = mwifiex_sdio_reg_dump, 2640277b024eSKalle Valo .device_dump = mwifiex_sdio_device_dump, 2641277b024eSKalle Valo .deaggr_pkt = mwifiex_deaggr_sdio_pkt, 2642277b024eSKalle Valo }; 2643277b024eSKalle Valo 2644277b024eSKalle Valo /* 2645277b024eSKalle Valo * This function initializes the SDIO driver. 2646277b024eSKalle Valo * 2647277b024eSKalle Valo * This initiates the semaphore and registers the device with 2648277b024eSKalle Valo * SDIO bus. 2649277b024eSKalle Valo */ 2650277b024eSKalle Valo static int 2651277b024eSKalle Valo mwifiex_sdio_init_module(void) 2652277b024eSKalle Valo { 2653277b024eSKalle Valo sema_init(&add_remove_card_sem, 1); 2654277b024eSKalle Valo 2655277b024eSKalle Valo /* Clear the flag in case user removes the card. */ 2656277b024eSKalle Valo user_rmmod = 0; 2657277b024eSKalle Valo 2658277b024eSKalle Valo return sdio_register_driver(&mwifiex_sdio); 2659277b024eSKalle Valo } 2660277b024eSKalle Valo 2661277b024eSKalle Valo /* 2662277b024eSKalle Valo * This function cleans up the SDIO driver. 2663277b024eSKalle Valo * 2664277b024eSKalle Valo * The following major steps are followed for cleanup - 2665277b024eSKalle Valo * - Resume the device if its suspended 2666277b024eSKalle Valo * - Disconnect the device if connected 2667277b024eSKalle Valo * - Shutdown the firmware 2668277b024eSKalle Valo * - Unregister the device from SDIO bus. 2669277b024eSKalle Valo */ 2670277b024eSKalle Valo static void 2671277b024eSKalle Valo mwifiex_sdio_cleanup_module(void) 2672277b024eSKalle Valo { 2673277b024eSKalle Valo if (!down_interruptible(&add_remove_card_sem)) 2674277b024eSKalle Valo up(&add_remove_card_sem); 2675277b024eSKalle Valo 2676277b024eSKalle Valo /* Set the flag as user is removing this module. */ 2677277b024eSKalle Valo user_rmmod = 1; 2678277b024eSKalle Valo cancel_work_sync(&sdio_work); 2679277b024eSKalle Valo 2680277b024eSKalle Valo sdio_unregister_driver(&mwifiex_sdio); 2681277b024eSKalle Valo } 2682277b024eSKalle Valo 2683277b024eSKalle Valo module_init(mwifiex_sdio_init_module); 2684277b024eSKalle Valo module_exit(mwifiex_sdio_cleanup_module); 2685277b024eSKalle Valo 2686277b024eSKalle Valo MODULE_AUTHOR("Marvell International Ltd."); 2687277b024eSKalle Valo MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); 2688277b024eSKalle Valo MODULE_VERSION(SDIO_VERSION); 2689277b024eSKalle Valo MODULE_LICENSE("GPL v2"); 2690277b024eSKalle Valo MODULE_FIRMWARE(SD8786_DEFAULT_FW_NAME); 2691277b024eSKalle Valo MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME); 2692277b024eSKalle Valo MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME); 2693277b024eSKalle Valo MODULE_FIRMWARE(SD8897_DEFAULT_FW_NAME); 2694277b024eSKalle Valo MODULE_FIRMWARE(SD8887_DEFAULT_FW_NAME); 2695277b024eSKalle Valo MODULE_FIRMWARE(SD8997_DEFAULT_FW_NAME); 2696