Commit 5fc499b6 authored by Shivasharan S's avatar Shivasharan S Committed by Martin K. Petersen
Browse files

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: default avatarShivasharan S <shivasharan.srikanteshwara@broadcom.com>
Signed-off-by: default avatarKashyap Desai <kashyap.desai@broadcom.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Reviewed-by: default avatarTomas Henzl <thenzl@redhat.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent b4a42213
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2488,4 +2488,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason);
int megasas_task_abort_fusion(struct scsi_cmnd *scmd);
int megasas_reset_target_fusion(struct scsi_cmnd *scmd);
u32 mega_mod64(u64 dividend, u32 divisor);
int megasas_alloc_fusion_context(struct megasas_instance *instance);
void megasas_free_fusion_context(struct megasas_instance *instance);
#endif				/*LSI_MEGARAID_SAS_H */
+4 −11
Original line number Diff line number Diff line
@@ -6029,18 +6029,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
	case PCI_DEVICE_ID_LSI_CUTLASS_52:
	case PCI_DEVICE_ID_LSI_CUTLASS_53:
	{
		instance->ctrl_context_pages =
			get_order(sizeof(struct fusion_context));
		instance->ctrl_context = (void *)__get_free_pages(GFP_KERNEL,
				instance->ctrl_context_pages);
		if (!instance->ctrl_context) {
			dev_printk(KERN_DEBUG, &pdev->dev, "Failed to allocate "
			       "memory for Fusion context info\n");
		if (megasas_alloc_fusion_context(instance)) {
			megasas_free_fusion_context(instance);
			goto fail_alloc_dma_buf;
		}
		fusion = instance->ctrl_context;
		memset(fusion, 0,
			((1 << PAGE_SHIFT) << instance->ctrl_context_pages));

		if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
			(instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA))
			fusion->adapter_type = THUNDERBOLT_SERIES;
@@ -6683,8 +6677,7 @@ skip_firing_dcmds:
					fusion->pd_seq_sync[i],
					fusion->pd_seq_phys[i]);
		}
		free_pages((ulong)instance->ctrl_context,
			instance->ctrl_context_pages);
		megasas_free_fusion_context(instance);
	} else {
		megasas_release_mfi(instance);
		pci_free_consistent(pdev, sizeof(u32),
+2 −1
Original line number Diff line number Diff line
@@ -489,6 +489,7 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance)
	if (instance->UnevenSpanSupport)
		mr_update_span_set(drv_map, ldSpanInfo);

	if (lbInfo)
		mr_update_load_balance_params(drv_map, lbInfo);

	num_lds = le16_to_cpu(drv_map->raidMap.ldCount);
+66 −5
Original line number Diff line number Diff line
@@ -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,7 +2398,8 @@ 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) &&
		if (fusion->load_balance_info &&
			(fusion->load_balance_info[device_id].loadBalanceFlag) &&
			(io_info.isRead)) {
			io_info.devHandle =
				get_updated_dev_handle(instance,
@@ -4270,9 +4272,10 @@ transition_to_ready:
				retval = FAILED;
			}
			/* Reset load balance info */
			if (fusion->load_balance_info)
				memset(fusion->load_balance_info, 0,
			       sizeof(struct LD_LOAD_BALANCE_INFO)
			       *MAX_LOGICAL_DRIVES_EXT);
				       (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,
+2 −1
Original line number Diff line number Diff line
@@ -1287,7 +1287,8 @@ struct fusion_context {
	struct MR_PD_CFG_SEQ_NUM_SYNC	*pd_seq_sync[JBOD_MAPS_COUNT];
	dma_addr_t pd_seq_phys[JBOD_MAPS_COUNT];
	u8 fast_path_io;
	struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES_EXT];
	struct LD_LOAD_BALANCE_INFO *load_balance_info;
	u32 load_balance_info_pages;
	LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES_EXT];
	u8 adapter_type;
	struct LD_STREAM_DETECT **stream_detect_by_ld;