diff options
Diffstat (limited to 'drivers/net/netxen/netxen_nic_init.c')
| -rw-r--r-- | drivers/net/netxen/netxen_nic_init.c | 169 | 
1 files changed, 153 insertions, 16 deletions
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 02876f59cbb2..045a7c8f5bdf 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -614,22 +614,123 @@ static struct uni_table_desc *nx_get_table_desc(const u8 *unirom, int section)  	return NULL;  } +#define	QLCNIC_FILEHEADER_SIZE	(14 * 4) +  static int -nx_set_product_offs(struct netxen_adapter *adapter) -{ -	struct uni_table_desc *ptab_descr; +netxen_nic_validate_header(struct netxen_adapter *adapter) + {  	const u8 *unirom = adapter->fw->data; -	uint32_t i; +	struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0]; +	u32 fw_file_size = adapter->fw->size; +	u32 tab_size;  	__le32 entries; +	__le32 entry_size; + +	if (fw_file_size < QLCNIC_FILEHEADER_SIZE) +		return -EINVAL; + +	entries = cpu_to_le32(directory->num_entries); +	entry_size = cpu_to_le32(directory->entry_size); +	tab_size = cpu_to_le32(directory->findex) + (entries * entry_size); + +	if (fw_file_size < tab_size) +		return -EINVAL; + +	return 0; +} + +static int +netxen_nic_validate_bootld(struct netxen_adapter *adapter) +{ +	struct uni_table_desc *tab_desc; +	struct uni_data_desc *descr; +	const u8 *unirom = adapter->fw->data; +	__le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] + +				NX_UNI_BOOTLD_IDX_OFF)); +	u32 offs; +	u32 tab_size; +	u32 data_size; + +	tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_BOOTLD); + +	if (!tab_desc) +		return -EINVAL; + +	tab_size = cpu_to_le32(tab_desc->findex) + +			(cpu_to_le32(tab_desc->entry_size) * (idx + 1)); + +	if (adapter->fw->size < tab_size) +		return -EINVAL; + +	offs = cpu_to_le32(tab_desc->findex) + +		(cpu_to_le32(tab_desc->entry_size) * (idx)); +	descr = (struct uni_data_desc *)&unirom[offs]; + +	data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size); + +	if (adapter->fw->size < data_size) +		return -EINVAL; + +	return 0; +} + +static int +netxen_nic_validate_fw(struct netxen_adapter *adapter) +{ +	struct uni_table_desc *tab_desc; +	struct uni_data_desc *descr; +	const u8 *unirom = adapter->fw->data; +	__le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] + +				NX_UNI_FIRMWARE_IDX_OFF)); +	u32 offs; +	u32 tab_size; +	u32 data_size; + +	tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_FW); + +	if (!tab_desc) +		return -EINVAL; + +	tab_size = cpu_to_le32(tab_desc->findex) + +			(cpu_to_le32(tab_desc->entry_size) * (idx + 1)); + +	if (adapter->fw->size < tab_size) +		return -EINVAL; + +	offs = cpu_to_le32(tab_desc->findex) + +		(cpu_to_le32(tab_desc->entry_size) * (idx)); +	descr = (struct uni_data_desc *)&unirom[offs]; +	data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size); + +	if (adapter->fw->size < data_size) +		return -EINVAL; +	return 0; +} + + +static int +netxen_nic_validate_product_offs(struct netxen_adapter *adapter) +{ +	struct uni_table_desc *ptab_descr; +	const u8 *unirom = adapter->fw->data;  	int mn_present = (NX_IS_REVISION_P2(adapter->ahw.revision_id)) ?  			1 : netxen_p3_has_mn(adapter); +	__le32 entries; +	__le32 entry_size; +	u32 tab_size; +	u32 i;  	ptab_descr = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_PRODUCT_TBL);  	if (ptab_descr == NULL) -		return -1; +		return -EINVAL;  	entries = cpu_to_le32(ptab_descr->num_entries); +	entry_size = cpu_to_le32(ptab_descr->entry_size); +	tab_size = cpu_to_le32(ptab_descr->findex) + (entries * entry_size); + +	if (adapter->fw->size < tab_size) +		return -EINVAL;  nomn:  	for (i = 0; i < entries; i++) { @@ -658,9 +759,38 @@ nomn:  		goto nomn;  	} -	return -1; +	return -EINVAL;  } +static int +netxen_nic_validate_unified_romimage(struct netxen_adapter *adapter) +{ +	if (netxen_nic_validate_header(adapter)) { +		dev_err(&adapter->pdev->dev, +				"unified image: header validation failed\n"); +		return -EINVAL; +	} + +	if (netxen_nic_validate_product_offs(adapter)) { +		dev_err(&adapter->pdev->dev, +				"unified image: product validation failed\n"); +		return -EINVAL; +	} + +	if (netxen_nic_validate_bootld(adapter)) { +		dev_err(&adapter->pdev->dev, +				"unified image: bootld validation failed\n"); +		return -EINVAL; +	} + +	if (netxen_nic_validate_fw(adapter)) { +		dev_err(&adapter->pdev->dev, +				"unified image: firmware validation failed\n"); +		return -EINVAL; +	} + +	return 0; +}  static struct uni_data_desc *nx_get_data_desc(struct netxen_adapter *adapter,  			u32 section, u32 idx_offset) @@ -890,6 +1020,16 @@ netxen_load_firmware(struct netxen_adapter *adapter)  			flashaddr += 8;  		} + +		size = (__force u32)nx_get_fw_size(adapter) % 8; +		if (size) { +			data = cpu_to_le64(ptr64[i]); + +			if (adapter->pci_mem_write(adapter, +						flashaddr, data)) +				return -EIO; +		} +  	} else {  		u64 data;  		u32 hi, lo; @@ -934,27 +1074,23 @@ static int  netxen_validate_firmware(struct netxen_adapter *adapter)  {  	__le32 val; -	u32 ver, min_ver, bios, min_size; +	u32 ver, min_ver, bios;  	struct pci_dev *pdev = adapter->pdev;  	const struct firmware *fw = adapter->fw;  	u8 fw_type = adapter->fw_type;  	if (fw_type == NX_UNIFIED_ROMIMAGE) { -		if (nx_set_product_offs(adapter)) +		if (netxen_nic_validate_unified_romimage(adapter))  			return -EINVAL; - -		min_size = NX_UNI_FW_MIN_SIZE;  	} else {  		val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]);  		if ((__force u32)val != NETXEN_BDINFO_MAGIC)  			return -EINVAL; -		min_size = NX_FW_MIN_SIZE; +		if (fw->size < NX_FW_MIN_SIZE) +			return -EINVAL;  	} -	if (fw->size < min_size) -		return -EINVAL; -  	val = nx_get_fw_version(adapter);  	if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) @@ -1225,10 +1361,12 @@ int netxen_init_firmware(struct netxen_adapter *adapter)  		return err;  	NXWR32(adapter, CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT); -	NXWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC);  	NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE);  	NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); +	if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) +		NXWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC); +  	return err;  } @@ -1763,6 +1901,5 @@ netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,  void netxen_nic_clear_stats(struct netxen_adapter *adapter)  {  	memset(&adapter->stats, 0, sizeof(adapter->stats)); -	return;  }  |