aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2014-06-20 00:38:55 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-06-25 15:32:46 -0400
commit54881c6b37c8d6127fa67c6baf0dc887f1920ae6 (patch)
tree22debbedfa6b76e8f463ca806916bc0d31bf50f1
parent088df424be7fe5706ea7c385638d23f6a68c6dd1 (diff)
mwifiex: add firmware dump feature for SDIO
Firmware dump feature is added for SDIO based chipsets which can be used with the help of ethtool commands. 1) Trigger firmware dump operation: ethtool --set-dump mlan0 0xff When the operation is completed, udev event will be sent to trigger external application. 2) Following udev rule can be used to get the data from ethtool: DRIVER=="mwifiex_sdio", ACTION=="change", RUN+="/sbin/mwifiex_sdio_fw_dump.sh" mwifiex_sdio_fw_dump.sh: #!/bin/bash ethtool --set-dump mlan0 0 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/ITCM.log ethtool --set-dump mlan0 1 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/DTCM.log ethtool --set-dump mlan0 2 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/SQRAM.log ethtool --set-dump mlan0 3 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/APU.log ethtool --set-dump mlan0 4 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/CIU.log ethtool --set-dump mlan0 5 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/ICU.log ethtool --set-dump mlan0 6 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/MAC.log Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c209
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h12
2 files changed, 221 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index b34270d425f4..95a1d1face95 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -50,6 +50,24 @@ static struct mwifiex_if_ops sdio_ops;
50 50
51static struct semaphore add_remove_card_sem; 51static struct semaphore add_remove_card_sem;
52 52
53static struct memory_type_mapping mem_type_mapping_tbl[] = {
54 {"ITCM", NULL, 0, 0xF0},
55 {"DTCM", NULL, 0, 0xF1},
56 {"SQRAM", NULL, 0, 0xF2},
57 {"APU", NULL, 0, 0xF3},
58 {"CIU", NULL, 0, 0xF4},
59 {"ICU", NULL, 0, 0xF5},
60 {"MAC", NULL, 0, 0xF6},
61 {"EXT7", NULL, 0, 0xF7},
62 {"EXT8", NULL, 0, 0xF8},
63 {"EXT9", NULL, 0, 0xF9},
64 {"EXT10", NULL, 0, 0xFA},
65 {"EXT11", NULL, 0, 0xFB},
66 {"EXT12", NULL, 0, 0xFC},
67 {"EXT13", NULL, 0, 0xFD},
68 {"EXTLAST", NULL, 0, 0xFE},
69};
70
53/* 71/*
54 * SDIO probe. 72 * SDIO probe.
55 * 73 *
@@ -87,6 +105,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
87 card->tx_buf_size = data->tx_buf_size; 105 card->tx_buf_size = data->tx_buf_size;
88 card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size; 106 card->mp_tx_agg_buf_size = data->mp_tx_agg_buf_size;
89 card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size; 107 card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size;
108 card->supports_fw_dump = data->supports_fw_dump;
90 } 109 }
91 110
92 sdio_claim_host(func); 111 sdio_claim_host(func);
@@ -1779,6 +1798,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
1779 adapter->dev = &func->dev; 1798 adapter->dev = &func->dev;
1780 1799
1781 strcpy(adapter->fw_name, card->firmware); 1800 strcpy(adapter->fw_name, card->firmware);
1801 adapter->mem_type_mapping_tbl = mem_type_mapping_tbl;
1802 adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl);
1782 1803
1783 return 0; 1804 return 0;
1784} 1805}
@@ -1936,6 +1957,180 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter)
1936 mmc_add_host(target); 1957 mmc_add_host(target);
1937} 1958}
1938 1959
1960/* This function read/write firmware */
1961static enum
1962rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter,
1963 u8 doneflag)
1964{
1965 struct sdio_mmc_card *card = adapter->card;
1966 int ret, tries;
1967 u8 ctrl_data = 0;
1968
1969 sdio_writeb(card->func, FW_DUMP_HOST_READY, card->reg->fw_dump_ctrl,
1970 &ret);
1971 if (ret) {
1972 dev_err(adapter->dev, "SDIO Write ERR\n");
1973 return RDWR_STATUS_FAILURE;
1974 }
1975 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
1976 ctrl_data = sdio_readb(card->func, card->reg->fw_dump_ctrl,
1977 &ret);
1978 if (ret) {
1979 dev_err(adapter->dev, "SDIO read err\n");
1980 return RDWR_STATUS_FAILURE;
1981 }
1982 if (ctrl_data == FW_DUMP_DONE)
1983 break;
1984 if (doneflag && ctrl_data == doneflag)
1985 return RDWR_STATUS_DONE;
1986 if (ctrl_data != FW_DUMP_HOST_READY) {
1987 dev_info(adapter->dev,
1988 "The ctrl reg was changed, re-try again!\n");
1989 sdio_writeb(card->func, FW_DUMP_HOST_READY,
1990 card->reg->fw_dump_ctrl, &ret);
1991 if (ret) {
1992 dev_err(adapter->dev, "SDIO write err\n");
1993 return RDWR_STATUS_FAILURE;
1994 }
1995 }
1996 usleep_range(100, 200);
1997 }
1998 if (ctrl_data == FW_DUMP_HOST_READY) {
1999 dev_err(adapter->dev, "Fail to pull ctrl_data\n");
2000 return RDWR_STATUS_FAILURE;
2001 }
2002
2003 return RDWR_STATUS_SUCCESS;
2004}
2005
2006/* This function dump firmware memory to file */
2007static void mwifiex_sdio_fw_dump_work(struct work_struct *work)
2008{
2009 struct mwifiex_adapter *adapter =
2010 container_of(work, struct mwifiex_adapter, iface_work);
2011 struct sdio_mmc_card *card = adapter->card;
2012 int ret = 0;
2013 unsigned int reg, reg_start, reg_end;
2014 u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0;
2015 struct timeval t;
2016 enum rdwr_status stat;
2017 u32 memory_size;
2018 static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL };
2019
2020 if (!card->supports_fw_dump)
2021 return;
2022
2023 for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) {
2024 struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
2025
2026 if (entry->mem_ptr) {
2027 vfree(entry->mem_ptr);
2028 entry->mem_ptr = NULL;
2029 }
2030 entry->mem_size = 0;
2031 }
2032
2033 mwifiex_pm_wakeup_card(adapter);
2034 sdio_claim_host(card->func);
2035
2036 do_gettimeofday(&t);
2037 dev_info(adapter->dev, "== mwifiex firmware dump start: %u.%06u ==\n",
2038 (u32)t.tv_sec, (u32)t.tv_usec);
2039
2040 stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag);
2041 if (stat == RDWR_STATUS_FAILURE)
2042 goto done;
2043
2044 reg = card->reg->fw_dump_start;
2045 /* Read the number of the memories which will dump */
2046 dump_num = sdio_readb(card->func, reg, &ret);
2047 if (ret) {
2048 dev_err(adapter->dev, "SDIO read memory length err\n");
2049 goto done;
2050 }
2051
2052 /* Read the length of every memory which will dump */
2053 for (idx = 0; idx < dump_num; idx++) {
2054 struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
2055
2056 stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag);
2057 if (stat == RDWR_STATUS_FAILURE)
2058 goto done;
2059
2060 memory_size = 0;
2061 reg = card->reg->fw_dump_start;
2062 for (i = 0; i < 4; i++) {
2063 read_reg = sdio_readb(card->func, reg, &ret);
2064 if (ret) {
2065 dev_err(adapter->dev, "SDIO read err\n");
2066 goto done;
2067 }
2068 memory_size |= (read_reg << i*8);
2069 reg++;
2070 }
2071
2072 if (memory_size == 0) {
2073 dev_info(adapter->dev, "Firmware dump Finished!\n");
2074 break;
2075 }
2076
2077 dev_info(adapter->dev,
2078 "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
2079 entry->mem_ptr = vmalloc(memory_size + 1);
2080 entry->mem_size = memory_size;
2081 if (!entry->mem_ptr) {
2082 dev_err(adapter->dev, "Vmalloc %s failed\n",
2083 entry->mem_name);
2084 goto done;
2085 }
2086 dbg_ptr = entry->mem_ptr;
2087 end_ptr = dbg_ptr + memory_size;
2088
2089 doneflag = entry->done_flag;
2090 do_gettimeofday(&t);
2091 dev_info(adapter->dev, "Start %s output %u.%06u, please wait...\n",
2092 entry->mem_name, (u32)t.tv_sec, (u32)t.tv_usec);
2093
2094 do {
2095 stat = mwifiex_sdio_rdwr_firmware(adapter, doneflag);
2096 if (stat == RDWR_STATUS_FAILURE)
2097 goto done;
2098
2099 reg_start = card->reg->fw_dump_start;
2100 reg_end = card->reg->fw_dump_end;
2101 for (reg = reg_start; reg <= reg_end; reg++) {
2102 *dbg_ptr = sdio_readb(card->func, reg, &ret);
2103 if (ret) {
2104 dev_err(adapter->dev,
2105 "SDIO read err\n");
2106 goto done;
2107 }
2108 if (dbg_ptr < end_ptr)
2109 dbg_ptr++;
2110 else
2111 dev_err(adapter->dev,
2112 "Allocated buf not enough\n");
2113 }
2114
2115 if (stat != RDWR_STATUS_DONE)
2116 continue;
2117
2118 dev_info(adapter->dev, "%s done: size=0x%tx\n",
2119 entry->mem_name, dbg_ptr - entry->mem_ptr);
2120 break;
2121 } while (1);
2122 }
2123 do_gettimeofday(&t);
2124 dev_info(adapter->dev, "== mwifiex firmware dump end: %u.%06u ==\n",
2125 (u32)t.tv_sec, (u32)t.tv_usec);
2126
2127 kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env);
2128
2129done:
2130 sdio_release_host(card->func);
2131 adapter->curr_mem_idx = 0;
2132}
2133
1939static void mwifiex_sdio_work(struct work_struct *work) 2134static void mwifiex_sdio_work(struct work_struct *work)
1940{ 2135{
1941 struct mwifiex_adapter *adapter = 2136 struct mwifiex_adapter *adapter =
@@ -1944,6 +2139,9 @@ static void mwifiex_sdio_work(struct work_struct *work)
1944 if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, 2139 if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET,
1945 &adapter->iface_work_flags)) 2140 &adapter->iface_work_flags))
1946 mwifiex_sdio_card_reset_work(adapter); 2141 mwifiex_sdio_card_reset_work(adapter);
2142 if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP,
2143 &adapter->iface_work_flags))
2144 mwifiex_sdio_fw_dump_work(work);
1947} 2145}
1948 2146
1949/* This function resets the card */ 2147/* This function resets the card */
@@ -1957,6 +2155,16 @@ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter)
1957 schedule_work(&adapter->iface_work); 2155 schedule_work(&adapter->iface_work);
1958} 2156}
1959 2157
2158/* This function dumps FW information */
2159static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter)
2160{
2161 if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags))
2162 return;
2163
2164 set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags);
2165 schedule_work(&adapter->iface_work);
2166}
2167
1960static struct mwifiex_if_ops sdio_ops = { 2168static struct mwifiex_if_ops sdio_ops = {
1961 .init_if = mwifiex_init_sdio, 2169 .init_if = mwifiex_init_sdio,
1962 .cleanup_if = mwifiex_cleanup_sdio, 2170 .cleanup_if = mwifiex_cleanup_sdio,
@@ -1978,6 +2186,7 @@ static struct mwifiex_if_ops sdio_ops = {
1978 .event_complete = mwifiex_sdio_event_complete, 2186 .event_complete = mwifiex_sdio_event_complete,
1979 .card_reset = mwifiex_sdio_card_reset, 2187 .card_reset = mwifiex_sdio_card_reset,
1980 .iface_work = mwifiex_sdio_work, 2188 .iface_work = mwifiex_sdio_work,
2189 .fw_dump = mwifiex_sdio_fw_dump,
1981}; 2190};
1982 2191
1983/* 2192/*
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
index 6eea30b43ed7..e5633095984e 100644
--- a/drivers/net/wireless/mwifiex/sdio.h
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -219,6 +219,9 @@ struct mwifiex_sdio_card_reg {
219 u8 rd_len_p0_l; 219 u8 rd_len_p0_l;
220 u8 rd_len_p0_u; 220 u8 rd_len_p0_u;
221 u8 card_misc_cfg_reg; 221 u8 card_misc_cfg_reg;
222 u8 fw_dump_ctrl;
223 u8 fw_dump_start;
224 u8 fw_dump_end;
222}; 225};
223 226
224struct sdio_mmc_card { 227struct sdio_mmc_card {
@@ -231,6 +234,7 @@ struct sdio_mmc_card {
231 u8 mp_agg_pkt_limit; 234 u8 mp_agg_pkt_limit;
232 bool supports_sdio_new_mode; 235 bool supports_sdio_new_mode;
233 bool has_control_mask; 236 bool has_control_mask;
237 bool supports_fw_dump;
234 u16 tx_buf_size; 238 u16 tx_buf_size;
235 u32 mp_tx_agg_buf_size; 239 u32 mp_tx_agg_buf_size;
236 u32 mp_rx_agg_buf_size; 240 u32 mp_rx_agg_buf_size;
@@ -257,6 +261,7 @@ struct mwifiex_sdio_device {
257 u8 mp_agg_pkt_limit; 261 u8 mp_agg_pkt_limit;
258 bool supports_sdio_new_mode; 262 bool supports_sdio_new_mode;
259 bool has_control_mask; 263 bool has_control_mask;
264 bool supports_fw_dump;
260 u16 tx_buf_size; 265 u16 tx_buf_size;
261 u32 mp_tx_agg_buf_size; 266 u32 mp_tx_agg_buf_size;
262 u32 mp_rx_agg_buf_size; 267 u32 mp_rx_agg_buf_size;
@@ -307,6 +312,9 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = {
307 .rd_len_p0_l = 0x0c, 312 .rd_len_p0_l = 0x0c,
308 .rd_len_p0_u = 0x0d, 313 .rd_len_p0_u = 0x0d,
309 .card_misc_cfg_reg = 0xcc, 314 .card_misc_cfg_reg = 0xcc,
315 .fw_dump_ctrl = 0xe2,
316 .fw_dump_start = 0xe3,
317 .fw_dump_end = 0xea,
310}; 318};
311 319
312static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { 320static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
@@ -319,6 +327,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
319 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, 327 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
320 .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 328 .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
321 .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 329 .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
330 .supports_fw_dump = false,
322}; 331};
323 332
324static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { 333static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
@@ -331,6 +340,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
331 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, 340 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
332 .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 341 .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
333 .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 342 .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
343 .supports_fw_dump = false,
334}; 344};
335 345
336static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { 346static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
@@ -343,6 +353,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
343 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, 353 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
344 .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 354 .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
345 .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K, 355 .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
356 .supports_fw_dump = false,
346}; 357};
347 358
348static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { 359static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
@@ -355,6 +366,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
355 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, 366 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
356 .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, 367 .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K,
357 .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, 368 .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K,
369 .supports_fw_dump = true,
358}; 370};
359 371
360/* 372/*