diff options
author | np <np@FreeBSD.org> | 2016-03-08 07:48:55 +0000 |
---|---|---|
committer | np <np@FreeBSD.org> | 2016-03-08 07:48:55 +0000 |
commit | 54eec7a19dd772dad64c0aafee6cad6981dc8910 (patch) | |
tree | 352d5273c7594e90a04077e19e62564598a0c3ee | |
parent | 475b5a6654dcd3f42eff929b1a113d1fcf7bb686 (diff) | |
download | FreeBSD-src-54eec7a19dd772dad64c0aafee6cad6981dc8910.zip FreeBSD-src-54eec7a19dd772dad64c0aafee6cad6981dc8910.tar.gz |
cxgbe(4): Updates to the shared routines that deal with the serial EEPROM,
flash, and VPD.
Obtained from: Chelsio Communications
-rw-r--r-- | sys/dev/cxgbe/adapter.h | 2 | ||||
-rw-r--r-- | sys/dev/cxgbe/common/common.h | 9 | ||||
-rw-r--r-- | sys/dev/cxgbe/common/t4_hw.c | 1024 | ||||
-rw-r--r-- | sys/dev/cxgbe/osdep.h | 2 | ||||
-rw-r--r-- | sys/dev/cxgbe/t4_main.c | 9 |
5 files changed, 616 insertions, 430 deletions
diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h index 3d54c65..358f618 100644 --- a/sys/dev/cxgbe/adapter.h +++ b/sys/dev/cxgbe/adapter.h @@ -734,6 +734,8 @@ struct adapter { unsigned int pf; unsigned int mbox; + unsigned int vpd_busy; + unsigned int vpd_flag; /* Interrupt information */ int intr_type; diff --git a/sys/dev/cxgbe/common/common.h b/sys/dev/cxgbe/common/common.h index a2ec22f..ad3b827 100644 --- a/sys/dev/cxgbe/common/common.h +++ b/sys/dev/cxgbe/common/common.h @@ -499,20 +499,24 @@ int t4_eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz); int t4_seeprom_wp(struct adapter *adapter, int enable); int t4_read_flash(struct adapter *adapter, unsigned int addr, unsigned int nwords, u32 *data, int byte_oriented); +int t4_write_flash(struct adapter *adapter, unsigned int addr, + unsigned int n, const u8 *data, int byte_oriented); int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); +int t4_load_bootcfg(struct adapter *adapter, const u8 *cfg_data, unsigned int size); int t4_load_boot(struct adapter *adap, u8 *boot_data, unsigned int boot_addr, unsigned int size); +int t4_flash_erase_sectors(struct adapter *adapter, int start, int end); int t4_flash_cfg_addr(struct adapter *adapter); int t4_load_cfg(struct adapter *adapter, const u8 *cfg_data, unsigned int size); int t4_get_fw_version(struct adapter *adapter, u32 *vers); int t4_get_tp_version(struct adapter *adapter, u32 *vers); int t4_check_fw_version(struct adapter *adapter); int t4_init_hw(struct adapter *adapter, u32 fw_params); -int t4_prep_adapter(struct adapter *adapter); +int t4_prep_adapter(struct adapter *adapter, u8 *buf); int t4_init_sge_params(struct adapter *adapter); int t4_init_tp_params(struct adapter *adap); int t4_filter_field_shift(const struct adapter *adap, int filter_sel); -int t4_port_init(struct port_info *p, int mbox, int pf, int vf); +int t4_port_init(struct adapter *adap, int mbox, int pf, int vf, int port_id); void t4_fatal_err(struct adapter *adapter); void t4_db_full(struct adapter *adapter); void t4_db_dropped(struct adapter *adapter); @@ -557,6 +561,7 @@ int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr); void t4_cim_read_pif_la(struct adapter *adap, u32 *pif_req, u32 *pif_rsp, unsigned int *pif_req_wrptr, unsigned int *pif_rsp_wrptr); void t4_cim_read_ma_la(struct adapter *adap, u32 *ma_req, u32 *ma_rsp); +int t4_get_flash_params(struct adapter *adapter); int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c index e8293c7..bcdf33a 100644 --- a/sys/dev/cxgbe/common/t4_hw.c +++ b/sys/dev/cxgbe/common/t4_hw.c @@ -2536,7 +2536,7 @@ void t4_get_regs(struct adapter *adap, u8 *buf, size_t buf_size) /* * Partial EEPROM Vital Product Data structure. Includes only the ID and - * VPD-R header. + * VPD-R sections. */ struct t4_vpd_hdr { u8 id_tag; @@ -2549,14 +2549,65 @@ struct t4_vpd_hdr { /* * EEPROM reads take a few tens of us while writes can take a bit over 5 ms. */ -#define EEPROM_MAX_RD_POLL 40 -#define EEPROM_MAX_WR_POLL 6 -#define EEPROM_STAT_ADDR 0x7bfc -#define VPD_BASE 0x400 -#define VPD_BASE_OLD 0 -#define VPD_LEN 1024 +#define EEPROM_DELAY 10 /* 10us per poll spin */ +#define EEPROM_MAX_POLL 5000 /* x 5000 == 50ms */ + +#define EEPROM_STAT_ADDR 0x7bfc +#define VPD_BASE 0x400 +#define VPD_BASE_OLD 0 +#define VPD_LEN 1024 #define VPD_INFO_FLD_HDR_SIZE 3 -#define CHELSIO_VPD_UNIQUE_ID 0x82 +#define CHELSIO_VPD_UNIQUE_ID 0x82 + +/* + * Small utility function to wait till any outstanding VPD Access is complete. + * We have a per-adapter state variable "VPD Busy" to indicate when we have a + * VPD Access in flight. This allows us to handle the problem of having a + * previous VPD Access time out and prevent an attempt to inject a new VPD + * Request before any in-flight VPD reguest has completed. + */ +static int t4_seeprom_wait(struct adapter *adapter) +{ + unsigned int base = adapter->params.pci.vpd_cap_addr; + int max_poll; + + /* + * If no VPD Access is in flight, we can just return success right + * away. + */ + if (!adapter->vpd_busy) + return 0; + + /* + * Poll the VPD Capability Address/Flag register waiting for it + * to indicate that the operation is complete. + */ + max_poll = EEPROM_MAX_POLL; + do { + u16 val; + + udelay(EEPROM_DELAY); + t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val); + + /* + * If the operation is complete, mark the VPD as no longer + * busy and return success. + */ + if ((val & PCI_VPD_ADDR_F) == adapter->vpd_flag) { + adapter->vpd_busy = 0; + return 0; + } + } while (--max_poll); + + /* + * Failure! Note that we leave the VPD Busy status set in order to + * avoid pushing a new VPD Access request into the VPD Capability till + * the current operation eventually succeeds. It's a bug to issue a + * new request when an existing request is in flight and will result + * in corrupt hardware state. + */ + return -ETIMEDOUT; +} /** * t4_seeprom_read - read a serial EEPROM location @@ -2570,23 +2621,44 @@ struct t4_vpd_hdr { */ int t4_seeprom_read(struct adapter *adapter, u32 addr, u32 *data) { - u16 val; - int attempts = EEPROM_MAX_RD_POLL; unsigned int base = adapter->params.pci.vpd_cap_addr; + int ret; + /* + * VPD Accesses must alway be 4-byte aligned! + */ if (addr >= EEPROMVSIZE || (addr & 3)) return -EINVAL; - t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR, (u16)addr); - do { - udelay(10); - t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val); - } while (!(val & PCI_VPD_ADDR_F) && --attempts); + /* + * Wait for any previous operation which may still be in flight to + * complete. + */ + ret = t4_seeprom_wait(adapter); + if (ret) { + CH_ERR(adapter, "VPD still busy from previous operation\n"); + return ret; + } - if (!(val & PCI_VPD_ADDR_F)) { - CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr); - return -EIO; + /* + * Issue our new VPD Read request, mark the VPD as being busy and wait + * for our request to complete. If it doesn't complete, note the + * error and return it to our caller. Note that we do not reset the + * VPD Busy status! + */ + t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR, (u16)addr); + adapter->vpd_busy = 1; + adapter->vpd_flag = PCI_VPD_ADDR_F; + ret = t4_seeprom_wait(adapter); + if (ret) { + CH_ERR(adapter, "VPD read of address %#x failed\n", addr); + return ret; } + + /* + * Grab the returned data, swizzle it into our endianess and + * return success. + */ t4_os_pci_read_cfg4(adapter, base + PCI_VPD_DATA, data); *data = le32_to_cpu(*data); return 0; @@ -2604,26 +2676,59 @@ int t4_seeprom_read(struct adapter *adapter, u32 addr, u32 *data) */ int t4_seeprom_write(struct adapter *adapter, u32 addr, u32 data) { - u16 val; - int attempts = EEPROM_MAX_WR_POLL; unsigned int base = adapter->params.pci.vpd_cap_addr; + int ret; + u32 stats_reg; + int max_poll; + /* + * VPD Accesses must alway be 4-byte aligned! + */ if (addr >= EEPROMVSIZE || (addr & 3)) return -EINVAL; + /* + * Wait for any previous operation which may still be in flight to + * complete. + */ + ret = t4_seeprom_wait(adapter); + if (ret) { + CH_ERR(adapter, "VPD still busy from previous operation\n"); + return ret; + } + + /* + * Issue our new VPD Read request, mark the VPD as being busy and wait + * for our request to complete. If it doesn't complete, note the + * error and return it to our caller. Note that we do not reset the + * VPD Busy status! + */ t4_os_pci_write_cfg4(adapter, base + PCI_VPD_DATA, cpu_to_le32(data)); t4_os_pci_write_cfg2(adapter, base + PCI_VPD_ADDR, (u16)addr | PCI_VPD_ADDR_F); + adapter->vpd_busy = 1; + adapter->vpd_flag = 0; + ret = t4_seeprom_wait(adapter); + if (ret) { + CH_ERR(adapter, "VPD write of address %#x failed\n", addr); + return ret; + } + + /* + * Reset PCI_VPD_DATA register after a transaction and wait for our + * request to complete. If it doesn't complete, return error. + */ + t4_os_pci_write_cfg4(adapter, base + PCI_VPD_DATA, 0); + max_poll = EEPROM_MAX_POLL; do { - msleep(1); - t4_os_pci_read_cfg2(adapter, base + PCI_VPD_ADDR, &val); - } while ((val & PCI_VPD_ADDR_F) && --attempts); + udelay(EEPROM_DELAY); + t4_seeprom_read(adapter, EEPROM_STAT_ADDR, &stats_reg); + } while ((stats_reg & 0x1) && --max_poll); + if (!max_poll) + return -ETIMEDOUT; - if (val & PCI_VPD_ADDR_F) { - CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr); - return -EIO; - } + /* Return success! */ return 0; } @@ -2672,33 +2777,33 @@ int t4_seeprom_wp(struct adapter *adapter, int enable) * get_vpd_keyword_val - Locates an information field keyword in the VPD * @v: Pointer to buffered vpd data structure * @kw: The keyword to search for - * + * * Returns the value of the information field keyword or * -ENOENT otherwise. */ static int get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw) { - int i; - unsigned int offset , len; - const u8 *buf = &v->id_tag; - const u8 *vpdr_len = &v->vpdr_tag; - offset = sizeof(struct t4_vpd_hdr); - len = (u16)vpdr_len[1] + ((u16)vpdr_len[2] << 8); - - if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN) { - return -ENOENT; - } + int i; + unsigned int offset , len; + const u8 *buf = (const u8 *)v; + const u8 *vpdr_len = &v->vpdr_len[0]; + offset = sizeof(struct t4_vpd_hdr); + len = (u16)vpdr_len[0] + ((u16)vpdr_len[1] << 8); + + if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN) { + return -ENOENT; + } - for (i = offset; i + VPD_INFO_FLD_HDR_SIZE <= offset + len;) { - if(memcmp(buf + i , kw , 2) == 0){ - i += VPD_INFO_FLD_HDR_SIZE; - return i; - } + for (i = offset; i + VPD_INFO_FLD_HDR_SIZE <= offset + len;) { + if(memcmp(buf + i , kw , 2) == 0){ + i += VPD_INFO_FLD_HDR_SIZE; + return i; + } - i += VPD_INFO_FLD_HDR_SIZE + buf[i+2]; - } + i += VPD_INFO_FLD_HDR_SIZE + buf[i+2]; + } - return -ENOENT; + return -ENOENT; } @@ -2706,14 +2811,16 @@ static int get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw) * get_vpd_params - read VPD parameters from VPD EEPROM * @adapter: adapter to read * @p: where to store the parameters + * @vpd: caller provided temporary space to read the VPD into * * Reads card parameters stored in VPD EEPROM. */ -static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) +static int get_vpd_params(struct adapter *adapter, struct vpd_params *p, + u8 *vpd) { int i, ret, addr; int ec, sn, pn, na; - u8 vpd[VPD_LEN], csum; + u8 csum; const struct t4_vpd_hdr *v; /* @@ -2721,31 +2828,43 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) * it at 0. */ ret = t4_seeprom_read(adapter, VPD_BASE, (u32 *)(vpd)); + if (ret) + return (ret); + + /* + * The VPD shall have a unique identifier specified by the PCI SIG. + * For chelsio adapters, the identifier is 0x82. The first byte of a VPD + * shall be CHELSIO_VPD_UNIQUE_ID (0x82). The VPD programming software + * is expected to automatically put this entry at the + * beginning of the VPD. + */ addr = *vpd == CHELSIO_VPD_UNIQUE_ID ? VPD_BASE : VPD_BASE_OLD; - for (i = 0; i < sizeof(vpd); i += 4) { + for (i = 0; i < VPD_LEN; i += 4) { ret = t4_seeprom_read(adapter, addr + i, (u32 *)(vpd + i)); if (ret) return ret; } v = (const struct t4_vpd_hdr *)vpd; - + #define FIND_VPD_KW(var,name) do { \ var = get_vpd_keyword_val(v , name); \ if (var < 0) { \ CH_ERR(adapter, "missing VPD keyword " name "\n"); \ return -EINVAL; \ } \ -} while (0) +} while (0) FIND_VPD_KW(i, "RV"); for (csum = 0; i >= 0; i--) csum += vpd[i]; if (csum) { - CH_ERR(adapter, "corrupted VPD EEPROM, actual csum %u\n", csum); + CH_ERR(adapter, + "corrupted VPD EEPROM, actual csum %u\n", csum); return -EINVAL; } + FIND_VPD_KW(ec, "EC"); FIND_VPD_KW(sn, "SN"); FIND_VPD_KW(pn, "PN"); @@ -2771,16 +2890,16 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) /* serial flash and firmware constants and flash config file constants */ enum { - SF_ATTEMPTS = 10, /* max retries for SF operations */ + SF_ATTEMPTS = 10, /* max retries for SF operations */ /* flash command opcodes */ - SF_PROG_PAGE = 2, /* program page */ - SF_WR_DISABLE = 4, /* disable writes */ - SF_RD_STATUS = 5, /* read status register */ - SF_WR_ENABLE = 6, /* enable writes */ - SF_RD_DATA_FAST = 0xb, /* read flash */ - SF_RD_ID = 0x9f, /* read ID */ - SF_ERASE_SECTOR = 0xd8, /* erase sector */ + SF_PROG_PAGE = 2, /* program page */ + SF_WR_DISABLE = 4, /* disable writes */ + SF_RD_STATUS = 5, /* read status register */ + SF_WR_ENABLE = 6, /* enable writes */ + SF_RD_DATA_FAST = 0xb, /* read flash */ + SF_RD_ID = 0x9f, /* read ID */ + SF_ERASE_SECTOR = 0xd8, /* erase sector */ }; /** @@ -2874,7 +2993,7 @@ static int flash_wait_op(struct adapter *adapter, int attempts, int delay) * Read the specified number of 32-bit words from the serial flash. * If @byte_oriented is set the read data is stored as a byte array * (i.e., big-endian), otherwise as 32-bit words in the platform's - * natural endianess. + * natural endianness. */ int t4_read_flash(struct adapter *adapter, unsigned int addr, unsigned int nwords, u32 *data, int byte_oriented) @@ -2897,7 +3016,7 @@ int t4_read_flash(struct adapter *adapter, unsigned int addr, if (ret) return ret; if (byte_oriented) - *data = htonl(*data); + *data = (__force __u32)(cpu_to_be32(*data)); } return 0; } @@ -2912,10 +3031,10 @@ int t4_read_flash(struct adapter *adapter, unsigned int addr, * * Writes up to a page of data (256 bytes) to the serial flash starting * at the given address. All the data must be written to the same page. - * If @byte_oriented is set the write data is stored as byte stream + * If @byte_oriented is set the write data is stored as byte stream * (i.e. matches what on disk), otherwise in big-endian. */ -static int t4_write_flash(struct adapter *adapter, unsigned int addr, +int t4_write_flash(struct adapter *adapter, unsigned int addr, unsigned int n, const u8 *data, int byte_oriented) { int ret; @@ -2937,7 +3056,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr, val = (val << 8) + *data++; if (!byte_oriented) - val = htonl(val); + val = cpu_to_be32(val); ret = sf1_write(adapter, c, c != left, 1, val); if (ret) @@ -2956,8 +3075,9 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr, return ret; if (memcmp(data - n, (u8 *)buf + offset, n)) { - CH_ERR(adapter, "failed to correctly write the flash page " - "at %#x\n", addr); + CH_ERR(adapter, + "failed to correctly write the flash page at %#x\n", + addr); return -EIO; } return 0; @@ -3057,17 +3177,21 @@ int t4_check_fw_version(struct adapter *adapter) * * Erases the sectors in the given inclusive range. */ -static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) +int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) { int ret = 0; + if (end >= adapter->params.sf_nsec) + return -EINVAL; + while (start <= end) { if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || (ret = sf1_write(adapter, 4, 0, 1, SF_ERASE_SECTOR | (start << 8))) != 0 || (ret = flash_wait_op(adapter, 14, 500)) != 0) { - CH_ERR(adapter, "erase of flash sector %d failed, " - "error %d\n", start, ret); + CH_ERR(adapter, + "erase of flash sector %d failed, error %d\n", + start, ret); break; } start++; @@ -3096,66 +3220,6 @@ int t4_flash_cfg_addr(struct adapter *adapter) return FLASH_CFG_START; } -/** - * t4_load_cfg - download config file - * @adap: the adapter - * @cfg_data: the cfg text file to write - * @size: text file size - * - * Write the supplied config text file to the card's serial flash. - */ -int t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size) -{ - int ret, i, n, cfg_addr; - unsigned int addr; - unsigned int flash_cfg_start_sec; - unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; - - cfg_addr = t4_flash_cfg_addr(adap); - if (cfg_addr < 0) - return cfg_addr; - - addr = cfg_addr; - flash_cfg_start_sec = addr / SF_SEC_SIZE; - - if (size > FLASH_CFG_MAX_SIZE) { - CH_ERR(adap, "cfg file too large, max is %u bytes\n", - FLASH_CFG_MAX_SIZE); - return -EFBIG; - } - - i = DIV_ROUND_UP(FLASH_CFG_MAX_SIZE, /* # of sectors spanned */ - sf_sec_size); - ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec, - flash_cfg_start_sec + i - 1); - /* - * If size == 0 then we're simply erasing the FLASH sectors associated - * with the on-adapter Firmware Configuration File. - */ - if (ret || size == 0) - goto out; - - /* this will write to the flash up to SF_PAGE_SIZE at a time */ - for (i = 0; i< size; i+= SF_PAGE_SIZE) { - if ( (size - i) < SF_PAGE_SIZE) - n = size - i; - else - n = SF_PAGE_SIZE; - ret = t4_write_flash(adap, addr, n, cfg_data, 1); - if (ret) - goto out; - - addr += SF_PAGE_SIZE; - cfg_data += SF_PAGE_SIZE; - } - -out: - if (ret) - CH_ERR(adap, "config file %s failed %d\n", - (size == 0 ? "clear" : "download"), ret); - return ret; -} - /** * t4_load_fw - download firmware @@ -3254,283 +3318,6 @@ out: return ret; } -/* BIOS boot headers */ -typedef struct pci_expansion_rom_header { - u8 signature[2]; /* ROM Signature. Should be 0xaa55 */ - u8 reserved[22]; /* Reserved per processor Architecture data */ - u8 pcir_offset[2]; /* Offset to PCI Data Structure */ -} pci_exp_rom_header_t; /* PCI_EXPANSION_ROM_HEADER */ - -/* Legacy PCI Expansion ROM Header */ -typedef struct legacy_pci_expansion_rom_header { - u8 signature[2]; /* ROM Signature. Should be 0xaa55 */ - u8 size512; /* Current Image Size in units of 512 bytes */ - u8 initentry_point[4]; - u8 cksum; /* Checksum computed on the entire Image */ - u8 reserved[16]; /* Reserved */ - u8 pcir_offset[2]; /* Offset to PCI Data Struture */ -} legacy_pci_exp_rom_header_t; /* LEGACY_PCI_EXPANSION_ROM_HEADER */ - -/* EFI PCI Expansion ROM Header */ -typedef struct efi_pci_expansion_rom_header { - u8 signature[2]; // ROM signature. The value 0xaa55 - u8 initialization_size[2]; /* Units 512. Includes this header */ - u8 efi_signature[4]; /* Signature from EFI image header. 0x0EF1 */ - u8 efi_subsystem[2]; /* Subsystem value for EFI image header */ - u8 efi_machine_type[2]; /* Machine type from EFI image header */ - u8 compression_type[2]; /* Compression type. */ - /* - * Compression type definition - * 0x0: uncompressed - * 0x1: Compressed - * 0x2-0xFFFF: Reserved - */ - u8 reserved[8]; /* Reserved */ - u8 efi_image_header_offset[2]; /* Offset to EFI Image */ - u8 pcir_offset[2]; /* Offset to PCI Data Structure */ -} efi_pci_exp_rom_header_t; /* EFI PCI Expansion ROM Header */ - -/* PCI Data Structure Format */ -typedef struct pcir_data_structure { /* PCI Data Structure */ - u8 signature[4]; /* Signature. The string "PCIR" */ - u8 vendor_id[2]; /* Vendor Identification */ - u8 device_id[2]; /* Device Identification */ - u8 vital_product[2]; /* Pointer to Vital Product Data */ - u8 length[2]; /* PCIR Data Structure Length */ - u8 revision; /* PCIR Data Structure Revision */ - u8 class_code[3]; /* Class Code */ - u8 image_length[2]; /* Image Length. Multiple of 512B */ - u8 code_revision[2]; /* Revision Level of Code/Data */ - u8 code_type; /* Code Type. */ - /* - * PCI Expansion ROM Code Types - * 0x00: Intel IA-32, PC-AT compatible. Legacy - * 0x01: Open Firmware standard for PCI. FCODE - * 0x02: Hewlett-Packard PA RISC. HP reserved - * 0x03: EFI Image. EFI - * 0x04-0xFF: Reserved. - */ - u8 indicator; /* Indicator. Identifies the last image in the ROM */ - u8 reserved[2]; /* Reserved */ -} pcir_data_t; /* PCI__DATA_STRUCTURE */ - -/* BOOT constants */ -enum { - BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */ - BOOT_SIGNATURE = 0xaa55, /* signature of BIOS boot ROM */ - BOOT_SIZE_INC = 512, /* image size measured in 512B chunks */ - BOOT_MIN_SIZE = sizeof(pci_exp_rom_header_t), /* basic header */ - BOOT_MAX_SIZE = 1024*BOOT_SIZE_INC, /* 1 byte * length increment */ - VENDOR_ID = 0x1425, /* Vendor ID */ - PCIR_SIGNATURE = 0x52494350 /* PCIR signature */ -}; - -/* - * modify_device_id - Modifies the device ID of the Boot BIOS image - * @adatper: the device ID to write. - * @boot_data: the boot image to modify. - * - * Write the supplied device ID to the boot BIOS image. - */ -static void modify_device_id(int device_id, u8 *boot_data) -{ - legacy_pci_exp_rom_header_t *header; - pcir_data_t *pcir_header; - u32 cur_header = 0; - - /* - * Loop through all chained images and change the device ID's - */ - while (1) { - header = (legacy_pci_exp_rom_header_t *) &boot_data[cur_header]; - pcir_header = (pcir_data_t *) &boot_data[cur_header + - le16_to_cpu(*(u16*)header->pcir_offset)]; - - /* - * Only modify the Device ID if code type is Legacy or HP. - * 0x00: Okay to modify - * 0x01: FCODE. Do not be modify - * 0x03: Okay to modify - * 0x04-0xFF: Do not modify - */ - if (pcir_header->code_type == 0x00) { - u8 csum = 0; - int i; - - /* - * Modify Device ID to match current adatper - */ - *(u16*) pcir_header->device_id = device_id; - - /* - * Set checksum temporarily to 0. - * We will recalculate it later. - */ - header->cksum = 0x0; - - /* - * Calculate and update checksum - */ - for (i = 0; i < (header->size512 * 512); i++) - csum += (u8)boot_data[cur_header + i]; - - /* - * Invert summed value to create the checksum - * Writing new checksum value directly to the boot data - */ - boot_data[cur_header + 7] = -csum; - - } else if (pcir_header->code_type == 0x03) { - - /* - * Modify Device ID to match current adatper - */ - *(u16*) pcir_header->device_id = device_id; - - } - - - /* - * Check indicator element to identify if this is the last - * image in the ROM. - */ - if (pcir_header->indicator & 0x80) - break; - - /* - * Move header pointer up to the next image in the ROM. - */ - cur_header += header->size512 * 512; - } -} - -/* - * t4_load_boot - download boot flash - * @adapter: the adapter - * @boot_data: the boot image to write - * @boot_addr: offset in flash to write boot_data - * @size: image size - * - * Write the supplied boot image to the card's serial flash. - * The boot image has the following sections: a 28-byte header and the - * boot image. - */ -int t4_load_boot(struct adapter *adap, u8 *boot_data, - unsigned int boot_addr, unsigned int size) -{ - pci_exp_rom_header_t *header; - int pcir_offset ; - pcir_data_t *pcir_header; - int ret, addr; - uint16_t device_id; - unsigned int i; - unsigned int boot_sector = boot_addr * 1024; - unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; - - /* - * Make sure the boot image does not encroach on the firmware region - */ - if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) { - CH_ERR(adap, "boot image encroaching on firmware region\n"); - return -EFBIG; - } - - /* - * Number of sectors spanned - */ - i = DIV_ROUND_UP(size ? size : FLASH_BOOTCFG_MAX_SIZE, - sf_sec_size); - ret = t4_flash_erase_sectors(adap, boot_sector >> 16, - (boot_sector >> 16) + i - 1); - - /* - * If size == 0 then we're simply erasing the FLASH sectors associated - * with the on-adapter option ROM file - */ - if (ret || (size == 0)) - goto out; - - /* Get boot header */ - header = (pci_exp_rom_header_t *)boot_data; - pcir_offset = le16_to_cpu(*(u16 *)header->pcir_offset); - /* PCIR Data Structure */ - pcir_header = (pcir_data_t *) &boot_data[pcir_offset]; - - /* - * Perform some primitive sanity testing to avoid accidentally - * writing garbage over the boot sectors. We ought to check for - * more but it's not worth it for now ... - */ - if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) { - CH_ERR(adap, "boot image too small/large\n"); - return -EFBIG; - } - - /* - * Check BOOT ROM header signature - */ - if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE ) { - CH_ERR(adap, "Boot image missing signature\n"); - return -EINVAL; - } - - /* - * Check PCI header signature - */ - if (le32_to_cpu(*(u32*)pcir_header->signature) != PCIR_SIGNATURE) { - CH_ERR(adap, "PCI header missing signature\n"); - return -EINVAL; - } - - /* - * Check Vendor ID matches Chelsio ID - */ - if (le16_to_cpu(*(u16*)pcir_header->vendor_id) != VENDOR_ID) { - CH_ERR(adap, "Vendor ID missing signature\n"); - return -EINVAL; - } - - /* - * Retrieve adapter's device ID - */ - t4_os_pci_read_cfg2(adap, PCI_DEVICE_ID, &device_id); - /* Want to deal with PF 0 so I strip off PF 4 indicator */ - device_id = (device_id & 0xff) | 0x4000; - - /* - * Check PCIE Device ID - */ - if (le16_to_cpu(*(u16*)pcir_header->device_id) != device_id) { - /* - * Change the device ID in the Boot BIOS image to match - * the Device ID of the current adapter. - */ - modify_device_id(device_id, boot_data); - } - - /* - * Skip over the first SF_PAGE_SIZE worth of data and write it after - * we finish copying the rest of the boot image. This will ensure - * that the BIOS boot header will only be written if the boot image - * was written in full. - */ - addr = boot_sector; - for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { - addr += SF_PAGE_SIZE; - boot_data += SF_PAGE_SIZE; - ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data, 0); - if (ret) - goto out; - } - - ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE, boot_data, 0); - -out: - if (ret) - CH_ERR(adap, "boot image download failed, error %d\n", ret); - return ret; -} - /** * t4_read_cimq_cfg - read CIM queue configuration * @adap: the adapter @@ -6029,7 +5816,7 @@ void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) } /** - * get_mps_bg_map - return the buffer groups associated with a port + * t4_get_mps_bg_map - return the buffer groups associated with a port * @adap: the adapter * @idx: the port index * @@ -6037,7 +5824,7 @@ void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]) * with the given port. Bit i is set if buffer group i is used by the * port. */ -static unsigned int get_mps_bg_map(struct adapter *adap, int idx) +static unsigned int t4_get_mps_bg_map(struct adapter *adap, int idx) { u32 n = G_NUMPORTS(t4_read_reg(adap, A_MPS_CMN_CTL)); @@ -6110,7 +5897,7 @@ void t4_get_port_stats_offset(struct adapter *adap, int idx, */ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p) { - u32 bgmap = get_mps_bg_map(adap, idx); + u32 bgmap = t4_get_mps_bg_map(adap, idx); #define GET_STAT(name) \ t4_read_reg64(adap, \ @@ -6193,7 +5980,7 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p) void t4_clr_port_stats(struct adapter *adap, int idx) { unsigned int i; - u32 bgmap = get_mps_bg_map(adap, idx); + u32 bgmap = t4_get_mps_bg_map(adap, idx); u32 port_base_addr; if (is_t4(adap)) @@ -6226,7 +6013,7 @@ void t4_clr_port_stats(struct adapter *adap, int idx) */ void t4_get_lb_stats(struct adapter *adap, int idx, struct lb_port_stats *p) { - u32 bgmap = get_mps_bg_map(adap, idx); + u32 bgmap = t4_get_mps_bg_map(adap, idx); #define GET_STAT(name) \ t4_read_reg64(adap, \ @@ -7702,21 +7489,43 @@ static void __devinit init_link_config(struct link_config *lc, } } -static int __devinit get_flash_params(struct adapter *adapter) +struct flash_desc { + u32 vendor_and_model_id; + u32 size_mb; +}; + +int t4_get_flash_params(struct adapter *adapter) { + /* + * Table for non-Numonix supported flash parts. Numonix parts are left + * to the preexisting well-tested code. All flash parts have 64KB + * sectors. + */ + static struct flash_desc supported_flash[] = { + { 0x150201, 4 << 20 }, /* Spansion 4MB S25FL032P */ + }; + int ret; u32 info = 0; ret = sf1_write(adapter, 1, 1, 0, SF_RD_ID); if (!ret) ret = sf1_read(adapter, 3, 0, 1, &info); - t4_write_reg(adapter, A_SF_OP, 0); /* unlock SF */ + t4_write_reg(adapter, A_SF_OP, 0); /* unlock SF */ if (ret < 0) return ret; - if ((info & 0xff) != 0x20) /* not a Numonix flash */ + for (ret = 0; ret < ARRAY_SIZE(supported_flash); ++ret) + if (supported_flash[ret].vendor_and_model_id == info) { + adapter->params.sf_size = supported_flash[ret].size_mb; + adapter->params.sf_nsec = + adapter->params.sf_size / SF_SEC_SIZE; + return 0; + } + + if ((info & 0xff) != 0x20) /* not a Numonix flash */ return -EINVAL; - info >>= 16; /* log2 of size */ + info >>= 16; /* log2 of size */ if (info >= 0x14 && info < 0x18) adapter->params.sf_nsec = 1 << (info - 16); else if (info == 0x18) @@ -7724,6 +7533,16 @@ static int __devinit get_flash_params(struct adapter *adapter) else return -EINVAL; adapter->params.sf_size = 1 << info; + + /* + * We should ~probably~ reject adapters with FLASHes which are too + * small but we have some legacy FPGAs with small FLASHes that we'd + * still like to use. So instead we emit a scary message ... + */ + if (adapter->params.sf_size < FLASH_MIN_SIZE) + CH_WARN(adapter, "WARNING!!! FLASH size %#x < %#x!!!\n", + adapter->params.sf_size, FLASH_MIN_SIZE); + return 0; } @@ -7793,13 +7612,13 @@ static const struct chip_params *get_chip_params(int chipid) /** * t4_prep_adapter - prepare SW and HW for operation * @adapter: the adapter - * @reset: if true perform a HW reset + * @buf: temporary space of at least VPD_LEN size provided by the caller. * * Initialize adapter SW state for the various HW modules, set initial * values for some adapter tunables, take PHYs out of reset, and * initialize the MDIO interface. */ -int __devinit t4_prep_adapter(struct adapter *adapter) +int t4_prep_adapter(struct adapter *adapter, u8 *buf) { int ret; uint16_t device_id; @@ -7828,11 +7647,11 @@ int __devinit t4_prep_adapter(struct adapter *adapter) adapter->params.pci.vpd_cap_addr = t4_os_find_pci_capability(adapter, PCI_CAP_ID_VPD); - ret = get_flash_params(adapter); + ret = t4_get_flash_params(adapter); if (ret < 0) return ret; - ret = get_vpd_params(adapter, &adapter->params.vpd); + ret = get_vpd_params(adapter, &adapter->params.vpd, buf); if (ret < 0) return ret; @@ -8060,13 +7879,13 @@ int t4_filter_field_shift(const struct adapter *adap, int filter_sel) return field_shift; } -int __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf) +int t4_port_init(struct adapter *adap, int mbox, int pf, int vf, int port_id) { u8 addr[6]; int ret, i, j; struct fw_port_cmd c; u16 rss_size; - adapter_t *adap = p->adapter; + struct port_info *p = adap2pinfo(adap, port_id); u32 param, val; memset(&c, 0, sizeof(c)); @@ -8093,18 +7912,18 @@ int __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf) p->vi[0].viid = ret; p->tx_chan = j; - p->rx_chan_map = get_mps_bg_map(adap, j); + p->rx_chan_map = t4_get_mps_bg_map(adap, j); p->lport = j; p->vi[0].rss_size = rss_size; t4_os_set_hw_addr(adap, p->port_id, addr); - ret = ntohl(c.u.info.lstatus_to_modtype); + ret = be32_to_cpu(c.u.info.lstatus_to_modtype); p->mdio_addr = (ret & F_FW_PORT_CMD_MDIOCAP) ? G_FW_PORT_CMD_MDIOADDR(ret) : -1; p->port_type = G_FW_PORT_CMD_PTYPE(ret); p->mod_type = G_FW_PORT_CMD_MODTYPE(ret); - init_link_config(&p->link_cfg, ntohs(c.u.info.pcap)); + init_link_config(&p->link_cfg, be16_to_cpu(c.u.info.pcap)); param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_RSSINFO) | @@ -8120,6 +7939,361 @@ int __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf) return 0; } +/* BIOS boot headers */ +typedef struct pci_expansion_rom_header { + u8 signature[2]; /* ROM Signature. Should be 0xaa55 */ + u8 reserved[22]; /* Reserved per processor Architecture data */ + u8 pcir_offset[2]; /* Offset to PCI Data Structure */ +} pci_exp_rom_header_t; /* PCI_EXPANSION_ROM_HEADER */ + +/* Legacy PCI Expansion ROM Header */ +typedef struct legacy_pci_expansion_rom_header { + u8 signature[2]; /* ROM Signature. Should be 0xaa55 */ + u8 size512; /* Current Image Size in units of 512 bytes */ + u8 initentry_point[4]; + u8 cksum; /* Checksum computed on the entire Image */ + u8 reserved[16]; /* Reserved */ + u8 pcir_offset[2]; /* Offset to PCI Data Struture */ +} legacy_pci_exp_rom_header_t; /* LEGACY_PCI_EXPANSION_ROM_HEADER */ + +/* EFI PCI Expansion ROM Header */ +typedef struct efi_pci_expansion_rom_header { + u8 signature[2]; // ROM signature. The value 0xaa55 + u8 initialization_size[2]; /* Units 512. Includes this header */ + u8 efi_signature[4]; /* Signature from EFI image header. 0x0EF1 */ + u8 efi_subsystem[2]; /* Subsystem value for EFI image header */ + u8 efi_machine_type[2]; /* Machine type from EFI image header */ + u8 compression_type[2]; /* Compression type. */ + /* + * Compression type definition + * 0x0: uncompressed + * 0x1: Compressed + * 0x2-0xFFFF: Reserved + */ + u8 reserved[8]; /* Reserved */ + u8 efi_image_header_offset[2]; /* Offset to EFI Image */ + u8 pcir_offset[2]; /* Offset to PCI Data Structure */ +} efi_pci_exp_rom_header_t; /* EFI PCI Expansion ROM Header */ + +/* PCI Data Structure Format */ +typedef struct pcir_data_structure { /* PCI Data Structure */ + u8 signature[4]; /* Signature. The string "PCIR" */ + u8 vendor_id[2]; /* Vendor Identification */ + u8 device_id[2]; /* Device Identification */ + u8 vital_product[2]; /* Pointer to Vital Product Data */ + u8 length[2]; /* PCIR Data Structure Length */ + u8 revision; /* PCIR Data Structure Revision */ + u8 class_code[3]; /* Class Code */ + u8 image_length[2]; /* Image Length. Multiple of 512B */ + u8 code_revision[2]; /* Revision Level of Code/Data */ + u8 code_type; /* Code Type. */ + /* + * PCI Expansion ROM Code Types + * 0x00: Intel IA-32, PC-AT compatible. Legacy + * 0x01: Open Firmware standard for PCI. FCODE + * 0x02: Hewlett-Packard PA RISC. HP reserved + * 0x03: EFI Image. EFI + * 0x04-0xFF: Reserved. + */ + u8 indicator; /* Indicator. Identifies the last image in the ROM */ + u8 reserved[2]; /* Reserved */ +} pcir_data_t; /* PCI__DATA_STRUCTURE */ + +/* BOOT constants */ +enum { + BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */ + BOOT_SIGNATURE = 0xaa55, /* signature of BIOS boot ROM */ + BOOT_SIZE_INC = 512, /* image size measured in 512B chunks */ + BOOT_MIN_SIZE = sizeof(pci_exp_rom_header_t), /* basic header */ + BOOT_MAX_SIZE = 1024*BOOT_SIZE_INC, /* 1 byte * length increment */ + VENDOR_ID = 0x1425, /* Vendor ID */ + PCIR_SIGNATURE = 0x52494350 /* PCIR signature */ +}; + +/* + * modify_device_id - Modifies the device ID of the Boot BIOS image + * @adatper: the device ID to write. + * @boot_data: the boot image to modify. + * + * Write the supplied device ID to the boot BIOS image. + */ +static void modify_device_id(int device_id, u8 *boot_data) +{ + legacy_pci_exp_rom_header_t *header; + pcir_data_t *pcir_header; + u32 cur_header = 0; + + /* + * Loop through all chained images and change the device ID's + */ + while (1) { + header = (legacy_pci_exp_rom_header_t *) &boot_data[cur_header]; + pcir_header = (pcir_data_t *) &boot_data[cur_header + + le16_to_cpu(*(u16*)header->pcir_offset)]; + + /* + * Only modify the Device ID if code type is Legacy or HP. + * 0x00: Okay to modify + * 0x01: FCODE. Do not be modify + * 0x03: Okay to modify + * 0x04-0xFF: Do not modify + */ + if (pcir_header->code_type == 0x00) { + u8 csum = 0; + int i; + + /* + * Modify Device ID to match current adatper + */ + *(u16*) pcir_header->device_id = device_id; + + /* + * Set checksum temporarily to 0. + * We will recalculate it later. + */ + header->cksum = 0x0; + + /* + * Calculate and update checksum + */ + for (i = 0; i < (header->size512 * 512); i++) + csum += (u8)boot_data[cur_header + i]; + + /* + * Invert summed value to create the checksum + * Writing new checksum value directly to the boot data + */ + boot_data[cur_header + 7] = -csum; + + } else if (pcir_header->code_type == 0x03) { + + /* + * Modify Device ID to match current adatper + */ + *(u16*) pcir_header->device_id = device_id; + + } + + + /* + * Check indicator element to identify if this is the last + * image in the ROM. + */ + if (pcir_header->indicator & 0x80) + break; + + /* + * Move header pointer up to the next image in the ROM. + */ + cur_header += header->size512 * 512; + } +} + +/* + * t4_load_boot - download boot flash + * @adapter: the adapter + * @boot_data: the boot image to write + * @boot_addr: offset in flash to write boot_data + * @size: image size + * + * Write the supplied boot image to the card's serial flash. + * The boot image has the following sections: a 28-byte header and the + * boot image. + */ +int t4_load_boot(struct adapter *adap, u8 *boot_data, + unsigned int boot_addr, unsigned int size) +{ + pci_exp_rom_header_t *header; + int pcir_offset ; + pcir_data_t *pcir_header; + int ret, addr; + uint16_t device_id; + unsigned int i; + unsigned int boot_sector = (boot_addr * 1024 ); + unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; + + /* + * Make sure the boot image does not encroach on the firmware region + */ + if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) { + CH_ERR(adap, "boot image encroaching on firmware region\n"); + return -EFBIG; + } + + /* + * The boot sector is comprised of the Expansion-ROM boot, iSCSI boot, + * and Boot configuration data sections. These 3 boot sections span + * sectors 0 to 7 in flash and live right before the FW image location. + */ + i = DIV_ROUND_UP(size ? size : FLASH_FW_START, + sf_sec_size); + ret = t4_flash_erase_sectors(adap, boot_sector >> 16, + (boot_sector >> 16) + i - 1); + + /* + * If size == 0 then we're simply erasing the FLASH sectors associated + * with the on-adapter option ROM file + */ + if (ret || (size == 0)) + goto out; + + /* Get boot header */ + header = (pci_exp_rom_header_t *)boot_data; + pcir_offset = le16_to_cpu(*(u16 *)header->pcir_offset); + /* PCIR Data Structure */ + pcir_header = (pcir_data_t *) &boot_data[pcir_offset]; + + /* + * Perform some primitive sanity testing to avoid accidentally + * writing garbage over the boot sectors. We ought to check for + * more but it's not worth it for now ... + */ + if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) { + CH_ERR(adap, "boot image too small/large\n"); + return -EFBIG; + } + +#ifndef CHELSIO_T4_DIAGS + /* + * Check BOOT ROM header signature + */ + if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE ) { + CH_ERR(adap, "Boot image missing signature\n"); + return -EINVAL; + } + + /* + * Check PCI header signature + */ + if (le32_to_cpu(*(u32*)pcir_header->signature) != PCIR_SIGNATURE) { + CH_ERR(adap, "PCI header missing signature\n"); + return -EINVAL; + } + + /* + * Check Vendor ID matches Chelsio ID + */ + if (le16_to_cpu(*(u16*)pcir_header->vendor_id) != VENDOR_ID) { + CH_ERR(adap, "Vendor ID missing signature\n"); + return -EINVAL; + } +#endif + + /* + * Retrieve adapter's device ID + */ + t4_os_pci_read_cfg2(adap, PCI_DEVICE_ID, &device_id); + /* Want to deal with PF 0 so I strip off PF 4 indicator */ + device_id = device_id & 0xf0ff; + + /* + * Check PCIE Device ID + */ + if (le16_to_cpu(*(u16*)pcir_header->device_id) != device_id) { + /* + * Change the device ID in the Boot BIOS image to match + * the Device ID of the current adapter. + */ + modify_device_id(device_id, boot_data); + } + + /* + * Skip over the first SF_PAGE_SIZE worth of data and write it after + * we finish copying the rest of the boot image. This will ensure + * that the BIOS boot header will only be written if the boot image + * was written in full. + */ + addr = boot_sector; + for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { + addr += SF_PAGE_SIZE; + boot_data += SF_PAGE_SIZE; + ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, boot_data, 0); + if (ret) + goto out; + } + + ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE, + (const u8 *)header, 0); + +out: + if (ret) + CH_ERR(adap, "boot image download failed, error %d\n", ret); + return ret; +} + +/* + * t4_flash_bootcfg_addr - return the address of the flash optionrom configuration + * @adapter: the adapter + * + * Return the address within the flash where the OptionROM Configuration + * is stored, or an error if the device FLASH is too small to contain + * a OptionROM Configuration. + */ +static int t4_flash_bootcfg_addr(struct adapter *adapter) +{ + /* + * If the device FLASH isn't large enough to hold a Firmware + * Configuration File, return an error. + */ + if (adapter->params.sf_size < FLASH_BOOTCFG_START + FLASH_BOOTCFG_MAX_SIZE) + return -ENOSPC; + + return FLASH_BOOTCFG_START; +} + +int t4_load_bootcfg(struct adapter *adap,const u8 *cfg_data, unsigned int size) +{ + int ret, i, n, cfg_addr; + unsigned int addr; + unsigned int flash_cfg_start_sec; + unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; + + cfg_addr = t4_flash_bootcfg_addr(adap); + if (cfg_addr < 0) + return cfg_addr; + + addr = cfg_addr; + flash_cfg_start_sec = addr / SF_SEC_SIZE; + + if (size > FLASH_BOOTCFG_MAX_SIZE) { + CH_ERR(adap, "bootcfg file too large, max is %u bytes\n", + FLASH_BOOTCFG_MAX_SIZE); + return -EFBIG; + } + + i = DIV_ROUND_UP(FLASH_BOOTCFG_MAX_SIZE,/* # of sectors spanned */ + sf_sec_size); + ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec, + flash_cfg_start_sec + i - 1); + + /* + * If size == 0 then we're simply erasing the FLASH sectors associated + * with the on-adapter OptionROM Configuration File. + */ + if (ret || size == 0) + goto out; + + /* this will write to the flash up to SF_PAGE_SIZE at a time */ + for (i = 0; i< size; i+= SF_PAGE_SIZE) { + if ( (size - i) < SF_PAGE_SIZE) + n = size - i; + else + n = SF_PAGE_SIZE; + ret = t4_write_flash(adap, addr, n, cfg_data, 0); + if (ret) + goto out; + + addr += SF_PAGE_SIZE; + cfg_data += SF_PAGE_SIZE; + } + +out: + if (ret) + CH_ERR(adap, "boot config data %s failed %d\n", + (size == 0 ? "clear" : "download"), ret); + return ret; +} + /** * t4_set_filter_mode - configure the optional components of filter tuples * @adap: the adapter diff --git a/sys/dev/cxgbe/osdep.h b/sys/dev/cxgbe/osdep.h index 403b535..cc12da3 100644 --- a/sys/dev/cxgbe/osdep.h +++ b/sys/dev/cxgbe/osdep.h @@ -80,6 +80,8 @@ typedef boolean_t bool; #define true TRUE #endif +#define __force + #define mdelay(x) DELAY((x) * 1000) #define udelay(x) DELAY(x) diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index 80f1e1c..a29a751 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -645,6 +645,7 @@ t4_attach(device_t dev) int rc = 0, i, j, n10g, n1g, rqidx, tqidx; struct intrs_and_queues iaq; struct sge *s; + uint8_t *buf; #ifdef TCP_OFFLOAD int ofld_rqidx, ofld_tqidx; #endif @@ -713,8 +714,10 @@ t4_attach(device_t dev) t4_register_cpl_handler(sc, CPL_T5_TRACE_PKT, t5_trace_pkt); t4_init_sge_cpl_handlers(sc); - /* Prepare the adapter for operation */ - rc = -t4_prep_adapter(sc); + /* Prepare the adapter for operation. */ + buf = malloc(PAGE_SIZE, M_CXGBE, M_ZERO | M_WAITOK); + rc = -t4_prep_adapter(sc, buf); + free(buf, M_CXGBE); if (rc != 0) { device_printf(dev, "failed to prepare adapter: %d.\n", rc); goto done; @@ -815,7 +818,7 @@ t4_attach(device_t dev) * Allocate the "main" VI and initialize parameters * like mac addr. */ - rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); + rc = -t4_port_init(sc, sc->mbox, sc->pf, 0, i); if (rc != 0) { device_printf(dev, "unable to initialize port %d: %d\n", i, rc); |