18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Adaptec AAC series RAID controller driver 48c2ecf20Sopenharmony_ci * (c) Copyright 2001 Red Hat Inc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * based on the old aacraid driver that is.. 78c2ecf20Sopenharmony_ci * Adaptec aacraid device driver for Linux. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2000-2010 Adaptec, Inc. 108c2ecf20Sopenharmony_ci * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 118c2ecf20Sopenharmony_ci * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Module Name: 148c2ecf20Sopenharmony_ci * src.c 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Abstract: Hardware Device Interface for PMC SRC based controllers 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/types.h> 228c2ecf20Sopenharmony_ci#include <linux/pci.h> 238c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 268c2ecf20Sopenharmony_ci#include <linux/delay.h> 278c2ecf20Sopenharmony_ci#include <linux/completion.h> 288c2ecf20Sopenharmony_ci#include <linux/time.h> 298c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 308c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "aacraid.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int aac_src_get_sync_status(struct aac_dev *dev); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic irqreturn_t aac_src_intr_message(int irq, void *dev_id) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct aac_msix_ctx *ctx; 398c2ecf20Sopenharmony_ci struct aac_dev *dev; 408c2ecf20Sopenharmony_ci unsigned long bellbits, bellbits_shifted; 418c2ecf20Sopenharmony_ci int vector_no; 428c2ecf20Sopenharmony_ci int isFastResponse, mode; 438c2ecf20Sopenharmony_ci u32 index, handle; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci ctx = (struct aac_msix_ctx *)dev_id; 468c2ecf20Sopenharmony_ci dev = ctx->dev; 478c2ecf20Sopenharmony_ci vector_no = ctx->vector_no; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (dev->msi_enabled) { 508c2ecf20Sopenharmony_ci mode = AAC_INT_MODE_MSI; 518c2ecf20Sopenharmony_ci if (vector_no == 0) { 528c2ecf20Sopenharmony_ci bellbits = src_readl(dev, MUnit.ODR_MSI); 538c2ecf20Sopenharmony_ci if (bellbits & 0x40000) 548c2ecf20Sopenharmony_ci mode |= AAC_INT_MODE_AIF; 558c2ecf20Sopenharmony_ci if (bellbits & 0x1000) 568c2ecf20Sopenharmony_ci mode |= AAC_INT_MODE_SYNC; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci } else { 598c2ecf20Sopenharmony_ci mode = AAC_INT_MODE_INTX; 608c2ecf20Sopenharmony_ci bellbits = src_readl(dev, MUnit.ODR_R); 618c2ecf20Sopenharmony_ci if (bellbits & PmDoorBellResponseSent) { 628c2ecf20Sopenharmony_ci bellbits = PmDoorBellResponseSent; 638c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, bellbits); 648c2ecf20Sopenharmony_ci src_readl(dev, MUnit.ODR_C); 658c2ecf20Sopenharmony_ci } else { 668c2ecf20Sopenharmony_ci bellbits_shifted = (bellbits >> SRC_ODR_SHIFT); 678c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, bellbits); 688c2ecf20Sopenharmony_ci src_readl(dev, MUnit.ODR_C); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (bellbits_shifted & DoorBellAifPending) 718c2ecf20Sopenharmony_ci mode |= AAC_INT_MODE_AIF; 728c2ecf20Sopenharmony_ci else if (bellbits_shifted & OUTBOUNDDOORBELL_0) 738c2ecf20Sopenharmony_ci mode |= AAC_INT_MODE_SYNC; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (mode & AAC_INT_MODE_SYNC) { 788c2ecf20Sopenharmony_ci unsigned long sflags; 798c2ecf20Sopenharmony_ci struct list_head *entry; 808c2ecf20Sopenharmony_ci int send_it = 0; 818c2ecf20Sopenharmony_ci extern int aac_sync_mode; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (!aac_sync_mode && !dev->msi_enabled) { 848c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, bellbits); 858c2ecf20Sopenharmony_ci src_readl(dev, MUnit.ODR_C); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (dev->sync_fib) { 898c2ecf20Sopenharmony_ci if (dev->sync_fib->callback) 908c2ecf20Sopenharmony_ci dev->sync_fib->callback(dev->sync_fib->callback_data, 918c2ecf20Sopenharmony_ci dev->sync_fib); 928c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->sync_fib->event_lock, sflags); 938c2ecf20Sopenharmony_ci if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) { 948c2ecf20Sopenharmony_ci dev->management_fib_count--; 958c2ecf20Sopenharmony_ci complete(&dev->sync_fib->event_wait); 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->sync_fib->event_lock, 988c2ecf20Sopenharmony_ci sflags); 998c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->sync_lock, sflags); 1008c2ecf20Sopenharmony_ci if (!list_empty(&dev->sync_fib_list)) { 1018c2ecf20Sopenharmony_ci entry = dev->sync_fib_list.next; 1028c2ecf20Sopenharmony_ci dev->sync_fib = list_entry(entry, 1038c2ecf20Sopenharmony_ci struct fib, 1048c2ecf20Sopenharmony_ci fiblink); 1058c2ecf20Sopenharmony_ci list_del(entry); 1068c2ecf20Sopenharmony_ci send_it = 1; 1078c2ecf20Sopenharmony_ci } else { 1088c2ecf20Sopenharmony_ci dev->sync_fib = NULL; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->sync_lock, sflags); 1118c2ecf20Sopenharmony_ci if (send_it) { 1128c2ecf20Sopenharmony_ci aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB, 1138c2ecf20Sopenharmony_ci (u32)dev->sync_fib->hw_fib_pa, 1148c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 1158c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, NULL); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci if (!dev->msi_enabled) 1198c2ecf20Sopenharmony_ci mode = 0; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (mode & AAC_INT_MODE_AIF) { 1248c2ecf20Sopenharmony_ci /* handle AIF */ 1258c2ecf20Sopenharmony_ci if (dev->sa_firmware) { 1268c2ecf20Sopenharmony_ci u32 events = src_readl(dev, MUnit.SCR0); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci aac_intr_normal(dev, events, 1, 0, NULL); 1298c2ecf20Sopenharmony_ci writel(events, &dev->IndexRegs->Mailbox[0]); 1308c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IDR, 1 << 23); 1318c2ecf20Sopenharmony_ci } else { 1328c2ecf20Sopenharmony_ci if (dev->aif_thread && dev->fsa_dev) 1338c2ecf20Sopenharmony_ci aac_intr_normal(dev, 0, 2, 0, NULL); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci if (dev->msi_enabled) 1368c2ecf20Sopenharmony_ci aac_src_access_devreg(dev, AAC_CLEAR_AIF_BIT); 1378c2ecf20Sopenharmony_ci mode = 0; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (mode) { 1418c2ecf20Sopenharmony_ci index = dev->host_rrq_idx[vector_no]; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci for (;;) { 1448c2ecf20Sopenharmony_ci isFastResponse = 0; 1458c2ecf20Sopenharmony_ci /* remove toggle bit (31) */ 1468c2ecf20Sopenharmony_ci handle = le32_to_cpu((dev->host_rrq[index]) 1478c2ecf20Sopenharmony_ci & 0x7fffffff); 1488c2ecf20Sopenharmony_ci /* check fast response bits (30, 1) */ 1498c2ecf20Sopenharmony_ci if (handle & 0x40000000) 1508c2ecf20Sopenharmony_ci isFastResponse = 1; 1518c2ecf20Sopenharmony_ci handle &= 0x0000ffff; 1528c2ecf20Sopenharmony_ci if (handle == 0) 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci handle >>= 2; 1558c2ecf20Sopenharmony_ci if (dev->msi_enabled && dev->max_msix > 1) 1568c2ecf20Sopenharmony_ci atomic_dec(&dev->rrq_outstanding[vector_no]); 1578c2ecf20Sopenharmony_ci aac_intr_normal(dev, handle, 0, isFastResponse, NULL); 1588c2ecf20Sopenharmony_ci dev->host_rrq[index++] = 0; 1598c2ecf20Sopenharmony_ci if (index == (vector_no + 1) * dev->vector_cap) 1608c2ecf20Sopenharmony_ci index = vector_no * dev->vector_cap; 1618c2ecf20Sopenharmony_ci dev->host_rrq_idx[vector_no] = index; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci mode = 0; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/** 1708c2ecf20Sopenharmony_ci * aac_src_disable_interrupt - Disable interrupts 1718c2ecf20Sopenharmony_ci * @dev: Adapter 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic void aac_src_disable_interrupt(struct aac_dev *dev) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/** 1808c2ecf20Sopenharmony_ci * aac_src_enable_interrupt_message - Enable interrupts 1818c2ecf20Sopenharmony_ci * @dev: Adapter 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void aac_src_enable_interrupt_message(struct aac_dev *dev) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci aac_src_access_devreg(dev, AAC_ENABLE_INTERRUPT); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/** 1908c2ecf20Sopenharmony_ci * src_sync_cmd - send a command and wait 1918c2ecf20Sopenharmony_ci * @dev: Adapter 1928c2ecf20Sopenharmony_ci * @command: Command to execute 1938c2ecf20Sopenharmony_ci * @p1: first parameter 1948c2ecf20Sopenharmony_ci * @p2: second parameter 1958c2ecf20Sopenharmony_ci * @p3: third parameter 1968c2ecf20Sopenharmony_ci * @p4: forth parameter 1978c2ecf20Sopenharmony_ci * @p5: fifth parameter 1988c2ecf20Sopenharmony_ci * @p6: sixth parameter 1998c2ecf20Sopenharmony_ci * @status: adapter status 2008c2ecf20Sopenharmony_ci * @r1: first return value 2018c2ecf20Sopenharmony_ci * @r2: second return valu 2028c2ecf20Sopenharmony_ci * @r3: third return value 2038c2ecf20Sopenharmony_ci * @r4: forth return value 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci * This routine will send a synchronous command to the adapter and wait 2068c2ecf20Sopenharmony_ci * for its completion. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int src_sync_cmd(struct aac_dev *dev, u32 command, 2108c2ecf20Sopenharmony_ci u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, 2118c2ecf20Sopenharmony_ci u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci unsigned long start; 2148c2ecf20Sopenharmony_ci unsigned long delay; 2158c2ecf20Sopenharmony_ci int ok; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * Write the command into Mailbox 0 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci writel(command, &dev->IndexRegs->Mailbox[0]); 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * Write the parameters into Mailboxes 1 - 6 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci writel(p1, &dev->IndexRegs->Mailbox[1]); 2258c2ecf20Sopenharmony_ci writel(p2, &dev->IndexRegs->Mailbox[2]); 2268c2ecf20Sopenharmony_ci writel(p3, &dev->IndexRegs->Mailbox[3]); 2278c2ecf20Sopenharmony_ci writel(p4, &dev->IndexRegs->Mailbox[4]); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* 2308c2ecf20Sopenharmony_ci * Clear the synch command doorbell to start on a clean slate. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci if (!dev->msi_enabled) 2338c2ecf20Sopenharmony_ci src_writel(dev, 2348c2ecf20Sopenharmony_ci MUnit.ODR_C, 2358c2ecf20Sopenharmony_ci OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * Disable doorbell interrupts 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* 2438c2ecf20Sopenharmony_ci * Force the completion of the mask register write before issuing 2448c2ecf20Sopenharmony_ci * the interrupt. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci src_readl(dev, MUnit.OIMR); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* 2498c2ecf20Sopenharmony_ci * Signal that there is a new synch command 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if ((!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) && 2548c2ecf20Sopenharmony_ci !dev->in_soft_reset) { 2558c2ecf20Sopenharmony_ci ok = 0; 2568c2ecf20Sopenharmony_ci start = jiffies; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (command == IOP_RESET_ALWAYS) { 2598c2ecf20Sopenharmony_ci /* Wait up to 10 sec */ 2608c2ecf20Sopenharmony_ci delay = 10*HZ; 2618c2ecf20Sopenharmony_ci } else { 2628c2ecf20Sopenharmony_ci /* Wait up to 5 minutes */ 2638c2ecf20Sopenharmony_ci delay = 300*HZ; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci while (time_before(jiffies, start+delay)) { 2668c2ecf20Sopenharmony_ci udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ 2678c2ecf20Sopenharmony_ci /* 2688c2ecf20Sopenharmony_ci * Mon960 will set doorbell0 bit when it has completed the command. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) { 2718c2ecf20Sopenharmony_ci /* 2728c2ecf20Sopenharmony_ci * Clear the doorbell. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci if (dev->msi_enabled) 2758c2ecf20Sopenharmony_ci aac_src_access_devreg(dev, 2768c2ecf20Sopenharmony_ci AAC_CLEAR_SYNC_BIT); 2778c2ecf20Sopenharmony_ci else 2788c2ecf20Sopenharmony_ci src_writel(dev, 2798c2ecf20Sopenharmony_ci MUnit.ODR_C, 2808c2ecf20Sopenharmony_ci OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); 2818c2ecf20Sopenharmony_ci ok = 1; 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci /* 2858c2ecf20Sopenharmony_ci * Yield the processor in case we are slow 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_ci msleep(1); 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci if (unlikely(ok != 1)) { 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * Restore interrupt mask even though we timed out 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci aac_adapter_enable_int(dev); 2948c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci /* 2978c2ecf20Sopenharmony_ci * Pull the synch status from Mailbox 0. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci if (status) 3008c2ecf20Sopenharmony_ci *status = readl(&dev->IndexRegs->Mailbox[0]); 3018c2ecf20Sopenharmony_ci if (r1) 3028c2ecf20Sopenharmony_ci *r1 = readl(&dev->IndexRegs->Mailbox[1]); 3038c2ecf20Sopenharmony_ci if (r2) 3048c2ecf20Sopenharmony_ci *r2 = readl(&dev->IndexRegs->Mailbox[2]); 3058c2ecf20Sopenharmony_ci if (r3) 3068c2ecf20Sopenharmony_ci *r3 = readl(&dev->IndexRegs->Mailbox[3]); 3078c2ecf20Sopenharmony_ci if (r4) 3088c2ecf20Sopenharmony_ci *r4 = readl(&dev->IndexRegs->Mailbox[4]); 3098c2ecf20Sopenharmony_ci if (command == GET_COMM_PREFERRED_SETTINGS) 3108c2ecf20Sopenharmony_ci dev->max_msix = 3118c2ecf20Sopenharmony_ci readl(&dev->IndexRegs->Mailbox[5]) & 0xFFFF; 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * Clear the synch command doorbell. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci if (!dev->msi_enabled) 3168c2ecf20Sopenharmony_ci src_writel(dev, 3178c2ecf20Sopenharmony_ci MUnit.ODR_C, 3188c2ecf20Sopenharmony_ci OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* 3228c2ecf20Sopenharmony_ci * Restore interrupt mask 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ci aac_adapter_enable_int(dev); 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/** 3298c2ecf20Sopenharmony_ci * aac_src_interrupt_adapter - interrupt adapter 3308c2ecf20Sopenharmony_ci * @dev: Adapter 3318c2ecf20Sopenharmony_ci * 3328c2ecf20Sopenharmony_ci * Send an interrupt to the i960 and breakpoint it. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic void aac_src_interrupt_adapter(struct aac_dev *dev) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci src_sync_cmd(dev, BREAKPOINT_REQUEST, 3388c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 3398c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, NULL); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci/** 3438c2ecf20Sopenharmony_ci * aac_src_notify_adapter - send an event to the adapter 3448c2ecf20Sopenharmony_ci * @dev: Adapter 3458c2ecf20Sopenharmony_ci * @event: Event to send 3468c2ecf20Sopenharmony_ci * 3478c2ecf20Sopenharmony_ci * Notify the i960 that something it probably cares about has 3488c2ecf20Sopenharmony_ci * happened. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic void aac_src_notify_adapter(struct aac_dev *dev, u32 event) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci switch (event) { 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci case AdapNormCmdQue: 3568c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 3578c2ecf20Sopenharmony_ci INBOUNDDOORBELL_1 << SRC_ODR_SHIFT); 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci case HostNormRespNotFull: 3608c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 3618c2ecf20Sopenharmony_ci INBOUNDDOORBELL_4 << SRC_ODR_SHIFT); 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci case AdapNormRespQue: 3648c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 3658c2ecf20Sopenharmony_ci INBOUNDDOORBELL_2 << SRC_ODR_SHIFT); 3668c2ecf20Sopenharmony_ci break; 3678c2ecf20Sopenharmony_ci case HostNormCmdNotFull: 3688c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 3698c2ecf20Sopenharmony_ci INBOUNDDOORBELL_3 << SRC_ODR_SHIFT); 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci case FastIo: 3728c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 3738c2ecf20Sopenharmony_ci INBOUNDDOORBELL_6 << SRC_ODR_SHIFT); 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci case AdapPrintfDone: 3768c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 3778c2ecf20Sopenharmony_ci INBOUNDDOORBELL_5 << SRC_ODR_SHIFT); 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci default: 3808c2ecf20Sopenharmony_ci BUG(); 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci/** 3868c2ecf20Sopenharmony_ci * aac_src_start_adapter - activate adapter 3878c2ecf20Sopenharmony_ci * @dev: Adapter 3888c2ecf20Sopenharmony_ci * 3898c2ecf20Sopenharmony_ci * Start up processing on an i960 based AAC adapter 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic void aac_src_start_adapter(struct aac_dev *dev) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci union aac_init *init; 3958c2ecf20Sopenharmony_ci int i; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* reset host_rrq_idx first */ 3988c2ecf20Sopenharmony_ci for (i = 0; i < dev->max_msix; i++) { 3998c2ecf20Sopenharmony_ci dev->host_rrq_idx[i] = i * dev->vector_cap; 4008c2ecf20Sopenharmony_ci atomic_set(&dev->rrq_outstanding[i], 0); 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci atomic_set(&dev->msix_counter, 0); 4038c2ecf20Sopenharmony_ci dev->fibs_pushed_no = 0; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci init = dev->init; 4068c2ecf20Sopenharmony_ci if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { 4078c2ecf20Sopenharmony_ci init->r8.host_elapsed_seconds = 4088c2ecf20Sopenharmony_ci cpu_to_le32(ktime_get_real_seconds()); 4098c2ecf20Sopenharmony_ci src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, 4108c2ecf20Sopenharmony_ci lower_32_bits(dev->init_pa), 4118c2ecf20Sopenharmony_ci upper_32_bits(dev->init_pa), 4128c2ecf20Sopenharmony_ci sizeof(struct _r8) + 4138c2ecf20Sopenharmony_ci (AAC_MAX_HRRQ - 1) * sizeof(struct _rrq), 4148c2ecf20Sopenharmony_ci 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 4158c2ecf20Sopenharmony_ci } else { 4168c2ecf20Sopenharmony_ci init->r7.host_elapsed_seconds = 4178c2ecf20Sopenharmony_ci cpu_to_le32(ktime_get_real_seconds()); 4188c2ecf20Sopenharmony_ci // We can only use a 32 bit address here 4198c2ecf20Sopenharmony_ci src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, 4208c2ecf20Sopenharmony_ci (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0, 4218c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, NULL); 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/** 4278c2ecf20Sopenharmony_ci * aac_src_check_health 4288c2ecf20Sopenharmony_ci * @dev: device to check if healthy 4298c2ecf20Sopenharmony_ci * 4308c2ecf20Sopenharmony_ci * Will attempt to determine if the specified adapter is alive and 4318c2ecf20Sopenharmony_ci * capable of handling requests, returning 0 if alive. 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_cistatic int aac_src_check_health(struct aac_dev *dev) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci u32 status = src_readl(dev, MUnit.OMR); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* 4388c2ecf20Sopenharmony_ci * Check to see if the board panic'd. 4398c2ecf20Sopenharmony_ci */ 4408c2ecf20Sopenharmony_ci if (unlikely(status & KERNEL_PANIC)) 4418c2ecf20Sopenharmony_ci goto err_blink; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* 4448c2ecf20Sopenharmony_ci * Check to see if the board failed any self tests. 4458c2ecf20Sopenharmony_ci */ 4468c2ecf20Sopenharmony_ci if (unlikely(status & SELF_TEST_FAILED)) 4478c2ecf20Sopenharmony_ci goto err_out; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* 4508c2ecf20Sopenharmony_ci * Check to see if the board failed any self tests. 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_ci if (unlikely(status & MONITOR_PANIC)) 4538c2ecf20Sopenharmony_ci goto err_out; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* 4568c2ecf20Sopenharmony_ci * Wait for the adapter to be up and running. 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_ci if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) 4598c2ecf20Sopenharmony_ci return -3; 4608c2ecf20Sopenharmony_ci /* 4618c2ecf20Sopenharmony_ci * Everything is OK 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci return 0; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cierr_out: 4668c2ecf20Sopenharmony_ci return -1; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cierr_blink: 4698c2ecf20Sopenharmony_ci return (status >> 16) & 0xFF; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic inline u32 aac_get_vector(struct aac_dev *dev) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci return atomic_inc_return(&dev->msix_counter)%dev->max_msix; 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci/** 4788c2ecf20Sopenharmony_ci * aac_src_deliver_message 4798c2ecf20Sopenharmony_ci * @fib: fib to issue 4808c2ecf20Sopenharmony_ci * 4818c2ecf20Sopenharmony_ci * Will send a fib, returning 0 if successful. 4828c2ecf20Sopenharmony_ci */ 4838c2ecf20Sopenharmony_cistatic int aac_src_deliver_message(struct fib *fib) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct aac_dev *dev = fib->dev; 4868c2ecf20Sopenharmony_ci struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; 4878c2ecf20Sopenharmony_ci u32 fibsize; 4888c2ecf20Sopenharmony_ci dma_addr_t address; 4898c2ecf20Sopenharmony_ci struct aac_fib_xporthdr *pFibX; 4908c2ecf20Sopenharmony_ci int native_hba; 4918c2ecf20Sopenharmony_ci#if !defined(writeq) 4928c2ecf20Sopenharmony_ci unsigned long flags; 4938c2ecf20Sopenharmony_ci#endif 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci u16 vector_no; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci atomic_inc(&q->numpending); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci native_hba = (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) ? 1 : 0; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (dev->msi_enabled && dev->max_msix > 1 && 5038c2ecf20Sopenharmony_ci (native_hba || fib->hw_fib_va->header.Command != AifRequest)) { 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) 5068c2ecf20Sopenharmony_ci && dev->sa_firmware) 5078c2ecf20Sopenharmony_ci vector_no = aac_get_vector(dev); 5088c2ecf20Sopenharmony_ci else 5098c2ecf20Sopenharmony_ci vector_no = fib->vector_no; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (native_hba) { 5128c2ecf20Sopenharmony_ci if (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF) { 5138c2ecf20Sopenharmony_ci struct aac_hba_tm_req *tm_req; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci tm_req = (struct aac_hba_tm_req *) 5168c2ecf20Sopenharmony_ci fib->hw_fib_va; 5178c2ecf20Sopenharmony_ci if (tm_req->iu_type == 5188c2ecf20Sopenharmony_ci HBA_IU_TYPE_SCSI_TM_REQ) { 5198c2ecf20Sopenharmony_ci ((struct aac_hba_tm_req *) 5208c2ecf20Sopenharmony_ci fib->hw_fib_va)->reply_qid 5218c2ecf20Sopenharmony_ci = vector_no; 5228c2ecf20Sopenharmony_ci ((struct aac_hba_tm_req *) 5238c2ecf20Sopenharmony_ci fib->hw_fib_va)->request_id 5248c2ecf20Sopenharmony_ci += (vector_no << 16); 5258c2ecf20Sopenharmony_ci } else { 5268c2ecf20Sopenharmony_ci ((struct aac_hba_reset_req *) 5278c2ecf20Sopenharmony_ci fib->hw_fib_va)->reply_qid 5288c2ecf20Sopenharmony_ci = vector_no; 5298c2ecf20Sopenharmony_ci ((struct aac_hba_reset_req *) 5308c2ecf20Sopenharmony_ci fib->hw_fib_va)->request_id 5318c2ecf20Sopenharmony_ci += (vector_no << 16); 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci } else { 5348c2ecf20Sopenharmony_ci ((struct aac_hba_cmd_req *) 5358c2ecf20Sopenharmony_ci fib->hw_fib_va)->reply_qid 5368c2ecf20Sopenharmony_ci = vector_no; 5378c2ecf20Sopenharmony_ci ((struct aac_hba_cmd_req *) 5388c2ecf20Sopenharmony_ci fib->hw_fib_va)->request_id 5398c2ecf20Sopenharmony_ci += (vector_no << 16); 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci } else { 5428c2ecf20Sopenharmony_ci fib->hw_fib_va->header.Handle += (vector_no << 16); 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci } else { 5458c2ecf20Sopenharmony_ci vector_no = 0; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci atomic_inc(&dev->rrq_outstanding[vector_no]); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (native_hba) { 5518c2ecf20Sopenharmony_ci address = fib->hw_fib_pa; 5528c2ecf20Sopenharmony_ci fibsize = (fib->hbacmd_size + 127) / 128 - 1; 5538c2ecf20Sopenharmony_ci if (fibsize > 31) 5548c2ecf20Sopenharmony_ci fibsize = 31; 5558c2ecf20Sopenharmony_ci address |= fibsize; 5568c2ecf20Sopenharmony_ci#if defined(writeq) 5578c2ecf20Sopenharmony_ci src_writeq(dev, MUnit.IQN_L, (u64)address); 5588c2ecf20Sopenharmony_ci#else 5598c2ecf20Sopenharmony_ci spin_lock_irqsave(&fib->dev->iq_lock, flags); 5608c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IQN_H, 5618c2ecf20Sopenharmony_ci upper_32_bits(address) & 0xffffffff); 5628c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IQN_L, address & 0xffffffff); 5638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fib->dev->iq_lock, flags); 5648c2ecf20Sopenharmony_ci#endif 5658c2ecf20Sopenharmony_ci } else { 5668c2ecf20Sopenharmony_ci if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 || 5678c2ecf20Sopenharmony_ci dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) { 5688c2ecf20Sopenharmony_ci /* Calculate the amount to the fibsize bits */ 5698c2ecf20Sopenharmony_ci fibsize = (le16_to_cpu(fib->hw_fib_va->header.Size) 5708c2ecf20Sopenharmony_ci + 127) / 128 - 1; 5718c2ecf20Sopenharmony_ci /* New FIB header, 32-bit */ 5728c2ecf20Sopenharmony_ci address = fib->hw_fib_pa; 5738c2ecf20Sopenharmony_ci fib->hw_fib_va->header.StructType = FIB_MAGIC2; 5748c2ecf20Sopenharmony_ci fib->hw_fib_va->header.SenderFibAddress = 5758c2ecf20Sopenharmony_ci cpu_to_le32((u32)address); 5768c2ecf20Sopenharmony_ci fib->hw_fib_va->header.u.TimeStamp = 0; 5778c2ecf20Sopenharmony_ci WARN_ON(upper_32_bits(address) != 0L); 5788c2ecf20Sopenharmony_ci } else { 5798c2ecf20Sopenharmony_ci /* Calculate the amount to the fibsize bits */ 5808c2ecf20Sopenharmony_ci fibsize = (sizeof(struct aac_fib_xporthdr) + 5818c2ecf20Sopenharmony_ci le16_to_cpu(fib->hw_fib_va->header.Size) 5828c2ecf20Sopenharmony_ci + 127) / 128 - 1; 5838c2ecf20Sopenharmony_ci /* Fill XPORT header */ 5848c2ecf20Sopenharmony_ci pFibX = (struct aac_fib_xporthdr *) 5858c2ecf20Sopenharmony_ci ((unsigned char *)fib->hw_fib_va - 5868c2ecf20Sopenharmony_ci sizeof(struct aac_fib_xporthdr)); 5878c2ecf20Sopenharmony_ci pFibX->Handle = fib->hw_fib_va->header.Handle; 5888c2ecf20Sopenharmony_ci pFibX->HostAddress = 5898c2ecf20Sopenharmony_ci cpu_to_le64((u64)fib->hw_fib_pa); 5908c2ecf20Sopenharmony_ci pFibX->Size = cpu_to_le32( 5918c2ecf20Sopenharmony_ci le16_to_cpu(fib->hw_fib_va->header.Size)); 5928c2ecf20Sopenharmony_ci address = fib->hw_fib_pa - 5938c2ecf20Sopenharmony_ci (u64)sizeof(struct aac_fib_xporthdr); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci if (fibsize > 31) 5968c2ecf20Sopenharmony_ci fibsize = 31; 5978c2ecf20Sopenharmony_ci address |= fibsize; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci#if defined(writeq) 6008c2ecf20Sopenharmony_ci src_writeq(dev, MUnit.IQ_L, (u64)address); 6018c2ecf20Sopenharmony_ci#else 6028c2ecf20Sopenharmony_ci spin_lock_irqsave(&fib->dev->iq_lock, flags); 6038c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IQ_H, 6048c2ecf20Sopenharmony_ci upper_32_bits(address) & 0xffffffff); 6058c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IQ_L, address & 0xffffffff); 6068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fib->dev->iq_lock, flags); 6078c2ecf20Sopenharmony_ci#endif 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci return 0; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci/** 6138c2ecf20Sopenharmony_ci * aac_src_ioremap 6148c2ecf20Sopenharmony_ci * @dev: device ioremap 6158c2ecf20Sopenharmony_ci * @size: mapping resize request 6168c2ecf20Sopenharmony_ci * 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_cistatic int aac_src_ioremap(struct aac_dev *dev, u32 size) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci if (!size) { 6218c2ecf20Sopenharmony_ci iounmap(dev->regs.src.bar1); 6228c2ecf20Sopenharmony_ci dev->regs.src.bar1 = NULL; 6238c2ecf20Sopenharmony_ci iounmap(dev->regs.src.bar0); 6248c2ecf20Sopenharmony_ci dev->base = dev->regs.src.bar0 = NULL; 6258c2ecf20Sopenharmony_ci return 0; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2), 6288c2ecf20Sopenharmony_ci AAC_MIN_SRC_BAR1_SIZE); 6298c2ecf20Sopenharmony_ci dev->base = NULL; 6308c2ecf20Sopenharmony_ci if (dev->regs.src.bar1 == NULL) 6318c2ecf20Sopenharmony_ci return -1; 6328c2ecf20Sopenharmony_ci dev->base = dev->regs.src.bar0 = ioremap(dev->base_start, size); 6338c2ecf20Sopenharmony_ci if (dev->base == NULL) { 6348c2ecf20Sopenharmony_ci iounmap(dev->regs.src.bar1); 6358c2ecf20Sopenharmony_ci dev->regs.src.bar1 = NULL; 6368c2ecf20Sopenharmony_ci return -1; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci dev->IndexRegs = &((struct src_registers __iomem *) 6398c2ecf20Sopenharmony_ci dev->base)->u.tupelo.IndexRegs; 6408c2ecf20Sopenharmony_ci return 0; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/** 6448c2ecf20Sopenharmony_ci * aac_srcv_ioremap 6458c2ecf20Sopenharmony_ci * @dev: device ioremap 6468c2ecf20Sopenharmony_ci * @size: mapping resize request 6478c2ecf20Sopenharmony_ci * 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_cistatic int aac_srcv_ioremap(struct aac_dev *dev, u32 size) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci if (!size) { 6528c2ecf20Sopenharmony_ci iounmap(dev->regs.src.bar0); 6538c2ecf20Sopenharmony_ci dev->base = dev->regs.src.bar0 = NULL; 6548c2ecf20Sopenharmony_ci return 0; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci dev->regs.src.bar1 = 6588c2ecf20Sopenharmony_ci ioremap(pci_resource_start(dev->pdev, 2), AAC_MIN_SRCV_BAR1_SIZE); 6598c2ecf20Sopenharmony_ci dev->base = NULL; 6608c2ecf20Sopenharmony_ci if (dev->regs.src.bar1 == NULL) 6618c2ecf20Sopenharmony_ci return -1; 6628c2ecf20Sopenharmony_ci dev->base = dev->regs.src.bar0 = ioremap(dev->base_start, size); 6638c2ecf20Sopenharmony_ci if (dev->base == NULL) { 6648c2ecf20Sopenharmony_ci iounmap(dev->regs.src.bar1); 6658c2ecf20Sopenharmony_ci dev->regs.src.bar1 = NULL; 6668c2ecf20Sopenharmony_ci return -1; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci dev->IndexRegs = &((struct src_registers __iomem *) 6698c2ecf20Sopenharmony_ci dev->base)->u.denali.IndexRegs; 6708c2ecf20Sopenharmony_ci return 0; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_civoid aac_set_intx_mode(struct aac_dev *dev) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci if (dev->msi_enabled) { 6768c2ecf20Sopenharmony_ci aac_src_access_devreg(dev, AAC_ENABLE_INTX); 6778c2ecf20Sopenharmony_ci dev->msi_enabled = 0; 6788c2ecf20Sopenharmony_ci msleep(5000); /* Delay 5 seconds */ 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic void aac_clear_omr(struct aac_dev *dev) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci u32 omr_value = 0; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci omr_value = src_readl(dev, MUnit.OMR); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* 6898c2ecf20Sopenharmony_ci * Check for PCI Errors or Kernel Panic 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci if ((omr_value == INVALID_OMR) || (omr_value & KERNEL_PANIC)) 6928c2ecf20Sopenharmony_ci omr_value = 0; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* 6958c2ecf20Sopenharmony_ci * Preserve MSIX Value if any 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_ci src_writel(dev, MUnit.OMR, omr_value & AAC_INT_MODE_MSIX); 6988c2ecf20Sopenharmony_ci src_readl(dev, MUnit.OMR); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic void aac_dump_fw_fib_iop_reset(struct aac_dev *dev) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci __le32 supported_options3; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (!aac_fib_dump) 7068c2ecf20Sopenharmony_ci return; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci supported_options3 = dev->supplement_adapter_info.supported_options3; 7098c2ecf20Sopenharmony_ci if (!(supported_options3 & AAC_OPTION_SUPPORTED3_IOP_RESET_FIB_DUMP)) 7108c2ecf20Sopenharmony_ci return; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci aac_adapter_sync_cmd(dev, IOP_RESET_FW_FIB_DUMP, 7138c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic bool aac_is_ctrl_up_and_running(struct aac_dev *dev) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci bool ctrl_up = true; 7198c2ecf20Sopenharmony_ci unsigned long status, start; 7208c2ecf20Sopenharmony_ci bool is_up = false; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci start = jiffies; 7238c2ecf20Sopenharmony_ci do { 7248c2ecf20Sopenharmony_ci schedule(); 7258c2ecf20Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (status == 0xffffffff) 7288c2ecf20Sopenharmony_ci status = 0; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (status & KERNEL_BOOTING) { 7318c2ecf20Sopenharmony_ci start = jiffies; 7328c2ecf20Sopenharmony_ci continue; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (time_after(jiffies, start+HZ*SOFT_RESET_TIME)) { 7368c2ecf20Sopenharmony_ci ctrl_up = false; 7378c2ecf20Sopenharmony_ci break; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci is_up = status & KERNEL_UP_AND_RUNNING; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci } while (!is_up); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci return ctrl_up; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic void aac_src_drop_io(struct aac_dev *dev) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci if (!dev->soft_reset_support) 7508c2ecf20Sopenharmony_ci return; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci aac_adapter_sync_cmd(dev, DROP_IO, 7538c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic void aac_notify_fw_of_iop_reset(struct aac_dev *dev) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, 0, 0, 0, 0, 0, 0, NULL, 7598c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL); 7608c2ecf20Sopenharmony_ci aac_src_drop_io(dev); 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic void aac_send_iop_reset(struct aac_dev *dev) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci aac_dump_fw_fib_iop_reset(dev); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci aac_notify_fw_of_iop_reset(dev); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci aac_set_intx_mode(dev); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci aac_clear_omr(dev); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IDR, IOP_SRC_RESET_MASK); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci msleep(5000); 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cistatic void aac_send_hardware_soft_reset(struct aac_dev *dev) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci u_int32_t val; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci aac_clear_omr(dev); 7838c2ecf20Sopenharmony_ci val = readl(((char *)(dev->base) + IBW_SWR_OFFSET)); 7848c2ecf20Sopenharmony_ci val |= 0x01; 7858c2ecf20Sopenharmony_ci writel(val, ((char *)(dev->base) + IBW_SWR_OFFSET)); 7868c2ecf20Sopenharmony_ci msleep_interruptible(20000); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int aac_src_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci bool is_ctrl_up; 7928c2ecf20Sopenharmony_ci int ret = 0; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (bled < 0) 7958c2ecf20Sopenharmony_ci goto invalid_out; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (bled) 7988c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "adapter kernel panic'd %x.\n", bled); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* 8018c2ecf20Sopenharmony_ci * When there is a BlinkLED, IOP_RESET has not effect 8028c2ecf20Sopenharmony_ci */ 8038c2ecf20Sopenharmony_ci if (bled >= 2 && dev->sa_firmware && reset_type & HW_IOP_RESET) 8048c2ecf20Sopenharmony_ci reset_type &= ~HW_IOP_RESET; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "Controller reset type is %d\n", reset_type); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (reset_type & HW_IOP_RESET) { 8118c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "Issuing IOP reset\n"); 8128c2ecf20Sopenharmony_ci aac_send_iop_reset(dev); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* 8158c2ecf20Sopenharmony_ci * Creates a delay or wait till up and running comes thru 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci is_ctrl_up = aac_is_ctrl_up_and_running(dev); 8188c2ecf20Sopenharmony_ci if (!is_ctrl_up) 8198c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "IOP reset failed\n"); 8208c2ecf20Sopenharmony_ci else { 8218c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "IOP reset succeeded\n"); 8228c2ecf20Sopenharmony_ci goto set_startup; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (!dev->sa_firmware) { 8278c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "ARC Reset attempt failed\n"); 8288c2ecf20Sopenharmony_ci ret = -ENODEV; 8298c2ecf20Sopenharmony_ci goto out; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (reset_type & HW_SOFT_RESET) { 8338c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "Issuing SOFT reset\n"); 8348c2ecf20Sopenharmony_ci aac_send_hardware_soft_reset(dev); 8358c2ecf20Sopenharmony_ci dev->msi_enabled = 0; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci is_ctrl_up = aac_is_ctrl_up_and_running(dev); 8388c2ecf20Sopenharmony_ci if (!is_ctrl_up) { 8398c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "SOFT reset failed\n"); 8408c2ecf20Sopenharmony_ci ret = -ENODEV; 8418c2ecf20Sopenharmony_ci goto out; 8428c2ecf20Sopenharmony_ci } else 8438c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "SOFT reset succeeded\n"); 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ciset_startup: 8478c2ecf20Sopenharmony_ci if (startup_timeout < 300) 8488c2ecf20Sopenharmony_ci startup_timeout = 300; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ciout: 8518c2ecf20Sopenharmony_ci return ret; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ciinvalid_out: 8548c2ecf20Sopenharmony_ci if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC) 8558c2ecf20Sopenharmony_ci ret = -ENODEV; 8568c2ecf20Sopenharmony_cigoto out; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci/** 8608c2ecf20Sopenharmony_ci * aac_src_select_comm - Select communications method 8618c2ecf20Sopenharmony_ci * @dev: Adapter 8628c2ecf20Sopenharmony_ci * @comm: communications method 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_cistatic int aac_src_select_comm(struct aac_dev *dev, int comm) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci switch (comm) { 8678c2ecf20Sopenharmony_ci case AAC_COMM_MESSAGE: 8688c2ecf20Sopenharmony_ci dev->a_ops.adapter_intr = aac_src_intr_message; 8698c2ecf20Sopenharmony_ci dev->a_ops.adapter_deliver = aac_src_deliver_message; 8708c2ecf20Sopenharmony_ci break; 8718c2ecf20Sopenharmony_ci default: 8728c2ecf20Sopenharmony_ci return 1; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci return 0; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci/** 8788c2ecf20Sopenharmony_ci * aac_src_init - initialize an Cardinal Frey Bar card 8798c2ecf20Sopenharmony_ci * @dev: device to configure 8808c2ecf20Sopenharmony_ci * 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ciint aac_src_init(struct aac_dev *dev) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci unsigned long start; 8868c2ecf20Sopenharmony_ci unsigned long status; 8878c2ecf20Sopenharmony_ci int restart = 0; 8888c2ecf20Sopenharmony_ci int instance = dev->id; 8898c2ecf20Sopenharmony_ci const char *name = dev->name; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci dev->a_ops.adapter_ioremap = aac_src_ioremap; 8928c2ecf20Sopenharmony_ci dev->a_ops.adapter_comm = aac_src_select_comm; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci dev->base_size = AAC_MIN_SRC_BAR0_SIZE; 8958c2ecf20Sopenharmony_ci if (aac_adapter_ioremap(dev, dev->base_size)) { 8968c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: unable to map adapter.\n", name); 8978c2ecf20Sopenharmony_ci goto error_iounmap; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* Failure to reset here is an option ... */ 9018c2ecf20Sopenharmony_ci dev->a_ops.adapter_sync_cmd = src_sync_cmd; 9028c2ecf20Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (dev->init_reset) { 9058c2ecf20Sopenharmony_ci dev->init_reset = false; 9068c2ecf20Sopenharmony_ci if (!aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) 9078c2ecf20Sopenharmony_ci ++restart; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* 9118c2ecf20Sopenharmony_ci * Check to see if the board panic'd while booting. 9128c2ecf20Sopenharmony_ci */ 9138c2ecf20Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 9148c2ecf20Sopenharmony_ci if (status & KERNEL_PANIC) { 9158c2ecf20Sopenharmony_ci if (aac_src_restart_adapter(dev, 9168c2ecf20Sopenharmony_ci aac_src_check_health(dev), IOP_HWSOFT_RESET)) 9178c2ecf20Sopenharmony_ci goto error_iounmap; 9188c2ecf20Sopenharmony_ci ++restart; 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci /* 9218c2ecf20Sopenharmony_ci * Check to see if the board failed any self tests. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 9248c2ecf20Sopenharmony_ci if (status & SELF_TEST_FAILED) { 9258c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter self-test failed.\n", 9268c2ecf20Sopenharmony_ci dev->name, instance); 9278c2ecf20Sopenharmony_ci goto error_iounmap; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci /* 9308c2ecf20Sopenharmony_ci * Check to see if the monitor panic'd while booting. 9318c2ecf20Sopenharmony_ci */ 9328c2ecf20Sopenharmony_ci if (status & MONITOR_PANIC) { 9338c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter monitor panic.\n", 9348c2ecf20Sopenharmony_ci dev->name, instance); 9358c2ecf20Sopenharmony_ci goto error_iounmap; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci start = jiffies; 9388c2ecf20Sopenharmony_ci /* 9398c2ecf20Sopenharmony_ci * Wait for the adapter to be up and running. Wait up to 3 minutes 9408c2ecf20Sopenharmony_ci */ 9418c2ecf20Sopenharmony_ci while (!((status = src_readl(dev, MUnit.OMR)) & 9428c2ecf20Sopenharmony_ci KERNEL_UP_AND_RUNNING)) { 9438c2ecf20Sopenharmony_ci if ((restart && 9448c2ecf20Sopenharmony_ci (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || 9458c2ecf20Sopenharmony_ci time_after(jiffies, start+HZ*startup_timeout)) { 9468c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 9478c2ecf20Sopenharmony_ci dev->name, instance, status); 9488c2ecf20Sopenharmony_ci goto error_iounmap; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci if (!restart && 9518c2ecf20Sopenharmony_ci ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || 9528c2ecf20Sopenharmony_ci time_after(jiffies, start + HZ * 9538c2ecf20Sopenharmony_ci ((startup_timeout > 60) 9548c2ecf20Sopenharmony_ci ? (startup_timeout - 60) 9558c2ecf20Sopenharmony_ci : (startup_timeout / 2))))) { 9568c2ecf20Sopenharmony_ci if (likely(!aac_src_restart_adapter(dev, 9578c2ecf20Sopenharmony_ci aac_src_check_health(dev), IOP_HWSOFT_RESET))) 9588c2ecf20Sopenharmony_ci start = jiffies; 9598c2ecf20Sopenharmony_ci ++restart; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci msleep(1); 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci if (restart && aac_commit) 9648c2ecf20Sopenharmony_ci aac_commit = 1; 9658c2ecf20Sopenharmony_ci /* 9668c2ecf20Sopenharmony_ci * Fill in the common function dispatch table. 9678c2ecf20Sopenharmony_ci */ 9688c2ecf20Sopenharmony_ci dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter; 9698c2ecf20Sopenharmony_ci dev->a_ops.adapter_disable_int = aac_src_disable_interrupt; 9708c2ecf20Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; 9718c2ecf20Sopenharmony_ci dev->a_ops.adapter_notify = aac_src_notify_adapter; 9728c2ecf20Sopenharmony_ci dev->a_ops.adapter_sync_cmd = src_sync_cmd; 9738c2ecf20Sopenharmony_ci dev->a_ops.adapter_check_health = aac_src_check_health; 9748c2ecf20Sopenharmony_ci dev->a_ops.adapter_restart = aac_src_restart_adapter; 9758c2ecf20Sopenharmony_ci dev->a_ops.adapter_start = aac_src_start_adapter; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* 9788c2ecf20Sopenharmony_ci * First clear out all interrupts. Then enable the one's that we 9798c2ecf20Sopenharmony_ci * can handle. 9808c2ecf20Sopenharmony_ci */ 9818c2ecf20Sopenharmony_ci aac_adapter_comm(dev, AAC_COMM_MESSAGE); 9828c2ecf20Sopenharmony_ci aac_adapter_disable_int(dev); 9838c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 0xffffffff); 9848c2ecf20Sopenharmony_ci aac_adapter_enable_int(dev); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (aac_init_adapter(dev) == NULL) 9878c2ecf20Sopenharmony_ci goto error_iounmap; 9888c2ecf20Sopenharmony_ci if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1) 9898c2ecf20Sopenharmony_ci goto error_iounmap; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci dev->msi = !pci_enable_msi(dev->pdev); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci dev->aac_msix[0].vector_no = 0; 9948c2ecf20Sopenharmony_ci dev->aac_msix[0].dev = dev; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, 9978c2ecf20Sopenharmony_ci IRQF_SHARED, "aacraid", &(dev->aac_msix[0])) < 0) { 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci if (dev->msi) 10008c2ecf20Sopenharmony_ci pci_disable_msi(dev->pdev); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: Interrupt unavailable.\n", 10038c2ecf20Sopenharmony_ci name, instance); 10048c2ecf20Sopenharmony_ci goto error_iounmap; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci dev->dbg_base = pci_resource_start(dev->pdev, 2); 10078c2ecf20Sopenharmony_ci dev->dbg_base_mapped = dev->regs.src.bar1; 10088c2ecf20Sopenharmony_ci dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE; 10098c2ecf20Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci aac_adapter_enable_int(dev); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (!dev->sync_mode) { 10148c2ecf20Sopenharmony_ci /* 10158c2ecf20Sopenharmony_ci * Tell the adapter that all is configured, and it can 10168c2ecf20Sopenharmony_ci * start accepting requests 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_ci aac_src_start_adapter(dev); 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cierror_iounmap: 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci return -1; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic int aac_src_wait_sync(struct aac_dev *dev, int *status) 10288c2ecf20Sopenharmony_ci{ 10298c2ecf20Sopenharmony_ci unsigned long start = jiffies; 10308c2ecf20Sopenharmony_ci unsigned long usecs = 0; 10318c2ecf20Sopenharmony_ci int delay = 5 * HZ; 10328c2ecf20Sopenharmony_ci int rc = 1; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci while (time_before(jiffies, start+delay)) { 10358c2ecf20Sopenharmony_ci /* 10368c2ecf20Sopenharmony_ci * Delay 5 microseconds to let Mon960 get info. 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_ci udelay(5); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci /* 10418c2ecf20Sopenharmony_ci * Mon960 will set doorbell0 bit when it has completed the 10428c2ecf20Sopenharmony_ci * command. 10438c2ecf20Sopenharmony_ci */ 10448c2ecf20Sopenharmony_ci if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) { 10458c2ecf20Sopenharmony_ci /* 10468c2ecf20Sopenharmony_ci * Clear: the doorbell. 10478c2ecf20Sopenharmony_ci */ 10488c2ecf20Sopenharmony_ci if (dev->msi_enabled) 10498c2ecf20Sopenharmony_ci aac_src_access_devreg(dev, AAC_CLEAR_SYNC_BIT); 10508c2ecf20Sopenharmony_ci else 10518c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 10528c2ecf20Sopenharmony_ci OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); 10538c2ecf20Sopenharmony_ci rc = 0; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci break; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* 10598c2ecf20Sopenharmony_ci * Yield the processor in case we are slow 10608c2ecf20Sopenharmony_ci */ 10618c2ecf20Sopenharmony_ci usecs = 1 * USEC_PER_MSEC; 10628c2ecf20Sopenharmony_ci usleep_range(usecs, usecs + 50); 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci /* 10658c2ecf20Sopenharmony_ci * Pull the synch status from Mailbox 0. 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_ci if (status && !rc) { 10688c2ecf20Sopenharmony_ci status[0] = readl(&dev->IndexRegs->Mailbox[0]); 10698c2ecf20Sopenharmony_ci status[1] = readl(&dev->IndexRegs->Mailbox[1]); 10708c2ecf20Sopenharmony_ci status[2] = readl(&dev->IndexRegs->Mailbox[2]); 10718c2ecf20Sopenharmony_ci status[3] = readl(&dev->IndexRegs->Mailbox[3]); 10728c2ecf20Sopenharmony_ci status[4] = readl(&dev->IndexRegs->Mailbox[4]); 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci return rc; 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci/** 10798c2ecf20Sopenharmony_ci * aac_src_soft_reset - perform soft reset to speed up 10808c2ecf20Sopenharmony_ci * access 10818c2ecf20Sopenharmony_ci * 10828c2ecf20Sopenharmony_ci * Assumptions: That the controller is in a state where we can 10838c2ecf20Sopenharmony_ci * bring it back to life with an init struct. We can only use 10848c2ecf20Sopenharmony_ci * fast sync commands, as the timeout is 5 seconds. 10858c2ecf20Sopenharmony_ci * 10868c2ecf20Sopenharmony_ci * @dev: device to configure 10878c2ecf20Sopenharmony_ci * 10888c2ecf20Sopenharmony_ci */ 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_cistatic int aac_src_soft_reset(struct aac_dev *dev) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci u32 status_omr = src_readl(dev, MUnit.OMR); 10938c2ecf20Sopenharmony_ci u32 status[5]; 10948c2ecf20Sopenharmony_ci int rc = 1; 10958c2ecf20Sopenharmony_ci int state = 0; 10968c2ecf20Sopenharmony_ci char *state_str[7] = { 10978c2ecf20Sopenharmony_ci "GET_ADAPTER_PROPERTIES Failed", 10988c2ecf20Sopenharmony_ci "GET_ADAPTER_PROPERTIES timeout", 10998c2ecf20Sopenharmony_ci "SOFT_RESET not supported", 11008c2ecf20Sopenharmony_ci "DROP_IO Failed", 11018c2ecf20Sopenharmony_ci "DROP_IO timeout", 11028c2ecf20Sopenharmony_ci "Check Health failed" 11038c2ecf20Sopenharmony_ci }; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (status_omr == INVALID_OMR) 11068c2ecf20Sopenharmony_ci return 1; // pcie hosed 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (!(status_omr & KERNEL_UP_AND_RUNNING)) 11098c2ecf20Sopenharmony_ci return 1; // not up and running 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* 11128c2ecf20Sopenharmony_ci * We go into soft reset mode to allow us to handle response 11138c2ecf20Sopenharmony_ci */ 11148c2ecf20Sopenharmony_ci dev->in_soft_reset = 1; 11158c2ecf20Sopenharmony_ci dev->msi_enabled = status_omr & AAC_INT_MODE_MSIX; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci /* Get adapter properties */ 11188c2ecf20Sopenharmony_ci rc = aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, 0, 0, 0, 11198c2ecf20Sopenharmony_ci 0, 0, 0, status+0, status+1, status+2, status+3, status+4); 11208c2ecf20Sopenharmony_ci if (rc) 11218c2ecf20Sopenharmony_ci goto out; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci state++; 11248c2ecf20Sopenharmony_ci if (aac_src_wait_sync(dev, status)) { 11258c2ecf20Sopenharmony_ci rc = 1; 11268c2ecf20Sopenharmony_ci goto out; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci state++; 11308c2ecf20Sopenharmony_ci if (!(status[1] & le32_to_cpu(AAC_OPT_EXTENDED) && 11318c2ecf20Sopenharmony_ci (status[4] & le32_to_cpu(AAC_EXTOPT_SOFT_RESET)))) { 11328c2ecf20Sopenharmony_ci rc = 2; 11338c2ecf20Sopenharmony_ci goto out; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if ((status[1] & le32_to_cpu(AAC_OPT_EXTENDED)) && 11378c2ecf20Sopenharmony_ci (status[4] & le32_to_cpu(AAC_EXTOPT_SA_FIRMWARE))) 11388c2ecf20Sopenharmony_ci dev->sa_firmware = 1; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci state++; 11418c2ecf20Sopenharmony_ci rc = aac_adapter_sync_cmd(dev, DROP_IO, 0, 0, 0, 0, 0, 0, 11428c2ecf20Sopenharmony_ci status+0, status+1, status+2, status+3, status+4); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci if (rc) 11458c2ecf20Sopenharmony_ci goto out; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci state++; 11488c2ecf20Sopenharmony_ci if (aac_src_wait_sync(dev, status)) { 11498c2ecf20Sopenharmony_ci rc = 3; 11508c2ecf20Sopenharmony_ci goto out; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (status[1]) 11548c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "%s: %d outstanding I/O pending\n", 11558c2ecf20Sopenharmony_ci __func__, status[1]); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci state++; 11588c2ecf20Sopenharmony_ci rc = aac_src_check_health(dev); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ciout: 11618c2ecf20Sopenharmony_ci dev->in_soft_reset = 0; 11628c2ecf20Sopenharmony_ci dev->msi_enabled = 0; 11638c2ecf20Sopenharmony_ci if (rc) 11648c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "%s: %s status = %d", __func__, 11658c2ecf20Sopenharmony_ci state_str[state], rc); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci return rc; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci/** 11708c2ecf20Sopenharmony_ci * aac_srcv_init - initialize an SRCv card 11718c2ecf20Sopenharmony_ci * @dev: device to configure 11728c2ecf20Sopenharmony_ci * 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ciint aac_srcv_init(struct aac_dev *dev) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci unsigned long start; 11788c2ecf20Sopenharmony_ci unsigned long status; 11798c2ecf20Sopenharmony_ci int restart = 0; 11808c2ecf20Sopenharmony_ci int instance = dev->id; 11818c2ecf20Sopenharmony_ci const char *name = dev->name; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci dev->a_ops.adapter_ioremap = aac_srcv_ioremap; 11848c2ecf20Sopenharmony_ci dev->a_ops.adapter_comm = aac_src_select_comm; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci dev->base_size = AAC_MIN_SRCV_BAR0_SIZE; 11878c2ecf20Sopenharmony_ci if (aac_adapter_ioremap(dev, dev->base_size)) { 11888c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: unable to map adapter.\n", name); 11898c2ecf20Sopenharmony_ci goto error_iounmap; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci /* Failure to reset here is an option ... */ 11938c2ecf20Sopenharmony_ci dev->a_ops.adapter_sync_cmd = src_sync_cmd; 11948c2ecf20Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci if (dev->init_reset) { 11978c2ecf20Sopenharmony_ci dev->init_reset = false; 11988c2ecf20Sopenharmony_ci if (aac_src_soft_reset(dev)) { 11998c2ecf20Sopenharmony_ci aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET); 12008c2ecf20Sopenharmony_ci ++restart; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* 12058c2ecf20Sopenharmony_ci * Check to see if flash update is running. 12068c2ecf20Sopenharmony_ci * Wait for the adapter to be up and running. Wait up to 5 minutes 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 12098c2ecf20Sopenharmony_ci if (status & FLASH_UPD_PENDING) { 12108c2ecf20Sopenharmony_ci start = jiffies; 12118c2ecf20Sopenharmony_ci do { 12128c2ecf20Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 12138c2ecf20Sopenharmony_ci if (time_after(jiffies, start+HZ*FWUPD_TIMEOUT)) { 12148c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter flash update failed.\n", 12158c2ecf20Sopenharmony_ci dev->name, instance); 12168c2ecf20Sopenharmony_ci goto error_iounmap; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci } while (!(status & FLASH_UPD_SUCCESS) && 12198c2ecf20Sopenharmony_ci !(status & FLASH_UPD_FAILED)); 12208c2ecf20Sopenharmony_ci /* Delay 10 seconds. 12218c2ecf20Sopenharmony_ci * Because right now FW is doing a soft reset, 12228c2ecf20Sopenharmony_ci * do not read scratch pad register at this time 12238c2ecf20Sopenharmony_ci */ 12248c2ecf20Sopenharmony_ci ssleep(10); 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci /* 12278c2ecf20Sopenharmony_ci * Check to see if the board panic'd while booting. 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 12308c2ecf20Sopenharmony_ci if (status & KERNEL_PANIC) { 12318c2ecf20Sopenharmony_ci if (aac_src_restart_adapter(dev, 12328c2ecf20Sopenharmony_ci aac_src_check_health(dev), IOP_HWSOFT_RESET)) 12338c2ecf20Sopenharmony_ci goto error_iounmap; 12348c2ecf20Sopenharmony_ci ++restart; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci /* 12378c2ecf20Sopenharmony_ci * Check to see if the board failed any self tests. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 12408c2ecf20Sopenharmony_ci if (status & SELF_TEST_FAILED) { 12418c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); 12428c2ecf20Sopenharmony_ci goto error_iounmap; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci /* 12458c2ecf20Sopenharmony_ci * Check to see if the monitor panic'd while booting. 12468c2ecf20Sopenharmony_ci */ 12478c2ecf20Sopenharmony_ci if (status & MONITOR_PANIC) { 12488c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); 12498c2ecf20Sopenharmony_ci goto error_iounmap; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci start = jiffies; 12538c2ecf20Sopenharmony_ci /* 12548c2ecf20Sopenharmony_ci * Wait for the adapter to be up and running. Wait up to 3 minutes 12558c2ecf20Sopenharmony_ci */ 12568c2ecf20Sopenharmony_ci do { 12578c2ecf20Sopenharmony_ci status = src_readl(dev, MUnit.OMR); 12588c2ecf20Sopenharmony_ci if (status == INVALID_OMR) 12598c2ecf20Sopenharmony_ci status = 0; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if ((restart && 12628c2ecf20Sopenharmony_ci (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || 12638c2ecf20Sopenharmony_ci time_after(jiffies, start+HZ*startup_timeout)) { 12648c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 12658c2ecf20Sopenharmony_ci dev->name, instance, status); 12668c2ecf20Sopenharmony_ci goto error_iounmap; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci if (!restart && 12698c2ecf20Sopenharmony_ci ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || 12708c2ecf20Sopenharmony_ci time_after(jiffies, start + HZ * 12718c2ecf20Sopenharmony_ci ((startup_timeout > 60) 12728c2ecf20Sopenharmony_ci ? (startup_timeout - 60) 12738c2ecf20Sopenharmony_ci : (startup_timeout / 2))))) { 12748c2ecf20Sopenharmony_ci if (likely(!aac_src_restart_adapter(dev, 12758c2ecf20Sopenharmony_ci aac_src_check_health(dev), IOP_HWSOFT_RESET))) 12768c2ecf20Sopenharmony_ci start = jiffies; 12778c2ecf20Sopenharmony_ci ++restart; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci msleep(1); 12808c2ecf20Sopenharmony_ci } while (!(status & KERNEL_UP_AND_RUNNING)); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci if (restart && aac_commit) 12838c2ecf20Sopenharmony_ci aac_commit = 1; 12848c2ecf20Sopenharmony_ci /* 12858c2ecf20Sopenharmony_ci * Fill in the common function dispatch table. 12868c2ecf20Sopenharmony_ci */ 12878c2ecf20Sopenharmony_ci dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter; 12888c2ecf20Sopenharmony_ci dev->a_ops.adapter_disable_int = aac_src_disable_interrupt; 12898c2ecf20Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; 12908c2ecf20Sopenharmony_ci dev->a_ops.adapter_notify = aac_src_notify_adapter; 12918c2ecf20Sopenharmony_ci dev->a_ops.adapter_sync_cmd = src_sync_cmd; 12928c2ecf20Sopenharmony_ci dev->a_ops.adapter_check_health = aac_src_check_health; 12938c2ecf20Sopenharmony_ci dev->a_ops.adapter_restart = aac_src_restart_adapter; 12948c2ecf20Sopenharmony_ci dev->a_ops.adapter_start = aac_src_start_adapter; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci /* 12978c2ecf20Sopenharmony_ci * First clear out all interrupts. Then enable the one's that we 12988c2ecf20Sopenharmony_ci * can handle. 12998c2ecf20Sopenharmony_ci */ 13008c2ecf20Sopenharmony_ci aac_adapter_comm(dev, AAC_COMM_MESSAGE); 13018c2ecf20Sopenharmony_ci aac_adapter_disable_int(dev); 13028c2ecf20Sopenharmony_ci src_writel(dev, MUnit.ODR_C, 0xffffffff); 13038c2ecf20Sopenharmony_ci aac_adapter_enable_int(dev); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci if (aac_init_adapter(dev) == NULL) 13068c2ecf20Sopenharmony_ci goto error_iounmap; 13078c2ecf20Sopenharmony_ci if ((dev->comm_interface != AAC_COMM_MESSAGE_TYPE2) && 13088c2ecf20Sopenharmony_ci (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3)) 13098c2ecf20Sopenharmony_ci goto error_iounmap; 13108c2ecf20Sopenharmony_ci if (dev->msi_enabled) 13118c2ecf20Sopenharmony_ci aac_src_access_devreg(dev, AAC_ENABLE_MSIX); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci if (aac_acquire_irq(dev)) 13148c2ecf20Sopenharmony_ci goto error_iounmap; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci dev->dbg_base = pci_resource_start(dev->pdev, 2); 13178c2ecf20Sopenharmony_ci dev->dbg_base_mapped = dev->regs.src.bar1; 13188c2ecf20Sopenharmony_ci dev->dbg_size = AAC_MIN_SRCV_BAR1_SIZE; 13198c2ecf20Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci aac_adapter_enable_int(dev); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci if (!dev->sync_mode) { 13248c2ecf20Sopenharmony_ci /* 13258c2ecf20Sopenharmony_ci * Tell the adapter that all is configured, and it can 13268c2ecf20Sopenharmony_ci * start accepting requests 13278c2ecf20Sopenharmony_ci */ 13288c2ecf20Sopenharmony_ci aac_src_start_adapter(dev); 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci return 0; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cierror_iounmap: 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci return -1; 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_civoid aac_src_access_devreg(struct aac_dev *dev, int mode) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci u_int32_t val; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci switch (mode) { 13428c2ecf20Sopenharmony_ci case AAC_ENABLE_INTERRUPT: 13438c2ecf20Sopenharmony_ci src_writel(dev, 13448c2ecf20Sopenharmony_ci MUnit.OIMR, 13458c2ecf20Sopenharmony_ci dev->OIMR = (dev->msi_enabled ? 13468c2ecf20Sopenharmony_ci AAC_INT_ENABLE_TYPE1_MSIX : 13478c2ecf20Sopenharmony_ci AAC_INT_ENABLE_TYPE1_INTX)); 13488c2ecf20Sopenharmony_ci break; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci case AAC_DISABLE_INTERRUPT: 13518c2ecf20Sopenharmony_ci src_writel(dev, 13528c2ecf20Sopenharmony_ci MUnit.OIMR, 13538c2ecf20Sopenharmony_ci dev->OIMR = AAC_INT_DISABLE_ALL); 13548c2ecf20Sopenharmony_ci break; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci case AAC_ENABLE_MSIX: 13578c2ecf20Sopenharmony_ci /* set bit 6 */ 13588c2ecf20Sopenharmony_ci val = src_readl(dev, MUnit.IDR); 13598c2ecf20Sopenharmony_ci val |= 0x40; 13608c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IDR, val); 13618c2ecf20Sopenharmony_ci src_readl(dev, MUnit.IDR); 13628c2ecf20Sopenharmony_ci /* unmask int. */ 13638c2ecf20Sopenharmony_ci val = PMC_ALL_INTERRUPT_BITS; 13648c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IOAR, val); 13658c2ecf20Sopenharmony_ci val = src_readl(dev, MUnit.OIMR); 13668c2ecf20Sopenharmony_ci src_writel(dev, 13678c2ecf20Sopenharmony_ci MUnit.OIMR, 13688c2ecf20Sopenharmony_ci val & (~(PMC_GLOBAL_INT_BIT2 | PMC_GLOBAL_INT_BIT0))); 13698c2ecf20Sopenharmony_ci break; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci case AAC_DISABLE_MSIX: 13728c2ecf20Sopenharmony_ci /* reset bit 6 */ 13738c2ecf20Sopenharmony_ci val = src_readl(dev, MUnit.IDR); 13748c2ecf20Sopenharmony_ci val &= ~0x40; 13758c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IDR, val); 13768c2ecf20Sopenharmony_ci src_readl(dev, MUnit.IDR); 13778c2ecf20Sopenharmony_ci break; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci case AAC_CLEAR_AIF_BIT: 13808c2ecf20Sopenharmony_ci /* set bit 5 */ 13818c2ecf20Sopenharmony_ci val = src_readl(dev, MUnit.IDR); 13828c2ecf20Sopenharmony_ci val |= 0x20; 13838c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IDR, val); 13848c2ecf20Sopenharmony_ci src_readl(dev, MUnit.IDR); 13858c2ecf20Sopenharmony_ci break; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci case AAC_CLEAR_SYNC_BIT: 13888c2ecf20Sopenharmony_ci /* set bit 4 */ 13898c2ecf20Sopenharmony_ci val = src_readl(dev, MUnit.IDR); 13908c2ecf20Sopenharmony_ci val |= 0x10; 13918c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IDR, val); 13928c2ecf20Sopenharmony_ci src_readl(dev, MUnit.IDR); 13938c2ecf20Sopenharmony_ci break; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci case AAC_ENABLE_INTX: 13968c2ecf20Sopenharmony_ci /* set bit 7 */ 13978c2ecf20Sopenharmony_ci val = src_readl(dev, MUnit.IDR); 13988c2ecf20Sopenharmony_ci val |= 0x80; 13998c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IDR, val); 14008c2ecf20Sopenharmony_ci src_readl(dev, MUnit.IDR); 14018c2ecf20Sopenharmony_ci /* unmask int. */ 14028c2ecf20Sopenharmony_ci val = PMC_ALL_INTERRUPT_BITS; 14038c2ecf20Sopenharmony_ci src_writel(dev, MUnit.IOAR, val); 14048c2ecf20Sopenharmony_ci src_readl(dev, MUnit.IOAR); 14058c2ecf20Sopenharmony_ci val = src_readl(dev, MUnit.OIMR); 14068c2ecf20Sopenharmony_ci src_writel(dev, MUnit.OIMR, 14078c2ecf20Sopenharmony_ci val & (~(PMC_GLOBAL_INT_BIT2))); 14088c2ecf20Sopenharmony_ci break; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci default: 14118c2ecf20Sopenharmony_ci break; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistatic int aac_src_get_sync_status(struct aac_dev *dev) 14168c2ecf20Sopenharmony_ci{ 14178c2ecf20Sopenharmony_ci int msix_val = 0; 14188c2ecf20Sopenharmony_ci int legacy_val = 0; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci msix_val = src_readl(dev, MUnit.ODR_MSI) & SRC_MSI_READ_MASK ? 1 : 0; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (!dev->msi_enabled) { 14238c2ecf20Sopenharmony_ci /* 14248c2ecf20Sopenharmony_ci * if Legacy int status indicates cmd is not complete 14258c2ecf20Sopenharmony_ci * sample MSIx register to see if it indiactes cmd complete, 14268c2ecf20Sopenharmony_ci * if yes set the controller in MSIx mode and consider cmd 14278c2ecf20Sopenharmony_ci * completed 14288c2ecf20Sopenharmony_ci */ 14298c2ecf20Sopenharmony_ci legacy_val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT; 14308c2ecf20Sopenharmony_ci if (!(legacy_val & 1) && msix_val) 14318c2ecf20Sopenharmony_ci dev->msi_enabled = 1; 14328c2ecf20Sopenharmony_ci return legacy_val; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci return msix_val; 14368c2ecf20Sopenharmony_ci} 1437