diff options
Diffstat (limited to 'drivers/net/ethernet/brocade/bna/bfa_ioc.c')
-rw-r--r-- | drivers/net/ethernet/brocade/bna/bfa_ioc.c | 618 |
1 files changed, 591 insertions, 27 deletions
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c index b81132a8ee79..537bba14f913 100644 --- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c +++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c | |||
@@ -22,6 +22,14 @@ | |||
22 | 22 | ||
23 | /* IOC local definitions */ | 23 | /* IOC local definitions */ |
24 | 24 | ||
25 | #define bfa_ioc_state_disabled(__sm) \ | ||
26 | (((__sm) == BFI_IOC_UNINIT) || \ | ||
27 | ((__sm) == BFI_IOC_INITING) || \ | ||
28 | ((__sm) == BFI_IOC_HWINIT) || \ | ||
29 | ((__sm) == BFI_IOC_DISABLED) || \ | ||
30 | ((__sm) == BFI_IOC_FAIL) || \ | ||
31 | ((__sm) == BFI_IOC_CFG_DISABLED)) | ||
32 | |||
25 | /* Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details. */ | 33 | /* Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details. */ |
26 | 34 | ||
27 | #define bfa_ioc_firmware_lock(__ioc) \ | 35 | #define bfa_ioc_firmware_lock(__ioc) \ |
@@ -84,8 +92,8 @@ static void bfa_ioc_pf_disabled(struct bfa_ioc *ioc); | |||
84 | static void bfa_ioc_pf_failed(struct bfa_ioc *ioc); | 92 | static void bfa_ioc_pf_failed(struct bfa_ioc *ioc); |
85 | static void bfa_ioc_pf_hwfailed(struct bfa_ioc *ioc); | 93 | static void bfa_ioc_pf_hwfailed(struct bfa_ioc *ioc); |
86 | static void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc); | 94 | static void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc); |
87 | static void bfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type, | 95 | static enum bfa_status bfa_ioc_boot(struct bfa_ioc *ioc, |
88 | u32 boot_param); | 96 | enum bfi_fwboot_type boot_type, u32 boot_param); |
89 | static u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr); | 97 | static u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr); |
90 | static void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc, | 98 | static void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc, |
91 | char *serial_num); | 99 | char *serial_num); |
@@ -1139,6 +1147,25 @@ bfa_nw_ioc_sem_release(void __iomem *sem_reg) | |||
1139 | writel(1, sem_reg); | 1147 | writel(1, sem_reg); |
1140 | } | 1148 | } |
1141 | 1149 | ||
1150 | /* Invalidate fwver signature */ | ||
1151 | enum bfa_status | ||
1152 | bfa_nw_ioc_fwsig_invalidate(struct bfa_ioc *ioc) | ||
1153 | { | ||
1154 | u32 pgnum, pgoff; | ||
1155 | u32 loff = 0; | ||
1156 | enum bfi_ioc_state ioc_fwstate; | ||
1157 | |||
1158 | ioc_fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc); | ||
1159 | if (!bfa_ioc_state_disabled(ioc_fwstate)) | ||
1160 | return BFA_STATUS_ADAPTER_ENABLED; | ||
1161 | |||
1162 | pgnum = bfa_ioc_smem_pgnum(ioc, loff); | ||
1163 | pgoff = PSS_SMEM_PGOFF(loff); | ||
1164 | writel(pgnum, ioc->ioc_regs.host_page_num_fn); | ||
1165 | writel(BFI_IOC_FW_INV_SIGN, ioc->ioc_regs.smem_page_start + loff); | ||
1166 | return BFA_STATUS_OK; | ||
1167 | } | ||
1168 | |||
1142 | /* Clear fwver hdr */ | 1169 | /* Clear fwver hdr */ |
1143 | static void | 1170 | static void |
1144 | bfa_ioc_fwver_clear(struct bfa_ioc *ioc) | 1171 | bfa_ioc_fwver_clear(struct bfa_ioc *ioc) |
@@ -1317,22 +1344,510 @@ bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr) | |||
1317 | } | 1344 | } |
1318 | } | 1345 | } |
1319 | 1346 | ||
1320 | /* Returns TRUE if same. */ | 1347 | static bool |
1348 | bfa_ioc_fwver_md5_check(struct bfi_ioc_image_hdr *fwhdr_1, | ||
1349 | struct bfi_ioc_image_hdr *fwhdr_2) | ||
1350 | { | ||
1351 | int i; | ||
1352 | |||
1353 | for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) { | ||
1354 | if (fwhdr_1->md5sum[i] != fwhdr_2->md5sum[i]) | ||
1355 | return false; | ||
1356 | } | ||
1357 | |||
1358 | return true; | ||
1359 | } | ||
1360 | |||
1361 | /* Returns TRUE if major minor and maintainence are same. | ||
1362 | * If patch version are same, check for MD5 Checksum to be same. | ||
1363 | */ | ||
1364 | static bool | ||
1365 | bfa_ioc_fw_ver_compatible(struct bfi_ioc_image_hdr *drv_fwhdr, | ||
1366 | struct bfi_ioc_image_hdr *fwhdr_to_cmp) | ||
1367 | { | ||
1368 | if (drv_fwhdr->signature != fwhdr_to_cmp->signature) | ||
1369 | return false; | ||
1370 | if (drv_fwhdr->fwver.major != fwhdr_to_cmp->fwver.major) | ||
1371 | return false; | ||
1372 | if (drv_fwhdr->fwver.minor != fwhdr_to_cmp->fwver.minor) | ||
1373 | return false; | ||
1374 | if (drv_fwhdr->fwver.maint != fwhdr_to_cmp->fwver.maint) | ||
1375 | return false; | ||
1376 | if (drv_fwhdr->fwver.patch == fwhdr_to_cmp->fwver.patch && | ||
1377 | drv_fwhdr->fwver.phase == fwhdr_to_cmp->fwver.phase && | ||
1378 | drv_fwhdr->fwver.build == fwhdr_to_cmp->fwver.build) | ||
1379 | return bfa_ioc_fwver_md5_check(drv_fwhdr, fwhdr_to_cmp); | ||
1380 | |||
1381 | return true; | ||
1382 | } | ||
1383 | |||
1384 | static bool | ||
1385 | bfa_ioc_flash_fwver_valid(struct bfi_ioc_image_hdr *flash_fwhdr) | ||
1386 | { | ||
1387 | if (flash_fwhdr->fwver.major == 0 || flash_fwhdr->fwver.major == 0xFF) | ||
1388 | return false; | ||
1389 | |||
1390 | return true; | ||
1391 | } | ||
1392 | |||
1393 | static bool | ||
1394 | fwhdr_is_ga(struct bfi_ioc_image_hdr *fwhdr) | ||
1395 | { | ||
1396 | if (fwhdr->fwver.phase == 0 && | ||
1397 | fwhdr->fwver.build == 0) | ||
1398 | return false; | ||
1399 | |||
1400 | return true; | ||
1401 | } | ||
1402 | |||
1403 | /* Returns TRUE if both are compatible and patch of fwhdr_to_cmp is better. */ | ||
1404 | static enum bfi_ioc_img_ver_cmp | ||
1405 | bfa_ioc_fw_ver_patch_cmp(struct bfi_ioc_image_hdr *base_fwhdr, | ||
1406 | struct bfi_ioc_image_hdr *fwhdr_to_cmp) | ||
1407 | { | ||
1408 | if (bfa_ioc_fw_ver_compatible(base_fwhdr, fwhdr_to_cmp) == false) | ||
1409 | return BFI_IOC_IMG_VER_INCOMP; | ||
1410 | |||
1411 | if (fwhdr_to_cmp->fwver.patch > base_fwhdr->fwver.patch) | ||
1412 | return BFI_IOC_IMG_VER_BETTER; | ||
1413 | else if (fwhdr_to_cmp->fwver.patch < base_fwhdr->fwver.patch) | ||
1414 | return BFI_IOC_IMG_VER_OLD; | ||
1415 | |||
1416 | /* GA takes priority over internal builds of the same patch stream. | ||
1417 | * At this point major minor maint and patch numbers are same. | ||
1418 | */ | ||
1419 | if (fwhdr_is_ga(base_fwhdr) == true) | ||
1420 | if (fwhdr_is_ga(fwhdr_to_cmp)) | ||
1421 | return BFI_IOC_IMG_VER_SAME; | ||
1422 | else | ||
1423 | return BFI_IOC_IMG_VER_OLD; | ||
1424 | else | ||
1425 | if (fwhdr_is_ga(fwhdr_to_cmp)) | ||
1426 | return BFI_IOC_IMG_VER_BETTER; | ||
1427 | |||
1428 | if (fwhdr_to_cmp->fwver.phase > base_fwhdr->fwver.phase) | ||
1429 | return BFI_IOC_IMG_VER_BETTER; | ||
1430 | else if (fwhdr_to_cmp->fwver.phase < base_fwhdr->fwver.phase) | ||
1431 | return BFI_IOC_IMG_VER_OLD; | ||
1432 | |||
1433 | if (fwhdr_to_cmp->fwver.build > base_fwhdr->fwver.build) | ||
1434 | return BFI_IOC_IMG_VER_BETTER; | ||
1435 | else if (fwhdr_to_cmp->fwver.build < base_fwhdr->fwver.build) | ||
1436 | return BFI_IOC_IMG_VER_OLD; | ||
1437 | |||
1438 | /* All Version Numbers are equal. | ||
1439 | * Md5 check to be done as a part of compatibility check. | ||
1440 | */ | ||
1441 | return BFI_IOC_IMG_VER_SAME; | ||
1442 | } | ||
1443 | |||
1444 | /* register definitions */ | ||
1445 | #define FLI_CMD_REG 0x0001d000 | ||
1446 | #define FLI_WRDATA_REG 0x0001d00c | ||
1447 | #define FLI_RDDATA_REG 0x0001d010 | ||
1448 | #define FLI_ADDR_REG 0x0001d004 | ||
1449 | #define FLI_DEV_STATUS_REG 0x0001d014 | ||
1450 | |||
1451 | #define BFA_FLASH_FIFO_SIZE 128 /* fifo size */ | ||
1452 | #define BFA_FLASH_CHECK_MAX 10000 /* max # of status check */ | ||
1453 | #define BFA_FLASH_BLOCKING_OP_MAX 1000000 /* max # of blocking op check */ | ||
1454 | #define BFA_FLASH_WIP_MASK 0x01 /* write in progress bit mask */ | ||
1455 | |||
1456 | #define NFC_STATE_RUNNING 0x20000001 | ||
1457 | #define NFC_STATE_PAUSED 0x00004560 | ||
1458 | #define NFC_VER_VALID 0x147 | ||
1459 | |||
1460 | enum bfa_flash_cmd { | ||
1461 | BFA_FLASH_FAST_READ = 0x0b, /* fast read */ | ||
1462 | BFA_FLASH_WRITE_ENABLE = 0x06, /* write enable */ | ||
1463 | BFA_FLASH_SECTOR_ERASE = 0xd8, /* sector erase */ | ||
1464 | BFA_FLASH_WRITE = 0x02, /* write */ | ||
1465 | BFA_FLASH_READ_STATUS = 0x05, /* read status */ | ||
1466 | }; | ||
1467 | |||
1468 | /* hardware error definition */ | ||
1469 | enum bfa_flash_err { | ||
1470 | BFA_FLASH_NOT_PRESENT = -1, /*!< flash not present */ | ||
1471 | BFA_FLASH_UNINIT = -2, /*!< flash not initialized */ | ||
1472 | BFA_FLASH_BAD = -3, /*!< flash bad */ | ||
1473 | BFA_FLASH_BUSY = -4, /*!< flash busy */ | ||
1474 | BFA_FLASH_ERR_CMD_ACT = -5, /*!< command active never cleared */ | ||
1475 | BFA_FLASH_ERR_FIFO_CNT = -6, /*!< fifo count never cleared */ | ||
1476 | BFA_FLASH_ERR_WIP = -7, /*!< write-in-progress never cleared */ | ||
1477 | BFA_FLASH_ERR_TIMEOUT = -8, /*!< fli timeout */ | ||
1478 | BFA_FLASH_ERR_LEN = -9, /*!< invalid length */ | ||
1479 | }; | ||
1480 | |||
1481 | /* flash command register data structure */ | ||
1482 | union bfa_flash_cmd_reg { | ||
1483 | struct { | ||
1484 | #ifdef __BIG_ENDIAN | ||
1485 | u32 act:1; | ||
1486 | u32 rsv:1; | ||
1487 | u32 write_cnt:9; | ||
1488 | u32 read_cnt:9; | ||
1489 | u32 addr_cnt:4; | ||
1490 | u32 cmd:8; | ||
1491 | #else | ||
1492 | u32 cmd:8; | ||
1493 | u32 addr_cnt:4; | ||
1494 | u32 read_cnt:9; | ||
1495 | u32 write_cnt:9; | ||
1496 | u32 rsv:1; | ||
1497 | u32 act:1; | ||
1498 | #endif | ||
1499 | } r; | ||
1500 | u32 i; | ||
1501 | }; | ||
1502 | |||
1503 | /* flash device status register data structure */ | ||
1504 | union bfa_flash_dev_status_reg { | ||
1505 | struct { | ||
1506 | #ifdef __BIG_ENDIAN | ||
1507 | u32 rsv:21; | ||
1508 | u32 fifo_cnt:6; | ||
1509 | u32 busy:1; | ||
1510 | u32 init_status:1; | ||
1511 | u32 present:1; | ||
1512 | u32 bad:1; | ||
1513 | u32 good:1; | ||
1514 | #else | ||
1515 | u32 good:1; | ||
1516 | u32 bad:1; | ||
1517 | u32 present:1; | ||
1518 | u32 init_status:1; | ||
1519 | u32 busy:1; | ||
1520 | u32 fifo_cnt:6; | ||
1521 | u32 rsv:21; | ||
1522 | #endif | ||
1523 | } r; | ||
1524 | u32 i; | ||
1525 | }; | ||
1526 | |||
1527 | /* flash address register data structure */ | ||
1528 | union bfa_flash_addr_reg { | ||
1529 | struct { | ||
1530 | #ifdef __BIG_ENDIAN | ||
1531 | u32 addr:24; | ||
1532 | u32 dummy:8; | ||
1533 | #else | ||
1534 | u32 dummy:8; | ||
1535 | u32 addr:24; | ||
1536 | #endif | ||
1537 | } r; | ||
1538 | u32 i; | ||
1539 | }; | ||
1540 | |||
1541 | /* Flash raw private functions */ | ||
1542 | static void | ||
1543 | bfa_flash_set_cmd(void __iomem *pci_bar, u8 wr_cnt, | ||
1544 | u8 rd_cnt, u8 ad_cnt, u8 op) | ||
1545 | { | ||
1546 | union bfa_flash_cmd_reg cmd; | ||
1547 | |||
1548 | cmd.i = 0; | ||
1549 | cmd.r.act = 1; | ||
1550 | cmd.r.write_cnt = wr_cnt; | ||
1551 | cmd.r.read_cnt = rd_cnt; | ||
1552 | cmd.r.addr_cnt = ad_cnt; | ||
1553 | cmd.r.cmd = op; | ||
1554 | writel(cmd.i, (pci_bar + FLI_CMD_REG)); | ||
1555 | } | ||
1556 | |||
1557 | static void | ||
1558 | bfa_flash_set_addr(void __iomem *pci_bar, u32 address) | ||
1559 | { | ||
1560 | union bfa_flash_addr_reg addr; | ||
1561 | |||
1562 | addr.r.addr = address & 0x00ffffff; | ||
1563 | addr.r.dummy = 0; | ||
1564 | writel(addr.i, (pci_bar + FLI_ADDR_REG)); | ||
1565 | } | ||
1566 | |||
1567 | static int | ||
1568 | bfa_flash_cmd_act_check(void __iomem *pci_bar) | ||
1569 | { | ||
1570 | union bfa_flash_cmd_reg cmd; | ||
1571 | |||
1572 | cmd.i = readl(pci_bar + FLI_CMD_REG); | ||
1573 | |||
1574 | if (cmd.r.act) | ||
1575 | return BFA_FLASH_ERR_CMD_ACT; | ||
1576 | |||
1577 | return 0; | ||
1578 | } | ||
1579 | |||
1580 | /* Flush FLI data fifo. */ | ||
1581 | static u32 | ||
1582 | bfa_flash_fifo_flush(void __iomem *pci_bar) | ||
1583 | { | ||
1584 | u32 i; | ||
1585 | u32 t; | ||
1586 | union bfa_flash_dev_status_reg dev_status; | ||
1587 | |||
1588 | dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG); | ||
1589 | |||
1590 | if (!dev_status.r.fifo_cnt) | ||
1591 | return 0; | ||
1592 | |||
1593 | /* fifo counter in terms of words */ | ||
1594 | for (i = 0; i < dev_status.r.fifo_cnt; i++) | ||
1595 | t = readl(pci_bar + FLI_RDDATA_REG); | ||
1596 | |||
1597 | /* Check the device status. It may take some time. */ | ||
1598 | for (i = 0; i < BFA_FLASH_CHECK_MAX; i++) { | ||
1599 | dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG); | ||
1600 | if (!dev_status.r.fifo_cnt) | ||
1601 | break; | ||
1602 | } | ||
1603 | |||
1604 | if (dev_status.r.fifo_cnt) | ||
1605 | return BFA_FLASH_ERR_FIFO_CNT; | ||
1606 | |||
1607 | return 0; | ||
1608 | } | ||
1609 | |||
1610 | /* Read flash status. */ | ||
1611 | static u32 | ||
1612 | bfa_flash_status_read(void __iomem *pci_bar) | ||
1613 | { | ||
1614 | union bfa_flash_dev_status_reg dev_status; | ||
1615 | u32 status; | ||
1616 | u32 ret_status; | ||
1617 | int i; | ||
1618 | |||
1619 | status = bfa_flash_fifo_flush(pci_bar); | ||
1620 | if (status < 0) | ||
1621 | return status; | ||
1622 | |||
1623 | bfa_flash_set_cmd(pci_bar, 0, 4, 0, BFA_FLASH_READ_STATUS); | ||
1624 | |||
1625 | for (i = 0; i < BFA_FLASH_CHECK_MAX; i++) { | ||
1626 | status = bfa_flash_cmd_act_check(pci_bar); | ||
1627 | if (!status) | ||
1628 | break; | ||
1629 | } | ||
1630 | |||
1631 | if (status) | ||
1632 | return status; | ||
1633 | |||
1634 | dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG); | ||
1635 | if (!dev_status.r.fifo_cnt) | ||
1636 | return BFA_FLASH_BUSY; | ||
1637 | |||
1638 | ret_status = readl(pci_bar + FLI_RDDATA_REG); | ||
1639 | ret_status >>= 24; | ||
1640 | |||
1641 | status = bfa_flash_fifo_flush(pci_bar); | ||
1642 | if (status < 0) | ||
1643 | return status; | ||
1644 | |||
1645 | return ret_status; | ||
1646 | } | ||
1647 | |||
1648 | /* Start flash read operation. */ | ||
1649 | static u32 | ||
1650 | bfa_flash_read_start(void __iomem *pci_bar, u32 offset, u32 len, | ||
1651 | char *buf) | ||
1652 | { | ||
1653 | u32 status; | ||
1654 | |||
1655 | /* len must be mutiple of 4 and not exceeding fifo size */ | ||
1656 | if (len == 0 || len > BFA_FLASH_FIFO_SIZE || (len & 0x03) != 0) | ||
1657 | return BFA_FLASH_ERR_LEN; | ||
1658 | |||
1659 | /* check status */ | ||
1660 | status = bfa_flash_status_read(pci_bar); | ||
1661 | if (status == BFA_FLASH_BUSY) | ||
1662 | status = bfa_flash_status_read(pci_bar); | ||
1663 | |||
1664 | if (status < 0) | ||
1665 | return status; | ||
1666 | |||
1667 | /* check if write-in-progress bit is cleared */ | ||
1668 | if (status & BFA_FLASH_WIP_MASK) | ||
1669 | return BFA_FLASH_ERR_WIP; | ||
1670 | |||
1671 | bfa_flash_set_addr(pci_bar, offset); | ||
1672 | |||
1673 | bfa_flash_set_cmd(pci_bar, 0, (u8)len, 4, BFA_FLASH_FAST_READ); | ||
1674 | |||
1675 | return 0; | ||
1676 | } | ||
1677 | |||
1678 | /* Check flash read operation. */ | ||
1679 | static u32 | ||
1680 | bfa_flash_read_check(void __iomem *pci_bar) | ||
1681 | { | ||
1682 | if (bfa_flash_cmd_act_check(pci_bar)) | ||
1683 | return 1; | ||
1684 | |||
1685 | return 0; | ||
1686 | } | ||
1687 | |||
1688 | /* End flash read operation. */ | ||
1689 | static void | ||
1690 | bfa_flash_read_end(void __iomem *pci_bar, u32 len, char *buf) | ||
1691 | { | ||
1692 | u32 i; | ||
1693 | |||
1694 | /* read data fifo up to 32 words */ | ||
1695 | for (i = 0; i < len; i += 4) { | ||
1696 | u32 w = readl(pci_bar + FLI_RDDATA_REG); | ||
1697 | *((u32 *)(buf + i)) = swab32(w); | ||
1698 | } | ||
1699 | |||
1700 | bfa_flash_fifo_flush(pci_bar); | ||
1701 | } | ||
1702 | |||
1703 | /* Perform flash raw read. */ | ||
1704 | |||
1705 | #define FLASH_BLOCKING_OP_MAX 500 | ||
1706 | #define FLASH_SEM_LOCK_REG 0x18820 | ||
1707 | |||
1708 | static int | ||
1709 | bfa_raw_sem_get(void __iomem *bar) | ||
1710 | { | ||
1711 | int locked; | ||
1712 | |||
1713 | locked = readl((bar + FLASH_SEM_LOCK_REG)); | ||
1714 | |||
1715 | return !locked; | ||
1716 | } | ||
1717 | |||
1718 | static enum bfa_status | ||
1719 | bfa_flash_sem_get(void __iomem *bar) | ||
1720 | { | ||
1721 | u32 n = FLASH_BLOCKING_OP_MAX; | ||
1722 | |||
1723 | while (!bfa_raw_sem_get(bar)) { | ||
1724 | if (--n <= 0) | ||
1725 | return BFA_STATUS_BADFLASH; | ||
1726 | udelay(10000); | ||
1727 | } | ||
1728 | return BFA_STATUS_OK; | ||
1729 | } | ||
1730 | |||
1731 | static void | ||
1732 | bfa_flash_sem_put(void __iomem *bar) | ||
1733 | { | ||
1734 | writel(0, (bar + FLASH_SEM_LOCK_REG)); | ||
1735 | } | ||
1736 | |||
1737 | static enum bfa_status | ||
1738 | bfa_flash_raw_read(void __iomem *pci_bar, u32 offset, char *buf, | ||
1739 | u32 len) | ||
1740 | { | ||
1741 | u32 n, status; | ||
1742 | u32 off, l, s, residue, fifo_sz; | ||
1743 | |||
1744 | residue = len; | ||
1745 | off = 0; | ||
1746 | fifo_sz = BFA_FLASH_FIFO_SIZE; | ||
1747 | status = bfa_flash_sem_get(pci_bar); | ||
1748 | if (status != BFA_STATUS_OK) | ||
1749 | return status; | ||
1750 | |||
1751 | while (residue) { | ||
1752 | s = offset + off; | ||
1753 | n = s / fifo_sz; | ||
1754 | l = (n + 1) * fifo_sz - s; | ||
1755 | if (l > residue) | ||
1756 | l = residue; | ||
1757 | |||
1758 | status = bfa_flash_read_start(pci_bar, offset + off, l, | ||
1759 | &buf[off]); | ||
1760 | if (status < 0) { | ||
1761 | bfa_flash_sem_put(pci_bar); | ||
1762 | return BFA_STATUS_FAILED; | ||
1763 | } | ||
1764 | |||
1765 | n = BFA_FLASH_BLOCKING_OP_MAX; | ||
1766 | while (bfa_flash_read_check(pci_bar)) { | ||
1767 | if (--n <= 0) { | ||
1768 | bfa_flash_sem_put(pci_bar); | ||
1769 | return BFA_STATUS_FAILED; | ||
1770 | } | ||
1771 | } | ||
1772 | |||
1773 | bfa_flash_read_end(pci_bar, l, &buf[off]); | ||
1774 | |||
1775 | residue -= l; | ||
1776 | off += l; | ||
1777 | } | ||
1778 | bfa_flash_sem_put(pci_bar); | ||
1779 | |||
1780 | return BFA_STATUS_OK; | ||
1781 | } | ||
1782 | |||
1783 | u32 | ||
1784 | bfa_nw_ioc_flash_img_get_size(struct bfa_ioc *ioc) | ||
1785 | { | ||
1786 | return BFI_FLASH_IMAGE_SZ/sizeof(u32); | ||
1787 | } | ||
1788 | |||
1789 | #define BFA_FLASH_PART_FWIMG_ADDR 0x100000 /* fw image address */ | ||
1790 | |||
1791 | enum bfa_status | ||
1792 | bfa_nw_ioc_flash_img_get_chnk(struct bfa_ioc *ioc, u32 off, | ||
1793 | u32 *fwimg) | ||
1794 | { | ||
1795 | return bfa_flash_raw_read(ioc->pcidev.pci_bar_kva, | ||
1796 | BFA_FLASH_PART_FWIMG_ADDR + (off * sizeof(u32)), | ||
1797 | (char *)fwimg, BFI_FLASH_CHUNK_SZ); | ||
1798 | } | ||
1799 | |||
1800 | static enum bfi_ioc_img_ver_cmp | ||
1801 | bfa_ioc_flash_fwver_cmp(struct bfa_ioc *ioc, | ||
1802 | struct bfi_ioc_image_hdr *base_fwhdr) | ||
1803 | { | ||
1804 | struct bfi_ioc_image_hdr *flash_fwhdr; | ||
1805 | enum bfa_status status; | ||
1806 | u32 fwimg[BFI_FLASH_CHUNK_SZ_WORDS]; | ||
1807 | |||
1808 | status = bfa_nw_ioc_flash_img_get_chnk(ioc, 0, fwimg); | ||
1809 | if (status != BFA_STATUS_OK) | ||
1810 | return BFI_IOC_IMG_VER_INCOMP; | ||
1811 | |||
1812 | flash_fwhdr = (struct bfi_ioc_image_hdr *)fwimg; | ||
1813 | if (bfa_ioc_flash_fwver_valid(flash_fwhdr)) | ||
1814 | return bfa_ioc_fw_ver_patch_cmp(base_fwhdr, flash_fwhdr); | ||
1815 | else | ||
1816 | return BFI_IOC_IMG_VER_INCOMP; | ||
1817 | } | ||
1818 | |||
1819 | /** | ||
1820 | * Returns TRUE if driver is willing to work with current smem f/w version. | ||
1821 | */ | ||
1321 | bool | 1822 | bool |
1322 | bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr) | 1823 | bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr) |
1323 | { | 1824 | { |
1324 | struct bfi_ioc_image_hdr *drv_fwhdr; | 1825 | struct bfi_ioc_image_hdr *drv_fwhdr; |
1325 | int i; | 1826 | enum bfi_ioc_img_ver_cmp smem_flash_cmp, drv_smem_cmp; |
1326 | 1827 | ||
1327 | drv_fwhdr = (struct bfi_ioc_image_hdr *) | 1828 | drv_fwhdr = (struct bfi_ioc_image_hdr *) |
1328 | bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); | 1829 | bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); |
1329 | 1830 | ||
1330 | for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) { | 1831 | /* If smem is incompatible or old, driver should not work with it. */ |
1331 | if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) | 1832 | drv_smem_cmp = bfa_ioc_fw_ver_patch_cmp(drv_fwhdr, fwhdr); |
1332 | return false; | 1833 | if (drv_smem_cmp == BFI_IOC_IMG_VER_INCOMP || |
1834 | drv_smem_cmp == BFI_IOC_IMG_VER_OLD) { | ||
1835 | return false; | ||
1333 | } | 1836 | } |
1334 | 1837 | ||
1335 | return true; | 1838 | /* IF Flash has a better F/W than smem do not work with smem. |
1839 | * If smem f/w == flash f/w, as smem f/w not old | incmp, work with it. | ||
1840 | * If Flash is old or incomp work with smem iff smem f/w == drv f/w. | ||
1841 | */ | ||
1842 | smem_flash_cmp = bfa_ioc_flash_fwver_cmp(ioc, fwhdr); | ||
1843 | |||
1844 | if (smem_flash_cmp == BFI_IOC_IMG_VER_BETTER) | ||
1845 | return false; | ||
1846 | else if (smem_flash_cmp == BFI_IOC_IMG_VER_SAME) | ||
1847 | return true; | ||
1848 | else | ||
1849 | return (drv_smem_cmp == BFI_IOC_IMG_VER_SAME) ? | ||
1850 | true : false; | ||
1336 | } | 1851 | } |
1337 | 1852 | ||
1338 | /* Return true if current running version is valid. Firmware signature and | 1853 | /* Return true if current running version is valid. Firmware signature and |
@@ -1341,15 +1856,9 @@ bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr) | |||
1341 | static bool | 1856 | static bool |
1342 | bfa_ioc_fwver_valid(struct bfa_ioc *ioc, u32 boot_env) | 1857 | bfa_ioc_fwver_valid(struct bfa_ioc *ioc, u32 boot_env) |
1343 | { | 1858 | { |
1344 | struct bfi_ioc_image_hdr fwhdr, *drv_fwhdr; | 1859 | struct bfi_ioc_image_hdr fwhdr; |
1345 | 1860 | ||
1346 | bfa_nw_ioc_fwver_get(ioc, &fwhdr); | 1861 | bfa_nw_ioc_fwver_get(ioc, &fwhdr); |
1347 | drv_fwhdr = (struct bfi_ioc_image_hdr *) | ||
1348 | bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); | ||
1349 | |||
1350 | if (fwhdr.signature != drv_fwhdr->signature) | ||
1351 | return false; | ||
1352 | |||
1353 | if (swab32(fwhdr.bootenv) != boot_env) | 1862 | if (swab32(fwhdr.bootenv) != boot_env) |
1354 | return false; | 1863 | return false; |
1355 | 1864 | ||
@@ -1388,8 +1897,10 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) | |||
1388 | false : bfa_ioc_fwver_valid(ioc, boot_env); | 1897 | false : bfa_ioc_fwver_valid(ioc, boot_env); |
1389 | 1898 | ||
1390 | if (!fwvalid) { | 1899 | if (!fwvalid) { |
1391 | bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env); | 1900 | if (bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env) == |
1392 | bfa_ioc_poll_fwinit(ioc); | 1901 | BFA_STATUS_OK) |
1902 | bfa_ioc_poll_fwinit(ioc); | ||
1903 | |||
1393 | return; | 1904 | return; |
1394 | } | 1905 | } |
1395 | 1906 | ||
@@ -1419,8 +1930,9 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) | |||
1419 | /** | 1930 | /** |
1420 | * Initialize the h/w for any other states. | 1931 | * Initialize the h/w for any other states. |
1421 | */ | 1932 | */ |
1422 | bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env); | 1933 | if (bfa_ioc_boot(ioc, BFI_FWBOOT_TYPE_NORMAL, boot_env) == |
1423 | bfa_ioc_poll_fwinit(ioc); | 1934 | BFA_STATUS_OK) |
1935 | bfa_ioc_poll_fwinit(ioc); | ||
1424 | } | 1936 | } |
1425 | 1937 | ||
1426 | void | 1938 | void |
@@ -1525,7 +2037,7 @@ bfa_ioc_hb_stop(struct bfa_ioc *ioc) | |||
1525 | } | 2037 | } |
1526 | 2038 | ||
1527 | /* Initiate a full firmware download. */ | 2039 | /* Initiate a full firmware download. */ |
1528 | static void | 2040 | static enum bfa_status |
1529 | bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, | 2041 | bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, |
1530 | u32 boot_env) | 2042 | u32 boot_env) |
1531 | { | 2043 | { |
@@ -1535,18 +2047,47 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, | |||
1535 | u32 chunkno = 0; | 2047 | u32 chunkno = 0; |
1536 | u32 i; | 2048 | u32 i; |
1537 | u32 asicmode; | 2049 | u32 asicmode; |
2050 | u32 fwimg_size; | ||
2051 | u32 fwimg_buf[BFI_FLASH_CHUNK_SZ_WORDS]; | ||
2052 | enum bfa_status status; | ||
2053 | |||
2054 | if (boot_env == BFI_FWBOOT_ENV_OS && | ||
2055 | boot_type == BFI_FWBOOT_TYPE_FLASH) { | ||
2056 | fwimg_size = BFI_FLASH_IMAGE_SZ/sizeof(u32); | ||
2057 | |||
2058 | status = bfa_nw_ioc_flash_img_get_chnk(ioc, | ||
2059 | BFA_IOC_FLASH_CHUNK_ADDR(chunkno), fwimg_buf); | ||
2060 | if (status != BFA_STATUS_OK) | ||
2061 | return status; | ||
1538 | 2062 | ||
1539 | fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), chunkno); | 2063 | fwimg = fwimg_buf; |
2064 | } else { | ||
2065 | fwimg_size = bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)); | ||
2066 | fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), | ||
2067 | BFA_IOC_FLASH_CHUNK_ADDR(chunkno)); | ||
2068 | } | ||
1540 | 2069 | ||
1541 | pgnum = bfa_ioc_smem_pgnum(ioc, loff); | 2070 | pgnum = bfa_ioc_smem_pgnum(ioc, loff); |
1542 | 2071 | ||
1543 | writel(pgnum, ioc->ioc_regs.host_page_num_fn); | 2072 | writel(pgnum, ioc->ioc_regs.host_page_num_fn); |
1544 | 2073 | ||
1545 | for (i = 0; i < bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)); i++) { | 2074 | for (i = 0; i < fwimg_size; i++) { |
1546 | if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) { | 2075 | if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) { |
1547 | chunkno = BFA_IOC_FLASH_CHUNK_NO(i); | 2076 | chunkno = BFA_IOC_FLASH_CHUNK_NO(i); |
1548 | fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), | 2077 | if (boot_env == BFI_FWBOOT_ENV_OS && |
2078 | boot_type == BFI_FWBOOT_TYPE_FLASH) { | ||
2079 | status = bfa_nw_ioc_flash_img_get_chnk(ioc, | ||
2080 | BFA_IOC_FLASH_CHUNK_ADDR(chunkno), | ||
2081 | fwimg_buf); | ||
2082 | if (status != BFA_STATUS_OK) | ||
2083 | return status; | ||
2084 | |||
2085 | fwimg = fwimg_buf; | ||
2086 | } else { | ||
2087 | fwimg = bfa_cb_image_get_chunk( | ||
2088 | bfa_ioc_asic_gen(ioc), | ||
1549 | BFA_IOC_FLASH_CHUNK_ADDR(chunkno)); | 2089 | BFA_IOC_FLASH_CHUNK_ADDR(chunkno)); |
2090 | } | ||
1550 | } | 2091 | } |
1551 | 2092 | ||
1552 | /** | 2093 | /** |
@@ -1574,6 +2115,10 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, | |||
1574 | /* | 2115 | /* |
1575 | * Set boot type, env and device mode at the end. | 2116 | * Set boot type, env and device mode at the end. |
1576 | */ | 2117 | */ |
2118 | if (boot_env == BFI_FWBOOT_ENV_OS && | ||
2119 | boot_type == BFI_FWBOOT_TYPE_FLASH) { | ||
2120 | boot_type = BFI_FWBOOT_TYPE_NORMAL; | ||
2121 | } | ||
1577 | asicmode = BFI_FWBOOT_DEVMODE(ioc->asic_gen, ioc->asic_mode, | 2122 | asicmode = BFI_FWBOOT_DEVMODE(ioc->asic_gen, ioc->asic_mode, |
1578 | ioc->port0_mode, ioc->port1_mode); | 2123 | ioc->port0_mode, ioc->port1_mode); |
1579 | writel(asicmode, ((ioc->ioc_regs.smem_page_start) | 2124 | writel(asicmode, ((ioc->ioc_regs.smem_page_start) |
@@ -1582,6 +2127,7 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, | |||
1582 | + (BFI_FWBOOT_TYPE_OFF))); | 2127 | + (BFI_FWBOOT_TYPE_OFF))); |
1583 | writel(boot_env, ((ioc->ioc_regs.smem_page_start) | 2128 | writel(boot_env, ((ioc->ioc_regs.smem_page_start) |
1584 | + (BFI_FWBOOT_ENV_OFF))); | 2129 | + (BFI_FWBOOT_ENV_OFF))); |
2130 | return BFA_STATUS_OK; | ||
1585 | } | 2131 | } |
1586 | 2132 | ||
1587 | static void | 2133 | static void |
@@ -1854,14 +2400,27 @@ bfa_ioc_pll_init(struct bfa_ioc *ioc) | |||
1854 | /* Interface used by diag module to do firmware boot with memory test | 2400 | /* Interface used by diag module to do firmware boot with memory test |
1855 | * as the entry vector. | 2401 | * as the entry vector. |
1856 | */ | 2402 | */ |
1857 | static void | 2403 | static enum bfa_status |
1858 | bfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type, | 2404 | bfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type, |
1859 | u32 boot_env) | 2405 | u32 boot_env) |
1860 | { | 2406 | { |
2407 | struct bfi_ioc_image_hdr *drv_fwhdr; | ||
2408 | enum bfa_status status; | ||
1861 | bfa_ioc_stats(ioc, ioc_boots); | 2409 | bfa_ioc_stats(ioc, ioc_boots); |
1862 | 2410 | ||
1863 | if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK) | 2411 | if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK) |
1864 | return; | 2412 | return BFA_STATUS_FAILED; |
2413 | if (boot_env == BFI_FWBOOT_ENV_OS && | ||
2414 | boot_type == BFI_FWBOOT_TYPE_NORMAL) { | ||
2415 | drv_fwhdr = (struct bfi_ioc_image_hdr *) | ||
2416 | bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); | ||
2417 | /* Work with Flash iff flash f/w is better than driver f/w. | ||
2418 | * Otherwise push drivers firmware. | ||
2419 | */ | ||
2420 | if (bfa_ioc_flash_fwver_cmp(ioc, drv_fwhdr) == | ||
2421 | BFI_IOC_IMG_VER_BETTER) | ||
2422 | boot_type = BFI_FWBOOT_TYPE_FLASH; | ||
2423 | } | ||
1865 | 2424 | ||
1866 | /** | 2425 | /** |
1867 | * Initialize IOC state of all functions on a chip reset. | 2426 | * Initialize IOC state of all functions on a chip reset. |
@@ -1875,8 +2434,13 @@ bfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type, | |||
1875 | } | 2434 | } |
1876 | 2435 | ||
1877 | bfa_ioc_msgflush(ioc); | 2436 | bfa_ioc_msgflush(ioc); |
1878 | bfa_ioc_download_fw(ioc, boot_type, boot_env); | 2437 | status = bfa_ioc_download_fw(ioc, boot_type, boot_env); |
1879 | bfa_ioc_lpu_start(ioc); | 2438 | if (status == BFA_STATUS_OK) |
2439 | bfa_ioc_lpu_start(ioc); | ||
2440 | else | ||
2441 | bfa_nw_iocpf_timeout(ioc); | ||
2442 | |||
2443 | return status; | ||
1880 | } | 2444 | } |
1881 | 2445 | ||
1882 | /* Enable/disable IOC failure auto recovery. */ | 2446 | /* Enable/disable IOC failure auto recovery. */ |