aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/megaraid/megaraid_sas_base.c
diff options
context:
space:
mode:
authorShivasharan S <shivasharan.srikanteshwara@broadcom.com>2018-12-17 00:47:40 -0800
committerMartin K. Petersen <martin.petersen@oracle.com>2018-12-19 21:37:15 -0500
commit272652fcbf1adf6321efe288583fa4a30a15af31 (patch)
treea12bc33d235f0357c5341dcc175b5b968f72d16a /drivers/scsi/megaraid/megaraid_sas_base.c
parentscsi: megaraid_sas: changes to function prototypes (diff)
downloadlinux-dev-272652fcbf1adf6321efe288583fa4a30a15af31.tar.xz
linux-dev-272652fcbf1adf6321efe288583fa4a30a15af31.zip
scsi: megaraid_sas: add retry logic in megasas_readl
Due to hardware errata in Aero controllers, reads to certain fusion registers could intermittently return zero. This behavior is transient in nature and subsequent reads will return valid value. For Aero controllers, any calls to readl to read from certain registers will be retried for maximum three times, if read returns zero. Signed-off-by: Shivasharan S <shivasharan.srikanteshwara@broadcom.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to '')
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c39
1 files changed, 32 insertions, 7 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index d99390cf5963..d0f4075fe36e 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -220,6 +220,28 @@ megasas_free_ctrl_dma_buffers(struct megasas_instance *instance);
static inline void
megasas_init_ctrl_params(struct megasas_instance *instance);
+u32 megasas_readl(struct megasas_instance *instance,
+ const volatile void __iomem *addr)
+{
+ u32 i = 0, ret_val;
+ /*
+ * Due to a HW errata in Aero controllers, reads to certain
+ * Fusion registers could intermittently return all zeroes.
+ * This behavior is transient in nature and subsequent reads will
+ * return valid value. As a workaround in driver, retry readl for
+ * upto three times until a non-zero value is read.
+ */
+ if (instance->adapter_type == AERO_SERIES) {
+ do {
+ ret_val = readl(addr);
+ i++;
+ } while (ret_val == 0 && i < 3);
+ return ret_val;
+ } else {
+ return readl(addr);
+ }
+}
+
/**
* megasas_set_dma_settings - Populate DMA address, length and flags for DCMDs
* @instance: Adapter soft state
@@ -3842,7 +3864,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
if (instance->adapter_type != MFI_SERIES) {
for (i = 0; i < (10 * 1000); i += 20) {
- if (readl(
+ if (megasas_readl(
+ instance,
&instance->
reg_set->
doorbell) & 1)
@@ -5401,7 +5424,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
if (instance->adapter_type >= VENTURA_SERIES) {
scratch_pad_2 =
- readl(&instance->reg_set->outbound_scratch_pad_2);
+ megasas_readl(instance,
+ &instance->reg_set->outbound_scratch_pad_2);
instance->max_raid_mapsize = ((scratch_pad_2 >>
MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT) &
MR_MAX_RAID_MAP_SIZE_MASK);
@@ -5413,8 +5437,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
if (msix_enable && !msix_disable) {
int irq_flags = PCI_IRQ_MSIX;
- scratch_pad_1 = readl
- (&instance->reg_set->outbound_scratch_pad_1);
+ scratch_pad_1 = megasas_readl
+ (instance, &instance->reg_set->outbound_scratch_pad_1);
/* Check max MSI-X vectors */
if (fusion) {
if (instance->adapter_type == THUNDERBOLT_SERIES) {
@@ -5525,7 +5549,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
if (instance->adapter_type >= VENTURA_SERIES) {
scratch_pad_3 =
- readl(&instance->reg_set->outbound_scratch_pad_3);
+ megasas_readl(instance,
+ &instance->reg_set->outbound_scratch_pad_3);
if ((scratch_pad_3 & MR_NVME_PAGE_SIZE_MASK) >=
MR_DEFAULT_NVME_PAGE_SHIFT)
instance->nvme_page_size =
@@ -6193,8 +6218,8 @@ megasas_set_dma_mask(struct megasas_instance *instance)
* If 32 bit DMA mask fails, then try for 64 bit mask
* for FW capable of handling 64 bit DMA.
*/
- scratch_pad_1 = readl
- (&instance->reg_set->outbound_scratch_pad_1);
+ scratch_pad_1 = megasas_readl
+ (instance, &instance->reg_set->outbound_scratch_pad_1);
if (!(scratch_pad_1 & MR_CAN_HANDLE_64_BIT_DMA_OFFSET))
goto fail_set_dma_mask;