isci: Move firmware loading to per PCI device
Moved the firmware loading from per adapter to per PCI device. This should prevent firmware from being loaded twice becuase of 2 SCU controller per PCI device. We do have to do it per PCI device because request_firmware() requires a struct device passed in. Signed-off-by: Dave Jiang <dave.jiang@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
92cd51153d
commit
858d4aa741
|
@ -354,67 +354,6 @@ void isci_host_deinit(struct isci_host *ihost)
|
||||||
scic_controller_reset(scic);
|
scic_controller_reset(scic);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int isci_verify_firmware(const struct firmware *fw,
|
|
||||||
struct isci_firmware *isci_fw)
|
|
||||||
{
|
|
||||||
const u8 *tmp;
|
|
||||||
|
|
||||||
if (fw->size < ISCI_FIRMWARE_MIN_SIZE)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
tmp = fw->data;
|
|
||||||
|
|
||||||
/* 12th char should be the NULL terminate for the ID string */
|
|
||||||
if (tmp[11] != '\0')
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (strncmp("#SCU MAGIC#", tmp, 11) != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
isci_fw->id = tmp;
|
|
||||||
isci_fw->version = fw->data[ISCI_FW_VER_OFS];
|
|
||||||
isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS];
|
|
||||||
|
|
||||||
tmp = fw->data + ISCI_FW_DATA_OFS;
|
|
||||||
|
|
||||||
while (*tmp != ISCI_FW_HDR_EOF) {
|
|
||||||
switch (*tmp) {
|
|
||||||
case ISCI_FW_HDR_PHYMASK:
|
|
||||||
tmp++;
|
|
||||||
isci_fw->phy_masks_size = *tmp;
|
|
||||||
tmp++;
|
|
||||||
isci_fw->phy_masks = (const u32 *)tmp;
|
|
||||||
tmp += sizeof(u32) * isci_fw->phy_masks_size;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ISCI_FW_HDR_PHYGEN:
|
|
||||||
tmp++;
|
|
||||||
isci_fw->phy_gens_size = *tmp;
|
|
||||||
tmp++;
|
|
||||||
isci_fw->phy_gens = (const u32 *)tmp;
|
|
||||||
tmp += sizeof(u32) * isci_fw->phy_gens_size;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ISCI_FW_HDR_SASADDR:
|
|
||||||
tmp++;
|
|
||||||
isci_fw->sas_addrs_size = *tmp;
|
|
||||||
tmp++;
|
|
||||||
isci_fw->sas_addrs = (const u64 *)tmp;
|
|
||||||
tmp += sizeof(u64) * isci_fw->sas_addrs_size;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
pr_err("bad field in firmware binary blob\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_info("isci firmware v%u.%u loaded.\n",
|
|
||||||
isci_fw->version, isci_fw->subversion);
|
|
||||||
|
|
||||||
return SCI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __iomem *scu_base(struct isci_host *isci_host)
|
static void __iomem *scu_base(struct isci_host *isci_host)
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev = isci_host->pdev;
|
struct pci_dev *pdev = isci_host->pdev;
|
||||||
|
@ -442,8 +381,6 @@ int isci_host_init(struct isci_host *isci_host)
|
||||||
struct scic_sds_port *scic_port;
|
struct scic_sds_port *scic_port;
|
||||||
union scic_oem_parameters scic_oem_params;
|
union scic_oem_parameters scic_oem_params;
|
||||||
union scic_user_parameters scic_user_params;
|
union scic_user_parameters scic_user_params;
|
||||||
const struct firmware *fw = NULL;
|
|
||||||
struct isci_firmware *isci_fw = NULL;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&isci_host->timer_list_struct.timers);
|
INIT_LIST_HEAD(&isci_host->timer_list_struct.timers);
|
||||||
isci_timer_list_construct(
|
isci_timer_list_construct(
|
||||||
|
@ -454,9 +391,11 @@ int isci_host_init(struct isci_host *isci_host)
|
||||||
controller = scic_controller_alloc(&isci_host->pdev->dev);
|
controller = scic_controller_alloc(&isci_host->pdev->dev);
|
||||||
|
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
err = -ENOMEM;
|
dev_err(&isci_host->pdev->dev,
|
||||||
dev_err(&isci_host->pdev->dev, "%s: failed (%d)\n", __func__, err);
|
"%s: failed (%d)\n",
|
||||||
goto out;
|
__func__,
|
||||||
|
err);
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
isci_host->core_controller = controller;
|
isci_host->core_controller = controller;
|
||||||
|
@ -476,8 +415,7 @@ int isci_host_init(struct isci_host *isci_host)
|
||||||
"%s: scic_controller_construct failed - status = %x\n",
|
"%s: scic_controller_construct failed - status = %x\n",
|
||||||
__func__,
|
__func__,
|
||||||
status);
|
status);
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isci_host->sas_ha.dev = &isci_host->pdev->dev;
|
isci_host->sas_ha.dev = &isci_host->pdev->dev;
|
||||||
|
@ -487,93 +425,52 @@ int isci_host_init(struct isci_host *isci_host)
|
||||||
* set association host adapter struct in core controller.
|
* set association host adapter struct in core controller.
|
||||||
*/
|
*/
|
||||||
sci_object_set_association(isci_host->core_controller,
|
sci_object_set_association(isci_host->core_controller,
|
||||||
(void *)isci_host
|
(void *)isci_host);
|
||||||
);
|
|
||||||
|
|
||||||
/* grab initial values stored in the controller object for OEM and USER
|
/* grab initial values stored in the controller object for OEM and USER
|
||||||
* parameters */
|
* parameters */
|
||||||
scic_oem_parameters_get(controller, &scic_oem_params);
|
scic_oem_parameters_get(controller, &scic_oem_params);
|
||||||
scic_user_parameters_get(controller, &scic_user_params);
|
scic_user_parameters_get(controller, &scic_user_params);
|
||||||
|
|
||||||
isci_fw = devm_kzalloc(&isci_host->pdev->dev,
|
if (isci_firmware) {
|
||||||
sizeof(struct isci_firmware),
|
/* grab any OEM and USER parameters specified in binary blob */
|
||||||
GFP_KERNEL);
|
|
||||||
if (!isci_fw) {
|
|
||||||
dev_warn(&isci_host->pdev->dev,
|
|
||||||
"allocating firmware struct failed\n");
|
|
||||||
dev_warn(&isci_host->pdev->dev,
|
|
||||||
"Default OEM configuration being used:"
|
|
||||||
" 4 narrow ports, and default SAS Addresses\n");
|
|
||||||
goto set_default_params;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = request_firmware(&fw, ISCI_FW_NAME, &isci_host->pdev->dev);
|
|
||||||
if (status) {
|
|
||||||
dev_warn(&isci_host->pdev->dev,
|
|
||||||
"Loading firmware failed, using default values\n");
|
|
||||||
dev_warn(&isci_host->pdev->dev,
|
|
||||||
"Default OEM configuration being used:"
|
|
||||||
" 4 narrow ports, and default SAS Addresses\n");
|
|
||||||
goto set_default_params;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
status = isci_verify_firmware(fw, isci_fw);
|
|
||||||
if (status != SCI_SUCCESS) {
|
|
||||||
dev_warn(&isci_host->pdev->dev,
|
|
||||||
"firmware verification failed\n");
|
|
||||||
dev_warn(&isci_host->pdev->dev,
|
|
||||||
"Default OEM configuration being used:"
|
|
||||||
" 4 narrow ports, and default SAS "
|
|
||||||
"Addresses\n");
|
|
||||||
goto set_default_params;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* grab any OEM and USER parameters specified at module load */
|
|
||||||
status = isci_parse_oem_parameters(&scic_oem_params,
|
status = isci_parse_oem_parameters(&scic_oem_params,
|
||||||
isci_host->id, isci_fw);
|
isci_host->id,
|
||||||
|
isci_firmware);
|
||||||
if (status != SCI_SUCCESS) {
|
if (status != SCI_SUCCESS) {
|
||||||
dev_warn(&isci_host->pdev->dev,
|
dev_warn(&isci_host->pdev->dev,
|
||||||
"parsing firmware oem parameters failed\n");
|
"parsing firmware oem parameters failed\n");
|
||||||
err = -EINVAL;
|
return -EINVAL;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status = isci_parse_user_parameters(&scic_user_params,
|
status = isci_parse_user_parameters(&scic_user_params,
|
||||||
isci_host->id, isci_fw);
|
isci_host->id,
|
||||||
|
isci_firmware);
|
||||||
if (status != SCI_SUCCESS) {
|
if (status != SCI_SUCCESS) {
|
||||||
dev_warn(&isci_host->pdev->dev,
|
dev_warn(&isci_host->pdev->dev,
|
||||||
"%s: isci_parse_user_parameters"
|
"%s: isci_parse_user_parameters"
|
||||||
" failed\n", __func__);
|
" failed\n", __func__);
|
||||||
err = -EINVAL;
|
return -EINVAL;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
set_default_params:
|
|
||||||
|
|
||||||
status = scic_oem_parameters_set(isci_host->core_controller,
|
status = scic_oem_parameters_set(isci_host->core_controller,
|
||||||
&scic_oem_params
|
&scic_oem_params);
|
||||||
);
|
|
||||||
|
|
||||||
if (status != SCI_SUCCESS) {
|
if (status != SCI_SUCCESS) {
|
||||||
dev_warn(&isci_host->pdev->dev,
|
dev_warn(&isci_host->pdev->dev,
|
||||||
"%s: scic_oem_parameters_set failed\n",
|
"%s: scic_oem_parameters_set failed\n",
|
||||||
__func__);
|
__func__);
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status = scic_user_parameters_set(isci_host->core_controller,
|
status = scic_user_parameters_set(isci_host->core_controller,
|
||||||
&scic_user_params
|
&scic_user_params);
|
||||||
);
|
|
||||||
|
|
||||||
if (status != SCI_SUCCESS) {
|
if (status != SCI_SUCCESS) {
|
||||||
dev_warn(&isci_host->pdev->dev,
|
dev_warn(&isci_host->pdev->dev,
|
||||||
"%s: scic_user_parameters_set failed\n",
|
"%s: scic_user_parameters_set failed\n",
|
||||||
__func__);
|
__func__);
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto out;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = scic_controller_initialize(isci_host->core_controller);
|
status = scic_controller_initialize(isci_host->core_controller);
|
||||||
|
@ -582,8 +479,7 @@ int isci_host_init(struct isci_host *isci_host)
|
||||||
"%s: scic_controller_initialize failed -"
|
"%s: scic_controller_initialize failed -"
|
||||||
" status = 0x%x\n",
|
" status = 0x%x\n",
|
||||||
__func__, status);
|
__func__, status);
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasklet_init(&isci_host->completion_tasklet,
|
tasklet_init(&isci_host->completion_tasklet,
|
||||||
|
@ -598,7 +494,7 @@ int isci_host_init(struct isci_host *isci_host)
|
||||||
err = isci_host_mdl_allocate_coherent(isci_host);
|
err = isci_host_mdl_allocate_coherent(isci_host);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto err_out;
|
return err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* keep the pool alloc size around, will use it for a bounds checking
|
* keep the pool alloc size around, will use it for a bounds checking
|
||||||
|
@ -610,40 +506,27 @@ int isci_host_init(struct isci_host *isci_host)
|
||||||
isci_host->dma_pool_alloc_size,
|
isci_host->dma_pool_alloc_size,
|
||||||
SLAB_HWCACHE_ALIGN, 0);
|
SLAB_HWCACHE_ALIGN, 0);
|
||||||
|
|
||||||
if (!isci_host->dma_pool) {
|
if (!isci_host->dma_pool)
|
||||||
err = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto req_obj_err_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (index = 0; index < SCI_MAX_PORTS; index++) {
|
for (index = 0; index < SCI_MAX_PORTS; index++)
|
||||||
isci_port_init(&isci_host->isci_ports[index],
|
isci_port_init(&isci_host->isci_ports[index],
|
||||||
isci_host, index);
|
isci_host,
|
||||||
}
|
index);
|
||||||
|
|
||||||
for (index = 0; index < SCI_MAX_PHYS; index++)
|
for (index = 0; index < SCI_MAX_PHYS; index++)
|
||||||
isci_phy_init(&isci_host->phys[index], isci_host, index);
|
isci_phy_init(&isci_host->phys[index], isci_host, index);
|
||||||
|
|
||||||
/* Why are we doing this? Is this even necessary? */
|
/* Why are we doing this? Is this even necessary? */
|
||||||
memcpy(&isci_host->sas_addr[0], &isci_host->phys[0].sas_addr[0],
|
memcpy(&isci_host->sas_addr[0],
|
||||||
|
&isci_host->phys[0].sas_addr[0],
|
||||||
SAS_ADDR_SIZE);
|
SAS_ADDR_SIZE);
|
||||||
|
|
||||||
/* Start the ports */
|
/* Start the ports */
|
||||||
for (index = 0; index < SCI_MAX_PORTS; index++) {
|
for (index = 0; index < SCI_MAX_PORTS; index++) {
|
||||||
|
|
||||||
scic_controller_get_port_handle(controller, index, &scic_port);
|
scic_controller_get_port_handle(controller, index, &scic_port);
|
||||||
scic_port_start(scic_port);
|
scic_port_start(scic_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
goto out;
|
return 0;
|
||||||
|
|
||||||
/* SPB_Debug: destroy request object cache */
|
|
||||||
req_obj_err_out:
|
|
||||||
/* SPB_Debug: destroy remote object cache */
|
|
||||||
err_out:
|
|
||||||
/* SPB_Debug: undo controller init, construct and alloc, remove from parent
|
|
||||||
* controller list. */
|
|
||||||
out:
|
|
||||||
if (fw)
|
|
||||||
release_firmware(fw);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,8 @@ static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = {
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct isci_firmware *isci_firmware;
|
||||||
|
|
||||||
static int __devinit isci_pci_probe(
|
static int __devinit isci_pci_probe(
|
||||||
struct pci_dev *pdev,
|
struct pci_dev *pdev,
|
||||||
const struct pci_device_id *device_id_p);
|
const struct pci_device_id *device_id_p);
|
||||||
|
@ -519,11 +521,73 @@ static void check_si_rev(struct pci_dev *pdev)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int isci_verify_firmware(const struct firmware *fw,
|
||||||
|
struct isci_firmware *isci_fw)
|
||||||
|
{
|
||||||
|
const u8 *tmp;
|
||||||
|
|
||||||
|
if (fw->size < ISCI_FIRMWARE_MIN_SIZE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
tmp = fw->data;
|
||||||
|
|
||||||
|
/* 12th char should be the NULL terminate for the ID string */
|
||||||
|
if (tmp[11] != '\0')
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (strncmp("#SCU MAGIC#", tmp, 11) != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
isci_fw->id = tmp;
|
||||||
|
isci_fw->version = fw->data[ISCI_FW_VER_OFS];
|
||||||
|
isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS];
|
||||||
|
|
||||||
|
tmp = fw->data + ISCI_FW_DATA_OFS;
|
||||||
|
|
||||||
|
while (*tmp != ISCI_FW_HDR_EOF) {
|
||||||
|
switch (*tmp) {
|
||||||
|
case ISCI_FW_HDR_PHYMASK:
|
||||||
|
tmp++;
|
||||||
|
isci_fw->phy_masks_size = *tmp;
|
||||||
|
tmp++;
|
||||||
|
isci_fw->phy_masks = (const u32 *)tmp;
|
||||||
|
tmp += sizeof(u32) * isci_fw->phy_masks_size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ISCI_FW_HDR_PHYGEN:
|
||||||
|
tmp++;
|
||||||
|
isci_fw->phy_gens_size = *tmp;
|
||||||
|
tmp++;
|
||||||
|
isci_fw->phy_gens = (const u32 *)tmp;
|
||||||
|
tmp += sizeof(u32) * isci_fw->phy_gens_size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ISCI_FW_HDR_SASADDR:
|
||||||
|
tmp++;
|
||||||
|
isci_fw->sas_addrs_size = *tmp;
|
||||||
|
tmp++;
|
||||||
|
isci_fw->sas_addrs = (const u64 *)tmp;
|
||||||
|
tmp += sizeof(u64) * isci_fw->sas_addrs_size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
pr_err("bad field in firmware binary blob\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("isci firmware v%u.%u loaded.\n",
|
||||||
|
isci_fw->version, isci_fw->subversion);
|
||||||
|
|
||||||
|
return SCI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
{
|
{
|
||||||
struct isci_pci_info *pci_info;
|
struct isci_pci_info *pci_info;
|
||||||
int err, i;
|
int err, i;
|
||||||
struct isci_host *isci_host;
|
struct isci_host *isci_host;
|
||||||
|
const struct firmware *fw = NULL;
|
||||||
|
|
||||||
check_si_rev(pdev);
|
check_si_rev(pdev);
|
||||||
|
|
||||||
|
@ -532,6 +596,33 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
pci_set_drvdata(pdev, pci_info);
|
pci_set_drvdata(pdev, pci_info);
|
||||||
|
|
||||||
|
err = request_firmware(&fw, ISCI_FW_NAME, &pdev->dev);
|
||||||
|
if (err) {
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"Loading firmware failed, using default values\n");
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"Default OEM configuration being used:"
|
||||||
|
" 4 narrow ports, and default SAS Addresses\n");
|
||||||
|
} else {
|
||||||
|
isci_firmware = devm_kzalloc(&pdev->dev,
|
||||||
|
sizeof(struct isci_firmware),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (isci_firmware) {
|
||||||
|
err = isci_verify_firmware(fw, isci_firmware);
|
||||||
|
if (err != SCI_SUCCESS) {
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"firmware verification failed\n");
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"Default OEM configuration being used:"
|
||||||
|
" 4 narrow ports, and default SAS "
|
||||||
|
"Addresses\n");
|
||||||
|
devm_kfree(&pdev->dev, isci_firmware);
|
||||||
|
isci_firmware = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_firmware(fw);
|
||||||
|
}
|
||||||
|
|
||||||
err = isci_pci_init(pdev);
|
err = isci_pci_init(pdev);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -86,6 +86,7 @@
|
||||||
#include "sci_status.h"
|
#include "sci_status.h"
|
||||||
|
|
||||||
extern struct kmem_cache *isci_kmem_cache;
|
extern struct kmem_cache *isci_kmem_cache;
|
||||||
|
extern struct isci_firmware *isci_firmware;
|
||||||
|
|
||||||
#define ISCI_FW_NAME "isci/isci_firmware.bin"
|
#define ISCI_FW_NAME "isci/isci_firmware.bin"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue