1
1
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2
2
/*
3
- * Copyright(c) 2020-2022 Intel Corporation
3
+ * Copyright(c) 2020-2023 Intel Corporation
4
4
*/
5
5
6
6
#include "iwl-drv.h"
@@ -31,17 +31,18 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait,
31
31
}
32
32
33
33
static int iwl_pnvm_handle_section (struct iwl_trans * trans , const u8 * data ,
34
- size_t len )
34
+ size_t len ,
35
+ struct iwl_pnvm_image * pnvm_data )
35
36
{
36
37
const struct iwl_ucode_tlv * tlv ;
37
38
u32 sha1 = 0 ;
38
39
u16 mac_type = 0 , rf_id = 0 ;
39
- struct iwl_pnvm_image pnvm_data = {};
40
40
bool hw_match = false;
41
- int ret ;
42
41
43
42
IWL_DEBUG_FW (trans , "Handling PNVM section\n" );
44
43
44
+ memset (pnvm_data , 0 , sizeof (* pnvm_data ));
45
+
45
46
while (len >= sizeof (* tlv )) {
46
47
u32 tlv_len , tlv_type ;
47
48
@@ -73,6 +74,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
73
74
IWL_DEBUG_FW (trans ,
74
75
"Got IWL_UCODE_TLV_PNVM_VERSION %0x\n" ,
75
76
sha1 );
77
+ pnvm_data -> version = sha1 ;
76
78
break ;
77
79
case IWL_UCODE_TLV_HW_TYPE :
78
80
if (tlv_len < 2 * sizeof (__le16 )) {
@@ -110,7 +112,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
110
112
break ;
111
113
}
112
114
113
- if (pnvm_data . n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX ) {
115
+ if (pnvm_data -> n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX ) {
114
116
IWL_DEBUG_FW (trans ,
115
117
"too many payloads to allocate in DRAM.\n" );
116
118
return - EINVAL ;
@@ -119,9 +121,9 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
119
121
IWL_DEBUG_FW (trans , "Adding data (size %d)\n" ,
120
122
data_len );
121
123
122
- pnvm_data . chunks [pnvm_data . n_chunks ].data = section -> data ;
123
- pnvm_data . chunks [pnvm_data . n_chunks ].len = data_len ;
124
- pnvm_data . n_chunks ++ ;
124
+ pnvm_data -> chunks [pnvm_data -> n_chunks ].data = section -> data ;
125
+ pnvm_data -> chunks [pnvm_data -> n_chunks ].len = data_len ;
126
+ pnvm_data -> n_chunks ++ ;
125
127
126
128
break ;
127
129
}
@@ -148,23 +150,17 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
148
150
return - ENOENT ;
149
151
}
150
152
151
- if (!pnvm_data . n_chunks ) {
153
+ if (!pnvm_data -> n_chunks ) {
152
154
IWL_DEBUG_FW (trans , "Empty PNVM, skipping.\n" );
153
155
return - ENOENT ;
154
156
}
155
157
156
- ret = iwl_trans_load_pnvm (trans , & pnvm_data );
157
- if (ret )
158
- return ret ;
159
-
160
- IWL_INFO (trans , "loaded PNVM version %08x\n" , sha1 );
161
-
162
- iwl_trans_set_pnvm (trans );
163
158
return 0 ;
164
159
}
165
160
166
161
static int iwl_pnvm_parse (struct iwl_trans * trans , const u8 * data ,
167
- size_t len )
162
+ size_t len ,
163
+ struct iwl_pnvm_image * pnvm_data )
168
164
{
169
165
const struct iwl_ucode_tlv * tlv ;
170
166
@@ -205,7 +201,8 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data,
205
201
trans -> sku_id [2 ] == le32_to_cpu (sku_id -> data [2 ])) {
206
202
int ret ;
207
203
208
- ret = iwl_pnvm_handle_section (trans , data , len );
204
+ ret = iwl_pnvm_handle_section (trans , data , len ,
205
+ pnvm_data );
209
206
if (!ret )
210
207
return 0 ;
211
208
} else {
@@ -248,70 +245,81 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len)
248
245
return 0 ;
249
246
}
250
247
248
+ static u8 * iwl_get_pnvm_image (struct iwl_trans * trans_p , size_t * len )
249
+ {
250
+ struct pnvm_sku_package * package ;
251
+ u8 * image = NULL ;
252
+
253
+ /* First attempt to get the PNVM from BIOS */
254
+ package = iwl_uefi_get_pnvm (trans_p , len );
255
+ if (!IS_ERR_OR_NULL (package )) {
256
+ if (* len >= sizeof (* package )) {
257
+ /* we need only the data */
258
+ * len -= sizeof (* package );
259
+ image = kmemdup (package -> data , * len , GFP_KERNEL );
260
+ }
261
+ /* free package regardless of whether kmemdup succeeded */
262
+ kfree (package );
263
+ if (image )
264
+ return image ;
265
+ }
266
+
267
+ /* If it's not available, try from the filesystem */
268
+ if (iwl_pnvm_get_from_fs (trans_p , & image , len ))
269
+ return NULL ;
270
+ return image ;
271
+ }
272
+
251
273
int iwl_pnvm_load (struct iwl_trans * trans ,
252
274
struct iwl_notif_wait_data * notif_wait )
253
275
{
254
276
u8 * data ;
255
- size_t len ;
256
- struct pnvm_sku_package * package ;
277
+ size_t length ;
257
278
struct iwl_notification_wait pnvm_wait ;
258
279
static const u16 ntf_cmds [] = { WIDE_ID (REGULATORY_AND_NVM_GROUP ,
259
280
PNVM_INIT_COMPLETE_NTFY ) };
281
+ struct iwl_pnvm_image pnvm_data ;
260
282
int ret ;
261
283
262
284
/* if the SKU_ID is empty, there's nothing to do */
263
285
if (!trans -> sku_id [0 ] && !trans -> sku_id [1 ] && !trans -> sku_id [2 ])
264
286
return 0 ;
265
287
266
- /*
267
- * If we already loaded (or tried to load) it before, we just
268
- * need to set it again.
269
- */
270
- if (trans -> pnvm_loaded ) {
271
- iwl_trans_set_pnvm (trans );
272
- goto skip_parse ;
273
- }
288
+ /* failed to get/parse the image in the past, no use to try again */
289
+ if (trans -> fail_to_parse_pnvm_image )
290
+ goto reduce_tables ;
274
291
275
- /* First attempt to get the PNVM from BIOS */
276
- package = iwl_uefi_get_pnvm (trans , & len );
277
- if (!IS_ERR_OR_NULL (package )) {
278
- if (len >= sizeof (* package )) {
279
- /* we need only the data */
280
- len -= sizeof (* package );
281
- data = kmemdup (package -> data , len , GFP_KERNEL );
282
- } else {
283
- data = NULL ;
292
+ /* get the image, parse and load it, if not loaded yet */
293
+ if (!trans -> pnvm_loaded ) {
294
+ data = iwl_get_pnvm_image (trans , & length );
295
+ if (!data ) {
296
+ trans -> fail_to_parse_pnvm_image = true;
297
+ goto reduce_tables ;
298
+ }
299
+ ret = iwl_pnvm_parse (trans , data , length , & pnvm_data );
300
+ if (ret ) {
301
+ trans -> fail_to_parse_pnvm_image = true;
302
+ kfree (data );
303
+ goto reduce_tables ;
284
304
}
285
305
286
- /* free package regardless of whether kmemdup succeeded */
287
- kfree (package );
288
-
289
- if (data )
290
- goto parse ;
291
- }
292
-
293
- /* If it's not available, try from the filesystem */
294
- ret = iwl_pnvm_get_from_fs (trans , & data , & len );
295
- if (ret ) {
296
- /*
297
- * Pretend we've loaded it - at least we've tried and
298
- * couldn't load it at all, so there's no point in
299
- * trying again over and over.
306
+ ret = iwl_trans_load_pnvm (trans , & pnvm_data );
307
+ /* can only free data after pvnm_data use, but
308
+ * pnvm_data.version used below is not a pointer
300
309
*/
301
- trans -> pnvm_loaded = true;
302
-
303
- goto skip_parse ;
310
+ kfree (data );
311
+ if (ret )
312
+ goto reduce_tables ;
313
+ IWL_INFO (trans , "loaded PNVM version %08x\n" ,
314
+ pnvm_data .version );
304
315
}
305
316
306
- parse :
307
- iwl_pnvm_parse (trans , data , len );
308
-
309
- kfree (data );
317
+ iwl_trans_set_pnvm (trans );
310
318
311
- skip_parse :
319
+ reduce_tables :
312
320
/* now try to get the reduce power table, if not loaded yet */
313
321
if (!trans -> reduce_power_loaded ) {
314
- data = iwl_uefi_get_reduced_power (trans , & len );
322
+ data = iwl_uefi_get_reduced_power (trans , & length );
315
323
if (IS_ERR_OR_NULL (data )) {
316
324
/*
317
325
* Pretend we've loaded it - at least we've tried and
@@ -320,7 +328,7 @@ int iwl_pnvm_load(struct iwl_trans *trans,
320
328
*/
321
329
trans -> reduce_power_loaded = true;
322
330
} else {
323
- ret = iwl_trans_set_reduce_power (trans , data , len );
331
+ ret = iwl_trans_set_reduce_power (trans , data , length );
324
332
if (ret )
325
333
IWL_DEBUG_FW (trans ,
326
334
"Failed to set reduce power table %d\n" ,
0 commit comments