162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Adaptec AAC series RAID controller driver 462306a36Sopenharmony_ci * (c) Copyright 2001 Red Hat Inc. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * based on the old aacraid driver that is.. 762306a36Sopenharmony_ci * Adaptec aacraid device driver for Linux. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (c) 2000-2010 Adaptec, Inc. 1062306a36Sopenharmony_ci * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 1162306a36Sopenharmony_ci * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Module Name: 1462306a36Sopenharmony_ci * src.c 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Abstract: Hardware Device Interface for PMC SRC based controllers 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/types.h> 2262306a36Sopenharmony_ci#include <linux/pci.h> 2362306a36Sopenharmony_ci#include <linux/spinlock.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/blkdev.h> 2662306a36Sopenharmony_ci#include <linux/delay.h> 2762306a36Sopenharmony_ci#include <linux/completion.h> 2862306a36Sopenharmony_ci#include <linux/time.h> 2962306a36Sopenharmony_ci#include <linux/interrupt.h> 3062306a36Sopenharmony_ci#include <scsi/scsi_host.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "aacraid.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int aac_src_get_sync_status(struct aac_dev *dev); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic irqreturn_t aac_src_intr_message(int irq, void *dev_id) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct aac_msix_ctx *ctx; 3962306a36Sopenharmony_ci struct aac_dev *dev; 4062306a36Sopenharmony_ci unsigned long bellbits, bellbits_shifted; 4162306a36Sopenharmony_ci int vector_no; 4262306a36Sopenharmony_ci int isFastResponse, mode; 4362306a36Sopenharmony_ci u32 index, handle; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci ctx = (struct aac_msix_ctx *)dev_id; 4662306a36Sopenharmony_ci dev = ctx->dev; 4762306a36Sopenharmony_ci vector_no = ctx->vector_no; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (dev->msi_enabled) { 5062306a36Sopenharmony_ci mode = AAC_INT_MODE_MSI; 5162306a36Sopenharmony_ci if (vector_no == 0) { 5262306a36Sopenharmony_ci bellbits = src_readl(dev, MUnit.ODR_MSI); 5362306a36Sopenharmony_ci if (bellbits & 0x40000) 5462306a36Sopenharmony_ci mode |= AAC_INT_MODE_AIF; 5562306a36Sopenharmony_ci if (bellbits & 0x1000) 5662306a36Sopenharmony_ci mode |= AAC_INT_MODE_SYNC; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci } else { 5962306a36Sopenharmony_ci mode = AAC_INT_MODE_INTX; 6062306a36Sopenharmony_ci bellbits = src_readl(dev, MUnit.ODR_R); 6162306a36Sopenharmony_ci if (bellbits & PmDoorBellResponseSent) { 6262306a36Sopenharmony_ci bellbits = PmDoorBellResponseSent; 6362306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, bellbits); 6462306a36Sopenharmony_ci src_readl(dev, MUnit.ODR_C); 6562306a36Sopenharmony_ci } else { 6662306a36Sopenharmony_ci bellbits_shifted = (bellbits >> SRC_ODR_SHIFT); 6762306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, bellbits); 6862306a36Sopenharmony_ci src_readl(dev, MUnit.ODR_C); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (bellbits_shifted & DoorBellAifPending) 7162306a36Sopenharmony_ci mode |= AAC_INT_MODE_AIF; 7262306a36Sopenharmony_ci else if (bellbits_shifted & OUTBOUNDDOORBELL_0) 7362306a36Sopenharmony_ci mode |= AAC_INT_MODE_SYNC; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (mode & AAC_INT_MODE_SYNC) { 7862306a36Sopenharmony_ci unsigned long sflags; 7962306a36Sopenharmony_ci struct list_head *entry; 8062306a36Sopenharmony_ci int send_it = 0; 8162306a36Sopenharmony_ci extern int aac_sync_mode; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (!aac_sync_mode && !dev->msi_enabled) { 8462306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, bellbits); 8562306a36Sopenharmony_ci src_readl(dev, MUnit.ODR_C); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (dev->sync_fib) { 8962306a36Sopenharmony_ci if (dev->sync_fib->callback) 9062306a36Sopenharmony_ci dev->sync_fib->callback(dev->sync_fib->callback_data, 9162306a36Sopenharmony_ci dev->sync_fib); 9262306a36Sopenharmony_ci spin_lock_irqsave(&dev->sync_fib->event_lock, sflags); 9362306a36Sopenharmony_ci if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) { 9462306a36Sopenharmony_ci dev->management_fib_count--; 9562306a36Sopenharmony_ci complete(&dev->sync_fib->event_wait); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sync_fib->event_lock, 9862306a36Sopenharmony_ci sflags); 9962306a36Sopenharmony_ci spin_lock_irqsave(&dev->sync_lock, sflags); 10062306a36Sopenharmony_ci if (!list_empty(&dev->sync_fib_list)) { 10162306a36Sopenharmony_ci entry = dev->sync_fib_list.next; 10262306a36Sopenharmony_ci dev->sync_fib = list_entry(entry, 10362306a36Sopenharmony_ci struct fib, 10462306a36Sopenharmony_ci fiblink); 10562306a36Sopenharmony_ci list_del(entry); 10662306a36Sopenharmony_ci send_it = 1; 10762306a36Sopenharmony_ci } else { 10862306a36Sopenharmony_ci dev->sync_fib = NULL; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sync_lock, sflags); 11162306a36Sopenharmony_ci if (send_it) { 11262306a36Sopenharmony_ci aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB, 11362306a36Sopenharmony_ci (u32)dev->sync_fib->hw_fib_pa, 11462306a36Sopenharmony_ci 0, 0, 0, 0, 0, 11562306a36Sopenharmony_ci NULL, NULL, NULL, NULL, NULL); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci if (!dev->msi_enabled) 11962306a36Sopenharmony_ci mode = 0; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (mode & AAC_INT_MODE_AIF) { 12462306a36Sopenharmony_ci /* handle AIF */ 12562306a36Sopenharmony_ci if (dev->sa_firmware) { 12662306a36Sopenharmony_ci u32 events = src_readl(dev, MUnit.SCR0); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci aac_intr_normal(dev, events, 1, 0, NULL); 12962306a36Sopenharmony_ci writel(events, &dev->IndexRegs->Mailbox[0]); 13062306a36Sopenharmony_ci src_writel(dev, MUnit.IDR, 1 << 23); 13162306a36Sopenharmony_ci } else { 13262306a36Sopenharmony_ci if (dev->aif_thread && dev->fsa_dev) 13362306a36Sopenharmony_ci aac_intr_normal(dev, 0, 2, 0, NULL); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci if (dev->msi_enabled) 13662306a36Sopenharmony_ci aac_src_access_devreg(dev, AAC_CLEAR_AIF_BIT); 13762306a36Sopenharmony_ci mode = 0; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (mode) { 14162306a36Sopenharmony_ci index = dev->host_rrq_idx[vector_no]; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci for (;;) { 14462306a36Sopenharmony_ci isFastResponse = 0; 14562306a36Sopenharmony_ci /* remove toggle bit (31) */ 14662306a36Sopenharmony_ci handle = le32_to_cpu((dev->host_rrq[index]) 14762306a36Sopenharmony_ci & 0x7fffffff); 14862306a36Sopenharmony_ci /* check fast response bits (30, 1) */ 14962306a36Sopenharmony_ci if (handle & 0x40000000) 15062306a36Sopenharmony_ci isFastResponse = 1; 15162306a36Sopenharmony_ci handle &= 0x0000ffff; 15262306a36Sopenharmony_ci if (handle == 0) 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci handle >>= 2; 15562306a36Sopenharmony_ci if (dev->msi_enabled && dev->max_msix > 1) 15662306a36Sopenharmony_ci atomic_dec(&dev->rrq_outstanding[vector_no]); 15762306a36Sopenharmony_ci aac_intr_normal(dev, handle, 0, isFastResponse, NULL); 15862306a36Sopenharmony_ci dev->host_rrq[index++] = 0; 15962306a36Sopenharmony_ci if (index == (vector_no + 1) * dev->vector_cap) 16062306a36Sopenharmony_ci index = vector_no * dev->vector_cap; 16162306a36Sopenharmony_ci dev->host_rrq_idx[vector_no] = index; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci mode = 0; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return IRQ_HANDLED; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/** 17062306a36Sopenharmony_ci * aac_src_disable_interrupt - Disable interrupts 17162306a36Sopenharmony_ci * @dev: Adapter 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic void aac_src_disable_interrupt(struct aac_dev *dev) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/** 18062306a36Sopenharmony_ci * aac_src_enable_interrupt_message - Enable interrupts 18162306a36Sopenharmony_ci * @dev: Adapter 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic void aac_src_enable_interrupt_message(struct aac_dev *dev) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci aac_src_access_devreg(dev, AAC_ENABLE_INTERRUPT); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/** 19062306a36Sopenharmony_ci * src_sync_cmd - send a command and wait 19162306a36Sopenharmony_ci * @dev: Adapter 19262306a36Sopenharmony_ci * @command: Command to execute 19362306a36Sopenharmony_ci * @p1: first parameter 19462306a36Sopenharmony_ci * @p2: second parameter 19562306a36Sopenharmony_ci * @p3: third parameter 19662306a36Sopenharmony_ci * @p4: forth parameter 19762306a36Sopenharmony_ci * @p5: fifth parameter 19862306a36Sopenharmony_ci * @p6: sixth parameter 19962306a36Sopenharmony_ci * @status: adapter status 20062306a36Sopenharmony_ci * @r1: first return value 20162306a36Sopenharmony_ci * @r2: second return valu 20262306a36Sopenharmony_ci * @r3: third return value 20362306a36Sopenharmony_ci * @r4: forth return value 20462306a36Sopenharmony_ci * 20562306a36Sopenharmony_ci * This routine will send a synchronous command to the adapter and wait 20662306a36Sopenharmony_ci * for its completion. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int src_sync_cmd(struct aac_dev *dev, u32 command, 21062306a36Sopenharmony_ci u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, 21162306a36Sopenharmony_ci u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci unsigned long start; 21462306a36Sopenharmony_ci unsigned long delay; 21562306a36Sopenharmony_ci int ok; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* 21862306a36Sopenharmony_ci * Write the command into Mailbox 0 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci writel(command, &dev->IndexRegs->Mailbox[0]); 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci * Write the parameters into Mailboxes 1 - 6 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci writel(p1, &dev->IndexRegs->Mailbox[1]); 22562306a36Sopenharmony_ci writel(p2, &dev->IndexRegs->Mailbox[2]); 22662306a36Sopenharmony_ci writel(p3, &dev->IndexRegs->Mailbox[3]); 22762306a36Sopenharmony_ci writel(p4, &dev->IndexRegs->Mailbox[4]); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* 23062306a36Sopenharmony_ci * Clear the synch command doorbell to start on a clean slate. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci if (!dev->msi_enabled) 23362306a36Sopenharmony_ci src_writel(dev, 23462306a36Sopenharmony_ci MUnit.ODR_C, 23562306a36Sopenharmony_ci OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* 23862306a36Sopenharmony_ci * Disable doorbell interrupts 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* 24362306a36Sopenharmony_ci * Force the completion of the mask register write before issuing 24462306a36Sopenharmony_ci * the interrupt. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci src_readl(dev, MUnit.OIMR); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* 24962306a36Sopenharmony_ci * Signal that there is a new synch command 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_ci src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if ((!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) && 25462306a36Sopenharmony_ci !dev->in_soft_reset) { 25562306a36Sopenharmony_ci ok = 0; 25662306a36Sopenharmony_ci start = jiffies; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (command == IOP_RESET_ALWAYS) { 25962306a36Sopenharmony_ci /* Wait up to 10 sec */ 26062306a36Sopenharmony_ci delay = 10*HZ; 26162306a36Sopenharmony_ci } else { 26262306a36Sopenharmony_ci /* Wait up to 5 minutes */ 26362306a36Sopenharmony_ci delay = 300*HZ; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci while (time_before(jiffies, start+delay)) { 26662306a36Sopenharmony_ci udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ 26762306a36Sopenharmony_ci /* 26862306a36Sopenharmony_ci * Mon960 will set doorbell0 bit when it has completed the command. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) { 27162306a36Sopenharmony_ci /* 27262306a36Sopenharmony_ci * Clear the doorbell. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ci if (dev->msi_enabled) 27562306a36Sopenharmony_ci aac_src_access_devreg(dev, 27662306a36Sopenharmony_ci AAC_CLEAR_SYNC_BIT); 27762306a36Sopenharmony_ci else 27862306a36Sopenharmony_ci src_writel(dev, 27962306a36Sopenharmony_ci MUnit.ODR_C, 28062306a36Sopenharmony_ci OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); 28162306a36Sopenharmony_ci ok = 1; 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci /* 28562306a36Sopenharmony_ci * Yield the processor in case we are slow 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci msleep(1); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci if (unlikely(ok != 1)) { 29062306a36Sopenharmony_ci /* 29162306a36Sopenharmony_ci * Restore interrupt mask even though we timed out 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci aac_adapter_enable_int(dev); 29462306a36Sopenharmony_ci return -ETIMEDOUT; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci /* 29762306a36Sopenharmony_ci * Pull the synch status from Mailbox 0. 29862306a36Sopenharmony_ci */ 29962306a36Sopenharmony_ci if (status) 30062306a36Sopenharmony_ci *status = readl(&dev->IndexRegs->Mailbox[0]); 30162306a36Sopenharmony_ci if (r1) 30262306a36Sopenharmony_ci *r1 = readl(&dev->IndexRegs->Mailbox[1]); 30362306a36Sopenharmony_ci if (r2) 30462306a36Sopenharmony_ci *r2 = readl(&dev->IndexRegs->Mailbox[2]); 30562306a36Sopenharmony_ci if (r3) 30662306a36Sopenharmony_ci *r3 = readl(&dev->IndexRegs->Mailbox[3]); 30762306a36Sopenharmony_ci if (r4) 30862306a36Sopenharmony_ci *r4 = readl(&dev->IndexRegs->Mailbox[4]); 30962306a36Sopenharmony_ci if (command == GET_COMM_PREFERRED_SETTINGS) 31062306a36Sopenharmony_ci dev->max_msix = 31162306a36Sopenharmony_ci readl(&dev->IndexRegs->Mailbox[5]) & 0xFFFF; 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * Clear the synch command doorbell. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_ci if (!dev->msi_enabled) 31662306a36Sopenharmony_ci src_writel(dev, 31762306a36Sopenharmony_ci MUnit.ODR_C, 31862306a36Sopenharmony_ci OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* 32262306a36Sopenharmony_ci * Restore interrupt mask 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_ci aac_adapter_enable_int(dev); 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/** 32962306a36Sopenharmony_ci * aac_src_interrupt_adapter - interrupt adapter 33062306a36Sopenharmony_ci * @dev: Adapter 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci * Send an interrupt to the i960 and breakpoint it. 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic void aac_src_interrupt_adapter(struct aac_dev *dev) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci src_sync_cmd(dev, BREAKPOINT_REQUEST, 33862306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, 33962306a36Sopenharmony_ci NULL, NULL, NULL, NULL, NULL); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci/** 34362306a36Sopenharmony_ci * aac_src_notify_adapter - send an event to the adapter 34462306a36Sopenharmony_ci * @dev: Adapter 34562306a36Sopenharmony_ci * @event: Event to send 34662306a36Sopenharmony_ci * 34762306a36Sopenharmony_ci * Notify the i960 that something it probably cares about has 34862306a36Sopenharmony_ci * happened. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void aac_src_notify_adapter(struct aac_dev *dev, u32 event) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci switch (event) { 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci case AdapNormCmdQue: 35662306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 35762306a36Sopenharmony_ci INBOUNDDOORBELL_1 << SRC_ODR_SHIFT); 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci case HostNormRespNotFull: 36062306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 36162306a36Sopenharmony_ci INBOUNDDOORBELL_4 << SRC_ODR_SHIFT); 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci case AdapNormRespQue: 36462306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 36562306a36Sopenharmony_ci INBOUNDDOORBELL_2 << SRC_ODR_SHIFT); 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci case HostNormCmdNotFull: 36862306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 36962306a36Sopenharmony_ci INBOUNDDOORBELL_3 << SRC_ODR_SHIFT); 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci case FastIo: 37262306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 37362306a36Sopenharmony_ci INBOUNDDOORBELL_6 << SRC_ODR_SHIFT); 37462306a36Sopenharmony_ci break; 37562306a36Sopenharmony_ci case AdapPrintfDone: 37662306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 37762306a36Sopenharmony_ci INBOUNDDOORBELL_5 << SRC_ODR_SHIFT); 37862306a36Sopenharmony_ci break; 37962306a36Sopenharmony_ci default: 38062306a36Sopenharmony_ci BUG(); 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci/** 38662306a36Sopenharmony_ci * aac_src_start_adapter - activate adapter 38762306a36Sopenharmony_ci * @dev: Adapter 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * Start up processing on an i960 based AAC adapter 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic void aac_src_start_adapter(struct aac_dev *dev) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci union aac_init *init; 39562306a36Sopenharmony_ci int i; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* reset host_rrq_idx first */ 39862306a36Sopenharmony_ci for (i = 0; i < dev->max_msix; i++) { 39962306a36Sopenharmony_ci dev->host_rrq_idx[i] = i * dev->vector_cap; 40062306a36Sopenharmony_ci atomic_set(&dev->rrq_outstanding[i], 0); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci atomic_set(&dev->msix_counter, 0); 40362306a36Sopenharmony_ci dev->fibs_pushed_no = 0; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci init = dev->init; 40662306a36Sopenharmony_ci if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { 40762306a36Sopenharmony_ci init->r8.host_elapsed_seconds = 40862306a36Sopenharmony_ci cpu_to_le32(ktime_get_real_seconds()); 40962306a36Sopenharmony_ci src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, 41062306a36Sopenharmony_ci lower_32_bits(dev->init_pa), 41162306a36Sopenharmony_ci upper_32_bits(dev->init_pa), 41262306a36Sopenharmony_ci sizeof(struct _r8) + 41362306a36Sopenharmony_ci (AAC_MAX_HRRQ - 1) * sizeof(struct _rrq), 41462306a36Sopenharmony_ci 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 41562306a36Sopenharmony_ci } else { 41662306a36Sopenharmony_ci init->r7.host_elapsed_seconds = 41762306a36Sopenharmony_ci cpu_to_le32(ktime_get_real_seconds()); 41862306a36Sopenharmony_ci // We can only use a 32 bit address here 41962306a36Sopenharmony_ci src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, 42062306a36Sopenharmony_ci (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0, 42162306a36Sopenharmony_ci NULL, NULL, NULL, NULL, NULL); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci/** 42762306a36Sopenharmony_ci * aac_src_check_health 42862306a36Sopenharmony_ci * @dev: device to check if healthy 42962306a36Sopenharmony_ci * 43062306a36Sopenharmony_ci * Will attempt to determine if the specified adapter is alive and 43162306a36Sopenharmony_ci * capable of handling requests, returning 0 if alive. 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_cistatic int aac_src_check_health(struct aac_dev *dev) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci u32 status = src_readl(dev, MUnit.OMR); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* 43862306a36Sopenharmony_ci * Check to see if the board panic'd. 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_ci if (unlikely(status & KERNEL_PANIC)) 44162306a36Sopenharmony_ci goto err_blink; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* 44462306a36Sopenharmony_ci * Check to see if the board failed any self tests. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_ci if (unlikely(status & SELF_TEST_FAILED)) 44762306a36Sopenharmony_ci goto err_out; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * Check to see if the board failed any self tests. 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_ci if (unlikely(status & MONITOR_PANIC)) 45362306a36Sopenharmony_ci goto err_out; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* 45662306a36Sopenharmony_ci * Wait for the adapter to be up and running. 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_ci if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) 45962306a36Sopenharmony_ci return -3; 46062306a36Sopenharmony_ci /* 46162306a36Sopenharmony_ci * Everything is OK 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cierr_out: 46662306a36Sopenharmony_ci return -1; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cierr_blink: 46962306a36Sopenharmony_ci return (status >> 16) & 0xFF; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic inline u32 aac_get_vector(struct aac_dev *dev) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci return atomic_inc_return(&dev->msix_counter)%dev->max_msix; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/** 47862306a36Sopenharmony_ci * aac_src_deliver_message 47962306a36Sopenharmony_ci * @fib: fib to issue 48062306a36Sopenharmony_ci * 48162306a36Sopenharmony_ci * Will send a fib, returning 0 if successful. 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_cistatic int aac_src_deliver_message(struct fib *fib) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct aac_dev *dev = fib->dev; 48662306a36Sopenharmony_ci struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; 48762306a36Sopenharmony_ci u32 fibsize; 48862306a36Sopenharmony_ci dma_addr_t address; 48962306a36Sopenharmony_ci struct aac_fib_xporthdr *pFibX; 49062306a36Sopenharmony_ci int native_hba; 49162306a36Sopenharmony_ci#if !defined(writeq) 49262306a36Sopenharmony_ci unsigned long flags; 49362306a36Sopenharmony_ci#endif 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci u16 vector_no; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci atomic_inc(&q->numpending); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci native_hba = (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) ? 1 : 0; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (dev->msi_enabled && dev->max_msix > 1 && 50362306a36Sopenharmony_ci (native_hba || fib->hw_fib_va->header.Command != AifRequest)) { 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) 50662306a36Sopenharmony_ci && dev->sa_firmware) 50762306a36Sopenharmony_ci vector_no = aac_get_vector(dev); 50862306a36Sopenharmony_ci else 50962306a36Sopenharmony_ci vector_no = fib->vector_no; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (native_hba) { 51262306a36Sopenharmony_ci if (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF) { 51362306a36Sopenharmony_ci struct aac_hba_tm_req *tm_req; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci tm_req = (struct aac_hba_tm_req *) 51662306a36Sopenharmony_ci fib->hw_fib_va; 51762306a36Sopenharmony_ci if (tm_req->iu_type == 51862306a36Sopenharmony_ci HBA_IU_TYPE_SCSI_TM_REQ) { 51962306a36Sopenharmony_ci ((struct aac_hba_tm_req *) 52062306a36Sopenharmony_ci fib->hw_fib_va)->reply_qid 52162306a36Sopenharmony_ci = vector_no; 52262306a36Sopenharmony_ci ((struct aac_hba_tm_req *) 52362306a36Sopenharmony_ci fib->hw_fib_va)->request_id 52462306a36Sopenharmony_ci += (vector_no << 16); 52562306a36Sopenharmony_ci } else { 52662306a36Sopenharmony_ci ((struct aac_hba_reset_req *) 52762306a36Sopenharmony_ci fib->hw_fib_va)->reply_qid 52862306a36Sopenharmony_ci = vector_no; 52962306a36Sopenharmony_ci ((struct aac_hba_reset_req *) 53062306a36Sopenharmony_ci fib->hw_fib_va)->request_id 53162306a36Sopenharmony_ci += (vector_no << 16); 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci } else { 53462306a36Sopenharmony_ci ((struct aac_hba_cmd_req *) 53562306a36Sopenharmony_ci fib->hw_fib_va)->reply_qid 53662306a36Sopenharmony_ci = vector_no; 53762306a36Sopenharmony_ci ((struct aac_hba_cmd_req *) 53862306a36Sopenharmony_ci fib->hw_fib_va)->request_id 53962306a36Sopenharmony_ci += (vector_no << 16); 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci } else { 54262306a36Sopenharmony_ci fib->hw_fib_va->header.Handle += (vector_no << 16); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci } else { 54562306a36Sopenharmony_ci vector_no = 0; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci atomic_inc(&dev->rrq_outstanding[vector_no]); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (native_hba) { 55162306a36Sopenharmony_ci address = fib->hw_fib_pa; 55262306a36Sopenharmony_ci fibsize = (fib->hbacmd_size + 127) / 128 - 1; 55362306a36Sopenharmony_ci if (fibsize > 31) 55462306a36Sopenharmony_ci fibsize = 31; 55562306a36Sopenharmony_ci address |= fibsize; 55662306a36Sopenharmony_ci#if defined(writeq) 55762306a36Sopenharmony_ci src_writeq(dev, MUnit.IQN_L, (u64)address); 55862306a36Sopenharmony_ci#else 55962306a36Sopenharmony_ci spin_lock_irqsave(&fib->dev->iq_lock, flags); 56062306a36Sopenharmony_ci src_writel(dev, MUnit.IQN_H, 56162306a36Sopenharmony_ci upper_32_bits(address) & 0xffffffff); 56262306a36Sopenharmony_ci src_writel(dev, MUnit.IQN_L, address & 0xffffffff); 56362306a36Sopenharmony_ci spin_unlock_irqrestore(&fib->dev->iq_lock, flags); 56462306a36Sopenharmony_ci#endif 56562306a36Sopenharmony_ci } else { 56662306a36Sopenharmony_ci if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || 56762306a36Sopenharmony_ci dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { 56862306a36Sopenharmony_ci /* Calculate the amount to the fibsize bits */ 56962306a36Sopenharmony_ci fibsize = (le16_to_cpu(fib->hw_fib_va->header.Size) 57062306a36Sopenharmony_ci + 127) / 128 - 1; 57162306a36Sopenharmony_ci /* New FIB header, 32-bit */ 57262306a36Sopenharmony_ci address = fib->hw_fib_pa; 57362306a36Sopenharmony_ci fib->hw_fib_va->header.StructType = FIB_MAGIC2; 57462306a36Sopenharmony_ci fib->hw_fib_va->header.SenderFibAddress = 57562306a36Sopenharmony_ci cpu_to_le32((u32)address); 57662306a36Sopenharmony_ci fib->hw_fib_va->header.u.TimeStamp = 0; 57762306a36Sopenharmony_ci WARN_ON(upper_32_bits(address) != 0L); 57862306a36Sopenharmony_ci } else { 57962306a36Sopenharmony_ci /* Calculate the amount to the fibsize bits */ 58062306a36Sopenharmony_ci fibsize = (sizeof(struct aac_fib_xporthdr) + 58162306a36Sopenharmony_ci le16_to_cpu(fib->hw_fib_va->header.Size) 58262306a36Sopenharmony_ci + 127) / 128 - 1; 58362306a36Sopenharmony_ci /* Fill XPORT header */ 58462306a36Sopenharmony_ci pFibX = (struct aac_fib_xporthdr *) 58562306a36Sopenharmony_ci ((unsigned char *)fib->hw_fib_va - 58662306a36Sopenharmony_ci sizeof(struct aac_fib_xporthdr)); 58762306a36Sopenharmony_ci pFibX->Handle = fib->hw_fib_va->header.Handle; 58862306a36Sopenharmony_ci pFibX->HostAddress = 58962306a36Sopenharmony_ci cpu_to_le64((u64)fib->hw_fib_pa); 59062306a36Sopenharmony_ci pFibX->Size = cpu_to_le32( 59162306a36Sopenharmony_ci le16_to_cpu(fib->hw_fib_va->header.Size)); 59262306a36Sopenharmony_ci address = fib->hw_fib_pa - 59362306a36Sopenharmony_ci (u64)sizeof(struct aac_fib_xporthdr); 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci if (fibsize > 31) 59662306a36Sopenharmony_ci fibsize = 31; 59762306a36Sopenharmony_ci address |= fibsize; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci#if defined(writeq) 60062306a36Sopenharmony_ci src_writeq(dev, MUnit.IQ_L, (u64)address); 60162306a36Sopenharmony_ci#else 60262306a36Sopenharmony_ci spin_lock_irqsave(&fib->dev->iq_lock, flags); 60362306a36Sopenharmony_ci src_writel(dev, MUnit.IQ_H, 60462306a36Sopenharmony_ci upper_32_bits(address) & 0xffffffff); 60562306a36Sopenharmony_ci src_writel(dev, MUnit.IQ_L, address & 0xffffffff); 60662306a36Sopenharmony_ci spin_unlock_irqrestore(&fib->dev->iq_lock, flags); 60762306a36Sopenharmony_ci#endif 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci return 0; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/** 61362306a36Sopenharmony_ci * aac_src_ioremap 61462306a36Sopenharmony_ci * @dev: device ioremap 61562306a36Sopenharmony_ci * @size: mapping resize request 61662306a36Sopenharmony_ci * 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_cistatic int aac_src_ioremap(struct aac_dev *dev, u32 size) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci if (!size) { 62162306a36Sopenharmony_ci iounmap(dev->regs.src.bar1); 62262306a36Sopenharmony_ci dev->regs.src.bar1 = NULL; 62362306a36Sopenharmony_ci iounmap(dev->regs.src.bar0); 62462306a36Sopenharmony_ci dev->base = dev->regs.src.bar0 = NULL; 62562306a36Sopenharmony_ci return 0; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2), 62862306a36Sopenharmony_ci AAC_MIN_SRC_BAR1_SIZE); 62962306a36Sopenharmony_ci dev->base = NULL; 63062306a36Sopenharmony_ci if (dev->regs.src.bar1 == NULL) 63162306a36Sopenharmony_ci return -1; 63262306a36Sopenharmony_ci dev->base = dev->regs.src.bar0 = ioremap(dev->base_start, size); 63362306a36Sopenharmony_ci if (dev->base == NULL) { 63462306a36Sopenharmony_ci iounmap(dev->regs.src.bar1); 63562306a36Sopenharmony_ci dev->regs.src.bar1 = NULL; 63662306a36Sopenharmony_ci return -1; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci dev->IndexRegs = &((struct src_registers __iomem *) 63962306a36Sopenharmony_ci dev->base)->u.tupelo.IndexRegs; 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci/** 64462306a36Sopenharmony_ci * aac_srcv_ioremap 64562306a36Sopenharmony_ci * @dev: device ioremap 64662306a36Sopenharmony_ci * @size: mapping resize request 64762306a36Sopenharmony_ci * 64862306a36Sopenharmony_ci */ 64962306a36Sopenharmony_cistatic int aac_srcv_ioremap(struct aac_dev *dev, u32 size) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci if (!size) { 65262306a36Sopenharmony_ci iounmap(dev->regs.src.bar0); 65362306a36Sopenharmony_ci dev->base = dev->regs.src.bar0 = NULL; 65462306a36Sopenharmony_ci return 0; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci dev->regs.src.bar1 = 65862306a36Sopenharmony_ci ioremap(pci_resource_start(dev->pdev, 2), AAC_MIN_SRCV_BAR1_SIZE); 65962306a36Sopenharmony_ci dev->base = NULL; 66062306a36Sopenharmony_ci if (dev->regs.src.bar1 == NULL) 66162306a36Sopenharmony_ci return -1; 66262306a36Sopenharmony_ci dev->base = dev->regs.src.bar0 = ioremap(dev->base_start, size); 66362306a36Sopenharmony_ci if (dev->base == NULL) { 66462306a36Sopenharmony_ci iounmap(dev->regs.src.bar1); 66562306a36Sopenharmony_ci dev->regs.src.bar1 = NULL; 66662306a36Sopenharmony_ci return -1; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci dev->IndexRegs = &((struct src_registers __iomem *) 66962306a36Sopenharmony_ci dev->base)->u.denali.IndexRegs; 67062306a36Sopenharmony_ci return 0; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_civoid aac_set_intx_mode(struct aac_dev *dev) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci if (dev->msi_enabled) { 67662306a36Sopenharmony_ci aac_src_access_devreg(dev, AAC_ENABLE_INTX); 67762306a36Sopenharmony_ci dev->msi_enabled = 0; 67862306a36Sopenharmony_ci msleep(5000); /* Delay 5 seconds */ 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic void aac_clear_omr(struct aac_dev *dev) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci u32 omr_value = 0; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci omr_value = src_readl(dev, MUnit.OMR); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* 68962306a36Sopenharmony_ci * Check for PCI Errors or Kernel Panic 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_ci if ((omr_value == INVALID_OMR) || (omr_value & KERNEL_PANIC)) 69262306a36Sopenharmony_ci omr_value = 0; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* 69562306a36Sopenharmony_ci * Preserve MSIX Value if any 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_ci src_writel(dev, MUnit.OMR, omr_value & AAC_INT_MODE_MSIX); 69862306a36Sopenharmony_ci src_readl(dev, MUnit.OMR); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic void aac_dump_fw_fib_iop_reset(struct aac_dev *dev) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci __le32 supported_options3; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (!aac_fib_dump) 70662306a36Sopenharmony_ci return; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci supported_options3 = dev->supplement_adapter_info.supported_options3; 70962306a36Sopenharmony_ci if (!(supported_options3 & AAC_OPTION_SUPPORTED3_IOP_RESET_FIB_DUMP)) 71062306a36Sopenharmony_ci return; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci aac_adapter_sync_cmd(dev, IOP_RESET_FW_FIB_DUMP, 71362306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic bool aac_is_ctrl_up_and_running(struct aac_dev *dev) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci bool ctrl_up = true; 71962306a36Sopenharmony_ci unsigned long status, start; 72062306a36Sopenharmony_ci bool is_up = false; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci start = jiffies; 72362306a36Sopenharmony_ci do { 72462306a36Sopenharmony_ci schedule(); 72562306a36Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (status == 0xffffffff) 72862306a36Sopenharmony_ci status = 0; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (status & KERNEL_BOOTING) { 73162306a36Sopenharmony_ci start = jiffies; 73262306a36Sopenharmony_ci continue; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (time_after(jiffies, start+HZ*SOFT_RESET_TIME)) { 73662306a36Sopenharmony_ci ctrl_up = false; 73762306a36Sopenharmony_ci break; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci is_up = status & KERNEL_UP_AND_RUNNING; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci } while (!is_up); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return ctrl_up; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic void aac_src_drop_io(struct aac_dev *dev) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci if (!dev->soft_reset_support) 75062306a36Sopenharmony_ci return; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci aac_adapter_sync_cmd(dev, DROP_IO, 75362306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic void aac_notify_fw_of_iop_reset(struct aac_dev *dev) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, 0, 0, 0, 0, 0, 0, NULL, 75962306a36Sopenharmony_ci NULL, NULL, NULL, NULL); 76062306a36Sopenharmony_ci aac_src_drop_io(dev); 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic void aac_send_iop_reset(struct aac_dev *dev) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci aac_dump_fw_fib_iop_reset(dev); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci aac_notify_fw_of_iop_reset(dev); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci aac_set_intx_mode(dev); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci aac_clear_omr(dev); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci src_writel(dev, MUnit.IDR, IOP_SRC_RESET_MASK); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci msleep(5000); 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic void aac_send_hardware_soft_reset(struct aac_dev *dev) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci u_int32_t val; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci aac_clear_omr(dev); 78362306a36Sopenharmony_ci val = readl(((char *)(dev->base) + IBW_SWR_OFFSET)); 78462306a36Sopenharmony_ci val |= 0x01; 78562306a36Sopenharmony_ci writel(val, ((char *)(dev->base) + IBW_SWR_OFFSET)); 78662306a36Sopenharmony_ci msleep_interruptible(20000); 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int aac_src_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci bool is_ctrl_up; 79262306a36Sopenharmony_ci int ret = 0; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (bled < 0) 79562306a36Sopenharmony_ci goto invalid_out; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (bled) 79862306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "adapter kernel panic'd %x.\n", bled); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* 80162306a36Sopenharmony_ci * When there is a BlinkLED, IOP_RESET has not effect 80262306a36Sopenharmony_ci */ 80362306a36Sopenharmony_ci if (bled >= 2 && dev->sa_firmware && reset_type & HW_IOP_RESET) 80462306a36Sopenharmony_ci reset_type &= ~HW_IOP_RESET; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "Controller reset type is %d\n", reset_type); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (reset_type & HW_IOP_RESET) { 81162306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "Issuing IOP reset\n"); 81262306a36Sopenharmony_ci aac_send_iop_reset(dev); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* 81562306a36Sopenharmony_ci * Creates a delay or wait till up and running comes thru 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ci is_ctrl_up = aac_is_ctrl_up_and_running(dev); 81862306a36Sopenharmony_ci if (!is_ctrl_up) 81962306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "IOP reset failed\n"); 82062306a36Sopenharmony_ci else { 82162306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "IOP reset succeeded\n"); 82262306a36Sopenharmony_ci goto set_startup; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (!dev->sa_firmware) { 82762306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "ARC Reset attempt failed\n"); 82862306a36Sopenharmony_ci ret = -ENODEV; 82962306a36Sopenharmony_ci goto out; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (reset_type & HW_SOFT_RESET) { 83362306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "Issuing SOFT reset\n"); 83462306a36Sopenharmony_ci aac_send_hardware_soft_reset(dev); 83562306a36Sopenharmony_ci dev->msi_enabled = 0; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci is_ctrl_up = aac_is_ctrl_up_and_running(dev); 83862306a36Sopenharmony_ci if (!is_ctrl_up) { 83962306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "SOFT reset failed\n"); 84062306a36Sopenharmony_ci ret = -ENODEV; 84162306a36Sopenharmony_ci goto out; 84262306a36Sopenharmony_ci } else 84362306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "SOFT reset succeeded\n"); 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ciset_startup: 84762306a36Sopenharmony_ci if (startup_timeout < 300) 84862306a36Sopenharmony_ci startup_timeout = 300; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ciout: 85162306a36Sopenharmony_ci return ret; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ciinvalid_out: 85462306a36Sopenharmony_ci if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC) 85562306a36Sopenharmony_ci ret = -ENODEV; 85662306a36Sopenharmony_cigoto out; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci/** 86062306a36Sopenharmony_ci * aac_src_select_comm - Select communications method 86162306a36Sopenharmony_ci * @dev: Adapter 86262306a36Sopenharmony_ci * @comm: communications method 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_cistatic int aac_src_select_comm(struct aac_dev *dev, int comm) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci switch (comm) { 86762306a36Sopenharmony_ci case AAC_COMM_MESSAGE: 86862306a36Sopenharmony_ci dev->a_ops.adapter_intr = aac_src_intr_message; 86962306a36Sopenharmony_ci dev->a_ops.adapter_deliver = aac_src_deliver_message; 87062306a36Sopenharmony_ci break; 87162306a36Sopenharmony_ci default: 87262306a36Sopenharmony_ci return 1; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci return 0; 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci/** 87862306a36Sopenharmony_ci * aac_src_init - initialize an Cardinal Frey Bar card 87962306a36Sopenharmony_ci * @dev: device to configure 88062306a36Sopenharmony_ci * 88162306a36Sopenharmony_ci */ 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ciint aac_src_init(struct aac_dev *dev) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci unsigned long start; 88662306a36Sopenharmony_ci unsigned long status; 88762306a36Sopenharmony_ci int restart = 0; 88862306a36Sopenharmony_ci int instance = dev->id; 88962306a36Sopenharmony_ci const char *name = dev->name; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci dev->a_ops.adapter_ioremap = aac_src_ioremap; 89262306a36Sopenharmony_ci dev->a_ops.adapter_comm = aac_src_select_comm; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci dev->base_size = AAC_MIN_SRC_BAR0_SIZE; 89562306a36Sopenharmony_ci if (aac_adapter_ioremap(dev, dev->base_size)) { 89662306a36Sopenharmony_ci printk(KERN_WARNING "%s: unable to map adapter.\n", name); 89762306a36Sopenharmony_ci goto error_iounmap; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci /* Failure to reset here is an option ... */ 90162306a36Sopenharmony_ci dev->a_ops.adapter_sync_cmd = src_sync_cmd; 90262306a36Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (dev->init_reset) { 90562306a36Sopenharmony_ci dev->init_reset = false; 90662306a36Sopenharmony_ci if (!aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) 90762306a36Sopenharmony_ci ++restart; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* 91162306a36Sopenharmony_ci * Check to see if the board panic'd while booting. 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 91462306a36Sopenharmony_ci if (status & KERNEL_PANIC) { 91562306a36Sopenharmony_ci if (aac_src_restart_adapter(dev, 91662306a36Sopenharmony_ci aac_src_check_health(dev), IOP_HWSOFT_RESET)) 91762306a36Sopenharmony_ci goto error_iounmap; 91862306a36Sopenharmony_ci ++restart; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci /* 92162306a36Sopenharmony_ci * Check to see if the board failed any self tests. 92262306a36Sopenharmony_ci */ 92362306a36Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 92462306a36Sopenharmony_ci if (status & SELF_TEST_FAILED) { 92562306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter self-test failed.\n", 92662306a36Sopenharmony_ci dev->name, instance); 92762306a36Sopenharmony_ci goto error_iounmap; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci /* 93062306a36Sopenharmony_ci * Check to see if the monitor panic'd while booting. 93162306a36Sopenharmony_ci */ 93262306a36Sopenharmony_ci if (status & MONITOR_PANIC) { 93362306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter monitor panic.\n", 93462306a36Sopenharmony_ci dev->name, instance); 93562306a36Sopenharmony_ci goto error_iounmap; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci start = jiffies; 93862306a36Sopenharmony_ci /* 93962306a36Sopenharmony_ci * Wait for the adapter to be up and running. Wait up to 3 minutes 94062306a36Sopenharmony_ci */ 94162306a36Sopenharmony_ci while (!((status = src_readl(dev, MUnit.OMR)) & 94262306a36Sopenharmony_ci KERNEL_UP_AND_RUNNING)) { 94362306a36Sopenharmony_ci if ((restart && 94462306a36Sopenharmony_ci (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || 94562306a36Sopenharmony_ci time_after(jiffies, start+HZ*startup_timeout)) { 94662306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 94762306a36Sopenharmony_ci dev->name, instance, status); 94862306a36Sopenharmony_ci goto error_iounmap; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci if (!restart && 95162306a36Sopenharmony_ci ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || 95262306a36Sopenharmony_ci time_after(jiffies, start + HZ * 95362306a36Sopenharmony_ci ((startup_timeout > 60) 95462306a36Sopenharmony_ci ? (startup_timeout - 60) 95562306a36Sopenharmony_ci : (startup_timeout / 2))))) { 95662306a36Sopenharmony_ci if (likely(!aac_src_restart_adapter(dev, 95762306a36Sopenharmony_ci aac_src_check_health(dev), IOP_HWSOFT_RESET))) 95862306a36Sopenharmony_ci start = jiffies; 95962306a36Sopenharmony_ci ++restart; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci msleep(1); 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci if (restart && aac_commit) 96462306a36Sopenharmony_ci aac_commit = 1; 96562306a36Sopenharmony_ci /* 96662306a36Sopenharmony_ci * Fill in the common function dispatch table. 96762306a36Sopenharmony_ci */ 96862306a36Sopenharmony_ci dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter; 96962306a36Sopenharmony_ci dev->a_ops.adapter_disable_int = aac_src_disable_interrupt; 97062306a36Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; 97162306a36Sopenharmony_ci dev->a_ops.adapter_notify = aac_src_notify_adapter; 97262306a36Sopenharmony_ci dev->a_ops.adapter_sync_cmd = src_sync_cmd; 97362306a36Sopenharmony_ci dev->a_ops.adapter_check_health = aac_src_check_health; 97462306a36Sopenharmony_ci dev->a_ops.adapter_restart = aac_src_restart_adapter; 97562306a36Sopenharmony_ci dev->a_ops.adapter_start = aac_src_start_adapter; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* 97862306a36Sopenharmony_ci * First clear out all interrupts. Then enable the one's that we 97962306a36Sopenharmony_ci * can handle. 98062306a36Sopenharmony_ci */ 98162306a36Sopenharmony_ci aac_adapter_comm(dev, AAC_COMM_MESSAGE); 98262306a36Sopenharmony_ci aac_adapter_disable_int(dev); 98362306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 0xffffffff); 98462306a36Sopenharmony_ci aac_adapter_enable_int(dev); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (aac_init_adapter(dev) == NULL) 98762306a36Sopenharmony_ci goto error_iounmap; 98862306a36Sopenharmony_ci if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1) 98962306a36Sopenharmony_ci goto error_iounmap; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci dev->msi = !pci_enable_msi(dev->pdev); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci dev->aac_msix[0].vector_no = 0; 99462306a36Sopenharmony_ci dev->aac_msix[0].dev = dev; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, 99762306a36Sopenharmony_ci IRQF_SHARED, "aacraid", &(dev->aac_msix[0])) < 0) { 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci if (dev->msi) 100062306a36Sopenharmony_ci pci_disable_msi(dev->pdev); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci printk(KERN_ERR "%s%d: Interrupt unavailable.\n", 100362306a36Sopenharmony_ci name, instance); 100462306a36Sopenharmony_ci goto error_iounmap; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci dev->dbg_base = pci_resource_start(dev->pdev, 2); 100762306a36Sopenharmony_ci dev->dbg_base_mapped = dev->regs.src.bar1; 100862306a36Sopenharmony_ci dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE; 100962306a36Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci aac_adapter_enable_int(dev); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (!dev->sync_mode) { 101462306a36Sopenharmony_ci /* 101562306a36Sopenharmony_ci * Tell the adapter that all is configured, and it can 101662306a36Sopenharmony_ci * start accepting requests 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ci aac_src_start_adapter(dev); 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci return 0; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cierror_iounmap: 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci return -1; 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic int aac_src_wait_sync(struct aac_dev *dev, int *status) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci unsigned long start = jiffies; 103062306a36Sopenharmony_ci unsigned long usecs = 0; 103162306a36Sopenharmony_ci int delay = 5 * HZ; 103262306a36Sopenharmony_ci int rc = 1; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci while (time_before(jiffies, start+delay)) { 103562306a36Sopenharmony_ci /* 103662306a36Sopenharmony_ci * Delay 5 microseconds to let Mon960 get info. 103762306a36Sopenharmony_ci */ 103862306a36Sopenharmony_ci udelay(5); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* 104162306a36Sopenharmony_ci * Mon960 will set doorbell0 bit when it has completed the 104262306a36Sopenharmony_ci * command. 104362306a36Sopenharmony_ci */ 104462306a36Sopenharmony_ci if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) { 104562306a36Sopenharmony_ci /* 104662306a36Sopenharmony_ci * Clear: the doorbell. 104762306a36Sopenharmony_ci */ 104862306a36Sopenharmony_ci if (dev->msi_enabled) 104962306a36Sopenharmony_ci aac_src_access_devreg(dev, AAC_CLEAR_SYNC_BIT); 105062306a36Sopenharmony_ci else 105162306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 105262306a36Sopenharmony_ci OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); 105362306a36Sopenharmony_ci rc = 0; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci break; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* 105962306a36Sopenharmony_ci * Yield the processor in case we are slow 106062306a36Sopenharmony_ci */ 106162306a36Sopenharmony_ci usecs = 1 * USEC_PER_MSEC; 106262306a36Sopenharmony_ci usleep_range(usecs, usecs + 50); 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci /* 106562306a36Sopenharmony_ci * Pull the synch status from Mailbox 0. 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_ci if (status && !rc) { 106862306a36Sopenharmony_ci status[0] = readl(&dev->IndexRegs->Mailbox[0]); 106962306a36Sopenharmony_ci status[1] = readl(&dev->IndexRegs->Mailbox[1]); 107062306a36Sopenharmony_ci status[2] = readl(&dev->IndexRegs->Mailbox[2]); 107162306a36Sopenharmony_ci status[3] = readl(&dev->IndexRegs->Mailbox[3]); 107262306a36Sopenharmony_ci status[4] = readl(&dev->IndexRegs->Mailbox[4]); 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return rc; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci/** 107962306a36Sopenharmony_ci * aac_src_soft_reset - perform soft reset to speed up 108062306a36Sopenharmony_ci * access 108162306a36Sopenharmony_ci * 108262306a36Sopenharmony_ci * Assumptions: That the controller is in a state where we can 108362306a36Sopenharmony_ci * bring it back to life with an init struct. We can only use 108462306a36Sopenharmony_ci * fast sync commands, as the timeout is 5 seconds. 108562306a36Sopenharmony_ci * 108662306a36Sopenharmony_ci * @dev: device to configure 108762306a36Sopenharmony_ci * 108862306a36Sopenharmony_ci */ 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_cistatic int aac_src_soft_reset(struct aac_dev *dev) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci u32 status_omr = src_readl(dev, MUnit.OMR); 109362306a36Sopenharmony_ci u32 status[5]; 109462306a36Sopenharmony_ci int rc = 1; 109562306a36Sopenharmony_ci int state = 0; 109662306a36Sopenharmony_ci char *state_str[7] = { 109762306a36Sopenharmony_ci "GET_ADAPTER_PROPERTIES Failed", 109862306a36Sopenharmony_ci "GET_ADAPTER_PROPERTIES timeout", 109962306a36Sopenharmony_ci "SOFT_RESET not supported", 110062306a36Sopenharmony_ci "DROP_IO Failed", 110162306a36Sopenharmony_ci "DROP_IO timeout", 110262306a36Sopenharmony_ci "Check Health failed" 110362306a36Sopenharmony_ci }; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (status_omr == INVALID_OMR) 110662306a36Sopenharmony_ci return 1; // pcie hosed 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (!(status_omr & KERNEL_UP_AND_RUNNING)) 110962306a36Sopenharmony_ci return 1; // not up and running 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci /* 111262306a36Sopenharmony_ci * We go into soft reset mode to allow us to handle response 111362306a36Sopenharmony_ci */ 111462306a36Sopenharmony_ci dev->in_soft_reset = 1; 111562306a36Sopenharmony_ci dev->msi_enabled = status_omr & AAC_INT_MODE_MSIX; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* Get adapter properties */ 111862306a36Sopenharmony_ci rc = aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, 0, 0, 0, 111962306a36Sopenharmony_ci 0, 0, 0, status+0, status+1, status+2, status+3, status+4); 112062306a36Sopenharmony_ci if (rc) 112162306a36Sopenharmony_ci goto out; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci state++; 112462306a36Sopenharmony_ci if (aac_src_wait_sync(dev, status)) { 112562306a36Sopenharmony_ci rc = 1; 112662306a36Sopenharmony_ci goto out; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci state++; 113062306a36Sopenharmony_ci if (!(status[1] & le32_to_cpu(AAC_OPT_EXTENDED) && 113162306a36Sopenharmony_ci (status[4] & le32_to_cpu(AAC_EXTOPT_SOFT_RESET)))) { 113262306a36Sopenharmony_ci rc = 2; 113362306a36Sopenharmony_ci goto out; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci if ((status[1] & le32_to_cpu(AAC_OPT_EXTENDED)) && 113762306a36Sopenharmony_ci (status[4] & le32_to_cpu(AAC_EXTOPT_SA_FIRMWARE))) 113862306a36Sopenharmony_ci dev->sa_firmware = 1; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci state++; 114162306a36Sopenharmony_ci rc = aac_adapter_sync_cmd(dev, DROP_IO, 0, 0, 0, 0, 0, 0, 114262306a36Sopenharmony_ci status+0, status+1, status+2, status+3, status+4); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (rc) 114562306a36Sopenharmony_ci goto out; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci state++; 114862306a36Sopenharmony_ci if (aac_src_wait_sync(dev, status)) { 114962306a36Sopenharmony_ci rc = 3; 115062306a36Sopenharmony_ci goto out; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci if (status[1]) 115462306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "%s: %d outstanding I/O pending\n", 115562306a36Sopenharmony_ci __func__, status[1]); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci state++; 115862306a36Sopenharmony_ci rc = aac_src_check_health(dev); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ciout: 116162306a36Sopenharmony_ci dev->in_soft_reset = 0; 116262306a36Sopenharmony_ci dev->msi_enabled = 0; 116362306a36Sopenharmony_ci if (rc) 116462306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "%s: %s status = %d", __func__, 116562306a36Sopenharmony_ci state_str[state], rc); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci return rc; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci/** 117062306a36Sopenharmony_ci * aac_srcv_init - initialize an SRCv card 117162306a36Sopenharmony_ci * @dev: device to configure 117262306a36Sopenharmony_ci * 117362306a36Sopenharmony_ci */ 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ciint aac_srcv_init(struct aac_dev *dev) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci unsigned long start; 117862306a36Sopenharmony_ci unsigned long status; 117962306a36Sopenharmony_ci int restart = 0; 118062306a36Sopenharmony_ci int instance = dev->id; 118162306a36Sopenharmony_ci const char *name = dev->name; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci dev->a_ops.adapter_ioremap = aac_srcv_ioremap; 118462306a36Sopenharmony_ci dev->a_ops.adapter_comm = aac_src_select_comm; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci dev->base_size = AAC_MIN_SRCV_BAR0_SIZE; 118762306a36Sopenharmony_ci if (aac_adapter_ioremap(dev, dev->base_size)) { 118862306a36Sopenharmony_ci printk(KERN_WARNING "%s: unable to map adapter.\n", name); 118962306a36Sopenharmony_ci goto error_iounmap; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci /* Failure to reset here is an option ... */ 119362306a36Sopenharmony_ci dev->a_ops.adapter_sync_cmd = src_sync_cmd; 119462306a36Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (dev->init_reset) { 119762306a36Sopenharmony_ci dev->init_reset = false; 119862306a36Sopenharmony_ci if (aac_src_soft_reset(dev)) { 119962306a36Sopenharmony_ci aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET); 120062306a36Sopenharmony_ci ++restart; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci /* 120562306a36Sopenharmony_ci * Check to see if flash update is running. 120662306a36Sopenharmony_ci * Wait for the adapter to be up and running. Wait up to 5 minutes 120762306a36Sopenharmony_ci */ 120862306a36Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 120962306a36Sopenharmony_ci if (status & FLASH_UPD_PENDING) { 121062306a36Sopenharmony_ci start = jiffies; 121162306a36Sopenharmony_ci do { 121262306a36Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 121362306a36Sopenharmony_ci if (time_after(jiffies, start+HZ*FWUPD_TIMEOUT)) { 121462306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter flash update failed.\n", 121562306a36Sopenharmony_ci dev->name, instance); 121662306a36Sopenharmony_ci goto error_iounmap; 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci } while (!(status & FLASH_UPD_SUCCESS) && 121962306a36Sopenharmony_ci !(status & FLASH_UPD_FAILED)); 122062306a36Sopenharmony_ci /* Delay 10 seconds. 122162306a36Sopenharmony_ci * Because right now FW is doing a soft reset, 122262306a36Sopenharmony_ci * do not read scratch pad register at this time 122362306a36Sopenharmony_ci */ 122462306a36Sopenharmony_ci ssleep(10); 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci /* 122762306a36Sopenharmony_ci * Check to see if the board panic'd while booting. 122862306a36Sopenharmony_ci */ 122962306a36Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 123062306a36Sopenharmony_ci if (status & KERNEL_PANIC) { 123162306a36Sopenharmony_ci if (aac_src_restart_adapter(dev, 123262306a36Sopenharmony_ci aac_src_check_health(dev), IOP_HWSOFT_RESET)) 123362306a36Sopenharmony_ci goto error_iounmap; 123462306a36Sopenharmony_ci ++restart; 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci /* 123762306a36Sopenharmony_ci * Check to see if the board failed any self tests. 123862306a36Sopenharmony_ci */ 123962306a36Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 124062306a36Sopenharmony_ci if (status & SELF_TEST_FAILED) { 124162306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); 124262306a36Sopenharmony_ci goto error_iounmap; 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci /* 124562306a36Sopenharmony_ci * Check to see if the monitor panic'd while booting. 124662306a36Sopenharmony_ci */ 124762306a36Sopenharmony_ci if (status & MONITOR_PANIC) { 124862306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); 124962306a36Sopenharmony_ci goto error_iounmap; 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci start = jiffies; 125362306a36Sopenharmony_ci /* 125462306a36Sopenharmony_ci * Wait for the adapter to be up and running. Wait up to 3 minutes 125562306a36Sopenharmony_ci */ 125662306a36Sopenharmony_ci do { 125762306a36Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 125862306a36Sopenharmony_ci if (status == INVALID_OMR) 125962306a36Sopenharmony_ci status = 0; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if ((restart && 126262306a36Sopenharmony_ci (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || 126362306a36Sopenharmony_ci time_after(jiffies, start+HZ*startup_timeout)) { 126462306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 126562306a36Sopenharmony_ci dev->name, instance, status); 126662306a36Sopenharmony_ci goto error_iounmap; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci if (!restart && 126962306a36Sopenharmony_ci ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || 127062306a36Sopenharmony_ci time_after(jiffies, start + HZ * 127162306a36Sopenharmony_ci ((startup_timeout > 60) 127262306a36Sopenharmony_ci ? (startup_timeout - 60) 127362306a36Sopenharmony_ci : (startup_timeout / 2))))) { 127462306a36Sopenharmony_ci if (likely(!aac_src_restart_adapter(dev, 127562306a36Sopenharmony_ci aac_src_check_health(dev), IOP_HWSOFT_RESET))) 127662306a36Sopenharmony_ci start = jiffies; 127762306a36Sopenharmony_ci ++restart; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci msleep(1); 128062306a36Sopenharmony_ci } while (!(status & KERNEL_UP_AND_RUNNING)); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci if (restart && aac_commit) 128362306a36Sopenharmony_ci aac_commit = 1; 128462306a36Sopenharmony_ci /* 128562306a36Sopenharmony_ci * Fill in the common function dispatch table. 128662306a36Sopenharmony_ci */ 128762306a36Sopenharmony_ci dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter; 128862306a36Sopenharmony_ci dev->a_ops.adapter_disable_int = aac_src_disable_interrupt; 128962306a36Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; 129062306a36Sopenharmony_ci dev->a_ops.adapter_notify = aac_src_notify_adapter; 129162306a36Sopenharmony_ci dev->a_ops.adapter_sync_cmd = src_sync_cmd; 129262306a36Sopenharmony_ci dev->a_ops.adapter_check_health = aac_src_check_health; 129362306a36Sopenharmony_ci dev->a_ops.adapter_restart = aac_src_restart_adapter; 129462306a36Sopenharmony_ci dev->a_ops.adapter_start = aac_src_start_adapter; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci /* 129762306a36Sopenharmony_ci * First clear out all interrupts. Then enable the one's that we 129862306a36Sopenharmony_ci * can handle. 129962306a36Sopenharmony_ci */ 130062306a36Sopenharmony_ci aac_adapter_comm(dev, AAC_COMM_MESSAGE); 130162306a36Sopenharmony_ci aac_adapter_disable_int(dev); 130262306a36Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 0xffffffff); 130362306a36Sopenharmony_ci aac_adapter_enable_int(dev); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (aac_init_adapter(dev) == NULL) 130662306a36Sopenharmony_ci goto error_iounmap; 130762306a36Sopenharmony_ci if ((dev->comm_interface != AAC_COMM_MESSAGE_TYPE2) && 130862306a36Sopenharmony_ci (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3)) 130962306a36Sopenharmony_ci goto error_iounmap; 131062306a36Sopenharmony_ci if (dev->msi_enabled) 131162306a36Sopenharmony_ci aac_src_access_devreg(dev, AAC_ENABLE_MSIX); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci if (aac_acquire_irq(dev)) 131462306a36Sopenharmony_ci goto error_iounmap; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci dev->dbg_base = pci_resource_start(dev->pdev, 2); 131762306a36Sopenharmony_ci dev->dbg_base_mapped = dev->regs.src.bar1; 131862306a36Sopenharmony_ci dev->dbg_size = AAC_MIN_SRCV_BAR1_SIZE; 131962306a36Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci aac_adapter_enable_int(dev); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci if (!dev->sync_mode) { 132462306a36Sopenharmony_ci /* 132562306a36Sopenharmony_ci * Tell the adapter that all is configured, and it can 132662306a36Sopenharmony_ci * start accepting requests 132762306a36Sopenharmony_ci */ 132862306a36Sopenharmony_ci aac_src_start_adapter(dev); 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci return 0; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_cierror_iounmap: 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci return -1; 133562306a36Sopenharmony_ci} 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_civoid aac_src_access_devreg(struct aac_dev *dev, int mode) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci u_int32_t val; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci switch (mode) { 134262306a36Sopenharmony_ci case AAC_ENABLE_INTERRUPT: 134362306a36Sopenharmony_ci src_writel(dev, 134462306a36Sopenharmony_ci MUnit.OIMR, 134562306a36Sopenharmony_ci dev->OIMR = (dev->msi_enabled ? 134662306a36Sopenharmony_ci AAC_INT_ENABLE_TYPE1_MSIX : 134762306a36Sopenharmony_ci AAC_INT_ENABLE_TYPE1_INTX)); 134862306a36Sopenharmony_ci break; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci case AAC_DISABLE_INTERRUPT: 135162306a36Sopenharmony_ci src_writel(dev, 135262306a36Sopenharmony_ci MUnit.OIMR, 135362306a36Sopenharmony_ci dev->OIMR = AAC_INT_DISABLE_ALL); 135462306a36Sopenharmony_ci break; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci case AAC_ENABLE_MSIX: 135762306a36Sopenharmony_ci /* set bit 6 */ 135862306a36Sopenharmony_ci val = src_readl(dev, MUnit.IDR); 135962306a36Sopenharmony_ci val |= 0x40; 136062306a36Sopenharmony_ci src_writel(dev, MUnit.IDR, val); 136162306a36Sopenharmony_ci src_readl(dev, MUnit.IDR); 136262306a36Sopenharmony_ci /* unmask int. */ 136362306a36Sopenharmony_ci val = PMC_ALL_INTERRUPT_BITS; 136462306a36Sopenharmony_ci src_writel(dev, MUnit.IOAR, val); 136562306a36Sopenharmony_ci val = src_readl(dev, MUnit.OIMR); 136662306a36Sopenharmony_ci src_writel(dev, 136762306a36Sopenharmony_ci MUnit.OIMR, 136862306a36Sopenharmony_ci val & (~(PMC_GLOBAL_INT_BIT2 | PMC_GLOBAL_INT_BIT0))); 136962306a36Sopenharmony_ci break; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci case AAC_DISABLE_MSIX: 137262306a36Sopenharmony_ci /* reset bit 6 */ 137362306a36Sopenharmony_ci val = src_readl(dev, MUnit.IDR); 137462306a36Sopenharmony_ci val &= ~0x40; 137562306a36Sopenharmony_ci src_writel(dev, MUnit.IDR, val); 137662306a36Sopenharmony_ci src_readl(dev, MUnit.IDR); 137762306a36Sopenharmony_ci break; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci case AAC_CLEAR_AIF_BIT: 138062306a36Sopenharmony_ci /* set bit 5 */ 138162306a36Sopenharmony_ci val = src_readl(dev, MUnit.IDR); 138262306a36Sopenharmony_ci val |= 0x20; 138362306a36Sopenharmony_ci src_writel(dev, MUnit.IDR, val); 138462306a36Sopenharmony_ci src_readl(dev, MUnit.IDR); 138562306a36Sopenharmony_ci break; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci case AAC_CLEAR_SYNC_BIT: 138862306a36Sopenharmony_ci /* set bit 4 */ 138962306a36Sopenharmony_ci val = src_readl(dev, MUnit.IDR); 139062306a36Sopenharmony_ci val |= 0x10; 139162306a36Sopenharmony_ci src_writel(dev, MUnit.IDR, val); 139262306a36Sopenharmony_ci src_readl(dev, MUnit.IDR); 139362306a36Sopenharmony_ci break; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci case AAC_ENABLE_INTX: 139662306a36Sopenharmony_ci /* set bit 7 */ 139762306a36Sopenharmony_ci val = src_readl(dev, MUnit.IDR); 139862306a36Sopenharmony_ci val |= 0x80; 139962306a36Sopenharmony_ci src_writel(dev, MUnit.IDR, val); 140062306a36Sopenharmony_ci src_readl(dev, MUnit.IDR); 140162306a36Sopenharmony_ci /* unmask int. */ 140262306a36Sopenharmony_ci val = PMC_ALL_INTERRUPT_BITS; 140362306a36Sopenharmony_ci src_writel(dev, MUnit.IOAR, val); 140462306a36Sopenharmony_ci src_readl(dev, MUnit.IOAR); 140562306a36Sopenharmony_ci val = src_readl(dev, MUnit.OIMR); 140662306a36Sopenharmony_ci src_writel(dev, MUnit.OIMR, 140762306a36Sopenharmony_ci val & (~(PMC_GLOBAL_INT_BIT2))); 140862306a36Sopenharmony_ci break; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci default: 141162306a36Sopenharmony_ci break; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic int aac_src_get_sync_status(struct aac_dev *dev) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci int msix_val = 0; 141862306a36Sopenharmony_ci int legacy_val = 0; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci msix_val = src_readl(dev, MUnit.ODR_MSI) & SRC_MSI_READ_MASK ? 1 : 0; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (!dev->msi_enabled) { 142362306a36Sopenharmony_ci /* 142462306a36Sopenharmony_ci * if Legacy int status indicates cmd is not complete 142562306a36Sopenharmony_ci * sample MSIx register to see if it indiactes cmd complete, 142662306a36Sopenharmony_ci * if yes set the controller in MSIx mode and consider cmd 142762306a36Sopenharmony_ci * completed 142862306a36Sopenharmony_ci */ 142962306a36Sopenharmony_ci legacy_val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT; 143062306a36Sopenharmony_ci if (!(legacy_val & 1) && msix_val) 143162306a36Sopenharmony_ci dev->msi_enabled = 1; 143262306a36Sopenharmony_ci return legacy_val; 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci return msix_val; 143662306a36Sopenharmony_ci} 1437