diff options
author | Dimitris Michailidis <dm@chelsio.com> | 2010-06-18 06:05:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-19 01:08:34 -0400 |
commit | 900a659687aa6349e52f7b1e3f922b77afe89b90 (patch) | |
tree | 5617d9684ec5d826a4c868398f62786081108467 /drivers/net/cxgb4 | |
parent | bb9c03d8a6893517737b16fdbeb54be3c73b3023 (diff) |
cxgb4: dynamically determine flash size and FW image location
Handle the larger flash memories on newer boards:
- get the size and number of sectors by probing the flash
- writes and erases can take longer, adjust the timeouts for these operations
- the FW image can be at different locations depending on flash size,
find its location dynamically as well.
Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/cxgb4')
-rw-r--r-- | drivers/net/cxgb4/cxgb4.h | 4 | ||||
-rw-r--r-- | drivers/net/cxgb4/t4_hw.c | 75 | ||||
-rw-r--r-- | drivers/net/cxgb4/t4_hw.h | 2 | ||||
-rw-r--r-- | drivers/net/cxgb4/t4_regs.h | 3 |
4 files changed, 61 insertions, 23 deletions
diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h index dd1770e075e6..bfa136622f10 100644 --- a/drivers/net/cxgb4/cxgb4.h +++ b/drivers/net/cxgb4/cxgb4.h | |||
@@ -219,6 +219,10 @@ struct adapter_params { | |||
219 | struct vpd_params vpd; | 219 | struct vpd_params vpd; |
220 | struct pci_params pci; | 220 | struct pci_params pci; |
221 | 221 | ||
222 | unsigned int sf_size; /* serial flash size in bytes */ | ||
223 | unsigned int sf_nsec; /* # of flash sectors */ | ||
224 | unsigned int sf_fw_start; /* start of FW image in flash */ | ||
225 | |||
222 | unsigned int fw_vers; | 226 | unsigned int fw_vers; |
223 | unsigned int tp_vers; | 227 | unsigned int tp_vers; |
224 | u8 api_vers[7]; | 228 | u8 api_vers[7]; |
diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c index da272a98fdbc..5c81c558ce62 100644 --- a/drivers/net/cxgb4/t4_hw.c +++ b/drivers/net/cxgb4/t4_hw.c | |||
@@ -449,12 +449,10 @@ enum { | |||
449 | SF_RD_STATUS = 5, /* read status register */ | 449 | SF_RD_STATUS = 5, /* read status register */ |
450 | SF_WR_ENABLE = 6, /* enable writes */ | 450 | SF_WR_ENABLE = 6, /* enable writes */ |
451 | SF_RD_DATA_FAST = 0xb, /* read flash */ | 451 | SF_RD_DATA_FAST = 0xb, /* read flash */ |
452 | SF_RD_ID = 0x9f, /* read ID */ | ||
452 | SF_ERASE_SECTOR = 0xd8, /* erase sector */ | 453 | SF_ERASE_SECTOR = 0xd8, /* erase sector */ |
453 | 454 | ||
454 | FW_START_SEC = 8, /* first flash sector for FW */ | 455 | FW_MAX_SIZE = 512 * 1024, |
455 | FW_END_SEC = 15, /* last flash sector for FW */ | ||
456 | FW_IMG_START = FW_START_SEC * SF_SEC_SIZE, | ||
457 | FW_MAX_SIZE = (FW_END_SEC - FW_START_SEC + 1) * SF_SEC_SIZE, | ||
458 | }; | 456 | }; |
459 | 457 | ||
460 | /** | 458 | /** |
@@ -558,7 +556,7 @@ static int t4_read_flash(struct adapter *adapter, unsigned int addr, | |||
558 | { | 556 | { |
559 | int ret; | 557 | int ret; |
560 | 558 | ||
561 | if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3)) | 559 | if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3)) |
562 | return -EINVAL; | 560 | return -EINVAL; |
563 | 561 | ||
564 | addr = swab32(addr) | SF_RD_DATA_FAST; | 562 | addr = swab32(addr) | SF_RD_DATA_FAST; |
@@ -596,7 +594,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr, | |||
596 | u32 buf[64]; | 594 | u32 buf[64]; |
597 | unsigned int i, c, left, val, offset = addr & 0xff; | 595 | unsigned int i, c, left, val, offset = addr & 0xff; |
598 | 596 | ||
599 | if (addr >= SF_SIZE || offset + n > SF_PAGE_SIZE) | 597 | if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE) |
600 | return -EINVAL; | 598 | return -EINVAL; |
601 | 599 | ||
602 | val = swab32(addr) | SF_PROG_PAGE; | 600 | val = swab32(addr) | SF_PROG_PAGE; |
@@ -614,7 +612,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr, | |||
614 | if (ret) | 612 | if (ret) |
615 | goto unlock; | 613 | goto unlock; |
616 | } | 614 | } |
617 | ret = flash_wait_op(adapter, 5, 1); | 615 | ret = flash_wait_op(adapter, 8, 1); |
618 | if (ret) | 616 | if (ret) |
619 | goto unlock; | 617 | goto unlock; |
620 | 618 | ||
@@ -647,9 +645,8 @@ unlock: | |||
647 | */ | 645 | */ |
648 | static int get_fw_version(struct adapter *adapter, u32 *vers) | 646 | static int get_fw_version(struct adapter *adapter, u32 *vers) |
649 | { | 647 | { |
650 | return t4_read_flash(adapter, | 648 | return t4_read_flash(adapter, adapter->params.sf_fw_start + |
651 | FW_IMG_START + offsetof(struct fw_hdr, fw_ver), 1, | 649 | offsetof(struct fw_hdr, fw_ver), 1, vers, 0); |
652 | vers, 0); | ||
653 | } | 650 | } |
654 | 651 | ||
655 | /** | 652 | /** |
@@ -661,8 +658,8 @@ static int get_fw_version(struct adapter *adapter, u32 *vers) | |||
661 | */ | 658 | */ |
662 | static int get_tp_version(struct adapter *adapter, u32 *vers) | 659 | static int get_tp_version(struct adapter *adapter, u32 *vers) |
663 | { | 660 | { |
664 | return t4_read_flash(adapter, FW_IMG_START + offsetof(struct fw_hdr, | 661 | return t4_read_flash(adapter, adapter->params.sf_fw_start + |
665 | tp_microcode_ver), | 662 | offsetof(struct fw_hdr, tp_microcode_ver), |
666 | 1, vers, 0); | 663 | 1, vers, 0); |
667 | } | 664 | } |
668 | 665 | ||
@@ -684,9 +681,9 @@ int t4_check_fw_version(struct adapter *adapter) | |||
684 | if (!ret) | 681 | if (!ret) |
685 | ret = get_tp_version(adapter, &adapter->params.tp_vers); | 682 | ret = get_tp_version(adapter, &adapter->params.tp_vers); |
686 | if (!ret) | 683 | if (!ret) |
687 | ret = t4_read_flash(adapter, | 684 | ret = t4_read_flash(adapter, adapter->params.sf_fw_start + |
688 | FW_IMG_START + offsetof(struct fw_hdr, intfver_nic), | 685 | offsetof(struct fw_hdr, intfver_nic), |
689 | 2, api_vers, 1); | 686 | 2, api_vers, 1); |
690 | if (ret) | 687 | if (ret) |
691 | return ret; | 688 | return ret; |
692 | 689 | ||
@@ -726,7 +723,7 @@ static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) | |||
726 | if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || | 723 | if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || |
727 | (ret = sf1_write(adapter, 4, 0, 1, | 724 | (ret = sf1_write(adapter, 4, 0, 1, |
728 | SF_ERASE_SECTOR | (start << 8))) != 0 || | 725 | SF_ERASE_SECTOR | (start << 8))) != 0 || |
729 | (ret = flash_wait_op(adapter, 5, 500)) != 0) { | 726 | (ret = flash_wait_op(adapter, 14, 500)) != 0) { |
730 | dev_err(adapter->pdev_dev, | 727 | dev_err(adapter->pdev_dev, |
731 | "erase of flash sector %d failed, error %d\n", | 728 | "erase of flash sector %d failed, error %d\n", |
732 | start, ret); | 729 | start, ret); |
@@ -754,6 +751,9 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) | |||
754 | u8 first_page[SF_PAGE_SIZE]; | 751 | u8 first_page[SF_PAGE_SIZE]; |
755 | const u32 *p = (const u32 *)fw_data; | 752 | const u32 *p = (const u32 *)fw_data; |
756 | const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data; | 753 | const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data; |
754 | unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; | ||
755 | unsigned int fw_img_start = adap->params.sf_fw_start; | ||
756 | unsigned int fw_start_sec = fw_img_start / sf_sec_size; | ||
757 | 757 | ||
758 | if (!size) { | 758 | if (!size) { |
759 | dev_err(adap->pdev_dev, "FW image has no data\n"); | 759 | dev_err(adap->pdev_dev, "FW image has no data\n"); |
@@ -784,8 +784,8 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) | |||
784 | return -EINVAL; | 784 | return -EINVAL; |
785 | } | 785 | } |
786 | 786 | ||
787 | i = DIV_ROUND_UP(size, SF_SEC_SIZE); /* # of sectors spanned */ | 787 | i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ |
788 | ret = t4_flash_erase_sectors(adap, FW_START_SEC, FW_START_SEC + i - 1); | 788 | ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1); |
789 | if (ret) | 789 | if (ret) |
790 | goto out; | 790 | goto out; |
791 | 791 | ||
@@ -796,11 +796,11 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) | |||
796 | */ | 796 | */ |
797 | memcpy(first_page, fw_data, SF_PAGE_SIZE); | 797 | memcpy(first_page, fw_data, SF_PAGE_SIZE); |
798 | ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); | 798 | ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); |
799 | ret = t4_write_flash(adap, FW_IMG_START, SF_PAGE_SIZE, first_page); | 799 | ret = t4_write_flash(adap, fw_img_start, SF_PAGE_SIZE, first_page); |
800 | if (ret) | 800 | if (ret) |
801 | goto out; | 801 | goto out; |
802 | 802 | ||
803 | addr = FW_IMG_START; | 803 | addr = fw_img_start; |
804 | for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { | 804 | for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { |
805 | addr += SF_PAGE_SIZE; | 805 | addr += SF_PAGE_SIZE; |
806 | fw_data += SF_PAGE_SIZE; | 806 | fw_data += SF_PAGE_SIZE; |
@@ -810,7 +810,7 @@ int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) | |||
810 | } | 810 | } |
811 | 811 | ||
812 | ret = t4_write_flash(adap, | 812 | ret = t4_write_flash(adap, |
813 | FW_IMG_START + offsetof(struct fw_hdr, fw_ver), | 813 | fw_img_start + offsetof(struct fw_hdr, fw_ver), |
814 | sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver); | 814 | sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver); |
815 | out: | 815 | out: |
816 | if (ret) | 816 | if (ret) |
@@ -3053,6 +3053,33 @@ static int __devinit wait_dev_ready(struct adapter *adap) | |||
3053 | return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO; | 3053 | return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO; |
3054 | } | 3054 | } |
3055 | 3055 | ||
3056 | static int __devinit get_flash_params(struct adapter *adap) | ||
3057 | { | ||
3058 | int ret; | ||
3059 | u32 info; | ||
3060 | |||
3061 | ret = sf1_write(adap, 1, 1, 0, SF_RD_ID); | ||
3062 | if (!ret) | ||
3063 | ret = sf1_read(adap, 3, 0, 1, &info); | ||
3064 | t4_write_reg(adap, SF_OP, 0); /* unlock SF */ | ||
3065 | if (ret) | ||
3066 | return ret; | ||
3067 | |||
3068 | if ((info & 0xff) != 0x20) /* not a Numonix flash */ | ||
3069 | return -EINVAL; | ||
3070 | info >>= 16; /* log2 of size */ | ||
3071 | if (info >= 0x14 && info < 0x18) | ||
3072 | adap->params.sf_nsec = 1 << (info - 16); | ||
3073 | else if (info == 0x18) | ||
3074 | adap->params.sf_nsec = 64; | ||
3075 | else | ||
3076 | return -EINVAL; | ||
3077 | adap->params.sf_size = 1 << info; | ||
3078 | adap->params.sf_fw_start = | ||
3079 | t4_read_reg(adap, CIM_BOOT_CFG) & BOOTADDR_MASK; | ||
3080 | return 0; | ||
3081 | } | ||
3082 | |||
3056 | /** | 3083 | /** |
3057 | * t4_prep_adapter - prepare SW and HW for operation | 3084 | * t4_prep_adapter - prepare SW and HW for operation |
3058 | * @adapter: the adapter | 3085 | * @adapter: the adapter |
@@ -3073,6 +3100,12 @@ int __devinit t4_prep_adapter(struct adapter *adapter) | |||
3073 | get_pci_mode(adapter, &adapter->params.pci); | 3100 | get_pci_mode(adapter, &adapter->params.pci); |
3074 | adapter->params.rev = t4_read_reg(adapter, PL_REV); | 3101 | adapter->params.rev = t4_read_reg(adapter, PL_REV); |
3075 | 3102 | ||
3103 | ret = get_flash_params(adapter); | ||
3104 | if (ret < 0) { | ||
3105 | dev_err(adapter->pdev_dev, "error %d identifying flash\n", ret); | ||
3106 | return ret; | ||
3107 | } | ||
3108 | |||
3076 | ret = get_vpd_params(adapter, &adapter->params.vpd); | 3109 | ret = get_vpd_params(adapter, &adapter->params.vpd); |
3077 | if (ret < 0) | 3110 | if (ret < 0) |
3078 | return ret; | 3111 | return ret; |
diff --git a/drivers/net/cxgb4/t4_hw.h b/drivers/net/cxgb4/t4_hw.h index 025623285c93..f886677b93ec 100644 --- a/drivers/net/cxgb4/t4_hw.h +++ b/drivers/net/cxgb4/t4_hw.h | |||
@@ -57,8 +57,6 @@ enum { | |||
57 | 57 | ||
58 | enum { | 58 | enum { |
59 | SF_PAGE_SIZE = 256, /* serial flash page size */ | 59 | SF_PAGE_SIZE = 256, /* serial flash page size */ |
60 | SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ | ||
61 | SF_SIZE = SF_SEC_SIZE * 16, /* serial flash size */ | ||
62 | }; | 60 | }; |
63 | 61 | ||
64 | enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */ | 62 | enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */ |
diff --git a/drivers/net/cxgb4/t4_regs.h b/drivers/net/cxgb4/t4_regs.h index 5ed56483cbc2..8fed46df886c 100644 --- a/drivers/net/cxgb4/t4_regs.h +++ b/drivers/net/cxgb4/t4_regs.h | |||
@@ -326,6 +326,9 @@ | |||
326 | 326 | ||
327 | #define EDC_1_BASE_ADDR 0x7980 | 327 | #define EDC_1_BASE_ADDR 0x7980 |
328 | 328 | ||
329 | #define CIM_BOOT_CFG 0x7b00 | ||
330 | #define BOOTADDR_MASK 0xffffff00U | ||
331 | |||
329 | #define CIM_PF_MAILBOX_DATA 0x240 | 332 | #define CIM_PF_MAILBOX_DATA 0x240 |
330 | #define CIM_PF_MAILBOX_CTRL 0x280 | 333 | #define CIM_PF_MAILBOX_CTRL 0x280 |
331 | #define MBMSGVALID 0x00000008U | 334 | #define MBMSGVALID 0x00000008U |