1919#include <linux/i2c.h>
2020#include <linux/mtd/mtd.h>
2121#include <linux/nvmem-consumer.h>
22+ #include <linux/crc16.h>
2223
2324#define PCI_VENDOR_ID_FACEBOOK 0x1d9b
2425#define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400
@@ -213,6 +214,17 @@ struct ptp_ocp_flash_info {
213214 void * data ;
214215};
215216
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+
216228struct ptp_ocp_i2c_info {
217229 const char * name ;
218230 unsigned long fixed_rate ;
@@ -1323,25 +1335,81 @@ ptp_ocp_find_flash(struct ptp_ocp *bp)
13231335 return dev ;
13241336}
13251337
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+
13261389static int
13271390ptp_ocp_devlink_flash (struct devlink * devlink , struct device * dev ,
13281391 const struct firmware * fw )
13291392{
13301393 struct mtd_info * mtd = dev_get_drvdata (dev );
13311394 struct ptp_ocp * bp = devlink_priv (devlink );
1332- size_t off , len , resid , wrote ;
1395+ size_t off , len , size , resid , wrote ;
13331396 struct erase_info erase ;
13341397 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 ;
13361404
13371405 off = 0 ;
13381406 base = bp -> flash_start ;
13391407 blksz = 4096 ;
1340- resid = fw -> size ;
1408+ resid = size ;
13411409
13421410 while (resid ) {
13431411 devlink_flash_update_status_notify (devlink , "Flashing" ,
1344- NULL , off , fw -> size );
1412+ NULL , off , size );
13451413
13461414 len = min_t (size_t , resid , blksz );
13471415 erase .addr = base + off ;
@@ -1351,7 +1419,7 @@ ptp_ocp_devlink_flash(struct devlink *devlink, struct device *dev,
13511419 if (err )
13521420 goto out ;
13531421
1354- err = mtd_write (mtd , base + off , len , & wrote , & fw -> data [ off ] );
1422+ err = mtd_write (mtd , base + off , len , & wrote , data + off );
13551423 if (err )
13561424 goto out ;
13571425
0 commit comments