19
19
#include <linux/i2c.h>
20
20
#include <linux/mtd/mtd.h>
21
21
#include <linux/nvmem-consumer.h>
22
+ #include <linux/crc16.h>
22
23
23
24
#define PCI_VENDOR_ID_FACEBOOK 0x1d9b
24
25
#define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400
@@ -213,6 +214,17 @@ struct ptp_ocp_flash_info {
213
214
void * data ;
214
215
};
215
216
217
+ struct ptp_ocp_firmware_header {
218
+ char magic [4 ];
219
+ __be16 pci_vendor_id ;
220
+ __be16 pci_device_id ;
221
+ __be32 image_size ;
222
+ __be16 hw_revision ;
223
+ __be16 crc ;
224
+ };
225
+
226
+ #define OCP_FIRMWARE_MAGIC_HEADER "OCPC"
227
+
216
228
struct ptp_ocp_i2c_info {
217
229
const char * name ;
218
230
unsigned long fixed_rate ;
@@ -1323,25 +1335,81 @@ ptp_ocp_find_flash(struct ptp_ocp *bp)
1323
1335
return dev ;
1324
1336
}
1325
1337
1338
+ static int
1339
+ ptp_ocp_devlink_fw_image (struct devlink * devlink , const struct firmware * fw ,
1340
+ const u8 * * data , size_t * size )
1341
+ {
1342
+ struct ptp_ocp * bp = devlink_priv (devlink );
1343
+ const struct ptp_ocp_firmware_header * hdr ;
1344
+ size_t offset , length ;
1345
+ u16 crc ;
1346
+
1347
+ hdr = (const struct ptp_ocp_firmware_header * )fw -> data ;
1348
+ if (memcmp (hdr -> magic , OCP_FIRMWARE_MAGIC_HEADER , 4 )) {
1349
+ devlink_flash_update_status_notify (devlink ,
1350
+ "No firmware header found, flashing raw image" ,
1351
+ NULL , 0 , 0 );
1352
+ offset = 0 ;
1353
+ length = fw -> size ;
1354
+ goto out ;
1355
+ }
1356
+
1357
+ if (be16_to_cpu (hdr -> pci_vendor_id ) != bp -> pdev -> vendor ||
1358
+ be16_to_cpu (hdr -> pci_device_id ) != bp -> pdev -> device ) {
1359
+ devlink_flash_update_status_notify (devlink ,
1360
+ "Firmware image compatibility check failed" ,
1361
+ NULL , 0 , 0 );
1362
+ return - EINVAL ;
1363
+ }
1364
+
1365
+ offset = sizeof (* hdr );
1366
+ length = be32_to_cpu (hdr -> image_size );
1367
+ if (length != (fw -> size - offset )) {
1368
+ devlink_flash_update_status_notify (devlink ,
1369
+ "Firmware image size check failed" ,
1370
+ NULL , 0 , 0 );
1371
+ return - EINVAL ;
1372
+ }
1373
+
1374
+ crc = crc16 (0xffff , & fw -> data [offset ], length );
1375
+ if (be16_to_cpu (hdr -> crc ) != crc ) {
1376
+ devlink_flash_update_status_notify (devlink ,
1377
+ "Firmware image CRC check failed" ,
1378
+ NULL , 0 , 0 );
1379
+ return - EINVAL ;
1380
+ }
1381
+
1382
+ out :
1383
+ * data = & fw -> data [offset ];
1384
+ * size = length ;
1385
+
1386
+ return 0 ;
1387
+ }
1388
+
1326
1389
static int
1327
1390
ptp_ocp_devlink_flash (struct devlink * devlink , struct device * dev ,
1328
1391
const struct firmware * fw )
1329
1392
{
1330
1393
struct mtd_info * mtd = dev_get_drvdata (dev );
1331
1394
struct ptp_ocp * bp = devlink_priv (devlink );
1332
- size_t off , len , resid , wrote ;
1395
+ size_t off , len , size , resid , wrote ;
1333
1396
struct erase_info erase ;
1334
1397
size_t base , blksz ;
1335
- int err = 0 ;
1398
+ const u8 * data ;
1399
+ int err ;
1400
+
1401
+ err = ptp_ocp_devlink_fw_image (devlink , fw , & data , & size );
1402
+ if (err )
1403
+ goto out ;
1336
1404
1337
1405
off = 0 ;
1338
1406
base = bp -> flash_start ;
1339
1407
blksz = 4096 ;
1340
- resid = fw -> size ;
1408
+ resid = size ;
1341
1409
1342
1410
while (resid ) {
1343
1411
devlink_flash_update_status_notify (devlink , "Flashing" ,
1344
- NULL , off , fw -> size );
1412
+ NULL , off , size );
1345
1413
1346
1414
len = min_t (size_t , resid , blksz );
1347
1415
erase .addr = base + off ;
@@ -1351,7 +1419,7 @@ ptp_ocp_devlink_flash(struct devlink *devlink, struct device *dev,
1351
1419
if (err )
1352
1420
goto out ;
1353
1421
1354
- err = mtd_write (mtd , base + off , len , & wrote , & fw -> data [ off ] );
1422
+ err = mtd_write (mtd , base + off , len , & wrote , data + off );
1355
1423
if (err )
1356
1424
goto out ;
1357
1425
0 commit comments