1828c91f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2277b024eSKalle Valo /* 3932183aaSGanapathi Bhat * NXP Wireless LAN device driver: SDIO specific handling 4277b024eSKalle Valo * 5932183aaSGanapathi Bhat * Copyright 2011-2020 NXP 6277b024eSKalle Valo */ 7277b024eSKalle Valo 8277b024eSKalle Valo #include <linux/firmware.h> 9277b024eSKalle Valo 10277b024eSKalle Valo #include "decl.h" 11277b024eSKalle Valo #include "ioctl.h" 12277b024eSKalle Valo #include "util.h" 13277b024eSKalle Valo #include "fw.h" 14277b024eSKalle Valo #include "main.h" 15277b024eSKalle Valo #include "wmm.h" 16277b024eSKalle Valo #include "11n.h" 17277b024eSKalle Valo #include "sdio.h" 18277b024eSKalle Valo 19277b024eSKalle Valo 20277b024eSKalle Valo #define SDIO_VERSION "1.0" 21277b024eSKalle Valo 2241efaf58SXinming Hu static void mwifiex_sdio_work(struct work_struct *work); 2341efaf58SXinming Hu 24277b024eSKalle Valo static struct mwifiex_if_ops sdio_ops; 25277b024eSKalle Valo 26992a2370SYueHaibing static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = { 27992a2370SYueHaibing .start_rd_port = 1, 28992a2370SYueHaibing .start_wr_port = 1, 29992a2370SYueHaibing .base_0_reg = 0x0040, 30992a2370SYueHaibing .base_1_reg = 0x0041, 31992a2370SYueHaibing .poll_reg = 0x30, 32992a2370SYueHaibing .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK, 33992a2370SYueHaibing .host_int_rsr_reg = 0x1, 34992a2370SYueHaibing .host_int_mask_reg = 0x02, 35992a2370SYueHaibing .host_int_status_reg = 0x03, 36992a2370SYueHaibing .status_reg_0 = 0x60, 37992a2370SYueHaibing .status_reg_1 = 0x61, 38992a2370SYueHaibing .sdio_int_mask = 0x3f, 39992a2370SYueHaibing .data_port_mask = 0x0000fffe, 40992a2370SYueHaibing .io_port_0_reg = 0x78, 41992a2370SYueHaibing .io_port_1_reg = 0x79, 42992a2370SYueHaibing .io_port_2_reg = 0x7A, 43992a2370SYueHaibing .max_mp_regs = 64, 44992a2370SYueHaibing .rd_bitmap_l = 0x04, 45992a2370SYueHaibing .rd_bitmap_u = 0x05, 46992a2370SYueHaibing .wr_bitmap_l = 0x06, 47992a2370SYueHaibing .wr_bitmap_u = 0x07, 48992a2370SYueHaibing .rd_len_p0_l = 0x08, 49992a2370SYueHaibing .rd_len_p0_u = 0x09, 50992a2370SYueHaibing .card_misc_cfg_reg = 0x6c, 51992a2370SYueHaibing .func1_dump_reg_start = 0x0, 52992a2370SYueHaibing .func1_dump_reg_end = 0x9, 53992a2370SYueHaibing .func1_scratch_reg = 0x60, 54992a2370SYueHaibing .func1_spec_reg_num = 5, 55992a2370SYueHaibing .func1_spec_reg_table = {0x28, 0x30, 0x34, 0x38, 0x3c}, 56992a2370SYueHaibing }; 57992a2370SYueHaibing 58992a2370SYueHaibing static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = { 59992a2370SYueHaibing .start_rd_port = 0, 60992a2370SYueHaibing .start_wr_port = 0, 61992a2370SYueHaibing .base_0_reg = 0x60, 62992a2370SYueHaibing .base_1_reg = 0x61, 63992a2370SYueHaibing .poll_reg = 0x50, 64992a2370SYueHaibing .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK | 65992a2370SYueHaibing CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK, 66992a2370SYueHaibing .host_int_rsr_reg = 0x1, 67992a2370SYueHaibing .host_int_status_reg = 0x03, 68992a2370SYueHaibing .host_int_mask_reg = 0x02, 69992a2370SYueHaibing .status_reg_0 = 0xc0, 70992a2370SYueHaibing .status_reg_1 = 0xc1, 71992a2370SYueHaibing .sdio_int_mask = 0xff, 72992a2370SYueHaibing .data_port_mask = 0xffffffff, 73992a2370SYueHaibing .io_port_0_reg = 0xD8, 74992a2370SYueHaibing .io_port_1_reg = 0xD9, 75992a2370SYueHaibing .io_port_2_reg = 0xDA, 76992a2370SYueHaibing .max_mp_regs = 184, 77992a2370SYueHaibing .rd_bitmap_l = 0x04, 78992a2370SYueHaibing .rd_bitmap_u = 0x05, 79992a2370SYueHaibing .rd_bitmap_1l = 0x06, 80992a2370SYueHaibing .rd_bitmap_1u = 0x07, 81992a2370SYueHaibing .wr_bitmap_l = 0x08, 82992a2370SYueHaibing .wr_bitmap_u = 0x09, 83992a2370SYueHaibing .wr_bitmap_1l = 0x0a, 84992a2370SYueHaibing .wr_bitmap_1u = 0x0b, 85992a2370SYueHaibing .rd_len_p0_l = 0x0c, 86992a2370SYueHaibing .rd_len_p0_u = 0x0d, 87992a2370SYueHaibing .card_misc_cfg_reg = 0xcc, 88992a2370SYueHaibing .card_cfg_2_1_reg = 0xcd, 89992a2370SYueHaibing .cmd_rd_len_0 = 0xb4, 90992a2370SYueHaibing .cmd_rd_len_1 = 0xb5, 91992a2370SYueHaibing .cmd_rd_len_2 = 0xb6, 92992a2370SYueHaibing .cmd_rd_len_3 = 0xb7, 93992a2370SYueHaibing .cmd_cfg_0 = 0xb8, 94992a2370SYueHaibing .cmd_cfg_1 = 0xb9, 95992a2370SYueHaibing .cmd_cfg_2 = 0xba, 96992a2370SYueHaibing .cmd_cfg_3 = 0xbb, 97992a2370SYueHaibing .fw_dump_host_ready = 0xee, 98992a2370SYueHaibing .fw_dump_ctrl = 0xe2, 99992a2370SYueHaibing .fw_dump_start = 0xe3, 100992a2370SYueHaibing .fw_dump_end = 0xea, 101992a2370SYueHaibing .func1_dump_reg_start = 0x0, 102992a2370SYueHaibing .func1_dump_reg_end = 0xb, 103992a2370SYueHaibing .func1_scratch_reg = 0xc0, 104992a2370SYueHaibing .func1_spec_reg_num = 8, 105992a2370SYueHaibing .func1_spec_reg_table = {0x4C, 0x50, 0x54, 0x55, 0x58, 106992a2370SYueHaibing 0x59, 0x5c, 0x5d}, 107992a2370SYueHaibing }; 108992a2370SYueHaibing 109992a2370SYueHaibing static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8977 = { 110992a2370SYueHaibing .start_rd_port = 0, 111992a2370SYueHaibing .start_wr_port = 0, 112992a2370SYueHaibing .base_0_reg = 0xF8, 113992a2370SYueHaibing .base_1_reg = 0xF9, 114992a2370SYueHaibing .poll_reg = 0x5C, 115992a2370SYueHaibing .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK | 116992a2370SYueHaibing CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK, 117992a2370SYueHaibing .host_int_rsr_reg = 0x4, 118992a2370SYueHaibing .host_int_status_reg = 0x0C, 119992a2370SYueHaibing .host_int_mask_reg = 0x08, 120992a2370SYueHaibing .status_reg_0 = 0xE8, 121992a2370SYueHaibing .status_reg_1 = 0xE9, 122992a2370SYueHaibing .sdio_int_mask = 0xff, 123992a2370SYueHaibing .data_port_mask = 0xffffffff, 124992a2370SYueHaibing .io_port_0_reg = 0xE4, 125992a2370SYueHaibing .io_port_1_reg = 0xE5, 126992a2370SYueHaibing .io_port_2_reg = 0xE6, 127992a2370SYueHaibing .max_mp_regs = 196, 128992a2370SYueHaibing .rd_bitmap_l = 0x10, 129992a2370SYueHaibing .rd_bitmap_u = 0x11, 130992a2370SYueHaibing .rd_bitmap_1l = 0x12, 131992a2370SYueHaibing .rd_bitmap_1u = 0x13, 132992a2370SYueHaibing .wr_bitmap_l = 0x14, 133992a2370SYueHaibing .wr_bitmap_u = 0x15, 134992a2370SYueHaibing .wr_bitmap_1l = 0x16, 135992a2370SYueHaibing .wr_bitmap_1u = 0x17, 136992a2370SYueHaibing .rd_len_p0_l = 0x18, 137992a2370SYueHaibing .rd_len_p0_u = 0x19, 138992a2370SYueHaibing .card_misc_cfg_reg = 0xd8, 139992a2370SYueHaibing .card_cfg_2_1_reg = 0xd9, 140992a2370SYueHaibing .cmd_rd_len_0 = 0xc0, 141992a2370SYueHaibing .cmd_rd_len_1 = 0xc1, 142992a2370SYueHaibing .cmd_rd_len_2 = 0xc2, 143992a2370SYueHaibing .cmd_rd_len_3 = 0xc3, 144992a2370SYueHaibing .cmd_cfg_0 = 0xc4, 145992a2370SYueHaibing .cmd_cfg_1 = 0xc5, 146992a2370SYueHaibing .cmd_cfg_2 = 0xc6, 147992a2370SYueHaibing .cmd_cfg_3 = 0xc7, 148992a2370SYueHaibing .fw_dump_host_ready = 0xcc, 149992a2370SYueHaibing .fw_dump_ctrl = 0xf0, 150992a2370SYueHaibing .fw_dump_start = 0xf1, 151992a2370SYueHaibing .fw_dump_end = 0xf8, 152992a2370SYueHaibing .func1_dump_reg_start = 0x10, 153992a2370SYueHaibing .func1_dump_reg_end = 0x17, 154992a2370SYueHaibing .func1_scratch_reg = 0xe8, 155992a2370SYueHaibing .func1_spec_reg_num = 13, 156992a2370SYueHaibing .func1_spec_reg_table = {0x08, 0x58, 0x5C, 0x5D, 157992a2370SYueHaibing 0x60, 0x61, 0x62, 0x64, 158992a2370SYueHaibing 0x65, 0x66, 0x68, 0x69, 159992a2370SYueHaibing 0x6a}, 160992a2370SYueHaibing }; 161992a2370SYueHaibing 162992a2370SYueHaibing static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8997 = { 163992a2370SYueHaibing .start_rd_port = 0, 164992a2370SYueHaibing .start_wr_port = 0, 165992a2370SYueHaibing .base_0_reg = 0xF8, 166992a2370SYueHaibing .base_1_reg = 0xF9, 167992a2370SYueHaibing .poll_reg = 0x5C, 168992a2370SYueHaibing .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK | 169992a2370SYueHaibing CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK, 170992a2370SYueHaibing .host_int_rsr_reg = 0x4, 171992a2370SYueHaibing .host_int_status_reg = 0x0C, 172992a2370SYueHaibing .host_int_mask_reg = 0x08, 173255ca28aSAndrejs Cainikovs .host_strap_reg = 0xF4, 174255ca28aSAndrejs Cainikovs .host_strap_mask = 0x01, 175255ca28aSAndrejs Cainikovs .host_strap_value = 0x00, 176992a2370SYueHaibing .status_reg_0 = 0xE8, 177992a2370SYueHaibing .status_reg_1 = 0xE9, 178992a2370SYueHaibing .sdio_int_mask = 0xff, 179992a2370SYueHaibing .data_port_mask = 0xffffffff, 180992a2370SYueHaibing .io_port_0_reg = 0xE4, 181992a2370SYueHaibing .io_port_1_reg = 0xE5, 182992a2370SYueHaibing .io_port_2_reg = 0xE6, 183992a2370SYueHaibing .max_mp_regs = 196, 184992a2370SYueHaibing .rd_bitmap_l = 0x10, 185992a2370SYueHaibing .rd_bitmap_u = 0x11, 186992a2370SYueHaibing .rd_bitmap_1l = 0x12, 187992a2370SYueHaibing .rd_bitmap_1u = 0x13, 188992a2370SYueHaibing .wr_bitmap_l = 0x14, 189992a2370SYueHaibing .wr_bitmap_u = 0x15, 190992a2370SYueHaibing .wr_bitmap_1l = 0x16, 191992a2370SYueHaibing .wr_bitmap_1u = 0x17, 192992a2370SYueHaibing .rd_len_p0_l = 0x18, 193992a2370SYueHaibing .rd_len_p0_u = 0x19, 194992a2370SYueHaibing .card_misc_cfg_reg = 0xd8, 195992a2370SYueHaibing .card_cfg_2_1_reg = 0xd9, 196992a2370SYueHaibing .cmd_rd_len_0 = 0xc0, 197992a2370SYueHaibing .cmd_rd_len_1 = 0xc1, 198992a2370SYueHaibing .cmd_rd_len_2 = 0xc2, 199992a2370SYueHaibing .cmd_rd_len_3 = 0xc3, 200992a2370SYueHaibing .cmd_cfg_0 = 0xc4, 201992a2370SYueHaibing .cmd_cfg_1 = 0xc5, 202992a2370SYueHaibing .cmd_cfg_2 = 0xc6, 203992a2370SYueHaibing .cmd_cfg_3 = 0xc7, 204992a2370SYueHaibing .fw_dump_host_ready = 0xcc, 205992a2370SYueHaibing .fw_dump_ctrl = 0xf0, 206992a2370SYueHaibing .fw_dump_start = 0xf1, 207992a2370SYueHaibing .fw_dump_end = 0xf8, 208992a2370SYueHaibing .func1_dump_reg_start = 0x10, 209992a2370SYueHaibing .func1_dump_reg_end = 0x17, 210992a2370SYueHaibing .func1_scratch_reg = 0xe8, 211992a2370SYueHaibing .func1_spec_reg_num = 13, 212992a2370SYueHaibing .func1_spec_reg_table = {0x08, 0x58, 0x5C, 0x5D, 213992a2370SYueHaibing 0x60, 0x61, 0x62, 0x64, 214992a2370SYueHaibing 0x65, 0x66, 0x68, 0x69, 215992a2370SYueHaibing 0x6a}, 216992a2370SYueHaibing }; 217992a2370SYueHaibing 218992a2370SYueHaibing static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8887 = { 219992a2370SYueHaibing .start_rd_port = 0, 220992a2370SYueHaibing .start_wr_port = 0, 221992a2370SYueHaibing .base_0_reg = 0x6C, 222992a2370SYueHaibing .base_1_reg = 0x6D, 223992a2370SYueHaibing .poll_reg = 0x5C, 224992a2370SYueHaibing .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK | 225992a2370SYueHaibing CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK, 226992a2370SYueHaibing .host_int_rsr_reg = 0x4, 227992a2370SYueHaibing .host_int_status_reg = 0x0C, 228992a2370SYueHaibing .host_int_mask_reg = 0x08, 229992a2370SYueHaibing .status_reg_0 = 0x90, 230992a2370SYueHaibing .status_reg_1 = 0x91, 231992a2370SYueHaibing .sdio_int_mask = 0xff, 232992a2370SYueHaibing .data_port_mask = 0xffffffff, 233992a2370SYueHaibing .io_port_0_reg = 0xE4, 234992a2370SYueHaibing .io_port_1_reg = 0xE5, 235992a2370SYueHaibing .io_port_2_reg = 0xE6, 236992a2370SYueHaibing .max_mp_regs = 196, 237992a2370SYueHaibing .rd_bitmap_l = 0x10, 238992a2370SYueHaibing .rd_bitmap_u = 0x11, 239992a2370SYueHaibing .rd_bitmap_1l = 0x12, 240992a2370SYueHaibing .rd_bitmap_1u = 0x13, 241992a2370SYueHaibing .wr_bitmap_l = 0x14, 242992a2370SYueHaibing .wr_bitmap_u = 0x15, 243992a2370SYueHaibing .wr_bitmap_1l = 0x16, 244992a2370SYueHaibing .wr_bitmap_1u = 0x17, 245992a2370SYueHaibing .rd_len_p0_l = 0x18, 246992a2370SYueHaibing .rd_len_p0_u = 0x19, 247992a2370SYueHaibing .card_misc_cfg_reg = 0xd8, 248992a2370SYueHaibing .card_cfg_2_1_reg = 0xd9, 249992a2370SYueHaibing .cmd_rd_len_0 = 0xc0, 250992a2370SYueHaibing .cmd_rd_len_1 = 0xc1, 251992a2370SYueHaibing .cmd_rd_len_2 = 0xc2, 252992a2370SYueHaibing .cmd_rd_len_3 = 0xc3, 253992a2370SYueHaibing .cmd_cfg_0 = 0xc4, 254992a2370SYueHaibing .cmd_cfg_1 = 0xc5, 255992a2370SYueHaibing .cmd_cfg_2 = 0xc6, 256992a2370SYueHaibing .cmd_cfg_3 = 0xc7, 257992a2370SYueHaibing .func1_dump_reg_start = 0x10, 258992a2370SYueHaibing .func1_dump_reg_end = 0x17, 259992a2370SYueHaibing .func1_scratch_reg = 0x90, 260992a2370SYueHaibing .func1_spec_reg_num = 13, 261992a2370SYueHaibing .func1_spec_reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 262992a2370SYueHaibing 0x61, 0x62, 0x64, 0x65, 0x66, 263992a2370SYueHaibing 0x68, 0x69, 0x6a}, 264992a2370SYueHaibing }; 265992a2370SYueHaibing 266bba047f1SLukas Wunner static const struct mwifiex_sdio_card_reg mwifiex_reg_sd89xx = { 267992a2370SYueHaibing .start_rd_port = 0, 268992a2370SYueHaibing .start_wr_port = 0, 269992a2370SYueHaibing .base_0_reg = 0xF8, 270992a2370SYueHaibing .base_1_reg = 0xF9, 271992a2370SYueHaibing .poll_reg = 0x5C, 272992a2370SYueHaibing .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK | 273992a2370SYueHaibing CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK, 274992a2370SYueHaibing .host_int_rsr_reg = 0x4, 275992a2370SYueHaibing .host_int_status_reg = 0x0C, 276992a2370SYueHaibing .host_int_mask_reg = 0x08, 277255ca28aSAndrejs Cainikovs .host_strap_reg = 0xF4, 278255ca28aSAndrejs Cainikovs .host_strap_mask = 0x01, 279255ca28aSAndrejs Cainikovs .host_strap_value = 0x00, 280992a2370SYueHaibing .status_reg_0 = 0xE8, 281992a2370SYueHaibing .status_reg_1 = 0xE9, 282992a2370SYueHaibing .sdio_int_mask = 0xff, 283992a2370SYueHaibing .data_port_mask = 0xffffffff, 284992a2370SYueHaibing .io_port_0_reg = 0xE4, 285992a2370SYueHaibing .io_port_1_reg = 0xE5, 286992a2370SYueHaibing .io_port_2_reg = 0xE6, 287992a2370SYueHaibing .max_mp_regs = 196, 288992a2370SYueHaibing .rd_bitmap_l = 0x10, 289992a2370SYueHaibing .rd_bitmap_u = 0x11, 290992a2370SYueHaibing .rd_bitmap_1l = 0x12, 291992a2370SYueHaibing .rd_bitmap_1u = 0x13, 292992a2370SYueHaibing .wr_bitmap_l = 0x14, 293992a2370SYueHaibing .wr_bitmap_u = 0x15, 294992a2370SYueHaibing .wr_bitmap_1l = 0x16, 295992a2370SYueHaibing .wr_bitmap_1u = 0x17, 296992a2370SYueHaibing .rd_len_p0_l = 0x18, 297992a2370SYueHaibing .rd_len_p0_u = 0x19, 298992a2370SYueHaibing .card_misc_cfg_reg = 0xd8, 299992a2370SYueHaibing .card_cfg_2_1_reg = 0xd9, 300992a2370SYueHaibing .cmd_rd_len_0 = 0xc0, 301992a2370SYueHaibing .cmd_rd_len_1 = 0xc1, 302992a2370SYueHaibing .cmd_rd_len_2 = 0xc2, 303992a2370SYueHaibing .cmd_rd_len_3 = 0xc3, 304992a2370SYueHaibing .cmd_cfg_0 = 0xc4, 305992a2370SYueHaibing .cmd_cfg_1 = 0xc5, 306992a2370SYueHaibing .cmd_cfg_2 = 0xc6, 307992a2370SYueHaibing .cmd_cfg_3 = 0xc7, 308992a2370SYueHaibing .fw_dump_host_ready = 0xcc, 309992a2370SYueHaibing .fw_dump_ctrl = 0xf9, 310992a2370SYueHaibing .fw_dump_start = 0xf1, 311992a2370SYueHaibing .fw_dump_end = 0xf8, 312992a2370SYueHaibing .func1_dump_reg_start = 0x10, 313992a2370SYueHaibing .func1_dump_reg_end = 0x17, 314992a2370SYueHaibing .func1_scratch_reg = 0xE8, 315992a2370SYueHaibing .func1_spec_reg_num = 13, 316992a2370SYueHaibing .func1_spec_reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60, 317992a2370SYueHaibing 0x61, 0x62, 0x64, 0x65, 0x66, 318992a2370SYueHaibing 0x68, 0x69, 0x6a}, 319992a2370SYueHaibing }; 320992a2370SYueHaibing 321992a2370SYueHaibing static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { 322992a2370SYueHaibing .firmware = SD8786_DEFAULT_FW_NAME, 323992a2370SYueHaibing .reg = &mwifiex_reg_sd87xx, 324992a2370SYueHaibing .max_ports = 16, 325992a2370SYueHaibing .mp_agg_pkt_limit = 8, 326992a2370SYueHaibing .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, 327992a2370SYueHaibing .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 328992a2370SYueHaibing .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 329992a2370SYueHaibing .supports_sdio_new_mode = false, 330992a2370SYueHaibing .has_control_mask = true, 331992a2370SYueHaibing .can_dump_fw = false, 332992a2370SYueHaibing .can_auto_tdls = false, 333992a2370SYueHaibing .can_ext_scan = false, 3341c5d463cSDavid Lin .fw_ready_extra_delay = false, 335992a2370SYueHaibing }; 336992a2370SYueHaibing 337992a2370SYueHaibing static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { 338992a2370SYueHaibing .firmware = SD8787_DEFAULT_FW_NAME, 339992a2370SYueHaibing .reg = &mwifiex_reg_sd87xx, 340992a2370SYueHaibing .max_ports = 16, 341992a2370SYueHaibing .mp_agg_pkt_limit = 8, 342992a2370SYueHaibing .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, 343992a2370SYueHaibing .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 344992a2370SYueHaibing .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 345992a2370SYueHaibing .supports_sdio_new_mode = false, 346992a2370SYueHaibing .has_control_mask = true, 347992a2370SYueHaibing .can_dump_fw = false, 348992a2370SYueHaibing .can_auto_tdls = false, 349992a2370SYueHaibing .can_ext_scan = true, 3501c5d463cSDavid Lin .fw_ready_extra_delay = false, 351992a2370SYueHaibing }; 352992a2370SYueHaibing 353992a2370SYueHaibing static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { 354992a2370SYueHaibing .firmware = SD8797_DEFAULT_FW_NAME, 355992a2370SYueHaibing .reg = &mwifiex_reg_sd87xx, 356992a2370SYueHaibing .max_ports = 16, 357992a2370SYueHaibing .mp_agg_pkt_limit = 8, 358992a2370SYueHaibing .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, 359992a2370SYueHaibing .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 360992a2370SYueHaibing .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 361992a2370SYueHaibing .supports_sdio_new_mode = false, 362992a2370SYueHaibing .has_control_mask = true, 363992a2370SYueHaibing .can_dump_fw = false, 364992a2370SYueHaibing .can_auto_tdls = false, 365992a2370SYueHaibing .can_ext_scan = true, 3661c5d463cSDavid Lin .fw_ready_extra_delay = false, 367992a2370SYueHaibing }; 368992a2370SYueHaibing 369992a2370SYueHaibing static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { 370992a2370SYueHaibing .firmware = SD8897_DEFAULT_FW_NAME, 371992a2370SYueHaibing .reg = &mwifiex_reg_sd8897, 372992a2370SYueHaibing .max_ports = 32, 373992a2370SYueHaibing .mp_agg_pkt_limit = 16, 374992a2370SYueHaibing .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, 375992a2370SYueHaibing .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, 376992a2370SYueHaibing .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, 377992a2370SYueHaibing .supports_sdio_new_mode = true, 378992a2370SYueHaibing .has_control_mask = false, 379992a2370SYueHaibing .can_dump_fw = true, 380992a2370SYueHaibing .can_auto_tdls = false, 381992a2370SYueHaibing .can_ext_scan = true, 3821c5d463cSDavid Lin .fw_ready_extra_delay = false, 383992a2370SYueHaibing }; 384992a2370SYueHaibing 385992a2370SYueHaibing static const struct mwifiex_sdio_device mwifiex_sdio_sd8977 = { 386992a2370SYueHaibing .firmware = SD8977_DEFAULT_FW_NAME, 387992a2370SYueHaibing .reg = &mwifiex_reg_sd8977, 388992a2370SYueHaibing .max_ports = 32, 389992a2370SYueHaibing .mp_agg_pkt_limit = 16, 390992a2370SYueHaibing .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, 391992a2370SYueHaibing .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, 392992a2370SYueHaibing .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, 393992a2370SYueHaibing .supports_sdio_new_mode = true, 394992a2370SYueHaibing .has_control_mask = false, 395992a2370SYueHaibing .can_dump_fw = true, 396992a2370SYueHaibing .fw_dump_enh = true, 397992a2370SYueHaibing .can_auto_tdls = false, 398992a2370SYueHaibing .can_ext_scan = true, 3991c5d463cSDavid Lin .fw_ready_extra_delay = false, 400992a2370SYueHaibing }; 401992a2370SYueHaibing 402bba047f1SLukas Wunner static const struct mwifiex_sdio_device mwifiex_sdio_sd8978 = { 403bba047f1SLukas Wunner .firmware_sdiouart = SD8978_SDIOUART_FW_NAME, 404bba047f1SLukas Wunner .reg = &mwifiex_reg_sd89xx, 405bba047f1SLukas Wunner .max_ports = 32, 406bba047f1SLukas Wunner .mp_agg_pkt_limit = 16, 407bba047f1SLukas Wunner .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, 408bba047f1SLukas Wunner .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, 409bba047f1SLukas Wunner .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, 410bba047f1SLukas Wunner .supports_sdio_new_mode = true, 411bba047f1SLukas Wunner .has_control_mask = false, 412bba047f1SLukas Wunner .can_dump_fw = true, 413bba047f1SLukas Wunner .fw_dump_enh = true, 414bba047f1SLukas Wunner .can_auto_tdls = false, 415bba047f1SLukas Wunner .can_ext_scan = true, 4161c5d463cSDavid Lin .fw_ready_extra_delay = true, 417bba047f1SLukas Wunner }; 418bba047f1SLukas Wunner 419992a2370SYueHaibing static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = { 420992a2370SYueHaibing .firmware = SD8997_DEFAULT_FW_NAME, 421562354abSAndrejs Cainikovs .firmware_sdiouart = SD8997_SDIOUART_FW_NAME, 422992a2370SYueHaibing .reg = &mwifiex_reg_sd8997, 423992a2370SYueHaibing .max_ports = 32, 424992a2370SYueHaibing .mp_agg_pkt_limit = 16, 425992a2370SYueHaibing .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, 426992a2370SYueHaibing .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, 427992a2370SYueHaibing .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, 428992a2370SYueHaibing .supports_sdio_new_mode = true, 429992a2370SYueHaibing .has_control_mask = false, 430992a2370SYueHaibing .can_dump_fw = true, 431992a2370SYueHaibing .fw_dump_enh = true, 432992a2370SYueHaibing .can_auto_tdls = false, 433992a2370SYueHaibing .can_ext_scan = true, 4341c5d463cSDavid Lin .fw_ready_extra_delay = false, 435992a2370SYueHaibing }; 436992a2370SYueHaibing 437992a2370SYueHaibing static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { 438992a2370SYueHaibing .firmware = SD8887_DEFAULT_FW_NAME, 439992a2370SYueHaibing .reg = &mwifiex_reg_sd8887, 440992a2370SYueHaibing .max_ports = 32, 441992a2370SYueHaibing .mp_agg_pkt_limit = 16, 442992a2370SYueHaibing .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, 443992a2370SYueHaibing .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, 444992a2370SYueHaibing .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, 445992a2370SYueHaibing .supports_sdio_new_mode = true, 446992a2370SYueHaibing .has_control_mask = false, 447992a2370SYueHaibing .can_dump_fw = false, 448992a2370SYueHaibing .can_auto_tdls = true, 449992a2370SYueHaibing .can_ext_scan = true, 4501c5d463cSDavid Lin .fw_ready_extra_delay = false, 451992a2370SYueHaibing }; 452992a2370SYueHaibing 453992a2370SYueHaibing static const struct mwifiex_sdio_device mwifiex_sdio_sd8987 = { 454992a2370SYueHaibing .firmware = SD8987_DEFAULT_FW_NAME, 455bba047f1SLukas Wunner .reg = &mwifiex_reg_sd89xx, 456992a2370SYueHaibing .max_ports = 32, 457992a2370SYueHaibing .mp_agg_pkt_limit = 16, 458992a2370SYueHaibing .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, 459992a2370SYueHaibing .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, 460992a2370SYueHaibing .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, 461992a2370SYueHaibing .supports_sdio_new_mode = true, 462992a2370SYueHaibing .has_control_mask = false, 463992a2370SYueHaibing .can_dump_fw = true, 464992a2370SYueHaibing .fw_dump_enh = true, 465992a2370SYueHaibing .can_auto_tdls = true, 466992a2370SYueHaibing .can_ext_scan = true, 4671c5d463cSDavid Lin .fw_ready_extra_delay = false, 468992a2370SYueHaibing }; 469992a2370SYueHaibing 470992a2370SYueHaibing static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = { 471992a2370SYueHaibing .firmware = SD8801_DEFAULT_FW_NAME, 472992a2370SYueHaibing .reg = &mwifiex_reg_sd87xx, 473992a2370SYueHaibing .max_ports = 16, 474992a2370SYueHaibing .mp_agg_pkt_limit = 8, 475992a2370SYueHaibing .supports_sdio_new_mode = false, 476992a2370SYueHaibing .has_control_mask = true, 477992a2370SYueHaibing .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, 478992a2370SYueHaibing .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 479992a2370SYueHaibing .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 480992a2370SYueHaibing .can_dump_fw = false, 481992a2370SYueHaibing .can_auto_tdls = false, 482992a2370SYueHaibing .can_ext_scan = true, 4831c5d463cSDavid Lin .fw_ready_extra_delay = false, 484992a2370SYueHaibing }; 485992a2370SYueHaibing 486277b024eSKalle Valo static struct memory_type_mapping generic_mem_type_map[] = { 487277b024eSKalle Valo {"DUMP", NULL, 0, 0xDD}, 488277b024eSKalle Valo }; 489277b024eSKalle Valo 490277b024eSKalle Valo static struct memory_type_mapping mem_type_mapping_tbl[] = { 491277b024eSKalle Valo {"ITCM", NULL, 0, 0xF0}, 492277b024eSKalle Valo {"DTCM", NULL, 0, 0xF1}, 493277b024eSKalle Valo {"SQRAM", NULL, 0, 0xF2}, 494277b024eSKalle Valo {"APU", NULL, 0, 0xF3}, 495277b024eSKalle Valo {"CIU", NULL, 0, 0xF4}, 496277b024eSKalle Valo {"ICU", NULL, 0, 0xF5}, 497277b024eSKalle Valo {"MAC", NULL, 0, 0xF6}, 498277b024eSKalle Valo {"EXT7", NULL, 0, 0xF7}, 499277b024eSKalle Valo {"EXT8", NULL, 0, 0xF8}, 500277b024eSKalle Valo {"EXT9", NULL, 0, 0xF9}, 501277b024eSKalle Valo {"EXT10", NULL, 0, 0xFA}, 502277b024eSKalle Valo {"EXT11", NULL, 0, 0xFB}, 503277b024eSKalle Valo {"EXT12", NULL, 0, 0xFC}, 504277b024eSKalle Valo {"EXT13", NULL, 0, 0xFD}, 505277b024eSKalle Valo {"EXTLAST", NULL, 0, 0xFE}, 506277b024eSKalle Valo }; 507277b024eSKalle Valo 508139f6973SKrzysztof Kozlowski static const struct of_device_id mwifiex_sdio_of_match_table[] __maybe_unused = { 50936dd7a4cSLukas Wunner { .compatible = "marvell,sd8787" }, 510ce4f6f0cSXinming Hu { .compatible = "marvell,sd8897" }, 511bba047f1SLukas Wunner { .compatible = "marvell,sd8978" }, 512ce4f6f0cSXinming Hu { .compatible = "marvell,sd8997" }, 513bba047f1SLukas Wunner { .compatible = "nxp,iw416" }, 514ce4f6f0cSXinming Hu { } 515ce4f6f0cSXinming Hu }; 516ce4f6f0cSXinming Hu 517ce4f6f0cSXinming Hu /* This function parse device tree node using mmc subnode devicetree API. 518ce4f6f0cSXinming Hu * The device node is saved in card->plt_of_node. 519ce4f6f0cSXinming Hu * if the device tree node exist and include interrupts attributes, this 520ce4f6f0cSXinming Hu * function will also request platform specific wakeup interrupt. 521ce4f6f0cSXinming Hu */ 522853402a0SRajat Jain static int mwifiex_sdio_probe_of(struct device *dev) 523ce4f6f0cSXinming Hu { 5246f49208fSJavier Martinez Canillas if (!of_match_node(mwifiex_sdio_of_match_table, dev->of_node)) { 5255e94913fSJavier Martinez Canillas dev_err(dev, "required compatible string missing\n"); 5265e94913fSJavier Martinez Canillas return -EINVAL; 527ce4f6f0cSXinming Hu } 528ce4f6f0cSXinming Hu 529ce4f6f0cSXinming Hu return 0; 530ce4f6f0cSXinming Hu } 531ce4f6f0cSXinming Hu 532277b024eSKalle Valo /* 533277b024eSKalle Valo * SDIO probe. 534277b024eSKalle Valo * 535277b024eSKalle Valo * This function probes an mwifiex device and registers it. It allocates 536277b024eSKalle Valo * the card structure, enables SDIO function number and initiates the 537277b024eSKalle Valo * device registration and initialization procedure by adding a logical 538277b024eSKalle Valo * interface. 539277b024eSKalle Valo */ 540277b024eSKalle Valo static int 541277b024eSKalle Valo mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) 542277b024eSKalle Valo { 543277b024eSKalle Valo int ret; 544277b024eSKalle Valo struct sdio_mmc_card *card = NULL; 545277b024eSKalle Valo 546277b024eSKalle Valo pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", 547277b024eSKalle Valo func->vendor, func->device, func->class, func->num); 548277b024eSKalle Valo 54966b9c182SBrian Norris card = devm_kzalloc(&func->dev, sizeof(*card), GFP_KERNEL); 550277b024eSKalle Valo if (!card) 551277b024eSKalle Valo return -ENOMEM; 552277b024eSKalle Valo 5534a79aa17SBrian Norris init_completion(&card->fw_done); 5544a79aa17SBrian Norris 555277b024eSKalle Valo card->func = func; 556277b024eSKalle Valo 557277b024eSKalle Valo func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; 558277b024eSKalle Valo 559277b024eSKalle Valo if (id->driver_data) { 560277b024eSKalle Valo struct mwifiex_sdio_device *data = (void *)id->driver_data; 561277b024eSKalle Valo 562277b024eSKalle Valo card->firmware = data->firmware; 563255ca28aSAndrejs Cainikovs card->firmware_sdiouart = data->firmware_sdiouart; 564277b024eSKalle Valo card->reg = data->reg; 565277b024eSKalle Valo card->max_ports = data->max_ports; 566277b024eSKalle Valo card->mp_agg_pkt_limit = data->mp_agg_pkt_limit; 567277b024eSKalle Valo card->supports_sdio_new_mode = data->supports_sdio_new_mode; 568277b024eSKalle Valo card->has_control_mask = data->has_control_mask; 569277b024eSKalle Valo card->tx_buf_size = data->tx_buf_size; 570277b024eSKalle Valo card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; 571277b024eSKalle Valo card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; 572277b024eSKalle Valo card->can_dump_fw = data->can_dump_fw; 573277b024eSKalle Valo card->fw_dump_enh = data->fw_dump_enh; 574277b024eSKalle Valo card->can_auto_tdls = data->can_auto_tdls; 575277b024eSKalle Valo card->can_ext_scan = data->can_ext_scan; 5761c5d463cSDavid Lin card->fw_ready_extra_delay = data->fw_ready_extra_delay; 577cc75c577SXinming Hu INIT_WORK(&card->work, mwifiex_sdio_work); 578277b024eSKalle Valo } 579277b024eSKalle Valo 580277b024eSKalle Valo sdio_claim_host(func); 581277b024eSKalle Valo ret = sdio_enable_func(func); 582277b024eSKalle Valo sdio_release_host(func); 583277b024eSKalle Valo 584277b024eSKalle Valo if (ret) { 585d3f04eceSJavier Martinez Canillas dev_err(&func->dev, "failed to enable function\n"); 58666b9c182SBrian Norris return ret; 587277b024eSKalle Valo } 588277b024eSKalle Valo 589ce4f6f0cSXinming Hu /* device tree node parsing and platform specific configuration*/ 590213d9421SJavier Martinez Canillas if (func->dev.of_node) { 591853402a0SRajat Jain ret = mwifiex_sdio_probe_of(&func->dev); 592853402a0SRajat Jain if (ret) 593213d9421SJavier Martinez Canillas goto err_disable; 594213d9421SJavier Martinez Canillas } 595ce4f6f0cSXinming Hu 5964a79aa17SBrian Norris ret = mwifiex_add_card(card, &card->fw_done, &sdio_ops, 5972e02b581SRajat Jain MWIFIEX_SDIO, &func->dev); 598032e0f54SJavier Martinez Canillas if (ret) { 599d3f04eceSJavier Martinez Canillas dev_err(&func->dev, "add card failed\n"); 600a82f65aaSJavier Martinez Canillas goto err_disable; 601a82f65aaSJavier Martinez Canillas } 602a82f65aaSJavier Martinez Canillas 603a82f65aaSJavier Martinez Canillas return 0; 604a82f65aaSJavier Martinez Canillas 605a82f65aaSJavier Martinez Canillas err_disable: 606277b024eSKalle Valo sdio_claim_host(func); 607032e0f54SJavier Martinez Canillas sdio_disable_func(func); 608277b024eSKalle Valo sdio_release_host(func); 609277b024eSKalle Valo 610277b024eSKalle Valo return ret; 611277b024eSKalle Valo } 612277b024eSKalle Valo 613277b024eSKalle Valo /* 614277b024eSKalle Valo * SDIO resume. 615277b024eSKalle Valo * 616277b024eSKalle Valo * Kernel needs to suspend all functions separately. Therefore all 617277b024eSKalle Valo * registered functions must have drivers with suspend and resume 618277b024eSKalle Valo * methods. Failing that the kernel simply removes the whole card. 619277b024eSKalle Valo * 620277b024eSKalle Valo * If already not resumed, this function turns on the traffic and 621277b024eSKalle Valo * sends a host sleep cancel request to the firmware. 622277b024eSKalle Valo */ 623277b024eSKalle Valo static int mwifiex_sdio_resume(struct device *dev) 624277b024eSKalle Valo { 625277b024eSKalle Valo struct sdio_func *func = dev_to_sdio_func(dev); 626277b024eSKalle Valo struct sdio_mmc_card *card; 627277b024eSKalle Valo struct mwifiex_adapter *adapter; 628277b024eSKalle Valo 629277b024eSKalle Valo card = sdio_get_drvdata(func); 630277b024eSKalle Valo if (!card || !card->adapter) { 6316caf34cbSBrian Norris dev_err(dev, "resume: invalid card or adapter\n"); 632277b024eSKalle Valo return 0; 633277b024eSKalle Valo } 634277b024eSKalle Valo 635277b024eSKalle Valo adapter = card->adapter; 636277b024eSKalle Valo 637b82d6c1fSDouglas Anderson if (!test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) { 638277b024eSKalle Valo mwifiex_dbg(adapter, WARN, 639277b024eSKalle Valo "device already resumed\n"); 640277b024eSKalle Valo return 0; 641277b024eSKalle Valo } 642277b024eSKalle Valo 643fc3a2fcaSGanapathi Bhat clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); 644277b024eSKalle Valo 645277b024eSKalle Valo /* Disable Host Sleep */ 646277b024eSKalle Valo mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), 647a92277bcSAmitkumar Karwar MWIFIEX_SYNC_CMD); 648277b024eSKalle Valo 649853402a0SRajat Jain mwifiex_disable_wake(adapter); 650ce4f6f0cSXinming Hu 651277b024eSKalle Valo return 0; 652277b024eSKalle Valo } 653277b024eSKalle Valo 65490ff71f9SXinming Hu /* Write data into SDIO card register. Caller claims SDIO device. */ 65590ff71f9SXinming Hu static int 65690ff71f9SXinming Hu mwifiex_write_reg_locked(struct sdio_func *func, u32 reg, u8 data) 65790ff71f9SXinming Hu { 65890ff71f9SXinming Hu int ret = -1; 65990ff71f9SXinming Hu 66090ff71f9SXinming Hu sdio_writeb(func, data, reg, &ret); 66190ff71f9SXinming Hu return ret; 66290ff71f9SXinming Hu } 66390ff71f9SXinming Hu 66490ff71f9SXinming Hu /* This function writes data into SDIO card register. 66590ff71f9SXinming Hu */ 66690ff71f9SXinming Hu static int 66790ff71f9SXinming Hu mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u8 data) 66890ff71f9SXinming Hu { 66990ff71f9SXinming Hu struct sdio_mmc_card *card = adapter->card; 67090ff71f9SXinming Hu int ret; 67190ff71f9SXinming Hu 67290ff71f9SXinming Hu sdio_claim_host(card->func); 67390ff71f9SXinming Hu ret = mwifiex_write_reg_locked(card->func, reg, data); 67490ff71f9SXinming Hu sdio_release_host(card->func); 67590ff71f9SXinming Hu 67690ff71f9SXinming Hu return ret; 67790ff71f9SXinming Hu } 67890ff71f9SXinming Hu 67990ff71f9SXinming Hu /* This function reads data from SDIO card register. 68090ff71f9SXinming Hu */ 68190ff71f9SXinming Hu static int 68290ff71f9SXinming Hu mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u8 *data) 68390ff71f9SXinming Hu { 68490ff71f9SXinming Hu struct sdio_mmc_card *card = adapter->card; 68590ff71f9SXinming Hu int ret = -1; 68690ff71f9SXinming Hu u8 val; 68790ff71f9SXinming Hu 68890ff71f9SXinming Hu sdio_claim_host(card->func); 68990ff71f9SXinming Hu val = sdio_readb(card->func, reg, &ret); 69090ff71f9SXinming Hu sdio_release_host(card->func); 69190ff71f9SXinming Hu 69290ff71f9SXinming Hu *data = val; 69390ff71f9SXinming Hu 69490ff71f9SXinming Hu return ret; 69590ff71f9SXinming Hu } 69690ff71f9SXinming Hu 69790ff71f9SXinming Hu /* This function writes multiple data into SDIO card memory. 69890ff71f9SXinming Hu * 69990ff71f9SXinming Hu * This does not work in suspended mode. 70090ff71f9SXinming Hu */ 70190ff71f9SXinming Hu static int 70290ff71f9SXinming Hu mwifiex_write_data_sync(struct mwifiex_adapter *adapter, 70390ff71f9SXinming Hu u8 *buffer, u32 pkt_len, u32 port) 70490ff71f9SXinming Hu { 70590ff71f9SXinming Hu struct sdio_mmc_card *card = adapter->card; 70690ff71f9SXinming Hu int ret; 70790ff71f9SXinming Hu u8 blk_mode = 70890ff71f9SXinming Hu (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; 70990ff71f9SXinming Hu u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; 71090ff71f9SXinming Hu u32 blk_cnt = 71190ff71f9SXinming Hu (blk_mode == 71290ff71f9SXinming Hu BLOCK_MODE) ? (pkt_len / 71390ff71f9SXinming Hu MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len; 71490ff71f9SXinming Hu u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); 71590ff71f9SXinming Hu 716fc3a2fcaSGanapathi Bhat if (test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) { 71790ff71f9SXinming Hu mwifiex_dbg(adapter, ERROR, 71890ff71f9SXinming Hu "%s: not allowed while suspended\n", __func__); 71990ff71f9SXinming Hu return -1; 72090ff71f9SXinming Hu } 72190ff71f9SXinming Hu 72290ff71f9SXinming Hu sdio_claim_host(card->func); 72390ff71f9SXinming Hu 72490ff71f9SXinming Hu ret = sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size); 72590ff71f9SXinming Hu 72690ff71f9SXinming Hu sdio_release_host(card->func); 72790ff71f9SXinming Hu 72890ff71f9SXinming Hu return ret; 72990ff71f9SXinming Hu } 73090ff71f9SXinming Hu 73190ff71f9SXinming Hu /* This function reads multiple data from SDIO card memory. 73290ff71f9SXinming Hu */ 73390ff71f9SXinming Hu static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, 73490ff71f9SXinming Hu u32 len, u32 port, u8 claim) 73590ff71f9SXinming Hu { 73690ff71f9SXinming Hu struct sdio_mmc_card *card = adapter->card; 73790ff71f9SXinming Hu int ret; 73890ff71f9SXinming Hu u8 blk_mode = (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE 73990ff71f9SXinming Hu : BLOCK_MODE; 74090ff71f9SXinming Hu u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; 74190ff71f9SXinming Hu u32 blk_cnt = (blk_mode == BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) 74290ff71f9SXinming Hu : len; 74390ff71f9SXinming Hu u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); 74490ff71f9SXinming Hu 74590ff71f9SXinming Hu if (claim) 74690ff71f9SXinming Hu sdio_claim_host(card->func); 74790ff71f9SXinming Hu 74890ff71f9SXinming Hu ret = sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size); 74990ff71f9SXinming Hu 75090ff71f9SXinming Hu if (claim) 75190ff71f9SXinming Hu sdio_release_host(card->func); 75290ff71f9SXinming Hu 75390ff71f9SXinming Hu return ret; 75490ff71f9SXinming Hu } 75590ff71f9SXinming Hu 75690ff71f9SXinming Hu /* This function reads the firmware status. 75790ff71f9SXinming Hu */ 75890ff71f9SXinming Hu static int 75990ff71f9SXinming Hu mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) 76090ff71f9SXinming Hu { 76190ff71f9SXinming Hu struct sdio_mmc_card *card = adapter->card; 76290ff71f9SXinming Hu const struct mwifiex_sdio_card_reg *reg = card->reg; 76390ff71f9SXinming Hu u8 fws0, fws1; 76490ff71f9SXinming Hu 76590ff71f9SXinming Hu if (mwifiex_read_reg(adapter, reg->status_reg_0, &fws0)) 76690ff71f9SXinming Hu return -1; 76790ff71f9SXinming Hu 76890ff71f9SXinming Hu if (mwifiex_read_reg(adapter, reg->status_reg_1, &fws1)) 76990ff71f9SXinming Hu return -1; 77090ff71f9SXinming Hu 77190ff71f9SXinming Hu *dat = (u16)((fws1 << 8) | fws0); 77290ff71f9SXinming Hu return 0; 77390ff71f9SXinming Hu } 77490ff71f9SXinming Hu 77590ff71f9SXinming Hu /* This function checks the firmware status in card. 77690ff71f9SXinming Hu */ 77790ff71f9SXinming Hu static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, 77890ff71f9SXinming Hu u32 poll_num) 77990ff71f9SXinming Hu { 7801c5d463cSDavid Lin struct sdio_mmc_card *card = adapter->card; 78190ff71f9SXinming Hu int ret = 0; 7823df95e26SDavid Lin u16 firmware_stat = 0; 78390ff71f9SXinming Hu u32 tries; 78490ff71f9SXinming Hu 78590ff71f9SXinming Hu for (tries = 0; tries < poll_num; tries++) { 78690ff71f9SXinming Hu ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); 78790ff71f9SXinming Hu if (ret) 78890ff71f9SXinming Hu continue; 78990ff71f9SXinming Hu if (firmware_stat == FIRMWARE_READY_SDIO) { 79090ff71f9SXinming Hu ret = 0; 79190ff71f9SXinming Hu break; 79290ff71f9SXinming Hu } 79390ff71f9SXinming Hu 79490ff71f9SXinming Hu msleep(100); 79590ff71f9SXinming Hu ret = -1; 79690ff71f9SXinming Hu } 79790ff71f9SXinming Hu 7981c5d463cSDavid Lin if (card->fw_ready_extra_delay && 7991c5d463cSDavid Lin firmware_stat == FIRMWARE_READY_SDIO) 8001c5d463cSDavid Lin /* firmware might pretend to be ready, when it's not. 8011c5d463cSDavid Lin * Wait a little bit more as a workaround. 8021c5d463cSDavid Lin */ 8031c5d463cSDavid Lin msleep(100); 8041c5d463cSDavid Lin 80590ff71f9SXinming Hu return ret; 80690ff71f9SXinming Hu } 80790ff71f9SXinming Hu 80890ff71f9SXinming Hu /* This function checks if WLAN is the winner. 80990ff71f9SXinming Hu */ 81090ff71f9SXinming Hu static int mwifiex_check_winner_status(struct mwifiex_adapter *adapter) 81190ff71f9SXinming Hu { 81290ff71f9SXinming Hu int ret = 0; 81390ff71f9SXinming Hu u8 winner = 0; 81490ff71f9SXinming Hu struct sdio_mmc_card *card = adapter->card; 81590ff71f9SXinming Hu 81690ff71f9SXinming Hu if (mwifiex_read_reg(adapter, card->reg->status_reg_0, &winner)) 81790ff71f9SXinming Hu return -1; 81890ff71f9SXinming Hu 81990ff71f9SXinming Hu if (winner) 82090ff71f9SXinming Hu adapter->winner = 0; 82190ff71f9SXinming Hu else 82290ff71f9SXinming Hu adapter->winner = 1; 82390ff71f9SXinming Hu 82490ff71f9SXinming Hu return ret; 82590ff71f9SXinming Hu } 82690ff71f9SXinming Hu 827277b024eSKalle Valo /* 828277b024eSKalle Valo * SDIO remove. 829277b024eSKalle Valo * 830277b024eSKalle Valo * This function removes the interface and frees up the card structure. 831277b024eSKalle Valo */ 832277b024eSKalle Valo static void 833a7513a4fSXinming Hu mwifiex_sdio_remove(struct sdio_func *func) 834277b024eSKalle Valo { 835277b024eSKalle Valo struct sdio_mmc_card *card; 836277b024eSKalle Valo struct mwifiex_adapter *adapter; 837277b024eSKalle Valo struct mwifiex_private *priv; 838045f0c1bSXinming Hu int ret = 0; 839045f0c1bSXinming Hu u16 firmware_stat; 840277b024eSKalle Valo 841277b024eSKalle Valo card = sdio_get_drvdata(func); 842277b024eSKalle Valo if (!card) 843277b024eSKalle Valo return; 844277b024eSKalle Valo 8454a79aa17SBrian Norris wait_for_completion(&card->fw_done); 8464a79aa17SBrian Norris 847277b024eSKalle Valo adapter = card->adapter; 848277b024eSKalle Valo if (!adapter || !adapter->priv_num) 849277b024eSKalle Valo return; 850277b024eSKalle Valo 851277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num); 852277b024eSKalle Valo 853045f0c1bSXinming Hu ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); 854f46a5b01SShawn Lin if (!ret && firmware_stat == FIRMWARE_READY_SDIO && 855f46a5b01SShawn Lin !adapter->mfg_mode) { 856277b024eSKalle Valo mwifiex_deauthenticate_all(adapter); 857277b024eSKalle Valo 858277b024eSKalle Valo priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); 859277b024eSKalle Valo mwifiex_disable_auto_ds(priv); 860277b024eSKalle Valo mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); 861277b024eSKalle Valo } 862277b024eSKalle Valo 8634a79aa17SBrian Norris mwifiex_remove_card(adapter); 864277b024eSKalle Valo } 865277b024eSKalle Valo 866277b024eSKalle Valo /* 867277b024eSKalle Valo * SDIO suspend. 868277b024eSKalle Valo * 869277b024eSKalle Valo * Kernel needs to suspend all functions separately. Therefore all 870277b024eSKalle Valo * registered functions must have drivers with suspend and resume 871277b024eSKalle Valo * methods. Failing that the kernel simply removes the whole card. 872277b024eSKalle Valo * 873277b024eSKalle Valo * If already not suspended, this function allocates and sends a host 874277b024eSKalle Valo * sleep activate request to the firmware and turns off the traffic. 875277b024eSKalle Valo */ 876277b024eSKalle Valo static int mwifiex_sdio_suspend(struct device *dev) 877277b024eSKalle Valo { 878277b024eSKalle Valo struct sdio_func *func = dev_to_sdio_func(dev); 879277b024eSKalle Valo struct sdio_mmc_card *card; 880277b024eSKalle Valo struct mwifiex_adapter *adapter; 881277b024eSKalle Valo mmc_pm_flag_t pm_flag = 0; 882277b024eSKalle Valo int ret = 0; 883277b024eSKalle Valo 884277b024eSKalle Valo pm_flag = sdio_get_host_pm_caps(func); 885277b024eSKalle Valo pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", 886277b024eSKalle Valo sdio_func_id(func), pm_flag); 887277b024eSKalle Valo if (!(pm_flag & MMC_PM_KEEP_POWER)) { 8886caf34cbSBrian Norris dev_err(dev, "%s: cannot remain alive while host is" 889277b024eSKalle Valo " suspended\n", sdio_func_id(func)); 890277b024eSKalle Valo return -ENOSYS; 891277b024eSKalle Valo } 892277b024eSKalle Valo 893277b024eSKalle Valo card = sdio_get_drvdata(func); 894b42dbb27SBrian Norris if (!card) { 895b42dbb27SBrian Norris dev_err(dev, "suspend: invalid card\n"); 896277b024eSKalle Valo return 0; 897277b024eSKalle Valo } 898277b024eSKalle Valo 899b42dbb27SBrian Norris /* Might still be loading firmware */ 900b42dbb27SBrian Norris wait_for_completion(&card->fw_done); 901b42dbb27SBrian Norris 902277b024eSKalle Valo adapter = card->adapter; 903b42dbb27SBrian Norris if (!adapter) { 904b42dbb27SBrian Norris dev_err(dev, "adapter is not valid\n"); 905b42dbb27SBrian Norris return 0; 906b42dbb27SBrian Norris } 907b42dbb27SBrian Norris 908cdb2256fSUlf Hansson if (!adapter->is_up) 909cdb2256fSUlf Hansson return -EBUSY; 910cdb2256fSUlf Hansson 911853402a0SRajat Jain mwifiex_enable_wake(adapter); 912ce4f6f0cSXinming Hu 913277b024eSKalle Valo /* Enable the Host Sleep */ 914277b024eSKalle Valo if (!mwifiex_enable_hs(adapter)) { 915277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 916277b024eSKalle Valo "cmd: failed to suspend\n"); 917fc3a2fcaSGanapathi Bhat clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); 918d96e3927SBrian Norris mwifiex_disable_wake(adapter); 919277b024eSKalle Valo return -EFAULT; 920277b024eSKalle Valo } 921277b024eSKalle Valo 922277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 923277b024eSKalle Valo "cmd: suspend with MMC_PM_KEEP_POWER\n"); 924277b024eSKalle Valo ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 925277b024eSKalle Valo 926277b024eSKalle Valo /* Indicate device suspended */ 927fc3a2fcaSGanapathi Bhat set_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); 928fc3a2fcaSGanapathi Bhat clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); 929277b024eSKalle Valo 930277b024eSKalle Valo return ret; 931277b024eSKalle Valo } 932277b024eSKalle Valo 93321c5c83cSArend Van Spriel static void mwifiex_sdio_coredump(struct device *dev) 93421c5c83cSArend Van Spriel { 93521c5c83cSArend Van Spriel struct sdio_func *func = dev_to_sdio_func(dev); 93621c5c83cSArend Van Spriel struct sdio_mmc_card *card; 93721c5c83cSArend Van Spriel 93821c5c83cSArend Van Spriel card = sdio_get_drvdata(func); 93921c5c83cSArend Van Spriel if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, 94021c5c83cSArend Van Spriel &card->work_flags)) 94121c5c83cSArend Van Spriel schedule_work(&card->work); 94221c5c83cSArend Van Spriel } 94321c5c83cSArend Van Spriel 944277b024eSKalle Valo /* WLAN IDs */ 945277b024eSKalle Valo static const struct sdio_device_id mwifiex_ids[] = { 9467d14c687SPali Rohár {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786_WLAN), 947277b024eSKalle Valo .driver_data = (unsigned long) &mwifiex_sdio_sd8786}, 9487d14c687SPali Rohár {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787_WLAN), 949277b024eSKalle Valo .driver_data = (unsigned long) &mwifiex_sdio_sd8787}, 9507d14c687SPali Rohár {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_WLAN), 951277b024eSKalle Valo .driver_data = (unsigned long) &mwifiex_sdio_sd8797}, 9527d14c687SPali Rohár {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897_WLAN), 953277b024eSKalle Valo .driver_data = (unsigned long) &mwifiex_sdio_sd8897}, 9547d14c687SPali Rohár {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887_WLAN), 955277b024eSKalle Valo .driver_data = (unsigned long)&mwifiex_sdio_sd8887}, 9567d14c687SPali Rohár {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801_WLAN), 957277b024eSKalle Valo .driver_data = (unsigned long)&mwifiex_sdio_sd8801}, 9587d14c687SPali Rohár {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8977_WLAN), 9591a0f5478SHemantkumar Suthar .driver_data = (unsigned long)&mwifiex_sdio_sd8977}, 960bba047f1SLukas Wunner {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8978_WLAN), 961bba047f1SLukas Wunner .driver_data = (unsigned long)&mwifiex_sdio_sd8978}, 9627d14c687SPali Rohár {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8987_WLAN), 963938c7c80STamás Szűcs .driver_data = (unsigned long)&mwifiex_sdio_sd8987}, 9647d14c687SPali Rohár {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8997_WLAN), 965277b024eSKalle Valo .driver_data = (unsigned long)&mwifiex_sdio_sd8997}, 966277b024eSKalle Valo {}, 967277b024eSKalle Valo }; 968277b024eSKalle Valo 969277b024eSKalle Valo MODULE_DEVICE_TABLE(sdio, mwifiex_ids); 970277b024eSKalle Valo 971277b024eSKalle Valo static const struct dev_pm_ops mwifiex_sdio_pm_ops = { 972277b024eSKalle Valo .suspend = mwifiex_sdio_suspend, 973277b024eSKalle Valo .resume = mwifiex_sdio_resume, 974277b024eSKalle Valo }; 975277b024eSKalle Valo 976277b024eSKalle Valo static struct sdio_driver mwifiex_sdio = { 977277b024eSKalle Valo .name = "mwifiex_sdio", 978277b024eSKalle Valo .id_table = mwifiex_ids, 979277b024eSKalle Valo .probe = mwifiex_sdio_probe, 980277b024eSKalle Valo .remove = mwifiex_sdio_remove, 981277b024eSKalle Valo .drv = { 982277b024eSKalle Valo .owner = THIS_MODULE, 98321c5c83cSArend Van Spriel .coredump = mwifiex_sdio_coredump, 984277b024eSKalle Valo .pm = &mwifiex_sdio_pm_ops, 985277b024eSKalle Valo } 986277b024eSKalle Valo }; 987277b024eSKalle Valo 988277b024eSKalle Valo /* 989277b024eSKalle Valo * This function wakes up the card. 990277b024eSKalle Valo * 991277b024eSKalle Valo * A host power up command is written to the card configuration 992277b024eSKalle Valo * register to wake up the card. 993277b024eSKalle Valo */ 994277b024eSKalle Valo static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) 995277b024eSKalle Valo { 996277b024eSKalle Valo mwifiex_dbg(adapter, EVENT, 997277b024eSKalle Valo "event: wakeup device...\n"); 998277b024eSKalle Valo 999277b024eSKalle Valo return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP); 1000277b024eSKalle Valo } 1001277b024eSKalle Valo 1002277b024eSKalle Valo /* 1003277b024eSKalle Valo * This function is called after the card has woken up. 1004277b024eSKalle Valo * 1005277b024eSKalle Valo * The card configuration register is reset. 1006277b024eSKalle Valo */ 1007277b024eSKalle Valo static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) 1008277b024eSKalle Valo { 1009277b024eSKalle Valo mwifiex_dbg(adapter, EVENT, 1010277b024eSKalle Valo "cmd: wakeup device completed\n"); 1011277b024eSKalle Valo 1012277b024eSKalle Valo return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0); 1013277b024eSKalle Valo } 1014277b024eSKalle Valo 10152095b142SArnd Bergmann static int mwifiex_sdio_dnld_fw(struct mwifiex_adapter *adapter, 10162095b142SArnd Bergmann struct mwifiex_fw_image *fw) 10172095b142SArnd Bergmann { 10182095b142SArnd Bergmann struct sdio_mmc_card *card = adapter->card; 10192095b142SArnd Bergmann int ret; 10202095b142SArnd Bergmann 10212095b142SArnd Bergmann sdio_claim_host(card->func); 10222095b142SArnd Bergmann ret = mwifiex_dnld_fw(adapter, fw); 10232095b142SArnd Bergmann sdio_release_host(card->func); 10242095b142SArnd Bergmann 10252095b142SArnd Bergmann return ret; 10262095b142SArnd Bergmann } 10272095b142SArnd Bergmann 1028277b024eSKalle Valo /* 1029277b024eSKalle Valo * This function is used to initialize IO ports for the 1030277b024eSKalle Valo * chipsets supporting SDIO new mode eg SD8897. 1031277b024eSKalle Valo */ 1032277b024eSKalle Valo static int mwifiex_init_sdio_new_mode(struct mwifiex_adapter *adapter) 1033277b024eSKalle Valo { 1034277b024eSKalle Valo u8 reg; 1035277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1036277b024eSKalle Valo 1037277b024eSKalle Valo adapter->ioport = MEM_PORT; 1038277b024eSKalle Valo 1039277b024eSKalle Valo /* enable sdio new mode */ 1040277b024eSKalle Valo if (mwifiex_read_reg(adapter, card->reg->card_cfg_2_1_reg, ®)) 1041277b024eSKalle Valo return -1; 1042277b024eSKalle Valo if (mwifiex_write_reg(adapter, card->reg->card_cfg_2_1_reg, 1043277b024eSKalle Valo reg | CMD53_NEW_MODE)) 1044277b024eSKalle Valo return -1; 1045277b024eSKalle Valo 1046277b024eSKalle Valo /* Configure cmd port and enable reading rx length from the register */ 1047277b024eSKalle Valo if (mwifiex_read_reg(adapter, card->reg->cmd_cfg_0, ®)) 1048277b024eSKalle Valo return -1; 1049277b024eSKalle Valo if (mwifiex_write_reg(adapter, card->reg->cmd_cfg_0, 1050277b024eSKalle Valo reg | CMD_PORT_RD_LEN_EN)) 1051277b024eSKalle Valo return -1; 1052277b024eSKalle Valo 1053277b024eSKalle Valo /* Enable Dnld/Upld ready auto reset for cmd port after cmd53 is 1054277b024eSKalle Valo * completed 1055277b024eSKalle Valo */ 1056277b024eSKalle Valo if (mwifiex_read_reg(adapter, card->reg->cmd_cfg_1, ®)) 1057277b024eSKalle Valo return -1; 1058277b024eSKalle Valo if (mwifiex_write_reg(adapter, card->reg->cmd_cfg_1, 1059277b024eSKalle Valo reg | CMD_PORT_AUTO_EN)) 1060277b024eSKalle Valo return -1; 1061277b024eSKalle Valo 1062277b024eSKalle Valo return 0; 1063277b024eSKalle Valo } 1064277b024eSKalle Valo 1065277b024eSKalle Valo /* This function initializes the IO ports. 1066277b024eSKalle Valo * 1067277b024eSKalle Valo * The following operations are performed - 1068277b024eSKalle Valo * - Read the IO ports (0, 1 and 2) 1069277b024eSKalle Valo * - Set host interrupt Reset-To-Read to clear 1070277b024eSKalle Valo * - Set auto re-enable interrupt 1071277b024eSKalle Valo */ 1072277b024eSKalle Valo static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) 1073277b024eSKalle Valo { 1074277b024eSKalle Valo u8 reg; 1075277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1076277b024eSKalle Valo 1077277b024eSKalle Valo adapter->ioport = 0; 1078277b024eSKalle Valo 1079277b024eSKalle Valo if (card->supports_sdio_new_mode) { 1080277b024eSKalle Valo if (mwifiex_init_sdio_new_mode(adapter)) 1081277b024eSKalle Valo return -1; 1082277b024eSKalle Valo goto cont; 1083277b024eSKalle Valo } 1084277b024eSKalle Valo 1085277b024eSKalle Valo /* Read the IO port */ 1086277b024eSKalle Valo if (!mwifiex_read_reg(adapter, card->reg->io_port_0_reg, ®)) 1087277b024eSKalle Valo adapter->ioport |= (reg & 0xff); 1088277b024eSKalle Valo else 1089277b024eSKalle Valo return -1; 1090277b024eSKalle Valo 1091277b024eSKalle Valo if (!mwifiex_read_reg(adapter, card->reg->io_port_1_reg, ®)) 1092277b024eSKalle Valo adapter->ioport |= ((reg & 0xff) << 8); 1093277b024eSKalle Valo else 1094277b024eSKalle Valo return -1; 1095277b024eSKalle Valo 1096277b024eSKalle Valo if (!mwifiex_read_reg(adapter, card->reg->io_port_2_reg, ®)) 1097277b024eSKalle Valo adapter->ioport |= ((reg & 0xff) << 16); 1098277b024eSKalle Valo else 1099277b024eSKalle Valo return -1; 1100277b024eSKalle Valo cont: 1101277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1102277b024eSKalle Valo "info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); 1103277b024eSKalle Valo 1104277b024eSKalle Valo /* Set Host interrupt reset to read to clear */ 1105a6b3a016SDmitry Antipov if (mwifiex_read_reg(adapter, card->reg->host_int_rsr_reg, ®)) 1106a6b3a016SDmitry Antipov return -1; 1107a6b3a016SDmitry Antipov if (mwifiex_write_reg(adapter, card->reg->host_int_rsr_reg, 1108a6b3a016SDmitry Antipov reg | card->reg->sdio_int_mask)) 1109277b024eSKalle Valo return -1; 1110277b024eSKalle Valo 1111277b024eSKalle Valo /* Dnld/Upld ready set to auto reset */ 1112a6b3a016SDmitry Antipov if (mwifiex_read_reg(adapter, card->reg->card_misc_cfg_reg, ®)) 1113a6b3a016SDmitry Antipov return -1; 1114a6b3a016SDmitry Antipov if (mwifiex_write_reg(adapter, card->reg->card_misc_cfg_reg, 1115a6b3a016SDmitry Antipov reg | AUTO_RE_ENABLE_INT)) 1116277b024eSKalle Valo return -1; 1117277b024eSKalle Valo 1118277b024eSKalle Valo return 0; 1119277b024eSKalle Valo } 1120277b024eSKalle Valo 1121277b024eSKalle Valo /* 1122277b024eSKalle Valo * This function sends data to the card. 1123277b024eSKalle Valo */ 1124277b024eSKalle Valo static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, 1125277b024eSKalle Valo u8 *payload, u32 pkt_len, u32 port) 1126277b024eSKalle Valo { 1127277b024eSKalle Valo u32 i = 0; 1128277b024eSKalle Valo int ret; 1129277b024eSKalle Valo 1130277b024eSKalle Valo do { 1131277b024eSKalle Valo ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port); 1132277b024eSKalle Valo if (ret) { 1133277b024eSKalle Valo i++; 1134277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1135277b024eSKalle Valo "host_to_card, write iomem\t" 1136277b024eSKalle Valo "(%d) failed: %d\n", i, ret); 1137277b024eSKalle Valo if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) 1138277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1139277b024eSKalle Valo "write CFG reg failed\n"); 1140277b024eSKalle Valo 1141277b024eSKalle Valo ret = -1; 1142277b024eSKalle Valo if (i > MAX_WRITE_IOMEM_RETRY) 1143277b024eSKalle Valo return ret; 1144277b024eSKalle Valo } 1145277b024eSKalle Valo } while (ret == -1); 1146277b024eSKalle Valo 1147277b024eSKalle Valo return ret; 1148277b024eSKalle Valo } 1149277b024eSKalle Valo 1150277b024eSKalle Valo /* 1151277b024eSKalle Valo * This function gets the read port. 1152277b024eSKalle Valo * 1153277b024eSKalle Valo * If control port bit is set in MP read bitmap, the control port 1154277b024eSKalle Valo * is returned, otherwise the current read port is returned and 1155277b024eSKalle Valo * the value is increased (provided it does not reach the maximum 1156277b024eSKalle Valo * limit, in which case it is reset to 1) 1157277b024eSKalle Valo */ 1158277b024eSKalle Valo static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) 1159277b024eSKalle Valo { 1160277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1161277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 1162277b024eSKalle Valo u32 rd_bitmap = card->mp_rd_bitmap; 1163277b024eSKalle Valo 1164277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1165277b024eSKalle Valo "data: mp_rd_bitmap=0x%08x\n", rd_bitmap); 1166277b024eSKalle Valo 1167277b024eSKalle Valo if (card->supports_sdio_new_mode) { 1168277b024eSKalle Valo if (!(rd_bitmap & reg->data_port_mask)) 1169277b024eSKalle Valo return -1; 1170277b024eSKalle Valo } else { 1171277b024eSKalle Valo if (!(rd_bitmap & (CTRL_PORT_MASK | reg->data_port_mask))) 1172277b024eSKalle Valo return -1; 1173277b024eSKalle Valo } 1174277b024eSKalle Valo 1175277b024eSKalle Valo if ((card->has_control_mask) && 1176277b024eSKalle Valo (card->mp_rd_bitmap & CTRL_PORT_MASK)) { 1177277b024eSKalle Valo card->mp_rd_bitmap &= (u32) (~CTRL_PORT_MASK); 1178277b024eSKalle Valo *port = CTRL_PORT; 1179277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1180277b024eSKalle Valo "data: port=%d mp_rd_bitmap=0x%08x\n", 1181277b024eSKalle Valo *port, card->mp_rd_bitmap); 1182277b024eSKalle Valo return 0; 1183277b024eSKalle Valo } 1184277b024eSKalle Valo 1185277b024eSKalle Valo if (!(card->mp_rd_bitmap & (1 << card->curr_rd_port))) 1186277b024eSKalle Valo return -1; 1187277b024eSKalle Valo 1188277b024eSKalle Valo /* We are now handling the SDIO data ports */ 1189277b024eSKalle Valo card->mp_rd_bitmap &= (u32)(~(1 << card->curr_rd_port)); 1190277b024eSKalle Valo *port = card->curr_rd_port; 1191277b024eSKalle Valo 1192277b024eSKalle Valo if (++card->curr_rd_port == card->max_ports) 1193277b024eSKalle Valo card->curr_rd_port = reg->start_rd_port; 1194277b024eSKalle Valo 1195277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1196277b024eSKalle Valo "data: port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n", 1197277b024eSKalle Valo *port, rd_bitmap, card->mp_rd_bitmap); 1198277b024eSKalle Valo 1199277b024eSKalle Valo return 0; 1200277b024eSKalle Valo } 1201277b024eSKalle Valo 1202277b024eSKalle Valo /* 1203277b024eSKalle Valo * This function gets the write port for data. 1204277b024eSKalle Valo * 1205277b024eSKalle Valo * The current write port is returned if available and the value is 1206277b024eSKalle Valo * increased (provided it does not reach the maximum limit, in which 1207277b024eSKalle Valo * case it is reset to 1) 1208277b024eSKalle Valo */ 1209277b024eSKalle Valo static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port) 1210277b024eSKalle Valo { 1211277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1212277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 1213277b024eSKalle Valo u32 wr_bitmap = card->mp_wr_bitmap; 1214277b024eSKalle Valo 1215277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1216277b024eSKalle Valo "data: mp_wr_bitmap=0x%08x\n", wr_bitmap); 1217277b024eSKalle Valo 1218277b024eSKalle Valo if (!(wr_bitmap & card->mp_data_port_mask)) { 1219277b024eSKalle Valo adapter->data_sent = true; 1220277b024eSKalle Valo return -EBUSY; 1221277b024eSKalle Valo } 1222277b024eSKalle Valo 1223277b024eSKalle Valo if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { 1224277b024eSKalle Valo card->mp_wr_bitmap &= (u32) (~(1 << card->curr_wr_port)); 1225277b024eSKalle Valo *port = card->curr_wr_port; 1226277b024eSKalle Valo if (++card->curr_wr_port == card->mp_end_port) 1227277b024eSKalle Valo card->curr_wr_port = reg->start_wr_port; 1228277b024eSKalle Valo } else { 1229277b024eSKalle Valo adapter->data_sent = true; 1230277b024eSKalle Valo return -EBUSY; 1231277b024eSKalle Valo } 1232277b024eSKalle Valo 1233277b024eSKalle Valo if ((card->has_control_mask) && (*port == CTRL_PORT)) { 1234277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1235277b024eSKalle Valo "invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n", 1236277b024eSKalle Valo *port, card->curr_wr_port, wr_bitmap, 1237277b024eSKalle Valo card->mp_wr_bitmap); 1238277b024eSKalle Valo return -1; 1239277b024eSKalle Valo } 1240277b024eSKalle Valo 1241277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1242277b024eSKalle Valo "data: port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n", 1243277b024eSKalle Valo *port, wr_bitmap, card->mp_wr_bitmap); 1244277b024eSKalle Valo 1245277b024eSKalle Valo return 0; 1246277b024eSKalle Valo } 1247277b024eSKalle Valo 1248277b024eSKalle Valo /* 1249277b024eSKalle Valo * This function polls the card status. 1250277b024eSKalle Valo */ 1251277b024eSKalle Valo static int 1252277b024eSKalle Valo mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) 1253277b024eSKalle Valo { 1254277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1255277b024eSKalle Valo u32 tries; 1256277b024eSKalle Valo u8 cs; 1257277b024eSKalle Valo 1258277b024eSKalle Valo for (tries = 0; tries < MAX_POLL_TRIES; tries++) { 1259277b024eSKalle Valo if (mwifiex_read_reg(adapter, card->reg->poll_reg, &cs)) 1260277b024eSKalle Valo break; 1261277b024eSKalle Valo else if ((cs & bits) == bits) 1262277b024eSKalle Valo return 0; 1263277b024eSKalle Valo 1264277b024eSKalle Valo usleep_range(10, 20); 1265277b024eSKalle Valo } 1266277b024eSKalle Valo 1267277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1268277b024eSKalle Valo "poll card status failed, tries = %d\n", tries); 1269277b024eSKalle Valo 1270277b024eSKalle Valo return -1; 1271277b024eSKalle Valo } 1272277b024eSKalle Valo 1273277b024eSKalle Valo /* 1274277b024eSKalle Valo * This function disables the host interrupt. 1275277b024eSKalle Valo * 1276277b024eSKalle Valo * The host interrupt mask is read, the disable bit is reset and 1277277b024eSKalle Valo * written back to the card host interrupt mask register. 1278277b024eSKalle Valo */ 1279277b024eSKalle Valo static void mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) 1280277b024eSKalle Valo { 1281277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1282277b024eSKalle Valo struct sdio_func *func = card->func; 1283277b024eSKalle Valo 1284277b024eSKalle Valo sdio_claim_host(func); 1285277b024eSKalle Valo mwifiex_write_reg_locked(func, card->reg->host_int_mask_reg, 0); 1286277b024eSKalle Valo sdio_release_irq(func); 1287277b024eSKalle Valo sdio_release_host(func); 1288277b024eSKalle Valo } 1289277b024eSKalle Valo 1290277b024eSKalle Valo /* 1291277b024eSKalle Valo * This function reads the interrupt status from card. 1292277b024eSKalle Valo */ 1293277b024eSKalle Valo static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) 1294277b024eSKalle Valo { 1295277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1296277b024eSKalle Valo u8 sdio_ireg; 1297277b024eSKalle Valo unsigned long flags; 1298277b024eSKalle Valo 1299277b024eSKalle Valo if (mwifiex_read_data_sync(adapter, card->mp_regs, 1300277b024eSKalle Valo card->reg->max_mp_regs, 1301277b024eSKalle Valo REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) { 1302277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "read mp_regs failed\n"); 1303277b024eSKalle Valo return; 1304277b024eSKalle Valo } 1305277b024eSKalle Valo 1306277b024eSKalle Valo sdio_ireg = card->mp_regs[card->reg->host_int_status_reg]; 1307277b024eSKalle Valo if (sdio_ireg) { 1308277b024eSKalle Valo /* 1309277b024eSKalle Valo * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS 1310277b024eSKalle Valo * For SDIO new mode CMD port interrupts 1311277b024eSKalle Valo * DN_LD_CMD_PORT_HOST_INT_STATUS and/or 1312277b024eSKalle Valo * UP_LD_CMD_PORT_HOST_INT_STATUS 1313277b024eSKalle Valo * Clear the interrupt status register 1314277b024eSKalle Valo */ 1315277b024eSKalle Valo mwifiex_dbg(adapter, INTR, 1316277b024eSKalle Valo "int: sdio_ireg = %#x\n", sdio_ireg); 1317277b024eSKalle Valo spin_lock_irqsave(&adapter->int_lock, flags); 1318277b024eSKalle Valo adapter->int_status |= sdio_ireg; 1319277b024eSKalle Valo spin_unlock_irqrestore(&adapter->int_lock, flags); 1320277b024eSKalle Valo } 1321277b024eSKalle Valo } 1322277b024eSKalle Valo 1323277b024eSKalle Valo /* 1324277b024eSKalle Valo * SDIO interrupt handler. 1325277b024eSKalle Valo * 1326277b024eSKalle Valo * This function reads the interrupt status from firmware and handles 1327277b024eSKalle Valo * the interrupt in current thread (ksdioirqd) right away. 1328277b024eSKalle Valo */ 1329277b024eSKalle Valo static void 1330277b024eSKalle Valo mwifiex_sdio_interrupt(struct sdio_func *func) 1331277b024eSKalle Valo { 1332277b024eSKalle Valo struct mwifiex_adapter *adapter; 1333277b024eSKalle Valo struct sdio_mmc_card *card; 1334277b024eSKalle Valo 1335277b024eSKalle Valo card = sdio_get_drvdata(func); 1336277b024eSKalle Valo if (!card || !card->adapter) { 133791442431SXinming Hu pr_err("int: func=%p card=%p adapter=%p\n", 1338277b024eSKalle Valo func, card, card ? card->adapter : NULL); 1339277b024eSKalle Valo return; 1340277b024eSKalle Valo } 1341277b024eSKalle Valo adapter = card->adapter; 1342277b024eSKalle Valo 1343277b024eSKalle Valo if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) 1344277b024eSKalle Valo adapter->ps_state = PS_STATE_AWAKE; 1345277b024eSKalle Valo 1346277b024eSKalle Valo mwifiex_interrupt_status(adapter); 1347277b024eSKalle Valo mwifiex_main_process(adapter); 1348277b024eSKalle Valo } 1349277b024eSKalle Valo 1350277b024eSKalle Valo /* 1351277b024eSKalle Valo * This function enables the host interrupt. 1352277b024eSKalle Valo * 1353277b024eSKalle Valo * The host interrupt enable mask is written to the card 1354277b024eSKalle Valo * host interrupt mask register. 1355277b024eSKalle Valo */ 1356277b024eSKalle Valo static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) 1357277b024eSKalle Valo { 1358277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1359277b024eSKalle Valo struct sdio_func *func = card->func; 1360277b024eSKalle Valo int ret; 1361277b024eSKalle Valo 1362277b024eSKalle Valo sdio_claim_host(func); 1363277b024eSKalle Valo 1364277b024eSKalle Valo /* Request the SDIO IRQ */ 1365277b024eSKalle Valo ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); 1366277b024eSKalle Valo if (ret) { 1367277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1368277b024eSKalle Valo "claim irq failed: ret=%d\n", ret); 1369277b024eSKalle Valo goto out; 1370277b024eSKalle Valo } 1371277b024eSKalle Valo 1372277b024eSKalle Valo /* Simply write the mask to the register */ 1373277b024eSKalle Valo ret = mwifiex_write_reg_locked(func, card->reg->host_int_mask_reg, 1374277b024eSKalle Valo card->reg->host_int_enable); 1375277b024eSKalle Valo if (ret) { 1376277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1377277b024eSKalle Valo "enable host interrupt failed\n"); 1378277b024eSKalle Valo sdio_release_irq(func); 1379277b024eSKalle Valo } 1380277b024eSKalle Valo 1381277b024eSKalle Valo out: 1382277b024eSKalle Valo sdio_release_host(func); 1383277b024eSKalle Valo return ret; 1384277b024eSKalle Valo } 1385277b024eSKalle Valo 1386277b024eSKalle Valo /* 1387277b024eSKalle Valo * This function sends a data buffer to the card. 1388277b024eSKalle Valo */ 1389277b024eSKalle Valo static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, 1390277b024eSKalle Valo u32 *type, u8 *buffer, 1391277b024eSKalle Valo u32 npayload, u32 ioport) 1392277b024eSKalle Valo { 1393277b024eSKalle Valo int ret; 1394277b024eSKalle Valo u32 nb; 1395277b024eSKalle Valo 1396277b024eSKalle Valo if (!buffer) { 1397277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1398277b024eSKalle Valo "%s: buffer is NULL\n", __func__); 1399277b024eSKalle Valo return -1; 1400277b024eSKalle Valo } 1401277b024eSKalle Valo 1402277b024eSKalle Valo ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1); 1403277b024eSKalle Valo 1404277b024eSKalle Valo if (ret) { 1405277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1406277b024eSKalle Valo "%s: read iomem failed: %d\n", __func__, 1407277b024eSKalle Valo ret); 1408277b024eSKalle Valo return -1; 1409277b024eSKalle Valo } 1410277b024eSKalle Valo 141192c70a95SDevidas Puranik nb = get_unaligned_le16((buffer)); 1412277b024eSKalle Valo if (nb > npayload) { 1413277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1414277b024eSKalle Valo "%s: invalid packet, nb=%d npayload=%d\n", 1415277b024eSKalle Valo __func__, nb, npayload); 1416277b024eSKalle Valo return -1; 1417277b024eSKalle Valo } 1418277b024eSKalle Valo 141992c70a95SDevidas Puranik *type = get_unaligned_le16((buffer + 2)); 1420277b024eSKalle Valo 1421277b024eSKalle Valo return ret; 1422277b024eSKalle Valo } 1423277b024eSKalle Valo 1424277b024eSKalle Valo /* 1425277b024eSKalle Valo * This function downloads the firmware to the card. 1426277b024eSKalle Valo * 1427277b024eSKalle Valo * Firmware is downloaded to the card in blocks. Every block download 1428277b024eSKalle Valo * is tested for CRC errors, and retried a number of times before 1429277b024eSKalle Valo * returning failure. 1430277b024eSKalle Valo */ 1431277b024eSKalle Valo static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, 1432277b024eSKalle Valo struct mwifiex_fw_image *fw) 1433277b024eSKalle Valo { 1434277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1435277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 1436277b024eSKalle Valo int ret; 1437277b024eSKalle Valo u8 *firmware = fw->fw_buf; 1438277b024eSKalle Valo u32 firmware_len = fw->fw_len; 1439277b024eSKalle Valo u32 offset = 0; 1440277b024eSKalle Valo u8 base0, base1; 1441277b024eSKalle Valo u8 *fwbuf; 1442277b024eSKalle Valo u16 len = 0; 1443277b024eSKalle Valo u32 txlen, tx_blocks = 0, tries; 1444277b024eSKalle Valo u32 i = 0; 1445277b024eSKalle Valo 1446277b024eSKalle Valo if (!firmware_len) { 1447277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1448277b024eSKalle Valo "firmware image not found! Terminating download\n"); 1449277b024eSKalle Valo return -1; 1450277b024eSKalle Valo } 1451277b024eSKalle Valo 1452277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1453277b024eSKalle Valo "info: downloading FW image (%d bytes)\n", 1454277b024eSKalle Valo firmware_len); 1455277b024eSKalle Valo 1456277b024eSKalle Valo /* Assume that the allocated buffer is 8-byte aligned */ 1457277b024eSKalle Valo fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL); 1458277b024eSKalle Valo if (!fwbuf) 1459277b024eSKalle Valo return -ENOMEM; 1460277b024eSKalle Valo 1461277b024eSKalle Valo sdio_claim_host(card->func); 1462277b024eSKalle Valo 1463277b024eSKalle Valo /* Perform firmware data transfer */ 1464277b024eSKalle Valo do { 1465277b024eSKalle Valo /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY 1466277b024eSKalle Valo bits */ 1467277b024eSKalle Valo ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY | 1468277b024eSKalle Valo DN_LD_CARD_RDY); 1469277b024eSKalle Valo if (ret) { 1470277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1471277b024eSKalle Valo "FW download with helper:\t" 1472277b024eSKalle Valo "poll status timeout @ %d\n", offset); 1473277b024eSKalle Valo goto done; 1474277b024eSKalle Valo } 1475277b024eSKalle Valo 1476277b024eSKalle Valo /* More data? */ 1477277b024eSKalle Valo if (offset >= firmware_len) 1478277b024eSKalle Valo break; 1479277b024eSKalle Valo 1480277b024eSKalle Valo for (tries = 0; tries < MAX_POLL_TRIES; tries++) { 1481277b024eSKalle Valo ret = mwifiex_read_reg(adapter, reg->base_0_reg, 1482277b024eSKalle Valo &base0); 1483277b024eSKalle Valo if (ret) { 1484277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1485277b024eSKalle Valo "dev BASE0 register read failed:\t" 1486277b024eSKalle Valo "base0=%#04X(%d). Terminating dnld\n", 1487277b024eSKalle Valo base0, base0); 1488277b024eSKalle Valo goto done; 1489277b024eSKalle Valo } 1490277b024eSKalle Valo ret = mwifiex_read_reg(adapter, reg->base_1_reg, 1491277b024eSKalle Valo &base1); 1492277b024eSKalle Valo if (ret) { 1493277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1494277b024eSKalle Valo "dev BASE1 register read failed:\t" 1495277b024eSKalle Valo "base1=%#04X(%d). Terminating dnld\n", 1496277b024eSKalle Valo base1, base1); 1497277b024eSKalle Valo goto done; 1498277b024eSKalle Valo } 1499277b024eSKalle Valo len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff)); 1500277b024eSKalle Valo 1501277b024eSKalle Valo if (len) 1502277b024eSKalle Valo break; 1503277b024eSKalle Valo 1504277b024eSKalle Valo usleep_range(10, 20); 1505277b024eSKalle Valo } 1506277b024eSKalle Valo 1507277b024eSKalle Valo if (!len) { 1508277b024eSKalle Valo break; 1509277b024eSKalle Valo } else if (len > MWIFIEX_UPLD_SIZE) { 1510277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1511277b024eSKalle Valo "FW dnld failed @ %d, invalid length %d\n", 1512277b024eSKalle Valo offset, len); 1513277b024eSKalle Valo ret = -1; 1514277b024eSKalle Valo goto done; 1515277b024eSKalle Valo } 1516277b024eSKalle Valo 1517277b024eSKalle Valo txlen = len; 1518277b024eSKalle Valo 1519277b024eSKalle Valo if (len & BIT(0)) { 1520277b024eSKalle Valo i++; 1521277b024eSKalle Valo if (i > MAX_WRITE_IOMEM_RETRY) { 1522277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1523277b024eSKalle Valo "FW dnld failed @ %d, over max retry\n", 1524277b024eSKalle Valo offset); 1525277b024eSKalle Valo ret = -1; 1526277b024eSKalle Valo goto done; 1527277b024eSKalle Valo } 1528277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1529277b024eSKalle Valo "CRC indicated by the helper:\t" 1530277b024eSKalle Valo "len = 0x%04X, txlen = %d\n", len, txlen); 1531277b024eSKalle Valo len &= ~BIT(0); 1532277b024eSKalle Valo /* Setting this to 0 to resend from same offset */ 1533277b024eSKalle Valo txlen = 0; 1534277b024eSKalle Valo } else { 1535277b024eSKalle Valo i = 0; 1536277b024eSKalle Valo 1537277b024eSKalle Valo /* Set blocksize to transfer - checking for last 1538277b024eSKalle Valo block */ 1539277b024eSKalle Valo if (firmware_len - offset < txlen) 1540277b024eSKalle Valo txlen = firmware_len - offset; 1541277b024eSKalle Valo 1542277b024eSKalle Valo tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE - 1) 1543277b024eSKalle Valo / MWIFIEX_SDIO_BLOCK_SIZE; 1544277b024eSKalle Valo 1545277b024eSKalle Valo /* Copy payload to buffer */ 1546277b024eSKalle Valo memmove(fwbuf, &firmware[offset], txlen); 1547277b024eSKalle Valo } 1548277b024eSKalle Valo 1549277b024eSKalle Valo ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks * 1550277b024eSKalle Valo MWIFIEX_SDIO_BLOCK_SIZE, 1551277b024eSKalle Valo adapter->ioport); 1552277b024eSKalle Valo if (ret) { 1553277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1554277b024eSKalle Valo "FW download, write iomem (%d) failed @ %d\n", 1555277b024eSKalle Valo i, offset); 1556277b024eSKalle Valo if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04)) 1557277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1558277b024eSKalle Valo "write CFG reg failed\n"); 1559277b024eSKalle Valo 1560277b024eSKalle Valo ret = -1; 1561277b024eSKalle Valo goto done; 1562277b024eSKalle Valo } 1563277b024eSKalle Valo 1564277b024eSKalle Valo offset += txlen; 1565277b024eSKalle Valo } while (true); 1566277b024eSKalle Valo 1567277b024eSKalle Valo mwifiex_dbg(adapter, MSG, 1568277b024eSKalle Valo "info: FW download over, size %d bytes\n", offset); 1569277b024eSKalle Valo 1570277b024eSKalle Valo ret = 0; 1571277b024eSKalle Valo done: 1572b977d305SMarty Faltesek sdio_release_host(card->func); 1573277b024eSKalle Valo kfree(fwbuf); 1574277b024eSKalle Valo return ret; 1575277b024eSKalle Valo } 1576277b024eSKalle Valo 1577277b024eSKalle Valo /* 1578ab55a976SDmitry Antipov * This function decodes sdio aggregation pkt. 1579277b024eSKalle Valo * 158008df8fbeSJason Wang * Based on the data block size and pkt_len, 1581277b024eSKalle Valo * skb data will be decoded to few packets. 1582277b024eSKalle Valo */ 1583277b024eSKalle Valo static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, 1584277b024eSKalle Valo struct sk_buff *skb) 1585277b024eSKalle Valo { 1586277b024eSKalle Valo u32 total_pkt_len, pkt_len; 1587277b024eSKalle Valo struct sk_buff *skb_deaggr; 1588277b024eSKalle Valo u16 blk_size; 1589277b024eSKalle Valo u8 blk_num; 1590277b024eSKalle Valo u8 *data; 1591277b024eSKalle Valo 1592277b024eSKalle Valo data = skb->data; 1593277b024eSKalle Valo total_pkt_len = skb->len; 1594277b024eSKalle Valo 1595f4c5d599SXinming Hu while (total_pkt_len >= (SDIO_HEADER_OFFSET + adapter->intf_hdr_len)) { 1596277b024eSKalle Valo if (total_pkt_len < adapter->sdio_rx_block_size) 1597277b024eSKalle Valo break; 1598277b024eSKalle Valo blk_num = *(data + BLOCK_NUMBER_OFFSET); 1599277b024eSKalle Valo blk_size = adapter->sdio_rx_block_size * blk_num; 1600277b024eSKalle Valo if (blk_size > total_pkt_len) { 1601277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1602277b024eSKalle Valo "%s: error in blk_size,\t" 1603277b024eSKalle Valo "blk_num=%d, blk_size=%d, total_pkt_len=%d\n", 1604277b024eSKalle Valo __func__, blk_num, blk_size, total_pkt_len); 1605277b024eSKalle Valo break; 1606277b024eSKalle Valo } 160792c70a95SDevidas Puranik pkt_len = get_unaligned_le16((data + 160892c70a95SDevidas Puranik SDIO_HEADER_OFFSET)); 1609277b024eSKalle Valo if ((pkt_len + SDIO_HEADER_OFFSET) > blk_size) { 1610277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1611277b024eSKalle Valo "%s: error in pkt_len,\t" 1612277b024eSKalle Valo "pkt_len=%d, blk_size=%d\n", 1613277b024eSKalle Valo __func__, pkt_len, blk_size); 1614277b024eSKalle Valo break; 1615277b024eSKalle Valo } 161600c54780SXinming Hu 161700c54780SXinming Hu skb_deaggr = mwifiex_alloc_dma_align_buf(pkt_len, GFP_KERNEL); 1618277b024eSKalle Valo if (!skb_deaggr) 1619277b024eSKalle Valo break; 1620277b024eSKalle Valo skb_put(skb_deaggr, pkt_len); 1621277b024eSKalle Valo memcpy(skb_deaggr->data, data + SDIO_HEADER_OFFSET, pkt_len); 1622f4c5d599SXinming Hu skb_pull(skb_deaggr, adapter->intf_hdr_len); 1623277b024eSKalle Valo 1624277b024eSKalle Valo mwifiex_handle_rx_packet(adapter, skb_deaggr); 1625277b024eSKalle Valo data += blk_size; 1626277b024eSKalle Valo total_pkt_len -= blk_size; 1627277b024eSKalle Valo } 1628277b024eSKalle Valo } 1629277b024eSKalle Valo 1630277b024eSKalle Valo /* 1631277b024eSKalle Valo * This function decodes a received packet. 1632277b024eSKalle Valo * 1633277b024eSKalle Valo * Based on the type, the packet is treated as either a data, or 1634277b024eSKalle Valo * a command response, or an event, and the correct handler 1635277b024eSKalle Valo * function is invoked. 1636277b024eSKalle Valo */ 1637277b024eSKalle Valo static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, 1638277b024eSKalle Valo struct sk_buff *skb, u32 upld_typ) 1639277b024eSKalle Valo { 1640277b024eSKalle Valo u8 *cmd_buf; 164192c70a95SDevidas Puranik u16 pkt_len; 1642277b024eSKalle Valo struct mwifiex_rxinfo *rx_info; 1643277b024eSKalle Valo 164492c70a95SDevidas Puranik pkt_len = get_unaligned_le16(skb->data); 164592c70a95SDevidas Puranik 1646277b024eSKalle Valo if (upld_typ != MWIFIEX_TYPE_AGGR_DATA) { 1647277b024eSKalle Valo skb_trim(skb, pkt_len); 1648f4c5d599SXinming Hu skb_pull(skb, adapter->intf_hdr_len); 1649277b024eSKalle Valo } 1650277b024eSKalle Valo 1651277b024eSKalle Valo switch (upld_typ) { 1652277b024eSKalle Valo case MWIFIEX_TYPE_AGGR_DATA: 1653277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1654277b024eSKalle Valo "info: --- Rx: Aggr Data packet ---\n"); 1655277b024eSKalle Valo rx_info = MWIFIEX_SKB_RXCB(skb); 1656277b024eSKalle Valo rx_info->buf_type = MWIFIEX_TYPE_AGGR_DATA; 1657277b024eSKalle Valo if (adapter->rx_work_enabled) { 1658277b024eSKalle Valo skb_queue_tail(&adapter->rx_data_q, skb); 1659277b024eSKalle Valo atomic_inc(&adapter->rx_pending); 1660277b024eSKalle Valo adapter->data_received = true; 1661277b024eSKalle Valo } else { 1662277b024eSKalle Valo mwifiex_deaggr_sdio_pkt(adapter, skb); 1663277b024eSKalle Valo dev_kfree_skb_any(skb); 1664277b024eSKalle Valo } 1665277b024eSKalle Valo break; 1666277b024eSKalle Valo 1667277b024eSKalle Valo case MWIFIEX_TYPE_DATA: 1668277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1669277b024eSKalle Valo "info: --- Rx: Data packet ---\n"); 1670277b024eSKalle Valo if (adapter->rx_work_enabled) { 1671277b024eSKalle Valo skb_queue_tail(&adapter->rx_data_q, skb); 1672277b024eSKalle Valo adapter->data_received = true; 1673277b024eSKalle Valo atomic_inc(&adapter->rx_pending); 1674277b024eSKalle Valo } else { 1675277b024eSKalle Valo mwifiex_handle_rx_packet(adapter, skb); 1676277b024eSKalle Valo } 1677277b024eSKalle Valo break; 1678277b024eSKalle Valo 1679277b024eSKalle Valo case MWIFIEX_TYPE_CMD: 1680277b024eSKalle Valo mwifiex_dbg(adapter, CMD, 1681277b024eSKalle Valo "info: --- Rx: Cmd Response ---\n"); 1682277b024eSKalle Valo /* take care of curr_cmd = NULL case */ 1683277b024eSKalle Valo if (!adapter->curr_cmd) { 1684277b024eSKalle Valo cmd_buf = adapter->upld_buf; 1685277b024eSKalle Valo 1686277b024eSKalle Valo if (adapter->ps_state == PS_STATE_SLEEP_CFM) 1687277b024eSKalle Valo mwifiex_process_sleep_confirm_resp(adapter, 1688277b024eSKalle Valo skb->data, 1689277b024eSKalle Valo skb->len); 1690277b024eSKalle Valo 1691277b024eSKalle Valo memcpy(cmd_buf, skb->data, 1692277b024eSKalle Valo min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, 1693277b024eSKalle Valo skb->len)); 1694277b024eSKalle Valo 1695277b024eSKalle Valo dev_kfree_skb_any(skb); 1696277b024eSKalle Valo } else { 1697277b024eSKalle Valo adapter->cmd_resp_received = true; 1698277b024eSKalle Valo adapter->curr_cmd->resp_skb = skb; 1699277b024eSKalle Valo } 1700277b024eSKalle Valo break; 1701277b024eSKalle Valo 1702277b024eSKalle Valo case MWIFIEX_TYPE_EVENT: 1703277b024eSKalle Valo mwifiex_dbg(adapter, EVENT, 1704277b024eSKalle Valo "info: --- Rx: Event ---\n"); 170592c70a95SDevidas Puranik adapter->event_cause = get_unaligned_le32(skb->data); 1706277b024eSKalle Valo 1707277b024eSKalle Valo if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) 1708277b024eSKalle Valo memcpy(adapter->event_body, 1709277b024eSKalle Valo skb->data + MWIFIEX_EVENT_HEADER_LEN, 1710277b024eSKalle Valo skb->len); 1711277b024eSKalle Valo 1712277b024eSKalle Valo /* event cause has been saved to adapter->event_cause */ 1713277b024eSKalle Valo adapter->event_received = true; 1714277b024eSKalle Valo adapter->event_skb = skb; 1715277b024eSKalle Valo 1716277b024eSKalle Valo break; 1717277b024eSKalle Valo 1718277b024eSKalle Valo default: 1719277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1720277b024eSKalle Valo "unknown upload type %#x\n", upld_typ); 1721277b024eSKalle Valo dev_kfree_skb_any(skb); 1722277b024eSKalle Valo break; 1723277b024eSKalle Valo } 1724277b024eSKalle Valo 1725277b024eSKalle Valo return 0; 1726277b024eSKalle Valo } 1727277b024eSKalle Valo 1728277b024eSKalle Valo /* 1729277b024eSKalle Valo * This function transfers received packets from card to driver, performing 1730277b024eSKalle Valo * aggregation if required. 1731277b024eSKalle Valo * 1732277b024eSKalle Valo * For data received on control port, or if aggregation is disabled, the 1733277b024eSKalle Valo * received buffers are uploaded as separate packets. However, if aggregation 1734277b024eSKalle Valo * is enabled and required, the buffers are copied onto an aggregation buffer, 1735277b024eSKalle Valo * provided there is space left, processed and finally uploaded. 1736277b024eSKalle Valo */ 1737277b024eSKalle Valo static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, 1738277b024eSKalle Valo u16 rx_len, u8 port) 1739277b024eSKalle Valo { 1740277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1741277b024eSKalle Valo s32 f_do_rx_aggr = 0; 1742277b024eSKalle Valo s32 f_do_rx_cur = 0; 1743277b024eSKalle Valo s32 f_aggr_cur = 0; 1744277b024eSKalle Valo s32 f_post_aggr_cur = 0; 1745277b024eSKalle Valo struct sk_buff *skb_deaggr; 1746277b024eSKalle Valo struct sk_buff *skb = NULL; 1747277b024eSKalle Valo u32 pkt_len, pkt_type, mport, pind; 1748277b024eSKalle Valo u8 *curr_ptr; 1749277b024eSKalle Valo 1750277b024eSKalle Valo if ((card->has_control_mask) && (port == CTRL_PORT)) { 1751277b024eSKalle Valo /* Read the command Resp without aggr */ 1752277b024eSKalle Valo mwifiex_dbg(adapter, CMD, 1753277b024eSKalle Valo "info: %s: no aggregation for cmd\t" 1754277b024eSKalle Valo "response\n", __func__); 1755277b024eSKalle Valo 1756277b024eSKalle Valo f_do_rx_cur = 1; 1757277b024eSKalle Valo goto rx_curr_single; 1758277b024eSKalle Valo } 1759277b024eSKalle Valo 1760277b024eSKalle Valo if (!card->mpa_rx.enabled) { 1761277b024eSKalle Valo mwifiex_dbg(adapter, WARN, 1762277b024eSKalle Valo "info: %s: rx aggregation disabled\n", 1763277b024eSKalle Valo __func__); 1764277b024eSKalle Valo 1765277b024eSKalle Valo f_do_rx_cur = 1; 1766277b024eSKalle Valo goto rx_curr_single; 1767277b024eSKalle Valo } 1768277b024eSKalle Valo 1769277b024eSKalle Valo if ((!card->has_control_mask && (card->mp_rd_bitmap & 1770277b024eSKalle Valo card->reg->data_port_mask)) || 1771277b024eSKalle Valo (card->has_control_mask && (card->mp_rd_bitmap & 1772277b024eSKalle Valo (~((u32) CTRL_PORT_MASK))))) { 1773277b024eSKalle Valo /* Some more data RX pending */ 1774277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1775277b024eSKalle Valo "info: %s: not last packet\n", __func__); 1776277b024eSKalle Valo 1777277b024eSKalle Valo if (MP_RX_AGGR_IN_PROGRESS(card)) { 1778277b024eSKalle Valo if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) { 1779277b024eSKalle Valo f_aggr_cur = 1; 1780277b024eSKalle Valo } else { 1781277b024eSKalle Valo /* No room in Aggr buf, do rx aggr now */ 1782277b024eSKalle Valo f_do_rx_aggr = 1; 1783277b024eSKalle Valo f_post_aggr_cur = 1; 1784277b024eSKalle Valo } 1785277b024eSKalle Valo } else { 1786277b024eSKalle Valo /* Rx aggr not in progress */ 1787277b024eSKalle Valo f_aggr_cur = 1; 1788277b024eSKalle Valo } 1789277b024eSKalle Valo 1790277b024eSKalle Valo } else { 1791277b024eSKalle Valo /* No more data RX pending */ 1792277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1793277b024eSKalle Valo "info: %s: last packet\n", __func__); 1794277b024eSKalle Valo 1795277b024eSKalle Valo if (MP_RX_AGGR_IN_PROGRESS(card)) { 1796277b024eSKalle Valo f_do_rx_aggr = 1; 1797277b024eSKalle Valo if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) 1798277b024eSKalle Valo f_aggr_cur = 1; 1799277b024eSKalle Valo else 1800277b024eSKalle Valo /* No room in Aggr buf, do rx aggr now */ 1801277b024eSKalle Valo f_do_rx_cur = 1; 1802277b024eSKalle Valo } else { 1803277b024eSKalle Valo f_do_rx_cur = 1; 1804277b024eSKalle Valo } 1805277b024eSKalle Valo } 1806277b024eSKalle Valo 1807277b024eSKalle Valo if (f_aggr_cur) { 1808277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1809277b024eSKalle Valo "info: current packet aggregation\n"); 1810277b024eSKalle Valo /* Curr pkt can be aggregated */ 1811277b024eSKalle Valo mp_rx_aggr_setup(card, rx_len, port); 1812277b024eSKalle Valo 1813277b024eSKalle Valo if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || 1814277b024eSKalle Valo mp_rx_aggr_port_limit_reached(card)) { 1815277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1816277b024eSKalle Valo "info: %s: aggregated packet\t" 1817277b024eSKalle Valo "limit reached\n", __func__); 1818277b024eSKalle Valo /* No more pkts allowed in Aggr buf, rx it */ 1819277b024eSKalle Valo f_do_rx_aggr = 1; 1820277b024eSKalle Valo } 1821277b024eSKalle Valo } 1822277b024eSKalle Valo 1823277b024eSKalle Valo if (f_do_rx_aggr) { 1824277b024eSKalle Valo /* do aggr RX now */ 1825277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 1826277b024eSKalle Valo "info: do_rx_aggr: num of packets: %d\n", 1827277b024eSKalle Valo card->mpa_rx.pkt_cnt); 1828277b024eSKalle Valo 1829277b024eSKalle Valo if (card->supports_sdio_new_mode) { 1830277b024eSKalle Valo int i; 1831277b024eSKalle Valo u32 port_count; 1832277b024eSKalle Valo 1833277b024eSKalle Valo for (i = 0, port_count = 0; i < card->max_ports; i++) 1834277b024eSKalle Valo if (card->mpa_rx.ports & BIT(i)) 1835277b024eSKalle Valo port_count++; 1836277b024eSKalle Valo 1837277b024eSKalle Valo /* Reading data from "start_port + 0" to "start_port + 1838277b024eSKalle Valo * port_count -1", so decrease the count by 1 1839277b024eSKalle Valo */ 1840277b024eSKalle Valo port_count--; 1841277b024eSKalle Valo mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | 1842277b024eSKalle Valo (port_count << 8)) + card->mpa_rx.start_port; 1843277b024eSKalle Valo } else { 1844277b024eSKalle Valo mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | 1845277b024eSKalle Valo (card->mpa_rx.ports << 4)) + 1846277b024eSKalle Valo card->mpa_rx.start_port; 1847277b024eSKalle Valo } 1848277b024eSKalle Valo 18490cb52aacSXinming Hu if (card->mpa_rx.pkt_cnt == 1) 1850ecd7eb7cSGanapathi Bhat mport = adapter->ioport + card->mpa_rx.start_port; 18510cb52aacSXinming Hu 1852277b024eSKalle Valo if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, 1853277b024eSKalle Valo card->mpa_rx.buf_len, mport, 1)) 1854277b024eSKalle Valo goto error; 1855277b024eSKalle Valo 1856277b024eSKalle Valo curr_ptr = card->mpa_rx.buf; 1857277b024eSKalle Valo 1858277b024eSKalle Valo for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { 1859277b024eSKalle Valo u32 *len_arr = card->mpa_rx.len_arr; 1860277b024eSKalle Valo 1861277b024eSKalle Valo /* get curr PKT len & type */ 186292c70a95SDevidas Puranik pkt_len = get_unaligned_le16(&curr_ptr[0]); 186392c70a95SDevidas Puranik pkt_type = get_unaligned_le16(&curr_ptr[2]); 1864277b024eSKalle Valo 1865277b024eSKalle Valo /* copy pkt to deaggr buf */ 1866277b024eSKalle Valo skb_deaggr = mwifiex_alloc_dma_align_buf(len_arr[pind], 186700c54780SXinming Hu GFP_KERNEL); 1868277b024eSKalle Valo if (!skb_deaggr) { 1869277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "skb allocation failure\t" 1870277b024eSKalle Valo "drop pkt len=%d type=%d\n", 1871277b024eSKalle Valo pkt_len, pkt_type); 1872277b024eSKalle Valo curr_ptr += len_arr[pind]; 1873277b024eSKalle Valo continue; 1874277b024eSKalle Valo } 1875277b024eSKalle Valo 1876277b024eSKalle Valo skb_put(skb_deaggr, len_arr[pind]); 1877277b024eSKalle Valo 1878277b024eSKalle Valo if ((pkt_type == MWIFIEX_TYPE_DATA || 1879277b024eSKalle Valo (pkt_type == MWIFIEX_TYPE_AGGR_DATA && 1880277b024eSKalle Valo adapter->sdio_rx_aggr_enable)) && 1881277b024eSKalle Valo (pkt_len <= len_arr[pind])) { 1882277b024eSKalle Valo 1883277b024eSKalle Valo memcpy(skb_deaggr->data, curr_ptr, pkt_len); 1884277b024eSKalle Valo 1885277b024eSKalle Valo skb_trim(skb_deaggr, pkt_len); 1886277b024eSKalle Valo 1887277b024eSKalle Valo /* Process de-aggr packet */ 1888277b024eSKalle Valo mwifiex_decode_rx_packet(adapter, skb_deaggr, 1889277b024eSKalle Valo pkt_type); 1890277b024eSKalle Valo } else { 1891277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1892277b024eSKalle Valo "drop wrong aggr pkt:\t" 1893277b024eSKalle Valo "sdio_single_port_rx_aggr=%d\t" 1894277b024eSKalle Valo "type=%d len=%d max_len=%d\n", 1895277b024eSKalle Valo adapter->sdio_rx_aggr_enable, 1896277b024eSKalle Valo pkt_type, pkt_len, len_arr[pind]); 1897277b024eSKalle Valo dev_kfree_skb_any(skb_deaggr); 1898277b024eSKalle Valo } 1899277b024eSKalle Valo curr_ptr += len_arr[pind]; 1900277b024eSKalle Valo } 1901277b024eSKalle Valo MP_RX_AGGR_BUF_RESET(card); 1902277b024eSKalle Valo } 1903277b024eSKalle Valo 1904277b024eSKalle Valo rx_curr_single: 1905277b024eSKalle Valo if (f_do_rx_cur) { 1906277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: RX: port: %d, rx_len: %d\n", 1907277b024eSKalle Valo port, rx_len); 1908277b024eSKalle Valo 19095c87a55aSMathias Krause skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL); 1910277b024eSKalle Valo if (!skb) { 1911277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 1912277b024eSKalle Valo "single skb allocated fail,\t" 1913277b024eSKalle Valo "drop pkt port=%d len=%d\n", port, rx_len); 1914277b024eSKalle Valo if (mwifiex_sdio_card_to_host(adapter, &pkt_type, 1915277b024eSKalle Valo card->mpa_rx.buf, rx_len, 1916277b024eSKalle Valo adapter->ioport + port)) 1917277b024eSKalle Valo goto error; 1918277b024eSKalle Valo return 0; 1919277b024eSKalle Valo } 1920277b024eSKalle Valo 1921277b024eSKalle Valo skb_put(skb, rx_len); 1922277b024eSKalle Valo 1923277b024eSKalle Valo if (mwifiex_sdio_card_to_host(adapter, &pkt_type, 1924277b024eSKalle Valo skb->data, skb->len, 1925277b024eSKalle Valo adapter->ioport + port)) 1926277b024eSKalle Valo goto error; 1927277b024eSKalle Valo if (!adapter->sdio_rx_aggr_enable && 1928277b024eSKalle Valo pkt_type == MWIFIEX_TYPE_AGGR_DATA) { 1929277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "drop wrong pkt type %d\t" 1930277b024eSKalle Valo "current SDIO RX Aggr not enabled\n", 1931277b024eSKalle Valo pkt_type); 1932277b024eSKalle Valo dev_kfree_skb_any(skb); 1933277b024eSKalle Valo return 0; 1934277b024eSKalle Valo } 1935277b024eSKalle Valo 1936277b024eSKalle Valo mwifiex_decode_rx_packet(adapter, skb, pkt_type); 1937277b024eSKalle Valo } 1938277b024eSKalle Valo if (f_post_aggr_cur) { 1939277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 1940277b024eSKalle Valo "info: current packet aggregation\n"); 1941277b024eSKalle Valo /* Curr pkt can be aggregated */ 1942277b024eSKalle Valo mp_rx_aggr_setup(card, rx_len, port); 1943277b024eSKalle Valo } 1944277b024eSKalle Valo 1945277b024eSKalle Valo return 0; 1946277b024eSKalle Valo error: 1947277b024eSKalle Valo if (MP_RX_AGGR_IN_PROGRESS(card)) 1948277b024eSKalle Valo MP_RX_AGGR_BUF_RESET(card); 1949277b024eSKalle Valo 1950277b024eSKalle Valo if (f_do_rx_cur && skb) 1951277b024eSKalle Valo /* Single transfer pending. Free curr buff also */ 1952277b024eSKalle Valo dev_kfree_skb_any(skb); 1953277b024eSKalle Valo 1954277b024eSKalle Valo return -1; 1955277b024eSKalle Valo } 1956277b024eSKalle Valo 1957277b024eSKalle Valo /* 1958277b024eSKalle Valo * This function checks the current interrupt status. 1959277b024eSKalle Valo * 1960277b024eSKalle Valo * The following interrupts are checked and handled by this function - 1961277b024eSKalle Valo * - Data sent 1962277b024eSKalle Valo * - Command sent 1963277b024eSKalle Valo * - Packets received 1964277b024eSKalle Valo * 1965277b024eSKalle Valo * Since the firmware does not generate download ready interrupt if the 1966277b024eSKalle Valo * port updated is command port only, command sent interrupt checking 1967277b024eSKalle Valo * should be done manually, and for every SDIO interrupt. 1968277b024eSKalle Valo * 1969277b024eSKalle Valo * In case of Rx packets received, the packets are uploaded from card to 1970277b024eSKalle Valo * host and processed accordingly. 1971277b024eSKalle Valo */ 1972277b024eSKalle Valo static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) 1973277b024eSKalle Valo { 1974277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 1975277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 1976277b024eSKalle Valo int ret = 0; 1977277b024eSKalle Valo u8 sdio_ireg; 1978277b024eSKalle Valo struct sk_buff *skb; 1979277b024eSKalle Valo u8 port = CTRL_PORT; 1980277b024eSKalle Valo u32 len_reg_l, len_reg_u; 1981277b024eSKalle Valo u32 rx_blocks; 1982277b024eSKalle Valo u16 rx_len; 1983277b024eSKalle Valo unsigned long flags; 1984277b024eSKalle Valo u32 bitmap; 1985277b024eSKalle Valo u8 cr; 1986277b024eSKalle Valo 1987277b024eSKalle Valo spin_lock_irqsave(&adapter->int_lock, flags); 1988277b024eSKalle Valo sdio_ireg = adapter->int_status; 1989277b024eSKalle Valo adapter->int_status = 0; 1990277b024eSKalle Valo spin_unlock_irqrestore(&adapter->int_lock, flags); 1991277b024eSKalle Valo 1992277b024eSKalle Valo if (!sdio_ireg) 1993277b024eSKalle Valo return ret; 1994277b024eSKalle Valo 1995277b024eSKalle Valo /* Following interrupt is only for SDIO new mode */ 1996277b024eSKalle Valo if (sdio_ireg & DN_LD_CMD_PORT_HOST_INT_STATUS && adapter->cmd_sent) 1997277b024eSKalle Valo adapter->cmd_sent = false; 1998277b024eSKalle Valo 1999277b024eSKalle Valo /* Following interrupt is only for SDIO new mode */ 2000277b024eSKalle Valo if (sdio_ireg & UP_LD_CMD_PORT_HOST_INT_STATUS) { 2001277b024eSKalle Valo u32 pkt_type; 2002277b024eSKalle Valo 2003277b024eSKalle Valo /* read the len of control packet */ 2004277b024eSKalle Valo rx_len = card->mp_regs[reg->cmd_rd_len_1] << 8; 2005277b024eSKalle Valo rx_len |= (u16)card->mp_regs[reg->cmd_rd_len_0]; 2006277b024eSKalle Valo rx_blocks = DIV_ROUND_UP(rx_len, MWIFIEX_SDIO_BLOCK_SIZE); 2007f4c5d599SXinming Hu if (rx_len <= adapter->intf_hdr_len || 2008277b024eSKalle Valo (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > 2009277b024eSKalle Valo MWIFIEX_RX_DATA_BUF_SIZE) 2010277b024eSKalle Valo return -1; 2011277b024eSKalle Valo rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); 2012277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n", rx_len); 2013277b024eSKalle Valo 20145c87a55aSMathias Krause skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL); 2015277b024eSKalle Valo if (!skb) 2016277b024eSKalle Valo return -1; 2017277b024eSKalle Valo 2018277b024eSKalle Valo skb_put(skb, rx_len); 2019277b024eSKalle Valo 2020277b024eSKalle Valo if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data, 2021277b024eSKalle Valo skb->len, adapter->ioport | 2022277b024eSKalle Valo CMD_PORT_SLCT)) { 2023277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2024277b024eSKalle Valo "%s: failed to card_to_host", __func__); 2025277b024eSKalle Valo dev_kfree_skb_any(skb); 2026277b024eSKalle Valo goto term_cmd; 2027277b024eSKalle Valo } 2028277b024eSKalle Valo 2029277b024eSKalle Valo if ((pkt_type != MWIFIEX_TYPE_CMD) && 2030277b024eSKalle Valo (pkt_type != MWIFIEX_TYPE_EVENT)) 2031277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2032277b024eSKalle Valo "%s:Received wrong packet on cmd port", 2033277b024eSKalle Valo __func__); 2034277b024eSKalle Valo 2035277b024eSKalle Valo mwifiex_decode_rx_packet(adapter, skb, pkt_type); 2036277b024eSKalle Valo } 2037277b024eSKalle Valo 2038277b024eSKalle Valo if (sdio_ireg & DN_LD_HOST_INT_STATUS) { 2039277b024eSKalle Valo bitmap = (u32) card->mp_regs[reg->wr_bitmap_l]; 2040277b024eSKalle Valo bitmap |= ((u32) card->mp_regs[reg->wr_bitmap_u]) << 8; 2041277b024eSKalle Valo if (card->supports_sdio_new_mode) { 2042277b024eSKalle Valo bitmap |= 2043277b024eSKalle Valo ((u32) card->mp_regs[reg->wr_bitmap_1l]) << 16; 2044277b024eSKalle Valo bitmap |= 2045277b024eSKalle Valo ((u32) card->mp_regs[reg->wr_bitmap_1u]) << 24; 2046277b024eSKalle Valo } 2047277b024eSKalle Valo card->mp_wr_bitmap = bitmap; 2048277b024eSKalle Valo 2049277b024eSKalle Valo mwifiex_dbg(adapter, INTR, 2050277b024eSKalle Valo "int: DNLD: wr_bitmap=0x%x\n", 2051277b024eSKalle Valo card->mp_wr_bitmap); 2052277b024eSKalle Valo if (adapter->data_sent && 2053277b024eSKalle Valo (card->mp_wr_bitmap & card->mp_data_port_mask)) { 2054277b024eSKalle Valo mwifiex_dbg(adapter, INTR, 2055277b024eSKalle Valo "info: <--- Tx DONE Interrupt --->\n"); 2056277b024eSKalle Valo adapter->data_sent = false; 2057277b024eSKalle Valo } 2058277b024eSKalle Valo } 2059277b024eSKalle Valo 2060277b024eSKalle Valo /* As firmware will not generate download ready interrupt if the port 2061277b024eSKalle Valo updated is command port only, cmd_sent should be done for any SDIO 2062277b024eSKalle Valo interrupt. */ 2063277b024eSKalle Valo if (card->has_control_mask && adapter->cmd_sent) { 2064277b024eSKalle Valo /* Check if firmware has attach buffer at command port and 2065277b024eSKalle Valo update just that in wr_bit_map. */ 2066277b024eSKalle Valo card->mp_wr_bitmap |= 2067277b024eSKalle Valo (u32) card->mp_regs[reg->wr_bitmap_l] & CTRL_PORT_MASK; 2068277b024eSKalle Valo if (card->mp_wr_bitmap & CTRL_PORT_MASK) 2069277b024eSKalle Valo adapter->cmd_sent = false; 2070277b024eSKalle Valo } 2071277b024eSKalle Valo 2072277b024eSKalle Valo mwifiex_dbg(adapter, INTR, "info: cmd_sent=%d data_sent=%d\n", 2073277b024eSKalle Valo adapter->cmd_sent, adapter->data_sent); 2074277b024eSKalle Valo if (sdio_ireg & UP_LD_HOST_INT_STATUS) { 2075277b024eSKalle Valo bitmap = (u32) card->mp_regs[reg->rd_bitmap_l]; 2076277b024eSKalle Valo bitmap |= ((u32) card->mp_regs[reg->rd_bitmap_u]) << 8; 2077277b024eSKalle Valo if (card->supports_sdio_new_mode) { 2078277b024eSKalle Valo bitmap |= 2079277b024eSKalle Valo ((u32) card->mp_regs[reg->rd_bitmap_1l]) << 16; 2080277b024eSKalle Valo bitmap |= 2081277b024eSKalle Valo ((u32) card->mp_regs[reg->rd_bitmap_1u]) << 24; 2082277b024eSKalle Valo } 2083277b024eSKalle Valo card->mp_rd_bitmap = bitmap; 2084277b024eSKalle Valo mwifiex_dbg(adapter, INTR, 2085277b024eSKalle Valo "int: UPLD: rd_bitmap=0x%x\n", 2086277b024eSKalle Valo card->mp_rd_bitmap); 2087277b024eSKalle Valo 2088277b024eSKalle Valo while (true) { 2089277b024eSKalle Valo ret = mwifiex_get_rd_port(adapter, &port); 2090277b024eSKalle Valo if (ret) { 2091277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 2092277b024eSKalle Valo "info: no more rd_port available\n"); 2093277b024eSKalle Valo break; 2094277b024eSKalle Valo } 2095277b024eSKalle Valo len_reg_l = reg->rd_len_p0_l + (port << 1); 2096277b024eSKalle Valo len_reg_u = reg->rd_len_p0_u + (port << 1); 2097277b024eSKalle Valo rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; 2098277b024eSKalle Valo rx_len |= (u16) card->mp_regs[len_reg_l]; 2099277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 2100277b024eSKalle Valo "info: RX: port=%d rx_len=%u\n", 2101277b024eSKalle Valo port, rx_len); 2102277b024eSKalle Valo rx_blocks = 2103277b024eSKalle Valo (rx_len + MWIFIEX_SDIO_BLOCK_SIZE - 2104277b024eSKalle Valo 1) / MWIFIEX_SDIO_BLOCK_SIZE; 2105f4c5d599SXinming Hu if (rx_len <= adapter->intf_hdr_len || 2106277b024eSKalle Valo (card->mpa_rx.enabled && 2107277b024eSKalle Valo ((rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > 2108277b024eSKalle Valo card->mpa_rx.buf_size))) { 2109277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2110277b024eSKalle Valo "invalid rx_len=%d\n", 2111277b024eSKalle Valo rx_len); 2112277b024eSKalle Valo return -1; 2113277b024eSKalle Valo } 2114277b024eSKalle Valo 2115277b024eSKalle Valo rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); 2116277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: rx_len = %d\n", 2117277b024eSKalle Valo rx_len); 2118277b024eSKalle Valo 2119277b024eSKalle Valo if (mwifiex_sdio_card_to_host_mp_aggr(adapter, rx_len, 2120277b024eSKalle Valo port)) { 2121277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2122277b024eSKalle Valo "card_to_host_mpa failed: int status=%#x\n", 2123277b024eSKalle Valo sdio_ireg); 2124277b024eSKalle Valo goto term_cmd; 2125277b024eSKalle Valo } 2126277b024eSKalle Valo } 2127277b024eSKalle Valo } 2128277b024eSKalle Valo 2129277b024eSKalle Valo return 0; 2130277b024eSKalle Valo 2131277b024eSKalle Valo term_cmd: 2132277b024eSKalle Valo /* terminate cmd */ 2133277b024eSKalle Valo if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr)) 2134277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "read CFG reg failed\n"); 2135277b024eSKalle Valo else 2136277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 2137277b024eSKalle Valo "info: CFG reg val = %d\n", cr); 2138277b024eSKalle Valo 2139277b024eSKalle Valo if (mwifiex_write_reg(adapter, CONFIGURATION_REG, (cr | 0x04))) 2140277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2141277b024eSKalle Valo "write CFG reg failed\n"); 2142277b024eSKalle Valo else 2143277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: write success\n"); 2144277b024eSKalle Valo 2145277b024eSKalle Valo if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr)) 2146277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2147277b024eSKalle Valo "read CFG reg failed\n"); 2148277b024eSKalle Valo else 2149277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 2150277b024eSKalle Valo "info: CFG reg val =%x\n", cr); 2151277b024eSKalle Valo 2152277b024eSKalle Valo return -1; 2153277b024eSKalle Valo } 2154277b024eSKalle Valo 2155277b024eSKalle Valo /* 2156277b024eSKalle Valo * This function aggregates transmission buffers in driver and downloads 2157277b024eSKalle Valo * the aggregated packet to card. 2158277b024eSKalle Valo * 2159277b024eSKalle Valo * The individual packets are aggregated by copying into an aggregation 2160277b024eSKalle Valo * buffer and then downloaded to the card. Previous unsent packets in the 2161277b024eSKalle Valo * aggregation buffer are pre-copied first before new packets are added. 2162277b024eSKalle Valo * Aggregation is done till there is space left in the aggregation buffer, 2163277b024eSKalle Valo * or till new packets are available. 2164277b024eSKalle Valo * 2165277b024eSKalle Valo * The function will only download the packet to the card when aggregation 2166277b024eSKalle Valo * stops, otherwise it will just aggregate the packet in aggregation buffer 2167277b024eSKalle Valo * and return. 2168277b024eSKalle Valo */ 2169277b024eSKalle Valo static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, 2170277b024eSKalle Valo u8 *payload, u32 pkt_len, u32 port, 2171277b024eSKalle Valo u32 next_pkt_len) 2172277b024eSKalle Valo { 2173277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2174277b024eSKalle Valo int ret = 0; 2175277b024eSKalle Valo s32 f_send_aggr_buf = 0; 2176277b024eSKalle Valo s32 f_send_cur_buf = 0; 2177277b024eSKalle Valo s32 f_precopy_cur_buf = 0; 2178277b024eSKalle Valo s32 f_postcopy_cur_buf = 0; 2179277b024eSKalle Valo u32 mport; 21808b7ef8b6SXinming Hu int index; 2181277b024eSKalle Valo 2182277b024eSKalle Valo if (!card->mpa_tx.enabled || 2183277b024eSKalle Valo (card->has_control_mask && (port == CTRL_PORT)) || 2184277b024eSKalle Valo (card->supports_sdio_new_mode && (port == CMD_PORT_SLCT))) { 2185277b024eSKalle Valo mwifiex_dbg(adapter, WARN, 2186277b024eSKalle Valo "info: %s: tx aggregation disabled\n", 2187277b024eSKalle Valo __func__); 2188277b024eSKalle Valo 2189277b024eSKalle Valo f_send_cur_buf = 1; 2190277b024eSKalle Valo goto tx_curr_single; 2191277b024eSKalle Valo } 2192277b024eSKalle Valo 2193277b024eSKalle Valo if (next_pkt_len) { 2194277b024eSKalle Valo /* More pkt in TX queue */ 2195277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 2196277b024eSKalle Valo "info: %s: more packets in queue.\n", 2197277b024eSKalle Valo __func__); 2198277b024eSKalle Valo 2199277b024eSKalle Valo if (MP_TX_AGGR_IN_PROGRESS(card)) { 2200277b024eSKalle Valo if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { 2201277b024eSKalle Valo f_precopy_cur_buf = 1; 2202277b024eSKalle Valo 2203277b024eSKalle Valo if (!(card->mp_wr_bitmap & 2204277b024eSKalle Valo (1 << card->curr_wr_port)) || 2205277b024eSKalle Valo !MP_TX_AGGR_BUF_HAS_ROOM( 2206277b024eSKalle Valo card, pkt_len + next_pkt_len)) 2207277b024eSKalle Valo f_send_aggr_buf = 1; 2208277b024eSKalle Valo } else { 2209277b024eSKalle Valo /* No room in Aggr buf, send it */ 2210277b024eSKalle Valo f_send_aggr_buf = 1; 2211277b024eSKalle Valo 2212277b024eSKalle Valo if (!(card->mp_wr_bitmap & 2213277b024eSKalle Valo (1 << card->curr_wr_port))) 2214277b024eSKalle Valo f_send_cur_buf = 1; 2215277b024eSKalle Valo else 2216277b024eSKalle Valo f_postcopy_cur_buf = 1; 2217277b024eSKalle Valo } 2218277b024eSKalle Valo } else { 2219277b024eSKalle Valo if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len) && 2220277b024eSKalle Valo (card->mp_wr_bitmap & (1 << card->curr_wr_port))) 2221277b024eSKalle Valo f_precopy_cur_buf = 1; 2222277b024eSKalle Valo else 2223277b024eSKalle Valo f_send_cur_buf = 1; 2224277b024eSKalle Valo } 2225277b024eSKalle Valo } else { 2226277b024eSKalle Valo /* Last pkt in TX queue */ 2227277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 2228277b024eSKalle Valo "info: %s: Last packet in Tx Queue.\n", 2229277b024eSKalle Valo __func__); 2230277b024eSKalle Valo 2231277b024eSKalle Valo if (MP_TX_AGGR_IN_PROGRESS(card)) { 2232277b024eSKalle Valo /* some packs in Aggr buf already */ 2233277b024eSKalle Valo f_send_aggr_buf = 1; 2234277b024eSKalle Valo 2235277b024eSKalle Valo if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) 2236277b024eSKalle Valo f_precopy_cur_buf = 1; 2237277b024eSKalle Valo else 2238277b024eSKalle Valo /* No room in Aggr buf, send it */ 2239277b024eSKalle Valo f_send_cur_buf = 1; 2240277b024eSKalle Valo } else { 2241277b024eSKalle Valo f_send_cur_buf = 1; 2242277b024eSKalle Valo } 2243277b024eSKalle Valo } 2244277b024eSKalle Valo 2245277b024eSKalle Valo if (f_precopy_cur_buf) { 2246277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 2247277b024eSKalle Valo "data: %s: precopy current buffer\n", 2248277b024eSKalle Valo __func__); 2249277b024eSKalle Valo MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); 2250277b024eSKalle Valo 2251277b024eSKalle Valo if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || 2252277b024eSKalle Valo mp_tx_aggr_port_limit_reached(card)) 2253277b024eSKalle Valo /* No more pkts allowed in Aggr buf, send it */ 2254277b024eSKalle Valo f_send_aggr_buf = 1; 2255277b024eSKalle Valo } 2256277b024eSKalle Valo 2257277b024eSKalle Valo if (f_send_aggr_buf) { 2258277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 2259277b024eSKalle Valo "data: %s: send aggr buffer: %d %d\n", 2260277b024eSKalle Valo __func__, card->mpa_tx.start_port, 2261277b024eSKalle Valo card->mpa_tx.ports); 2262277b024eSKalle Valo if (card->supports_sdio_new_mode) { 2263277b024eSKalle Valo u32 port_count; 2264277b024eSKalle Valo int i; 2265277b024eSKalle Valo 2266277b024eSKalle Valo for (i = 0, port_count = 0; i < card->max_ports; i++) 2267277b024eSKalle Valo if (card->mpa_tx.ports & BIT(i)) 2268277b024eSKalle Valo port_count++; 2269277b024eSKalle Valo 2270277b024eSKalle Valo /* Writing data from "start_port + 0" to "start_port + 2271277b024eSKalle Valo * port_count -1", so decrease the count by 1 2272277b024eSKalle Valo */ 2273277b024eSKalle Valo port_count--; 2274277b024eSKalle Valo mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | 2275277b024eSKalle Valo (port_count << 8)) + card->mpa_tx.start_port; 2276277b024eSKalle Valo } else { 2277277b024eSKalle Valo mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | 2278277b024eSKalle Valo (card->mpa_tx.ports << 4)) + 2279277b024eSKalle Valo card->mpa_tx.start_port; 2280277b024eSKalle Valo } 2281277b024eSKalle Valo 22820cb52aacSXinming Hu if (card->mpa_tx.pkt_cnt == 1) 2283ecd7eb7cSGanapathi Bhat mport = adapter->ioport + card->mpa_tx.start_port; 22840cb52aacSXinming Hu 2285277b024eSKalle Valo ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, 2286277b024eSKalle Valo card->mpa_tx.buf_len, mport); 2287277b024eSKalle Valo 2288ab55a976SDmitry Antipov /* Save the last multi port tx aggregation info to debug log. */ 22898b7ef8b6SXinming Hu index = adapter->dbg.last_sdio_mp_index; 22908b7ef8b6SXinming Hu index = (index + 1) % MWIFIEX_DBG_SDIO_MP_NUM; 22918b7ef8b6SXinming Hu adapter->dbg.last_sdio_mp_index = index; 22928b7ef8b6SXinming Hu adapter->dbg.last_mp_wr_ports[index] = mport; 22938b7ef8b6SXinming Hu adapter->dbg.last_mp_wr_bitmap[index] = card->mp_wr_bitmap; 22948b7ef8b6SXinming Hu adapter->dbg.last_mp_wr_len[index] = card->mpa_tx.buf_len; 22958b7ef8b6SXinming Hu adapter->dbg.last_mp_curr_wr_port[index] = card->curr_wr_port; 22968b7ef8b6SXinming Hu 2297277b024eSKalle Valo MP_TX_AGGR_BUF_RESET(card); 2298277b024eSKalle Valo } 2299277b024eSKalle Valo 2300277b024eSKalle Valo tx_curr_single: 2301277b024eSKalle Valo if (f_send_cur_buf) { 2302277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 2303277b024eSKalle Valo "data: %s: send current buffer %d\n", 2304277b024eSKalle Valo __func__, port); 2305277b024eSKalle Valo ret = mwifiex_write_data_to_card(adapter, payload, pkt_len, 2306277b024eSKalle Valo adapter->ioport + port); 2307277b024eSKalle Valo } 2308277b024eSKalle Valo 2309277b024eSKalle Valo if (f_postcopy_cur_buf) { 2310277b024eSKalle Valo mwifiex_dbg(adapter, DATA, 2311277b024eSKalle Valo "data: %s: postcopy current buffer\n", 2312277b024eSKalle Valo __func__); 2313277b024eSKalle Valo MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); 2314277b024eSKalle Valo } 2315277b024eSKalle Valo 2316277b024eSKalle Valo return ret; 2317277b024eSKalle Valo } 2318277b024eSKalle Valo 2319277b024eSKalle Valo /* 2320277b024eSKalle Valo * This function downloads data from driver to card. 2321277b024eSKalle Valo * 2322277b024eSKalle Valo * Both commands and data packets are transferred to the card by this 2323277b024eSKalle Valo * function. 2324277b024eSKalle Valo * 2325277b024eSKalle Valo * This function adds the SDIO specific header to the front of the buffer 2326277b024eSKalle Valo * before transferring. The header contains the length of the packet and 2327277b024eSKalle Valo * the type. The firmware handles the packets based upon this set type. 2328277b024eSKalle Valo */ 2329277b024eSKalle Valo static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, 2330277b024eSKalle Valo u8 type, struct sk_buff *skb, 2331277b024eSKalle Valo struct mwifiex_tx_param *tx_param) 2332277b024eSKalle Valo { 2333277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2334277b024eSKalle Valo int ret; 2335277b024eSKalle Valo u32 buf_block_len; 2336277b024eSKalle Valo u32 blk_size; 2337277b024eSKalle Valo u32 port = CTRL_PORT; 2338277b024eSKalle Valo u8 *payload = (u8 *)skb->data; 2339277b024eSKalle Valo u32 pkt_len = skb->len; 2340277b024eSKalle Valo 2341277b024eSKalle Valo /* Allocate buffer and copy payload */ 2342277b024eSKalle Valo blk_size = MWIFIEX_SDIO_BLOCK_SIZE; 2343277b024eSKalle Valo buf_block_len = (pkt_len + blk_size - 1) / blk_size; 234492c70a95SDevidas Puranik put_unaligned_le16((u16)pkt_len, payload + 0); 234592c70a95SDevidas Puranik put_unaligned_le16((u32)type, payload + 2); 234692c70a95SDevidas Puranik 2347277b024eSKalle Valo 2348277b024eSKalle Valo /* 2349277b024eSKalle Valo * This is SDIO specific header 2350277b024eSKalle Valo * u16 length, 2351277b024eSKalle Valo * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1, 2352277b024eSKalle Valo * MWIFIEX_TYPE_EVENT = 3) 2353277b024eSKalle Valo */ 2354277b024eSKalle Valo if (type == MWIFIEX_TYPE_DATA) { 2355277b024eSKalle Valo ret = mwifiex_get_wr_port_data(adapter, &port); 2356277b024eSKalle Valo if (ret) { 2357277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2358277b024eSKalle Valo "%s: no wr_port available\n", 2359277b024eSKalle Valo __func__); 2360277b024eSKalle Valo return ret; 2361277b024eSKalle Valo } 2362277b024eSKalle Valo } else { 2363277b024eSKalle Valo adapter->cmd_sent = true; 2364277b024eSKalle Valo /* Type must be MWIFIEX_TYPE_CMD */ 2365277b024eSKalle Valo 2366f4c5d599SXinming Hu if (pkt_len <= adapter->intf_hdr_len || 2367277b024eSKalle Valo pkt_len > MWIFIEX_UPLD_SIZE) 2368277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2369277b024eSKalle Valo "%s: payload=%p, nb=%d\n", 2370277b024eSKalle Valo __func__, payload, pkt_len); 2371277b024eSKalle Valo 2372277b024eSKalle Valo if (card->supports_sdio_new_mode) 2373277b024eSKalle Valo port = CMD_PORT_SLCT; 2374277b024eSKalle Valo } 2375277b024eSKalle Valo 2376277b024eSKalle Valo /* Transfer data to card */ 2377277b024eSKalle Valo pkt_len = buf_block_len * blk_size; 2378277b024eSKalle Valo 2379277b024eSKalle Valo if (tx_param) 2380277b024eSKalle Valo ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, 2381277b024eSKalle Valo port, tx_param->next_pkt_len 2382277b024eSKalle Valo ); 2383277b024eSKalle Valo else 2384277b024eSKalle Valo ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len, 2385277b024eSKalle Valo port, 0); 2386277b024eSKalle Valo 2387277b024eSKalle Valo if (ret) { 2388277b024eSKalle Valo if (type == MWIFIEX_TYPE_CMD) 2389277b024eSKalle Valo adapter->cmd_sent = false; 2390277b024eSKalle Valo if (type == MWIFIEX_TYPE_DATA) { 2391277b024eSKalle Valo adapter->data_sent = false; 2392277b024eSKalle Valo /* restore curr_wr_port in error cases */ 2393277b024eSKalle Valo card->curr_wr_port = port; 2394277b024eSKalle Valo card->mp_wr_bitmap |= (u32)(1 << card->curr_wr_port); 2395277b024eSKalle Valo } 2396277b024eSKalle Valo } else { 2397277b024eSKalle Valo if (type == MWIFIEX_TYPE_DATA) { 2398277b024eSKalle Valo if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port))) 2399277b024eSKalle Valo adapter->data_sent = true; 2400277b024eSKalle Valo else 2401277b024eSKalle Valo adapter->data_sent = false; 2402277b024eSKalle Valo } 2403277b024eSKalle Valo } 2404277b024eSKalle Valo 2405277b024eSKalle Valo return ret; 2406277b024eSKalle Valo } 2407277b024eSKalle Valo 2408277b024eSKalle Valo /* 2409277b024eSKalle Valo * This function allocates the MPA Tx and Rx buffers. 2410277b024eSKalle Valo */ 2411277b024eSKalle Valo static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, 2412277b024eSKalle Valo u32 mpa_tx_buf_size, u32 mpa_rx_buf_size) 2413277b024eSKalle Valo { 2414277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2415277b024eSKalle Valo u32 rx_buf_size; 2416277b024eSKalle Valo int ret = 0; 2417277b024eSKalle Valo 2418277b024eSKalle Valo card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); 2419277b024eSKalle Valo if (!card->mpa_tx.buf) { 2420277b024eSKalle Valo ret = -1; 2421277b024eSKalle Valo goto error; 2422277b024eSKalle Valo } 2423277b024eSKalle Valo 2424277b024eSKalle Valo card->mpa_tx.buf_size = mpa_tx_buf_size; 2425277b024eSKalle Valo 2426277b024eSKalle Valo rx_buf_size = max_t(u32, mpa_rx_buf_size, 2427277b024eSKalle Valo (u32)SDIO_MAX_AGGR_BUF_SIZE); 2428277b024eSKalle Valo card->mpa_rx.buf = kzalloc(rx_buf_size, GFP_KERNEL); 2429277b024eSKalle Valo if (!card->mpa_rx.buf) { 2430277b024eSKalle Valo ret = -1; 2431277b024eSKalle Valo goto error; 2432277b024eSKalle Valo } 2433277b024eSKalle Valo 2434277b024eSKalle Valo card->mpa_rx.buf_size = rx_buf_size; 2435277b024eSKalle Valo 2436277b024eSKalle Valo error: 2437277b024eSKalle Valo if (ret) { 2438277b024eSKalle Valo kfree(card->mpa_tx.buf); 2439277b024eSKalle Valo kfree(card->mpa_rx.buf); 2440277b024eSKalle Valo card->mpa_tx.buf_size = 0; 2441277b024eSKalle Valo card->mpa_rx.buf_size = 0; 244253708f4fSTom Rix card->mpa_tx.buf = NULL; 244353708f4fSTom Rix card->mpa_rx.buf = NULL; 2444277b024eSKalle Valo } 2445277b024eSKalle Valo 2446277b024eSKalle Valo return ret; 2447277b024eSKalle Valo } 2448277b024eSKalle Valo 2449277b024eSKalle Valo /* 2450277b024eSKalle Valo * This function unregisters the SDIO device. 2451277b024eSKalle Valo * 2452277b024eSKalle Valo * The SDIO IRQ is released, the function is disabled and driver 2453277b024eSKalle Valo * data is set to null. 2454277b024eSKalle Valo */ 2455277b024eSKalle Valo static void 2456277b024eSKalle Valo mwifiex_unregister_dev(struct mwifiex_adapter *adapter) 2457277b024eSKalle Valo { 2458277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2459277b024eSKalle Valo 2460277b024eSKalle Valo if (adapter->card) { 2461bcf28a2fSXinming Hu card->adapter = NULL; 2462277b024eSKalle Valo sdio_claim_host(card->func); 2463277b024eSKalle Valo sdio_disable_func(card->func); 2464277b024eSKalle Valo sdio_release_host(card->func); 2465277b024eSKalle Valo } 2466277b024eSKalle Valo } 2467277b024eSKalle Valo 2468277b024eSKalle Valo /* 2469277b024eSKalle Valo * This function registers the SDIO device. 2470277b024eSKalle Valo * 2471277b024eSKalle Valo * SDIO IRQ is claimed, block size is set and driver data is initialized. 2472277b024eSKalle Valo */ 2473277b024eSKalle Valo static int mwifiex_register_dev(struct mwifiex_adapter *adapter) 2474277b024eSKalle Valo { 2475277b024eSKalle Valo int ret; 2476277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2477277b024eSKalle Valo struct sdio_func *func = card->func; 2478255ca28aSAndrejs Cainikovs const char *firmware = card->firmware; 2479277b024eSKalle Valo 2480277b024eSKalle Valo /* save adapter pointer in card */ 2481277b024eSKalle Valo card->adapter = adapter; 2482277b024eSKalle Valo adapter->tx_buf_size = card->tx_buf_size; 2483277b024eSKalle Valo 2484277b024eSKalle Valo sdio_claim_host(func); 2485277b024eSKalle Valo 2486277b024eSKalle Valo /* Set block size */ 2487277b024eSKalle Valo ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); 2488277b024eSKalle Valo sdio_release_host(func); 2489277b024eSKalle Valo if (ret) { 2490277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2491277b024eSKalle Valo "cannot set SDIO block size\n"); 2492277b024eSKalle Valo return ret; 2493277b024eSKalle Valo } 2494277b024eSKalle Valo 2495255ca28aSAndrejs Cainikovs /* Select correct firmware (sdsd or sdiouart) firmware based on the strapping 2496255ca28aSAndrejs Cainikovs * option 2497255ca28aSAndrejs Cainikovs */ 2498255ca28aSAndrejs Cainikovs if (card->firmware_sdiouart) { 2499255ca28aSAndrejs Cainikovs u8 val; 2500255ca28aSAndrejs Cainikovs 2501255ca28aSAndrejs Cainikovs mwifiex_read_reg(adapter, card->reg->host_strap_reg, &val); 2502255ca28aSAndrejs Cainikovs if ((val & card->reg->host_strap_mask) == card->reg->host_strap_value) 2503255ca28aSAndrejs Cainikovs firmware = card->firmware_sdiouart; 2504255ca28aSAndrejs Cainikovs } 2505255ca28aSAndrejs Cainikovs strcpy(adapter->fw_name, firmware); 2506255ca28aSAndrejs Cainikovs 2507277b024eSKalle Valo if (card->fw_dump_enh) { 2508277b024eSKalle Valo adapter->mem_type_mapping_tbl = generic_mem_type_map; 2509277b024eSKalle Valo adapter->num_mem_types = 1; 2510277b024eSKalle Valo } else { 2511277b024eSKalle Valo adapter->mem_type_mapping_tbl = mem_type_mapping_tbl; 2512277b024eSKalle Valo adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); 2513277b024eSKalle Valo } 2514277b024eSKalle Valo 2515277b024eSKalle Valo return 0; 2516277b024eSKalle Valo } 2517277b024eSKalle Valo 2518277b024eSKalle Valo /* 2519277b024eSKalle Valo * This function initializes the SDIO driver. 2520277b024eSKalle Valo * 2521277b024eSKalle Valo * The following initializations steps are followed - 2522277b024eSKalle Valo * - Read the Host interrupt status register to acknowledge 2523277b024eSKalle Valo * the first interrupt got from bootloader 2524277b024eSKalle Valo * - Disable host interrupt mask register 2525277b024eSKalle Valo * - Get SDIO port 2526277b024eSKalle Valo * - Initialize SDIO variables in card 2527277b024eSKalle Valo * - Allocate MP registers 2528277b024eSKalle Valo * - Allocate MPA Tx and Rx buffers 2529277b024eSKalle Valo */ 2530277b024eSKalle Valo static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) 2531277b024eSKalle Valo { 2532277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2533277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 2534277b024eSKalle Valo int ret; 2535277b024eSKalle Valo u8 sdio_ireg; 2536277b024eSKalle Valo 2537277b024eSKalle Valo sdio_set_drvdata(card->func, card); 2538277b024eSKalle Valo 2539277b024eSKalle Valo /* 2540277b024eSKalle Valo * Read the host_int_status_reg for ACK the first interrupt got 2541277b024eSKalle Valo * from the bootloader. If we don't do this we get a interrupt 2542277b024eSKalle Valo * as soon as we register the irq. 2543277b024eSKalle Valo */ 2544277b024eSKalle Valo mwifiex_read_reg(adapter, card->reg->host_int_status_reg, &sdio_ireg); 2545277b024eSKalle Valo 2546277b024eSKalle Valo /* Get SDIO ioport */ 2547a6b3a016SDmitry Antipov if (mwifiex_init_sdio_ioport(adapter)) 2548a6b3a016SDmitry Antipov return -EIO; 2549277b024eSKalle Valo 2550277b024eSKalle Valo /* Initialize SDIO variables in card */ 2551277b024eSKalle Valo card->mp_rd_bitmap = 0; 2552277b024eSKalle Valo card->mp_wr_bitmap = 0; 2553277b024eSKalle Valo card->curr_rd_port = reg->start_rd_port; 2554277b024eSKalle Valo card->curr_wr_port = reg->start_wr_port; 2555277b024eSKalle Valo 2556277b024eSKalle Valo card->mp_data_port_mask = reg->data_port_mask; 2557277b024eSKalle Valo 2558277b024eSKalle Valo card->mpa_tx.buf_len = 0; 2559277b024eSKalle Valo card->mpa_tx.pkt_cnt = 0; 2560277b024eSKalle Valo card->mpa_tx.start_port = 0; 2561277b024eSKalle Valo 2562277b024eSKalle Valo card->mpa_tx.enabled = 1; 2563277b024eSKalle Valo card->mpa_tx.pkt_aggr_limit = card->mp_agg_pkt_limit; 2564277b024eSKalle Valo 2565277b024eSKalle Valo card->mpa_rx.buf_len = 0; 2566277b024eSKalle Valo card->mpa_rx.pkt_cnt = 0; 2567277b024eSKalle Valo card->mpa_rx.start_port = 0; 2568277b024eSKalle Valo 2569277b024eSKalle Valo card->mpa_rx.enabled = 1; 2570277b024eSKalle Valo card->mpa_rx.pkt_aggr_limit = card->mp_agg_pkt_limit; 2571277b024eSKalle Valo 2572277b024eSKalle Valo /* Allocate buffers for SDIO MP-A */ 2573277b024eSKalle Valo card->mp_regs = kzalloc(reg->max_mp_regs, GFP_KERNEL); 2574277b024eSKalle Valo if (!card->mp_regs) 2575277b024eSKalle Valo return -ENOMEM; 2576277b024eSKalle Valo 25776396bb22SKees Cook card->mpa_rx.len_arr = kcalloc(card->mp_agg_pkt_limit, 25786396bb22SKees Cook sizeof(*card->mpa_rx.len_arr), 25796396bb22SKees Cook GFP_KERNEL); 258050f85e22SInsu Yun if (!card->mpa_rx.len_arr) { 258150f85e22SInsu Yun kfree(card->mp_regs); 258250f85e22SInsu Yun return -ENOMEM; 258350f85e22SInsu Yun } 258450f85e22SInsu Yun 2585277b024eSKalle Valo ret = mwifiex_alloc_sdio_mpa_buffers(adapter, 2586277b024eSKalle Valo card->mp_tx_agg_buf_size, 2587277b024eSKalle Valo card->mp_rx_agg_buf_size); 2588277b024eSKalle Valo 2589277b024eSKalle Valo /* Allocate 32k MPA Tx/Rx buffers if 64k memory allocation fails */ 2590277b024eSKalle Valo if (ret && (card->mp_tx_agg_buf_size == MWIFIEX_MP_AGGR_BUF_SIZE_MAX || 2591277b024eSKalle Valo card->mp_rx_agg_buf_size == MWIFIEX_MP_AGGR_BUF_SIZE_MAX)) { 2592277b024eSKalle Valo /* Disable rx single port aggregation */ 2593277b024eSKalle Valo adapter->host_disable_sdio_rx_aggr = true; 2594277b024eSKalle Valo 2595277b024eSKalle Valo ret = mwifiex_alloc_sdio_mpa_buffers 2596277b024eSKalle Valo (adapter, MWIFIEX_MP_AGGR_BUF_SIZE_32K, 2597277b024eSKalle Valo MWIFIEX_MP_AGGR_BUF_SIZE_32K); 2598277b024eSKalle Valo if (ret) { 2599277b024eSKalle Valo /* Disable multi port aggregation */ 2600277b024eSKalle Valo card->mpa_tx.enabled = 0; 2601277b024eSKalle Valo card->mpa_rx.enabled = 0; 2602277b024eSKalle Valo } 2603277b024eSKalle Valo } 2604277b024eSKalle Valo 2605277b024eSKalle Valo adapter->auto_tdls = card->can_auto_tdls; 2606277b024eSKalle Valo adapter->ext_scan = card->can_ext_scan; 2607277b024eSKalle Valo return 0; 2608277b024eSKalle Valo } 2609277b024eSKalle Valo 2610277b024eSKalle Valo /* 2611277b024eSKalle Valo * This function resets the MPA Tx and Rx buffers. 2612277b024eSKalle Valo */ 2613277b024eSKalle Valo static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter) 2614277b024eSKalle Valo { 2615277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2616277b024eSKalle Valo 2617277b024eSKalle Valo MP_TX_AGGR_BUF_RESET(card); 2618277b024eSKalle Valo MP_RX_AGGR_BUF_RESET(card); 2619277b024eSKalle Valo } 2620277b024eSKalle Valo 2621277b024eSKalle Valo /* 2622277b024eSKalle Valo * This function cleans up the allocated card buffers. 2623277b024eSKalle Valo * 2624277b024eSKalle Valo * The following are freed by this function - 2625277b024eSKalle Valo * - MP registers 2626277b024eSKalle Valo * - MPA Tx buffer 2627277b024eSKalle Valo * - MPA Rx buffer 2628277b024eSKalle Valo */ 2629277b024eSKalle Valo static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter) 2630277b024eSKalle Valo { 2631277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2632277b024eSKalle Valo 26335caa7f38SBrian Norris cancel_work_sync(&card->work); 26345caa7f38SBrian Norris 2635277b024eSKalle Valo kfree(card->mp_regs); 2636277b024eSKalle Valo kfree(card->mpa_rx.len_arr); 2637277b024eSKalle Valo kfree(card->mpa_tx.buf); 2638277b024eSKalle Valo kfree(card->mpa_rx.buf); 2639277b024eSKalle Valo } 2640277b024eSKalle Valo 2641277b024eSKalle Valo /* 2642277b024eSKalle Valo * This function updates the MP end port in card. 2643277b024eSKalle Valo */ 2644277b024eSKalle Valo static void 2645277b024eSKalle Valo mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) 2646277b024eSKalle Valo { 2647277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2648277b024eSKalle Valo const struct mwifiex_sdio_card_reg *reg = card->reg; 2649277b024eSKalle Valo int i; 2650277b024eSKalle Valo 2651277b024eSKalle Valo card->mp_end_port = port; 2652277b024eSKalle Valo 2653277b024eSKalle Valo card->mp_data_port_mask = reg->data_port_mask; 2654277b024eSKalle Valo 2655277b024eSKalle Valo if (reg->start_wr_port) { 2656277b024eSKalle Valo for (i = 1; i <= card->max_ports - card->mp_end_port; i++) 2657277b024eSKalle Valo card->mp_data_port_mask &= 2658277b024eSKalle Valo ~(1 << (card->max_ports - i)); 2659277b024eSKalle Valo } 2660277b024eSKalle Valo 2661277b024eSKalle Valo card->curr_wr_port = reg->start_wr_port; 2662277b024eSKalle Valo 2663277b024eSKalle Valo mwifiex_dbg(adapter, CMD, 2664277b024eSKalle Valo "cmd: mp_end_port %d, data port mask 0x%x\n", 2665277b024eSKalle Valo port, card->mp_data_port_mask); 2666277b024eSKalle Valo } 2667277b024eSKalle Valo 2668c742e623SXinming Hu static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) 2669277b024eSKalle Valo { 2670c742e623SXinming Hu struct sdio_mmc_card *card = adapter->card; 2671277b024eSKalle Valo struct sdio_func *func = card->func; 2672755b37c9SBrian Norris int ret; 2673277b024eSKalle Valo 2674cdb2256fSUlf Hansson /* Prepare the adapter for the reset. */ 2675c742e623SXinming Hu mwifiex_shutdown_sw(adapter); 2676cc75c577SXinming Hu clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); 2677cc75c577SXinming Hu clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); 267874c8719bSAmitkumar Karwar 2679cdb2256fSUlf Hansson /* Run a HW reset of the SDIO interface. */ 2680cdb2256fSUlf Hansson sdio_claim_host(func); 2681b71597edSWolfram Sang ret = mmc_hw_reset(func->card); 2682cdb2256fSUlf Hansson sdio_release_host(func); 2683cdb2256fSUlf Hansson 2684cdb2256fSUlf Hansson switch (ret) { 2685cdb2256fSUlf Hansson case 1: 2686cdb2256fSUlf Hansson dev_dbg(&func->dev, "SDIO HW reset asynchronous\n"); 2687cdb2256fSUlf Hansson complete_all(adapter->fw_done); 2688cdb2256fSUlf Hansson break; 2689cdb2256fSUlf Hansson case 0: 2690755b37c9SBrian Norris ret = mwifiex_reinit_sw(adapter); 2691755b37c9SBrian Norris if (ret) 2692755b37c9SBrian Norris dev_err(&func->dev, "reinit failed: %d\n", ret); 2693cdb2256fSUlf Hansson break; 2694cdb2256fSUlf Hansson default: 2695cdb2256fSUlf Hansson dev_err(&func->dev, "SDIO HW reset failed: %d\n", ret); 2696cdb2256fSUlf Hansson break; 2697cdb2256fSUlf Hansson } 2698277b024eSKalle Valo } 2699277b024eSKalle Valo 2700277b024eSKalle Valo /* This function read/write firmware */ 2701277b024eSKalle Valo static enum 2702277b024eSKalle Valo rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, 2703277b024eSKalle Valo u8 doneflag) 2704277b024eSKalle Valo { 2705277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2706277b024eSKalle Valo int ret, tries; 2707277b024eSKalle Valo u8 ctrl_data = 0; 2708277b024eSKalle Valo 2709277b024eSKalle Valo sdio_writeb(card->func, card->reg->fw_dump_host_ready, 2710277b024eSKalle Valo card->reg->fw_dump_ctrl, &ret); 2711277b024eSKalle Valo if (ret) { 2712277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO Write ERR\n"); 2713277b024eSKalle Valo return RDWR_STATUS_FAILURE; 2714277b024eSKalle Valo } 2715277b024eSKalle Valo for (tries = 0; tries < MAX_POLL_TRIES; tries++) { 2716277b024eSKalle Valo ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl, 2717277b024eSKalle Valo &ret); 2718277b024eSKalle Valo if (ret) { 2719277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO read err\n"); 2720277b024eSKalle Valo return RDWR_STATUS_FAILURE; 2721277b024eSKalle Valo } 2722277b024eSKalle Valo if (ctrl_data == FW_DUMP_DONE) 2723277b024eSKalle Valo break; 2724277b024eSKalle Valo if (doneflag && ctrl_data == doneflag) 2725277b024eSKalle Valo return RDWR_STATUS_DONE; 2726277b024eSKalle Valo if (ctrl_data != card->reg->fw_dump_host_ready) { 2727277b024eSKalle Valo mwifiex_dbg(adapter, WARN, 2728277b024eSKalle Valo "The ctrl reg was changed, re-try again\n"); 2729277b024eSKalle Valo sdio_writeb(card->func, card->reg->fw_dump_host_ready, 2730277b024eSKalle Valo card->reg->fw_dump_ctrl, &ret); 2731277b024eSKalle Valo if (ret) { 2732277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO write err\n"); 2733277b024eSKalle Valo return RDWR_STATUS_FAILURE; 2734277b024eSKalle Valo } 2735277b024eSKalle Valo } 2736277b024eSKalle Valo usleep_range(100, 200); 2737277b024eSKalle Valo } 2738277b024eSKalle Valo if (ctrl_data == card->reg->fw_dump_host_ready) { 2739277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2740277b024eSKalle Valo "Fail to pull ctrl_data\n"); 2741277b024eSKalle Valo return RDWR_STATUS_FAILURE; 2742277b024eSKalle Valo } 2743277b024eSKalle Valo 2744277b024eSKalle Valo return RDWR_STATUS_SUCCESS; 2745277b024eSKalle Valo } 2746277b024eSKalle Valo 2747277b024eSKalle Valo /* This function dump firmware memory to file */ 2748277b024eSKalle Valo static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter) 2749277b024eSKalle Valo { 2750277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2751277b024eSKalle Valo int ret = 0; 2752277b024eSKalle Valo unsigned int reg, reg_start, reg_end; 2753277b024eSKalle Valo u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0; 2754277b024eSKalle Valo enum rdwr_status stat; 2755277b024eSKalle Valo u32 memory_size; 2756277b024eSKalle Valo 2757277b024eSKalle Valo if (!card->can_dump_fw) 2758277b024eSKalle Valo return; 2759277b024eSKalle Valo 2760277b024eSKalle Valo for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) { 2761277b024eSKalle Valo struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; 2762277b024eSKalle Valo 2763277b024eSKalle Valo if (entry->mem_ptr) { 2764277b024eSKalle Valo vfree(entry->mem_ptr); 2765277b024eSKalle Valo entry->mem_ptr = NULL; 2766277b024eSKalle Valo } 2767277b024eSKalle Valo entry->mem_size = 0; 2768277b024eSKalle Valo } 2769277b024eSKalle Valo 2770277b024eSKalle Valo mwifiex_pm_wakeup_card(adapter); 2771277b024eSKalle Valo sdio_claim_host(card->func); 2772277b024eSKalle Valo 2773277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n"); 2774277b024eSKalle Valo 2775277b024eSKalle Valo stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); 2776277b024eSKalle Valo if (stat == RDWR_STATUS_FAILURE) 2777277b024eSKalle Valo goto done; 2778277b024eSKalle Valo 2779277b024eSKalle Valo reg = card->reg->fw_dump_start; 2780277b024eSKalle Valo /* Read the number of the memories which will dump */ 2781277b024eSKalle Valo dump_num = sdio_readb(card->func, reg, &ret); 2782277b024eSKalle Valo if (ret) { 2783277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO read memory length err\n"); 2784277b024eSKalle Valo goto done; 2785277b024eSKalle Valo } 2786277b024eSKalle Valo 2787277b024eSKalle Valo /* Read the length of every memory which will dump */ 2788277b024eSKalle Valo for (idx = 0; idx < dump_num; idx++) { 2789277b024eSKalle Valo struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx]; 2790277b024eSKalle Valo 2791277b024eSKalle Valo stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); 2792277b024eSKalle Valo if (stat == RDWR_STATUS_FAILURE) 2793277b024eSKalle Valo goto done; 2794277b024eSKalle Valo 2795277b024eSKalle Valo memory_size = 0; 2796277b024eSKalle Valo reg = card->reg->fw_dump_start; 2797277b024eSKalle Valo for (i = 0; i < 4; i++) { 2798277b024eSKalle Valo read_reg = sdio_readb(card->func, reg, &ret); 2799277b024eSKalle Valo if (ret) { 2800277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO read err\n"); 2801277b024eSKalle Valo goto done; 2802277b024eSKalle Valo } 2803277b024eSKalle Valo memory_size |= (read_reg << i*8); 2804277b024eSKalle Valo reg++; 2805277b024eSKalle Valo } 2806277b024eSKalle Valo 2807277b024eSKalle Valo if (memory_size == 0) { 2808277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, "Firmware dump Finished!\n"); 2809277b024eSKalle Valo ret = mwifiex_write_reg(adapter, 2810277b024eSKalle Valo card->reg->fw_dump_ctrl, 2811277b024eSKalle Valo FW_DUMP_READ_DONE); 2812277b024eSKalle Valo if (ret) { 2813277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "SDIO write err\n"); 2814277b024eSKalle Valo return; 2815277b024eSKalle Valo } 2816277b024eSKalle Valo break; 2817277b024eSKalle Valo } 2818277b024eSKalle Valo 2819277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, 2820277b024eSKalle Valo "%s_SIZE=0x%x\n", entry->mem_name, memory_size); 2821277b024eSKalle Valo entry->mem_ptr = vmalloc(memory_size + 1); 2822277b024eSKalle Valo entry->mem_size = memory_size; 2823277b024eSKalle Valo if (!entry->mem_ptr) { 2824277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "Vmalloc %s failed\n", 2825277b024eSKalle Valo entry->mem_name); 2826277b024eSKalle Valo goto done; 2827277b024eSKalle Valo } 2828277b024eSKalle Valo dbg_ptr = entry->mem_ptr; 2829277b024eSKalle Valo end_ptr = dbg_ptr + memory_size; 2830277b024eSKalle Valo 2831277b024eSKalle Valo doneflag = entry->done_flag; 2832277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, 2833277b024eSKalle Valo "Start %s output, please wait...\n", 2834277b024eSKalle Valo entry->mem_name); 2835277b024eSKalle Valo 2836277b024eSKalle Valo do { 2837277b024eSKalle Valo stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag); 2838277b024eSKalle Valo if (stat == RDWR_STATUS_FAILURE) 2839277b024eSKalle Valo goto done; 2840277b024eSKalle Valo 2841277b024eSKalle Valo reg_start = card->reg->fw_dump_start; 2842277b024eSKalle Valo reg_end = card->reg->fw_dump_end; 2843277b024eSKalle Valo for (reg = reg_start; reg <= reg_end; reg++) { 2844277b024eSKalle Valo *dbg_ptr = sdio_readb(card->func, reg, &ret); 2845277b024eSKalle Valo if (ret) { 2846277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2847277b024eSKalle Valo "SDIO read err\n"); 2848277b024eSKalle Valo goto done; 2849277b024eSKalle Valo } 2850277b024eSKalle Valo if (dbg_ptr < end_ptr) 2851277b024eSKalle Valo dbg_ptr++; 2852277b024eSKalle Valo else 2853277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2854277b024eSKalle Valo "Allocated buf not enough\n"); 2855277b024eSKalle Valo } 2856277b024eSKalle Valo 2857277b024eSKalle Valo if (stat != RDWR_STATUS_DONE) 2858277b024eSKalle Valo continue; 2859277b024eSKalle Valo 2860277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, "%s done: size=0x%tx\n", 2861277b024eSKalle Valo entry->mem_name, dbg_ptr - entry->mem_ptr); 2862277b024eSKalle Valo break; 2863277b024eSKalle Valo } while (1); 2864277b024eSKalle Valo } 2865277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n"); 2866277b024eSKalle Valo 2867277b024eSKalle Valo done: 2868277b024eSKalle Valo sdio_release_host(card->func); 2869277b024eSKalle Valo } 2870277b024eSKalle Valo 2871277b024eSKalle Valo static void mwifiex_sdio_generic_fw_dump(struct mwifiex_adapter *adapter) 2872277b024eSKalle Valo { 2873277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2874277b024eSKalle Valo struct memory_type_mapping *entry = &generic_mem_type_map[0]; 2875277b024eSKalle Valo unsigned int reg, reg_start, reg_end; 2876277b024eSKalle Valo u8 start_flag = 0, done_flag = 0; 2877277b024eSKalle Valo u8 *dbg_ptr, *end_ptr; 2878277b024eSKalle Valo enum rdwr_status stat; 2879277b024eSKalle Valo int ret = -1, tries; 2880277b024eSKalle Valo 2881277b024eSKalle Valo if (!card->fw_dump_enh) 2882277b024eSKalle Valo return; 2883277b024eSKalle Valo 2884277b024eSKalle Valo if (entry->mem_ptr) { 2885277b024eSKalle Valo vfree(entry->mem_ptr); 2886277b024eSKalle Valo entry->mem_ptr = NULL; 2887277b024eSKalle Valo } 2888277b024eSKalle Valo entry->mem_size = 0; 2889277b024eSKalle Valo 2890277b024eSKalle Valo mwifiex_pm_wakeup_card(adapter); 2891277b024eSKalle Valo sdio_claim_host(card->func); 2892277b024eSKalle Valo 2893277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n"); 2894277b024eSKalle Valo 2895277b024eSKalle Valo stat = mwifiex_sdio_rdwr_firmware(adapter, done_flag); 2896277b024eSKalle Valo if (stat == RDWR_STATUS_FAILURE) 2897277b024eSKalle Valo goto done; 2898277b024eSKalle Valo 2899277b024eSKalle Valo reg_start = card->reg->fw_dump_start; 2900277b024eSKalle Valo reg_end = card->reg->fw_dump_end; 2901277b024eSKalle Valo for (reg = reg_start; reg <= reg_end; reg++) { 2902277b024eSKalle Valo for (tries = 0; tries < MAX_POLL_TRIES; tries++) { 2903277b024eSKalle Valo start_flag = sdio_readb(card->func, reg, &ret); 2904277b024eSKalle Valo if (ret) { 2905277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2906277b024eSKalle Valo "SDIO read err\n"); 2907277b024eSKalle Valo goto done; 2908277b024eSKalle Valo } 2909277b024eSKalle Valo if (start_flag == 0) 2910277b024eSKalle Valo break; 2911277b024eSKalle Valo if (tries == MAX_POLL_TRIES) { 2912277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2913277b024eSKalle Valo "FW not ready to dump\n"); 2914277b024eSKalle Valo ret = -1; 2915277b024eSKalle Valo goto done; 2916277b024eSKalle Valo } 2917277b024eSKalle Valo } 2918277b024eSKalle Valo usleep_range(100, 200); 2919277b024eSKalle Valo } 2920277b024eSKalle Valo 2921277b024eSKalle Valo entry->mem_ptr = vmalloc(0xf0000 + 1); 2922277b024eSKalle Valo if (!entry->mem_ptr) { 2923277b024eSKalle Valo ret = -1; 2924277b024eSKalle Valo goto done; 2925277b024eSKalle Valo } 2926277b024eSKalle Valo dbg_ptr = entry->mem_ptr; 2927277b024eSKalle Valo entry->mem_size = 0xf0000; 2928277b024eSKalle Valo end_ptr = dbg_ptr + entry->mem_size; 2929277b024eSKalle Valo 2930277b024eSKalle Valo done_flag = entry->done_flag; 2931277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, 2932277b024eSKalle Valo "Start %s output, please wait...\n", entry->mem_name); 2933277b024eSKalle Valo 2934277b024eSKalle Valo while (true) { 2935277b024eSKalle Valo stat = mwifiex_sdio_rdwr_firmware(adapter, done_flag); 2936277b024eSKalle Valo if (stat == RDWR_STATUS_FAILURE) 2937277b024eSKalle Valo goto done; 2938277b024eSKalle Valo for (reg = reg_start; reg <= reg_end; reg++) { 2939277b024eSKalle Valo *dbg_ptr = sdio_readb(card->func, reg, &ret); 2940277b024eSKalle Valo if (ret) { 2941277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 2942277b024eSKalle Valo "SDIO read err\n"); 2943277b024eSKalle Valo goto done; 2944277b024eSKalle Valo } 2945277b024eSKalle Valo dbg_ptr++; 2946277b024eSKalle Valo if (dbg_ptr >= end_ptr) { 2947277b024eSKalle Valo u8 *tmp_ptr; 2948277b024eSKalle Valo 2949277b024eSKalle Valo tmp_ptr = vmalloc(entry->mem_size + 0x4000 + 1); 2950277b024eSKalle Valo if (!tmp_ptr) 2951277b024eSKalle Valo goto done; 2952277b024eSKalle Valo 2953277b024eSKalle Valo memcpy(tmp_ptr, entry->mem_ptr, 2954277b024eSKalle Valo entry->mem_size); 2955277b024eSKalle Valo vfree(entry->mem_ptr); 2956277b024eSKalle Valo entry->mem_ptr = tmp_ptr; 2957277b024eSKalle Valo tmp_ptr = NULL; 2958277b024eSKalle Valo dbg_ptr = entry->mem_ptr + entry->mem_size; 2959277b024eSKalle Valo entry->mem_size += 0x4000; 2960277b024eSKalle Valo end_ptr = entry->mem_ptr + entry->mem_size; 2961277b024eSKalle Valo } 2962277b024eSKalle Valo } 2963277b024eSKalle Valo if (stat == RDWR_STATUS_DONE) { 2964277b024eSKalle Valo entry->mem_size = dbg_ptr - entry->mem_ptr; 2965277b024eSKalle Valo mwifiex_dbg(adapter, DUMP, "dump %s done size=0x%x\n", 2966277b024eSKalle Valo entry->mem_name, entry->mem_size); 2967277b024eSKalle Valo ret = 0; 2968277b024eSKalle Valo break; 2969277b024eSKalle Valo } 2970277b024eSKalle Valo } 2971277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n"); 2972277b024eSKalle Valo 2973277b024eSKalle Valo done: 2974277b024eSKalle Valo if (ret) { 2975277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, "firmware dump failed\n"); 2976277b024eSKalle Valo if (entry->mem_ptr) { 2977277b024eSKalle Valo vfree(entry->mem_ptr); 2978277b024eSKalle Valo entry->mem_ptr = NULL; 2979277b024eSKalle Valo } 2980277b024eSKalle Valo entry->mem_size = 0; 2981277b024eSKalle Valo } 2982277b024eSKalle Valo sdio_release_host(card->func); 2983277b024eSKalle Valo } 2984277b024eSKalle Valo 2985277b024eSKalle Valo static void mwifiex_sdio_device_dump_work(struct mwifiex_adapter *adapter) 2986277b024eSKalle Valo { 2987277b024eSKalle Valo struct sdio_mmc_card *card = adapter->card; 2988277b024eSKalle Valo 2989d0e2b44eSXinming Hu adapter->devdump_data = vzalloc(MWIFIEX_FW_DUMP_SIZE); 2990d0e2b44eSXinming Hu if (!adapter->devdump_data) { 2991d0e2b44eSXinming Hu mwifiex_dbg(adapter, ERROR, 2992d0e2b44eSXinming Hu "vzalloc devdump data failure!\n"); 2993d0e2b44eSXinming Hu return; 2994d0e2b44eSXinming Hu } 2995d0e2b44eSXinming Hu 2996d0e2b44eSXinming Hu mwifiex_drv_info_dump(adapter); 2997277b024eSKalle Valo if (card->fw_dump_enh) 2998277b024eSKalle Valo mwifiex_sdio_generic_fw_dump(adapter); 2999277b024eSKalle Valo else 3000277b024eSKalle Valo mwifiex_sdio_fw_dump(adapter); 3001d0e2b44eSXinming Hu mwifiex_prepare_fw_dump_info(adapter); 3002d0e2b44eSXinming Hu mwifiex_upload_device_dump(adapter); 3003277b024eSKalle Valo } 3004277b024eSKalle Valo 3005277b024eSKalle Valo static void mwifiex_sdio_work(struct work_struct *work) 3006277b024eSKalle Valo { 3007cc75c577SXinming Hu struct sdio_mmc_card *card = 3008cc75c577SXinming Hu container_of(work, struct sdio_mmc_card, work); 3009cc75c577SXinming Hu 3010277b024eSKalle Valo if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, 3011cc75c577SXinming Hu &card->work_flags)) 3012cc75c577SXinming Hu mwifiex_sdio_device_dump_work(card->adapter); 3013277b024eSKalle Valo if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, 3014cc75c577SXinming Hu &card->work_flags)) 3015cc75c577SXinming Hu mwifiex_sdio_card_reset_work(card->adapter); 3016277b024eSKalle Valo } 3017277b024eSKalle Valo 3018277b024eSKalle Valo /* This function resets the card */ 3019277b024eSKalle Valo static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) 3020277b024eSKalle Valo { 3021cc75c577SXinming Hu struct sdio_mmc_card *card = adapter->card; 3022cc75c577SXinming Hu 302321f569afSBrian Norris if (!test_and_set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags)) 3024cc75c577SXinming Hu schedule_work(&card->work); 3025277b024eSKalle Valo } 3026277b024eSKalle Valo 3027277b024eSKalle Valo /* This function dumps FW information */ 3028277b024eSKalle Valo static void mwifiex_sdio_device_dump(struct mwifiex_adapter *adapter) 3029277b024eSKalle Valo { 3030cc75c577SXinming Hu struct sdio_mmc_card *card = adapter->card; 3031cc75c577SXinming Hu 303221f569afSBrian Norris if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, 303321f569afSBrian Norris &card->work_flags)) 3034cc75c577SXinming Hu schedule_work(&card->work); 3035277b024eSKalle Valo } 3036277b024eSKalle Valo 3037277b024eSKalle Valo /* Function to dump SDIO function registers and SDIO scratch registers in case 3038277b024eSKalle Valo * of FW crash 3039277b024eSKalle Valo */ 3040277b024eSKalle Valo static int 3041277b024eSKalle Valo mwifiex_sdio_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf) 3042277b024eSKalle Valo { 3043277b024eSKalle Valo char *p = drv_buf; 3044277b024eSKalle Valo struct sdio_mmc_card *cardp = adapter->card; 3045277b024eSKalle Valo int ret = 0; 3046277b024eSKalle Valo u8 count, func, data, index = 0, size = 0; 3047277b024eSKalle Valo u8 reg, reg_start, reg_end; 3048277b024eSKalle Valo char buf[256], *ptr; 3049277b024eSKalle Valo 3050277b024eSKalle Valo if (!p) 3051277b024eSKalle Valo return 0; 3052277b024eSKalle Valo 3053277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "SDIO register dump start\n"); 3054277b024eSKalle Valo 3055277b024eSKalle Valo mwifiex_pm_wakeup_card(adapter); 3056277b024eSKalle Valo 3057277b024eSKalle Valo sdio_claim_host(cardp->func); 3058277b024eSKalle Valo 3059277b024eSKalle Valo for (count = 0; count < 5; count++) { 3060277b024eSKalle Valo memset(buf, 0, sizeof(buf)); 3061277b024eSKalle Valo ptr = buf; 3062277b024eSKalle Valo 3063277b024eSKalle Valo switch (count) { 3064277b024eSKalle Valo case 0: 3065277b024eSKalle Valo /* Read the registers of SDIO function0 */ 3066277b024eSKalle Valo func = count; 3067277b024eSKalle Valo reg_start = 0; 3068277b024eSKalle Valo reg_end = 9; 3069277b024eSKalle Valo break; 3070277b024eSKalle Valo case 1: 3071277b024eSKalle Valo /* Read the registers of SDIO function1 */ 3072277b024eSKalle Valo func = count; 3073277b024eSKalle Valo reg_start = cardp->reg->func1_dump_reg_start; 3074277b024eSKalle Valo reg_end = cardp->reg->func1_dump_reg_end; 3075277b024eSKalle Valo break; 3076277b024eSKalle Valo case 2: 3077277b024eSKalle Valo index = 0; 3078277b024eSKalle Valo func = 1; 3079277b024eSKalle Valo reg_start = cardp->reg->func1_spec_reg_table[index++]; 3080277b024eSKalle Valo size = cardp->reg->func1_spec_reg_num; 3081277b024eSKalle Valo reg_end = cardp->reg->func1_spec_reg_table[size-1]; 3082277b024eSKalle Valo break; 3083277b024eSKalle Valo default: 3084277b024eSKalle Valo /* Read the scratch registers of SDIO function1 */ 3085277b024eSKalle Valo if (count == 4) 3086277b024eSKalle Valo mdelay(100); 3087277b024eSKalle Valo func = 1; 3088277b024eSKalle Valo reg_start = cardp->reg->func1_scratch_reg; 3089277b024eSKalle Valo reg_end = reg_start + MWIFIEX_SDIO_SCRATCH_SIZE; 3090277b024eSKalle Valo } 3091277b024eSKalle Valo 3092277b024eSKalle Valo if (count != 2) 3093277b024eSKalle Valo ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", 3094277b024eSKalle Valo func, reg_start, reg_end); 3095277b024eSKalle Valo else 3096277b024eSKalle Valo ptr += sprintf(ptr, "SDIO Func%d: ", func); 3097277b024eSKalle Valo 3098277b024eSKalle Valo for (reg = reg_start; reg <= reg_end;) { 3099277b024eSKalle Valo if (func == 0) 3100277b024eSKalle Valo data = sdio_f0_readb(cardp->func, reg, &ret); 3101277b024eSKalle Valo else 3102277b024eSKalle Valo data = sdio_readb(cardp->func, reg, &ret); 3103277b024eSKalle Valo 3104277b024eSKalle Valo if (count == 2) 3105277b024eSKalle Valo ptr += sprintf(ptr, "(%#x) ", reg); 3106277b024eSKalle Valo if (!ret) { 3107277b024eSKalle Valo ptr += sprintf(ptr, "%02x ", data); 3108277b024eSKalle Valo } else { 3109277b024eSKalle Valo ptr += sprintf(ptr, "ERR"); 3110277b024eSKalle Valo break; 3111277b024eSKalle Valo } 3112277b024eSKalle Valo 3113277b024eSKalle Valo if (count == 2 && reg < reg_end) 3114277b024eSKalle Valo reg = cardp->reg->func1_spec_reg_table[index++]; 3115277b024eSKalle Valo else 3116277b024eSKalle Valo reg++; 3117277b024eSKalle Valo } 3118277b024eSKalle Valo 3119277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "%s\n", buf); 3120277b024eSKalle Valo p += sprintf(p, "%s\n", buf); 3121277b024eSKalle Valo } 3122277b024eSKalle Valo 3123277b024eSKalle Valo sdio_release_host(cardp->func); 3124277b024eSKalle Valo 3125277b024eSKalle Valo mwifiex_dbg(adapter, MSG, "SDIO register dump end\n"); 3126277b024eSKalle Valo 3127277b024eSKalle Valo return p - drv_buf; 3128277b024eSKalle Valo } 3129277b024eSKalle Valo 3130c742e623SXinming Hu /* sdio device/function initialization, code is extracted 3131c742e623SXinming Hu * from init_if handler and register_dev handler. 3132c742e623SXinming Hu */ 3133c742e623SXinming Hu static void mwifiex_sdio_up_dev(struct mwifiex_adapter *adapter) 3134c742e623SXinming Hu { 3135c742e623SXinming Hu struct sdio_mmc_card *card = adapter->card; 3136c742e623SXinming Hu u8 sdio_ireg; 3137c742e623SXinming Hu 3138c742e623SXinming Hu sdio_claim_host(card->func); 3139c742e623SXinming Hu sdio_enable_func(card->func); 3140c742e623SXinming Hu sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); 3141c742e623SXinming Hu sdio_release_host(card->func); 3142c742e623SXinming Hu 3143c742e623SXinming Hu /* tx_buf_size might be changed to 3584 by firmware during 3144c742e623SXinming Hu * data transfer, we will reset to default size. 3145c742e623SXinming Hu */ 3146c742e623SXinming Hu adapter->tx_buf_size = card->tx_buf_size; 3147c742e623SXinming Hu 3148c742e623SXinming Hu /* Read the host_int_status_reg for ACK the first interrupt got 3149c742e623SXinming Hu * from the bootloader. If we don't do this we get a interrupt 3150c742e623SXinming Hu * as soon as we register the irq. 3151c742e623SXinming Hu */ 3152c742e623SXinming Hu mwifiex_read_reg(adapter, card->reg->host_int_status_reg, &sdio_ireg); 3153c742e623SXinming Hu 3154a6b3a016SDmitry Antipov if (mwifiex_init_sdio_ioport(adapter)) 3155a6b3a016SDmitry Antipov dev_err(&card->func->dev, "error enabling SDIO port\n"); 3156c742e623SXinming Hu } 3157c742e623SXinming Hu 3158277b024eSKalle Valo static struct mwifiex_if_ops sdio_ops = { 3159277b024eSKalle Valo .init_if = mwifiex_init_sdio, 3160277b024eSKalle Valo .cleanup_if = mwifiex_cleanup_sdio, 3161277b024eSKalle Valo .check_fw_status = mwifiex_check_fw_status, 31622fd5c6edSchunfan chen .check_winner_status = mwifiex_check_winner_status, 3163277b024eSKalle Valo .prog_fw = mwifiex_prog_fw_w_helper, 3164277b024eSKalle Valo .register_dev = mwifiex_register_dev, 3165277b024eSKalle Valo .unregister_dev = mwifiex_unregister_dev, 3166277b024eSKalle Valo .enable_int = mwifiex_sdio_enable_host_int, 3167277b024eSKalle Valo .disable_int = mwifiex_sdio_disable_host_int, 3168277b024eSKalle Valo .process_int_status = mwifiex_process_int_status, 3169277b024eSKalle Valo .host_to_card = mwifiex_sdio_host_to_card, 3170277b024eSKalle Valo .wakeup = mwifiex_pm_wakeup_card, 3171277b024eSKalle Valo .wakeup_complete = mwifiex_pm_wakeup_card_complete, 3172277b024eSKalle Valo 3173277b024eSKalle Valo /* SDIO specific */ 3174277b024eSKalle Valo .update_mp_end_port = mwifiex_update_mp_end_port, 3175277b024eSKalle Valo .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, 3176277b024eSKalle Valo .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete, 3177277b024eSKalle Valo .event_complete = mwifiex_sdio_event_complete, 31782095b142SArnd Bergmann .dnld_fw = mwifiex_sdio_dnld_fw, 3179277b024eSKalle Valo .card_reset = mwifiex_sdio_card_reset, 3180277b024eSKalle Valo .reg_dump = mwifiex_sdio_reg_dump, 3181277b024eSKalle Valo .device_dump = mwifiex_sdio_device_dump, 3182277b024eSKalle Valo .deaggr_pkt = mwifiex_deaggr_sdio_pkt, 3183c742e623SXinming Hu .up_dev = mwifiex_sdio_up_dev, 3184277b024eSKalle Valo }; 3185277b024eSKalle Valo 3186*170861bcSKrzysztof Kozlowski module_sdio_driver(mwifiex_sdio); 3187277b024eSKalle Valo 3188277b024eSKalle Valo MODULE_AUTHOR("Marvell International Ltd."); 3189277b024eSKalle Valo MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); 3190277b024eSKalle Valo MODULE_VERSION(SDIO_VERSION); 3191277b024eSKalle Valo MODULE_LICENSE("GPL v2"); 3192277b024eSKalle Valo MODULE_FIRMWARE(SD8786_DEFAULT_FW_NAME); 3193277b024eSKalle Valo MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME); 3194277b024eSKalle Valo MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME); 3195c76936a7SVíctor Gonzalo MODULE_FIRMWARE(SD8801_DEFAULT_FW_NAME); 3196277b024eSKalle Valo MODULE_FIRMWARE(SD8897_DEFAULT_FW_NAME); 3197277b024eSKalle Valo MODULE_FIRMWARE(SD8887_DEFAULT_FW_NAME); 31981a0f5478SHemantkumar Suthar MODULE_FIRMWARE(SD8977_DEFAULT_FW_NAME); 3199bba047f1SLukas Wunner MODULE_FIRMWARE(SD8978_SDIOUART_FW_NAME); 3200938c7c80STamás Szűcs MODULE_FIRMWARE(SD8987_DEFAULT_FW_NAME); 3201277b024eSKalle Valo MODULE_FIRMWARE(SD8997_DEFAULT_FW_NAME); 3202562354abSAndrejs Cainikovs MODULE_FIRMWARE(SD8997_SDIOUART_FW_NAME); 3203