diff options
author | Shivasharan S <shivasharan.srikanteshwara@broadcom.com> | 2017-02-10 00:59:17 -0800 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2017-02-13 07:26:22 -0500 |
commit | 5fc499b612c5401a7ae0674086befcdf8b148516 (patch) | |
tree | c2e4b571415353ed30bfdb6ce89fc5bbaba25e8f /drivers/scsi/megaraid/megaraid_sas_fusion.c | |
parent | b4a42213a7eb8ec8556f27e6750bbc5c9193e86e (diff) | |
download | talos-obmc-linux-5fc499b612c5401a7ae0674086befcdf8b148516.tar.gz talos-obmc-linux-5fc499b612c5401a7ae0674086befcdf8b148516.zip |
scsi: megaraid_sas: reduce size of fusion_context and use vmalloc if kmalloc fails
Currently fusion context has fixed array load_balance_info. Use dynamic
allocation. In few places, driver do not want physically contigious
memory. Attempt to use vmalloc if physical contiguous memory is not
available.
Signed-off-by: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas_fusion.c')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_fusion.c | 71 |
1 files changed, 66 insertions, 5 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 1252a3c08e1a..9019b82b467f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -47,6 +47,7 @@ #include <linux/blkdev.h> #include <linux/mutex.h> #include <linux/poll.h> +#include <linux/vmalloc.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -2397,8 +2398,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); } - if ((fusion->load_balance_info[device_id].loadBalanceFlag) && - (io_info.isRead)) { + if (fusion->load_balance_info && + (fusion->load_balance_info[device_id].loadBalanceFlag) && + (io_info.isRead)) { io_info.devHandle = get_updated_dev_handle(instance, &fusion->load_balance_info[device_id], @@ -4270,9 +4272,10 @@ transition_to_ready: retval = FAILED; } /* Reset load balance info */ - memset(fusion->load_balance_info, 0, - sizeof(struct LD_LOAD_BALANCE_INFO) - *MAX_LOGICAL_DRIVES_EXT); + if (fusion->load_balance_info) + memset(fusion->load_balance_info, 0, + (sizeof(struct LD_LOAD_BALANCE_INFO) * + MAX_LOGICAL_DRIVES_EXT)); if (!megasas_get_map_info(instance)) megasas_sync_map_info(instance); @@ -4426,6 +4429,64 @@ void megasas_fusion_ocr_wq(struct work_struct *work) megasas_reset_fusion(instance->host, 0); } +/* Allocate fusion context */ +int +megasas_alloc_fusion_context(struct megasas_instance *instance) +{ + struct fusion_context *fusion; + + instance->ctrl_context_pages = get_order(sizeof(struct fusion_context)); + instance->ctrl_context = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + instance->ctrl_context_pages); + if (!instance->ctrl_context) { + /* fall back to using vmalloc for fusion_context */ + instance->ctrl_context = vzalloc(sizeof(struct fusion_context)); + if (!instance->ctrl_context) { + dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + } + + fusion = instance->ctrl_context; + + fusion->load_balance_info_pages = get_order(MAX_LOGICAL_DRIVES_EXT * + sizeof(struct LD_LOAD_BALANCE_INFO)); + fusion->load_balance_info = + (struct LD_LOAD_BALANCE_INFO *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + fusion->load_balance_info_pages); + if (!fusion->load_balance_info) { + fusion->load_balance_info = vzalloc(MAX_LOGICAL_DRIVES_EXT * + sizeof(struct LD_LOAD_BALANCE_INFO)); + if (!fusion->load_balance_info) + dev_err(&instance->pdev->dev, "Failed to allocate load_balance_info, " + "continuing without Load Balance support\n"); + } + + return 0; +} + +void +megasas_free_fusion_context(struct megasas_instance *instance) +{ + struct fusion_context *fusion = instance->ctrl_context; + + if (fusion) { + if (fusion->load_balance_info) { + if (is_vmalloc_addr(fusion->load_balance_info)) + vfree(fusion->load_balance_info); + else + free_pages((ulong)fusion->load_balance_info, + fusion->load_balance_info_pages); + } + + if (is_vmalloc_addr(fusion)) + vfree(fusion); + else + free_pages((ulong)fusion, + instance->ctrl_context_pages); + } +} + struct megasas_instance_template megasas_instance_template_fusion = { .enable_intr = megasas_enable_intr_fusion, .disable_intr = megasas_disable_intr_fusion, |