iwlwifi: mvm: Change NVM default section read size
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / iwlwifi / mvm / nvm.c
1 /******************************************************************************
2  *
3  * This file is provided under a dual BSD/GPLv2 license.  When using or
4  * redistributing this file, you may do so under either license.
5  *
6  * GPL LICENSE SUMMARY
7  *
8  * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of version 2 of the GNU General Public License as
12  * published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
22  * USA
23  *
24  * The full GNU General Public License is included in this distribution
25  * in the file called COPYING.
26  *
27  * Contact Information:
28  *  Intel Linux Wireless <ilw@linux.intel.com>
29  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30  *
31  * BSD LICENSE
32  *
33  * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  *
40  *  * Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  *  * Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in
44  *    the documentation and/or other materials provided with the
45  *    distribution.
46  *  * Neither the name Intel Corporation nor the names of its
47  *    contributors may be used to endorse or promote products derived
48  *    from this software without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
54  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
56  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61  *
62  *****************************************************************************/
63 #include "iwl-trans.h"
64 #include "mvm.h"
65 #include "iwl-eeprom-parse.h"
66 #include "iwl-eeprom-read.h"
67 #include "iwl-nvm-parse.h"
68
69 /* list of NVM sections we are allowed/need to read */
70 static const int nvm_to_read[] = {
71         NVM_SECTION_TYPE_HW,
72         NVM_SECTION_TYPE_SW,
73         NVM_SECTION_TYPE_CALIBRATION,
74         NVM_SECTION_TYPE_PRODUCTION,
75 };
76
77 /* Default NVM size to read */
78 #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024);
79
80 /* used to simplify the shared operations on NCM_ACCESS_CMD versions */
81 union iwl_nvm_access_cmd {
82         struct iwl_nvm_access_cmd_ver1 ver1;
83         struct iwl_nvm_access_cmd_ver2 ver2;
84 };
85 union iwl_nvm_access_resp {
86         struct iwl_nvm_access_resp_ver1 ver1;
87         struct iwl_nvm_access_resp_ver2 ver2;
88 };
89
90 static inline void iwl_nvm_fill_read_ver1(struct iwl_nvm_access_cmd_ver1 *cmd,
91                                           u16 offset, u16 length)
92 {
93         cmd->offset = cpu_to_le16(offset);
94         cmd->length = cpu_to_le16(length);
95         cmd->cache_refresh = 1;
96 }
97
98 static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd,
99                                           u16 offset, u16 length, u16 section)
100 {
101         cmd->offset = cpu_to_le16(offset);
102         cmd->length = cpu_to_le16(length);
103         cmd->type = cpu_to_le16(section);
104 }
105
106 static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
107                               u16 offset, u16 length, u8 *data)
108 {
109         union iwl_nvm_access_cmd nvm_access_cmd;
110         union iwl_nvm_access_resp *nvm_resp;
111         struct iwl_rx_packet *pkt;
112         struct iwl_host_cmd cmd = {
113                 .id = NVM_ACCESS_CMD,
114                 .flags = CMD_SYNC | CMD_WANT_SKB,
115                 .data = { &nvm_access_cmd, },
116         };
117         int ret, bytes_read, offset_read;
118         u8 *resp_data;
119
120         memset(&nvm_access_cmd, 0, sizeof(nvm_access_cmd));
121
122         /* TODO: not sure family should be the decider, maybe FW version? */
123         if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
124                 iwl_nvm_fill_read_ver2(&(nvm_access_cmd.ver2),
125                                        offset, length, section);
126                 cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver2);
127         } else {
128                 iwl_nvm_fill_read_ver1(&(nvm_access_cmd.ver1),
129                                        offset, length);
130                 cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver1);
131         }
132
133         ret = iwl_mvm_send_cmd(mvm, &cmd);
134         if (ret)
135                 return ret;
136
137         pkt = cmd.resp_pkt;
138         if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
139                 IWL_ERR(mvm, "Bad return from NVM_ACCES_COMMAND (0x%08X)\n",
140                         pkt->hdr.flags);
141                 ret = -EIO;
142                 goto exit;
143         }
144
145         /* Extract NVM response */
146         nvm_resp = (void *)pkt->data;
147         if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
148                 ret = le16_to_cpu(nvm_resp->ver2.status);
149                 bytes_read = le16_to_cpu(nvm_resp->ver2.length);
150                 offset_read = le16_to_cpu(nvm_resp->ver2.offset);
151                 resp_data = nvm_resp->ver2.data;
152         } else {
153                 ret = le16_to_cpu(nvm_resp->ver1.length) <= 0;
154                 bytes_read = le16_to_cpu(nvm_resp->ver1.length);
155                 offset_read = le16_to_cpu(nvm_resp->ver1.offset);
156                 resp_data = nvm_resp->ver1.data;
157         }
158         if (ret) {
159                 IWL_ERR(mvm,
160                         "NVM access command failed with status %d (device: %s)\n",
161                         ret, mvm->cfg->name);
162                 ret = -EINVAL;
163                 goto exit;
164         }
165
166         if (offset_read != offset) {
167                 IWL_ERR(mvm, "NVM ACCESS response with invalid offset %d\n",
168                         offset_read);
169                 ret = -EINVAL;
170                 goto exit;
171         }
172
173         /* Write data to NVM */
174         memcpy(data + offset, resp_data, bytes_read);
175         ret = bytes_read;
176
177 exit:
178         iwl_free_resp(&cmd);
179         return ret;
180 }
181
182 /*
183  * Reads an NVM section completely.
184  * NICs prior to 7000 family doesn't have a real NVM, but just read
185  * section 0 which is the EEPROM. Because the EEPROM reading is unlimited
186  * by uCode, we need to manually check in this case that we don't
187  * overflow and try to read more than the EEPROM size.
188  * For 7000 family NICs, we supply the maximal size we can read, and
189  * the uCode fills the response with as much data as we can,
190  * without overflowing, so no check is needed.
191  */
192 static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
193                                 u8 *data)
194 {
195         u16 length, offset = 0;
196         int ret;
197         bool old_eeprom = mvm->cfg->device_family != IWL_DEVICE_FAMILY_7000;
198
199         /* Set nvm section read length */
200         length = IWL_NVM_DEFAULT_CHUNK_SIZE;
201
202         /*
203          * if length is greater than EEPROM size, truncate it because uCode
204          * doesn't check it by itself, and exit the loop when reached.
205          */
206         if (old_eeprom && length > mvm->cfg->base_params->eeprom_size)
207                 length = mvm->cfg->base_params->eeprom_size;
208         ret = length;
209
210         /* Read the NVM until exhausted (reading less than requested) */
211         while (ret == length) {
212                 ret = iwl_nvm_read_chunk(mvm, section, offset, length, data);
213                 if (ret < 0) {
214                         IWL_ERR(mvm,
215                                 "Cannot read NVM from section %d offset %d, length %d\n",
216                                 section, offset, length);
217                         return ret;
218                 }
219                 offset += ret;
220                 if (old_eeprom && offset == mvm->cfg->base_params->eeprom_size)
221                         break;
222         }
223
224         IWL_INFO(mvm, "NVM section %d read completed\n", section);
225         return offset;
226 }
227
228 static struct iwl_nvm_data *
229 iwl_parse_nvm_sections(struct iwl_mvm *mvm)
230 {
231         struct iwl_nvm_section *sections = mvm->nvm_sections;
232         const __le16 *hw, *sw, *calib;
233
234         /* Checking for required sections */
235         if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
236             !mvm->nvm_sections[NVM_SECTION_TYPE_HW].data) {
237                 IWL_ERR(mvm, "Can't parse empty NVM sections\n");
238                 return NULL;
239         }
240
241         if (WARN_ON(!mvm->cfg))
242                 return NULL;
243
244         hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data;
245         sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
246         calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data;
247         return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib);
248 }
249
250 int iwl_nvm_init(struct iwl_mvm *mvm)
251 {
252         int ret, i, section;
253         u8 *nvm_buffer, *temp;
254
255         if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
256                 /* TODO: find correct NVM max size for a section */
257                 nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
258                                      GFP_KERNEL);
259                 if (!nvm_buffer)
260                         return -ENOMEM;
261                 for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
262                         section = nvm_to_read[i];
263                         /* we override the constness for initial read */
264                         ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
265                         if (ret < 0)
266                                 break;
267                         temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
268                         if (!temp) {
269                                 ret = -ENOMEM;
270                                 break;
271                         }
272                         mvm->nvm_sections[section].data = temp;
273                         mvm->nvm_sections[section].length = ret;
274                 }
275                 kfree(nvm_buffer);
276                 if (ret < 0)
277                         return ret;
278         } else {
279                 /* allocate eeprom */
280                 mvm->eeprom_blob_size = mvm->cfg->base_params->eeprom_size;
281                 IWL_DEBUG_EEPROM(mvm->trans->dev, "NVM size = %zd\n",
282                                  mvm->eeprom_blob_size);
283                 mvm->eeprom_blob = kzalloc(mvm->eeprom_blob_size, GFP_KERNEL);
284                 if (!mvm->eeprom_blob)
285                         return -ENOMEM;
286
287                 ret = iwl_nvm_read_section(mvm, 0, mvm->eeprom_blob);
288                 if (ret != mvm->eeprom_blob_size) {
289                         IWL_ERR(mvm, "Read partial NVM %d/%zd\n",
290                                 ret, mvm->eeprom_blob_size);
291                         kfree(mvm->eeprom_blob);
292                         mvm->eeprom_blob = NULL;
293                         return -EINVAL;
294                 }
295         }
296
297         ret = 0;
298         if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
299                 mvm->nvm_data = iwl_parse_nvm_sections(mvm);
300         else
301                 mvm->nvm_data =
302                         iwl_parse_eeprom_data(mvm->trans->dev,
303                                               mvm->cfg,
304                                               mvm->eeprom_blob,
305                                               mvm->eeprom_blob_size);
306
307         if (!mvm->nvm_data) {
308                 kfree(mvm->eeprom_blob);
309                 mvm->eeprom_blob = NULL;
310                 ret = -ENOMEM;
311         }
312
313         return ret;
314 }