Merge branch 'cxgb4-add-support-to-read-write-flash'
Vishal Kulkarni says: ==================== cxgb4: add support to read/write flash This series of patches adds support to read/write different binary images of serial flash present in Chelsio terminator. V2 changes: Patch 1: No change Patch 2: No change Patch 3: Fix 4 compilation warnings reported by C=1, W=1 flags Patch 4: No change Patch 5: No change ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
7cc373db7e
@ -70,7 +70,8 @@ enum cudbg_dbg_entity_type {
|
||||
CUDBG_HMA_INDIRECT = 67,
|
||||
CUDBG_HMA = 68,
|
||||
CUDBG_QDESC = 70,
|
||||
CUDBG_MAX_ENTITY = 71,
|
||||
CUDBG_FLASH = 71,
|
||||
CUDBG_MAX_ENTITY = 72,
|
||||
};
|
||||
|
||||
struct cudbg_init {
|
||||
|
@ -3156,3 +3156,40 @@ out_free:
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cudbg_collect_flash(struct cudbg_init *pdbg_init,
|
||||
struct cudbg_buffer *dbg_buff,
|
||||
struct cudbg_error *cudbg_err)
|
||||
{
|
||||
struct adapter *padap = pdbg_init->adap;
|
||||
u32 count = padap->params.sf_size, n;
|
||||
struct cudbg_buffer temp_buff = {0};
|
||||
u32 addr, i;
|
||||
int rc;
|
||||
|
||||
addr = FLASH_EXP_ROM_START;
|
||||
|
||||
for (i = 0; i < count; i += SF_PAGE_SIZE) {
|
||||
n = min_t(u32, count - i, SF_PAGE_SIZE);
|
||||
|
||||
rc = cudbg_get_buff(pdbg_init, dbg_buff, n, &temp_buff);
|
||||
if (rc) {
|
||||
cudbg_err->sys_warn = CUDBG_STATUS_PARTIAL_DATA;
|
||||
goto out;
|
||||
}
|
||||
rc = t4_read_flash(padap, addr, n, (u32 *)temp_buff.data, 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
addr += (n * 4);
|
||||
rc = cudbg_write_and_release_buff(pdbg_init, &temp_buff,
|
||||
dbg_buff);
|
||||
if (rc) {
|
||||
cudbg_err->sys_warn = CUDBG_STATUS_PARTIAL_DATA;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
@ -162,7 +162,9 @@ int cudbg_collect_hma_meminfo(struct cudbg_init *pdbg_init,
|
||||
int cudbg_collect_qdesc(struct cudbg_init *pdbg_init,
|
||||
struct cudbg_buffer *dbg_buff,
|
||||
struct cudbg_error *cudbg_err);
|
||||
|
||||
int cudbg_collect_flash(struct cudbg_init *pdbg_init,
|
||||
struct cudbg_buffer *dbg_buff,
|
||||
struct cudbg_error *cudbg_err);
|
||||
struct cudbg_entity_hdr *cudbg_get_entity_hdr(void *outbuf, int i);
|
||||
void cudbg_align_debug_buffer(struct cudbg_buffer *dbg_buff,
|
||||
struct cudbg_entity_hdr *entity_hdr);
|
||||
|
@ -139,6 +139,64 @@ enum cc_fec {
|
||||
FEC_BASER_RS = 1 << 2 /* BaseR/Reed-Solomon */
|
||||
};
|
||||
|
||||
enum {
|
||||
CXGB4_ETHTOOL_FLASH_FW = 1,
|
||||
CXGB4_ETHTOOL_FLASH_PHY = 2,
|
||||
CXGB4_ETHTOOL_FLASH_BOOT = 3,
|
||||
CXGB4_ETHTOOL_FLASH_BOOTCFG = 4
|
||||
};
|
||||
|
||||
struct cxgb4_bootcfg_data {
|
||||
__le16 signature;
|
||||
__u8 reserved[2];
|
||||
};
|
||||
|
||||
struct cxgb4_pcir_data {
|
||||
__le32 signature; /* Signature. The string "PCIR" */
|
||||
__le16 vendor_id; /* Vendor Identification */
|
||||
__le16 device_id; /* 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;
|
||||
__u8 indicator;
|
||||
__u8 reserved[2];
|
||||
};
|
||||
|
||||
/* BIOS boot headers */
|
||||
struct cxgb4_pci_exp_rom_header {
|
||||
__le16 signature; /* ROM Signature. Should be 0xaa55 */
|
||||
__u8 reserved[22]; /* Reserved per processor Architecture data */
|
||||
__le16 pcir_offset; /* Offset to PCI Data Structure */
|
||||
};
|
||||
|
||||
/* Legacy PCI Expansion ROM Header */
|
||||
struct legacy_pci_rom_hdr {
|
||||
__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 */
|
||||
__le16 pcir_offset; /* Offset to PCI Data Struture */
|
||||
};
|
||||
|
||||
#define CXGB4_HDR_CODE1 0x00
|
||||
#define CXGB4_HDR_CODE2 0x03
|
||||
#define CXGB4_HDR_INDI 0x80
|
||||
|
||||
/* BOOT constants */
|
||||
enum {
|
||||
BOOT_CFG_SIG = 0x4243,
|
||||
BOOT_SIZE_INC = 512,
|
||||
BOOT_SIGNATURE = 0xaa55,
|
||||
BOOT_MIN_SIZE = sizeof(struct cxgb4_pci_exp_rom_header),
|
||||
BOOT_MAX_SIZE = 1024 * BOOT_SIZE_INC,
|
||||
PCIR_SIGNATURE = 0x52494350
|
||||
};
|
||||
|
||||
struct port_stats {
|
||||
u64 tx_octets; /* total # of octets in good frames */
|
||||
u64 tx_frames; /* all good frames */
|
||||
@ -492,6 +550,11 @@ struct trace_params {
|
||||
unsigned char port;
|
||||
};
|
||||
|
||||
struct cxgb4_fw_data {
|
||||
__be32 signature;
|
||||
__u8 reserved[4];
|
||||
};
|
||||
|
||||
/* Firmware Port Capabilities types. */
|
||||
|
||||
typedef u16 fw_port_cap16_t; /* 16-bit Port Capabilities integral value */
|
||||
@ -1988,6 +2051,10 @@ void t4_register_netevent_notifier(void);
|
||||
int t4_i2c_rd(struct adapter *adap, unsigned int mbox, int port,
|
||||
unsigned int devid, unsigned int offset,
|
||||
unsigned int len, u8 *buf);
|
||||
int t4_load_boot(struct adapter *adap, u8 *boot_data,
|
||||
unsigned int boot_addr, unsigned int size);
|
||||
int t4_load_bootcfg(struct adapter *adap,
|
||||
const u8 *cfg_data, unsigned int size);
|
||||
void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, struct sge_fl *fl);
|
||||
void free_tx_desc(struct adapter *adap, struct sge_txq *q,
|
||||
unsigned int n, bool unmap);
|
||||
|
@ -66,6 +66,10 @@ static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
|
||||
{ CUDBG_HMA_INDIRECT, cudbg_collect_hma_indirect },
|
||||
};
|
||||
|
||||
static const struct cxgb4_collect_entity cxgb4_collect_flash_dump[] = {
|
||||
{ CUDBG_FLASH, cudbg_collect_flash },
|
||||
};
|
||||
|
||||
static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
|
||||
{
|
||||
struct cudbg_tcam tcam_region = { 0 };
|
||||
@ -330,6 +334,9 @@ u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag)
|
||||
}
|
||||
}
|
||||
|
||||
if (flag & CXGB4_ETH_DUMP_FLASH)
|
||||
len += adap->params.sf_size;
|
||||
|
||||
/* If compression is enabled, a smaller destination buffer is enough */
|
||||
wsize = cudbg_get_workspace_size();
|
||||
if (wsize && len > CUDBG_DUMP_BUFF_SIZE)
|
||||
@ -468,6 +475,13 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
|
||||
buf,
|
||||
&total_size);
|
||||
|
||||
if (flag & CXGB4_ETH_DUMP_FLASH)
|
||||
cxgb4_cudbg_collect_entity(&cudbg_init, &dbg_buff,
|
||||
cxgb4_collect_flash_dump,
|
||||
ARRAY_SIZE(cxgb4_collect_flash_dump),
|
||||
buf,
|
||||
&total_size);
|
||||
|
||||
cudbg_free_compress_buff(&cudbg_init);
|
||||
cudbg_hdr->data_len = total_size;
|
||||
if (cudbg_init.compress_type != CUDBG_COMPRESSION_NONE)
|
||||
|
@ -27,6 +27,7 @@ enum CXGB4_ETHTOOL_DUMP_FLAGS {
|
||||
CXGB4_ETH_DUMP_NONE = ETH_FW_DUMP_DISABLE,
|
||||
CXGB4_ETH_DUMP_MEM = (1 << 0), /* On-Chip Memory Dumps */
|
||||
CXGB4_ETH_DUMP_HW = (1 << 1), /* various FW and HW dumps */
|
||||
CXGB4_ETH_DUMP_FLASH = (1 << 2), /* Dump flash memory */
|
||||
};
|
||||
|
||||
#define CXGB4_ETH_DUMP_ALL (CXGB4_ETH_DUMP_MEM | CXGB4_ETH_DUMP_HW)
|
||||
|
@ -23,6 +23,14 @@ static void set_msglevel(struct net_device *dev, u32 val)
|
||||
netdev2adap(dev)->msg_enable = val;
|
||||
}
|
||||
|
||||
static const char * const flash_region_strings[] = {
|
||||
"All",
|
||||
"Firmware",
|
||||
"PHY Firmware",
|
||||
"Boot",
|
||||
"Boot CFG",
|
||||
};
|
||||
|
||||
static const char stats_strings[][ETH_GSTRING_LEN] = {
|
||||
"tx_octets_ok ",
|
||||
"tx_frames_ok ",
|
||||
@ -1235,15 +1243,210 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int set_flash(struct net_device *netdev, struct ethtool_flash *ef)
|
||||
static int cxgb4_ethtool_flash_bootcfg(struct net_device *netdev,
|
||||
const u8 *data, u32 size)
|
||||
{
|
||||
struct adapter *adap = netdev2adap(netdev);
|
||||
int ret;
|
||||
const struct firmware *fw;
|
||||
|
||||
ret = t4_load_bootcfg(adap, data, size);
|
||||
if (ret)
|
||||
dev_err(adap->pdev_dev, "Failed to load boot cfg image\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cxgb4_ethtool_flash_boot(struct net_device *netdev,
|
||||
const u8 *bdata, u32 size)
|
||||
{
|
||||
struct adapter *adap = netdev2adap(netdev);
|
||||
unsigned int offset;
|
||||
u8 *data;
|
||||
int ret;
|
||||
|
||||
data = kmemdup(bdata, size, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
offset = OFFSET_G(t4_read_reg(adap, PF_REG(0, PCIE_PF_EXPROM_OFST_A)));
|
||||
|
||||
ret = t4_load_boot(adap, data, offset, size);
|
||||
if (ret)
|
||||
dev_err(adap->pdev_dev, "Failed to load boot image\n");
|
||||
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CXGB4_PHY_SIG 0x130000ea
|
||||
|
||||
static int cxgb4_validate_phy_image(const u8 *data, u32 *size)
|
||||
{
|
||||
struct cxgb4_fw_data *header;
|
||||
|
||||
header = (struct cxgb4_fw_data *)data;
|
||||
if (be32_to_cpu(header->signature) != CXGB4_PHY_SIG)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxgb4_ethtool_flash_phy(struct net_device *netdev,
|
||||
const u8 *data, u32 size)
|
||||
{
|
||||
struct adapter *adap = netdev2adap(netdev);
|
||||
int ret;
|
||||
|
||||
ret = cxgb4_validate_phy_image(data, NULL);
|
||||
if (ret) {
|
||||
dev_err(adap->pdev_dev, "PHY signature mismatch\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = t4_load_phy_fw(adap, MEMWIN_NIC, &adap->win0_lock,
|
||||
NULL, data, size);
|
||||
if (ret)
|
||||
dev_err(adap->pdev_dev, "Failed to load PHY FW\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cxgb4_ethtool_flash_fw(struct net_device *netdev,
|
||||
const u8 *data, u32 size)
|
||||
{
|
||||
struct adapter *adap = netdev2adap(netdev);
|
||||
unsigned int mbox = PCIE_FW_MASTER_M + 1;
|
||||
u32 pcie_fw;
|
||||
int ret;
|
||||
|
||||
/* If the adapter has been fully initialized then we'll go ahead and
|
||||
* try to get the firmware's cooperation in upgrading to the new
|
||||
* firmware image otherwise we'll try to do the entire job from the
|
||||
* host ... and we always "force" the operation in this path.
|
||||
*/
|
||||
if (adap->flags & CXGB4_FULL_INIT_DONE)
|
||||
mbox = adap->mbox;
|
||||
|
||||
ret = t4_fw_upgrade(adap, mbox, data, size, 1);
|
||||
if (ret)
|
||||
dev_err(adap->pdev_dev,
|
||||
"Failed to flash firmware\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cxgb4_ethtool_flash_region(struct net_device *netdev,
|
||||
const u8 *data, u32 size, u32 region)
|
||||
{
|
||||
struct adapter *adap = netdev2adap(netdev);
|
||||
int ret;
|
||||
|
||||
switch (region) {
|
||||
case CXGB4_ETHTOOL_FLASH_FW:
|
||||
ret = cxgb4_ethtool_flash_fw(netdev, data, size);
|
||||
break;
|
||||
case CXGB4_ETHTOOL_FLASH_PHY:
|
||||
ret = cxgb4_ethtool_flash_phy(netdev, data, size);
|
||||
break;
|
||||
case CXGB4_ETHTOOL_FLASH_BOOT:
|
||||
ret = cxgb4_ethtool_flash_boot(netdev, data, size);
|
||||
break;
|
||||
case CXGB4_ETHTOOL_FLASH_BOOTCFG:
|
||||
ret = cxgb4_ethtool_flash_bootcfg(netdev, data, size);
|
||||
break;
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
dev_info(adap->pdev_dev,
|
||||
"loading %s successful, reload cxgb4 driver\n",
|
||||
flash_region_strings[region]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CXGB4_FW_SIG 0x4368656c
|
||||
#define CXGB4_FW_SIG_OFFSET 0x160
|
||||
|
||||
static int cxgb4_validate_fw_image(const u8 *data, u32 *size)
|
||||
{
|
||||
struct cxgb4_fw_data *header;
|
||||
|
||||
header = (struct cxgb4_fw_data *)&data[CXGB4_FW_SIG_OFFSET];
|
||||
if (be32_to_cpu(header->signature) != CXGB4_FW_SIG)
|
||||
return -EINVAL;
|
||||
|
||||
if (size)
|
||||
*size = be16_to_cpu(((struct fw_hdr *)data)->len512) * 512;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxgb4_validate_bootcfg_image(const u8 *data, u32 *size)
|
||||
{
|
||||
struct cxgb4_bootcfg_data *header;
|
||||
|
||||
header = (struct cxgb4_bootcfg_data *)data;
|
||||
if (le16_to_cpu(header->signature) != BOOT_CFG_SIG)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxgb4_validate_boot_image(const u8 *data, u32 *size)
|
||||
{
|
||||
struct cxgb4_pci_exp_rom_header *exp_header;
|
||||
struct cxgb4_pcir_data *pcir_header;
|
||||
struct legacy_pci_rom_hdr *header;
|
||||
const u8 *cur_header = data;
|
||||
u16 pcir_offset;
|
||||
|
||||
exp_header = (struct cxgb4_pci_exp_rom_header *)data;
|
||||
|
||||
if (le16_to_cpu(exp_header->signature) != BOOT_SIGNATURE)
|
||||
return -EINVAL;
|
||||
|
||||
if (size) {
|
||||
do {
|
||||
header = (struct legacy_pci_rom_hdr *)cur_header;
|
||||
pcir_offset = le16_to_cpu(header->pcir_offset);
|
||||
pcir_header = (struct cxgb4_pcir_data *)(cur_header +
|
||||
pcir_offset);
|
||||
|
||||
*size += header->size512 * 512;
|
||||
cur_header += header->size512 * 512;
|
||||
} while (!(pcir_header->indicator & CXGB4_HDR_INDI));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxgb4_ethtool_get_flash_region(const u8 *data, u32 *size)
|
||||
{
|
||||
if (!cxgb4_validate_fw_image(data, size))
|
||||
return CXGB4_ETHTOOL_FLASH_FW;
|
||||
if (!cxgb4_validate_boot_image(data, size))
|
||||
return CXGB4_ETHTOOL_FLASH_BOOT;
|
||||
if (!cxgb4_validate_phy_image(data, size))
|
||||
return CXGB4_ETHTOOL_FLASH_PHY;
|
||||
if (!cxgb4_validate_bootcfg_image(data, size))
|
||||
return CXGB4_ETHTOOL_FLASH_BOOTCFG;
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int set_flash(struct net_device *netdev, struct ethtool_flash *ef)
|
||||
{
|
||||
struct adapter *adap = netdev2adap(netdev);
|
||||
const struct firmware *fw;
|
||||
unsigned int master;
|
||||
u8 master_vld = 0;
|
||||
const u8 *fw_data;
|
||||
size_t fw_size;
|
||||
u32 size = 0;
|
||||
u32 pcie_fw;
|
||||
int region;
|
||||
int ret;
|
||||
|
||||
pcie_fw = t4_read_reg(adap, PCIE_FW_A);
|
||||
master = PCIE_FW_MASTER_G(pcie_fw);
|
||||
@ -1261,19 +1464,32 @@ static int set_flash(struct net_device *netdev, struct ethtool_flash *ef)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* If the adapter has been fully initialized then we'll go ahead and
|
||||
* try to get the firmware's cooperation in upgrading to the new
|
||||
* firmware image otherwise we'll try to do the entire job from the
|
||||
* host ... and we always "force" the operation in this path.
|
||||
*/
|
||||
if (adap->flags & CXGB4_FULL_INIT_DONE)
|
||||
mbox = adap->mbox;
|
||||
fw_data = fw->data;
|
||||
fw_size = fw->size;
|
||||
if (ef->region == ETHTOOL_FLASH_ALL_REGIONS) {
|
||||
while (fw_size > 0) {
|
||||
size = 0;
|
||||
region = cxgb4_ethtool_get_flash_region(fw_data, &size);
|
||||
if (region < 0 || !size) {
|
||||
ret = region;
|
||||
goto out_free_fw;
|
||||
}
|
||||
|
||||
ret = t4_fw_upgrade(adap, mbox, fw->data, fw->size, 1);
|
||||
ret = cxgb4_ethtool_flash_region(netdev, fw_data, size,
|
||||
region);
|
||||
if (ret)
|
||||
goto out_free_fw;
|
||||
|
||||
fw_data += size;
|
||||
fw_size -= size;
|
||||
}
|
||||
} else {
|
||||
ret = cxgb4_ethtool_flash_region(netdev, fw_data, fw_size,
|
||||
ef->region);
|
||||
}
|
||||
|
||||
out_free_fw:
|
||||
release_firmware(fw);
|
||||
if (!ret)
|
||||
dev_info(adap->pdev_dev,
|
||||
"loaded firmware %s, reload cxgb4 driver\n", ef->data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -10481,3 +10481,280 @@ int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf,
|
||||
|
||||
return t4_wr_mbox(adap, adap->mbox, &vlan_cmd, sizeof(vlan_cmd), NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* modify_device_id - Modifies the device ID of the Boot BIOS image
|
||||
* @device_id: 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)
|
||||
{
|
||||
struct cxgb4_pcir_data *pcir_header;
|
||||
struct legacy_pci_rom_hdr *header;
|
||||
u8 *cur_header = boot_data;
|
||||
u16 pcir_offset;
|
||||
|
||||
/* Loop through all chained images and change the device ID's */
|
||||
do {
|
||||
header = (struct legacy_pci_rom_hdr *)cur_header;
|
||||
pcir_offset = le16_to_cpu(header->pcir_offset);
|
||||
pcir_header = (struct cxgb4_pcir_data *)(cur_header +
|
||||
pcir_offset);
|
||||
|
||||
/**
|
||||
* Only modify the Device ID if code type is Legacy or HP.
|
||||
* 0x00: Okay to modify
|
||||
* 0x01: FCODE. Do not modify
|
||||
* 0x03: Okay to modify
|
||||
* 0x04-0xFF: Do not modify
|
||||
*/
|
||||
if (pcir_header->code_type == CXGB4_HDR_CODE1) {
|
||||
u8 csum = 0;
|
||||
int i;
|
||||
|
||||
/**
|
||||
* Modify Device ID to match current adatper
|
||||
*/
|
||||
pcir_header->device_id = cpu_to_le16(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 += cur_header[i];
|
||||
|
||||
/**
|
||||
* Invert summed value to create the checksum
|
||||
* Writing new checksum value directly to the boot data
|
||||
*/
|
||||
cur_header[7] = -csum;
|
||||
|
||||
} else if (pcir_header->code_type == CXGB4_HDR_CODE2) {
|
||||
/**
|
||||
* Modify Device ID to match current adatper
|
||||
*/
|
||||
pcir_header->device_id = cpu_to_le16(device_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move header pointer up to the next image in the ROM.
|
||||
*/
|
||||
cur_header += header->size512 * 512;
|
||||
} while (!(pcir_header->indicator & CXGB4_HDR_INDI));
|
||||
}
|
||||
|
||||
/**
|
||||
* t4_load_boot - download boot flash
|
||||
* @adap: 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)
|
||||
{
|
||||
unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
|
||||
unsigned int boot_sector = (boot_addr * 1024);
|
||||
struct cxgb4_pci_exp_rom_header *header;
|
||||
struct cxgb4_pcir_data *pcir_header;
|
||||
int pcir_offset;
|
||||
unsigned int i;
|
||||
u16 device_id;
|
||||
int ret, addr;
|
||||
|
||||
/**
|
||||
* Make sure the boot image does not encroach on the firmware region
|
||||
*/
|
||||
if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) {
|
||||
dev_err(adap->pdev_dev, "boot image encroaching on firmware region\n");
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
/* Get boot header */
|
||||
header = (struct cxgb4_pci_exp_rom_header *)boot_data;
|
||||
pcir_offset = le16_to_cpu(header->pcir_offset);
|
||||
/* PCIR Data Structure */
|
||||
pcir_header = (struct cxgb4_pcir_data *)&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) {
|
||||
dev_err(adap->pdev_dev, "boot image too small/large\n");
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(header->signature) != BOOT_SIGNATURE) {
|
||||
dev_err(adap->pdev_dev, "Boot image missing signature\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check PCI header signature */
|
||||
if (le32_to_cpu(pcir_header->signature) != PCIR_SIGNATURE) {
|
||||
dev_err(adap->pdev_dev, "PCI header missing signature\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check Vendor ID matches Chelsio ID*/
|
||||
if (le16_to_cpu(pcir_header->vendor_id) != PCI_VENDOR_ID_CHELSIO) {
|
||||
dev_err(adap->pdev_dev, "Vendor ID missing signature\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
/* Retrieve adapter's device ID */
|
||||
pci_read_config_word(adap->pdev, 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(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);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = t4_write_flash(adap, boot_sector, SF_PAGE_SIZE,
|
||||
(const u8 *)header);
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
dev_err(adap->pdev_dev, "boot image load 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)
|
||||
{
|
||||
unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
|
||||
struct cxgb4_bootcfg_data *header;
|
||||
unsigned int flash_cfg_start_sec;
|
||||
unsigned int addr, npad;
|
||||
int ret, i, n, cfg_addr;
|
||||
|
||||
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) {
|
||||
dev_err(adap->pdev_dev, "bootcfg file too large, max is %u bytes\n",
|
||||
FLASH_BOOTCFG_MAX_SIZE);
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
header = (struct cxgb4_bootcfg_data *)cfg_data;
|
||||
if (le16_to_cpu(header->signature) != BOOT_CFG_SIG) {
|
||||
dev_err(adap->pdev_dev, "Wrong bootcfg signature\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
i = DIV_ROUND_UP(FLASH_BOOTCFG_MAX_SIZE,
|
||||
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) {
|
||||
n = min_t(u32, size - i, SF_PAGE_SIZE);
|
||||
|
||||
ret = t4_write_flash(adap, addr, n, cfg_data);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
addr += SF_PAGE_SIZE;
|
||||
cfg_data += SF_PAGE_SIZE;
|
||||
}
|
||||
|
||||
npad = ((size + 4 - 1) & ~3) - size;
|
||||
for (i = 0; i < npad; i++) {
|
||||
u8 data = 0;
|
||||
|
||||
ret = t4_write_flash(adap, cfg_addr + size + i, 1, &data);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
dev_err(adap->pdev_dev, "boot config data %s failed %d\n",
|
||||
(size == 0 ? "clear" : "download"), ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -563,6 +563,12 @@
|
||||
#define AIVEC_V(x) ((x) << AIVEC_S)
|
||||
|
||||
#define PCIE_PF_CLI_A 0x44
|
||||
|
||||
#define PCIE_PF_EXPROM_OFST_A 0x4c
|
||||
#define OFFSET_S 10
|
||||
#define OFFSET_M 0x3fffU
|
||||
#define OFFSET_G(x) (((x) >> OFFSET_S) & OFFSET_M)
|
||||
|
||||
#define PCIE_INT_CAUSE_A 0x3004
|
||||
|
||||
#define UNXSPLCPLERR_S 29
|
||||
|
Loading…
Reference in New Issue
Block a user