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 * rx.c 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Abstract: Hardware miniport for Drawbridge specific hardware functions. 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/blkdev.h> 258c2ecf20Sopenharmony_ci#include <linux/delay.h> 268c2ecf20Sopenharmony_ci#include <linux/completion.h> 278c2ecf20Sopenharmony_ci#include <linux/time.h> 288c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "aacraid.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic irqreturn_t aac_rx_intr_producer(int irq, void *dev_id) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct aac_dev *dev = dev_id; 378c2ecf20Sopenharmony_ci unsigned long bellbits; 388c2ecf20Sopenharmony_ci u8 intstat = rx_readb(dev, MUnit.OISR); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci /* 418c2ecf20Sopenharmony_ci * Read mask and invert because drawbridge is reversed. 428c2ecf20Sopenharmony_ci * This allows us to only service interrupts that have 438c2ecf20Sopenharmony_ci * been enabled. 448c2ecf20Sopenharmony_ci * Check to see if this is our interrupt. If it isn't just return 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci if (likely(intstat & ~(dev->OIMR))) { 478c2ecf20Sopenharmony_ci bellbits = rx_readl(dev, OutboundDoorbellReg); 488c2ecf20Sopenharmony_ci if (unlikely(bellbits & DoorBellPrintfReady)) { 498c2ecf20Sopenharmony_ci aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5])); 508c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); 518c2ecf20Sopenharmony_ci rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci else if (unlikely(bellbits & DoorBellAdapterNormCmdReady)) { 548c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); 558c2ecf20Sopenharmony_ci aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci else if (likely(bellbits & DoorBellAdapterNormRespReady)) { 588c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); 598c2ecf20Sopenharmony_ci aac_response_normal(&dev->queues->queue[HostNormRespQueue]); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci else if (unlikely(bellbits & DoorBellAdapterNormCmdNotFull)) { 628c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci else if (unlikely(bellbits & DoorBellAdapterNormRespNotFull)) { 658c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); 668c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci return IRQ_HANDLED; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci return IRQ_NONE; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic irqreturn_t aac_rx_intr_message(int irq, void *dev_id) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci int isAif, isFastResponse, isSpecial; 768c2ecf20Sopenharmony_ci struct aac_dev *dev = dev_id; 778c2ecf20Sopenharmony_ci u32 Index = rx_readl(dev, MUnit.OutboundQueue); 788c2ecf20Sopenharmony_ci if (unlikely(Index == 0xFFFFFFFFL)) 798c2ecf20Sopenharmony_ci Index = rx_readl(dev, MUnit.OutboundQueue); 808c2ecf20Sopenharmony_ci if (likely(Index != 0xFFFFFFFFL)) { 818c2ecf20Sopenharmony_ci do { 828c2ecf20Sopenharmony_ci isAif = isFastResponse = isSpecial = 0; 838c2ecf20Sopenharmony_ci if (Index & 0x00000002L) { 848c2ecf20Sopenharmony_ci isAif = 1; 858c2ecf20Sopenharmony_ci if (Index == 0xFFFFFFFEL) 868c2ecf20Sopenharmony_ci isSpecial = 1; 878c2ecf20Sopenharmony_ci Index &= ~0x00000002L; 888c2ecf20Sopenharmony_ci } else { 898c2ecf20Sopenharmony_ci if (Index & 0x00000001L) 908c2ecf20Sopenharmony_ci isFastResponse = 1; 918c2ecf20Sopenharmony_ci Index >>= 2; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci if (!isSpecial) { 948c2ecf20Sopenharmony_ci if (unlikely(aac_intr_normal(dev, 958c2ecf20Sopenharmony_ci Index, isAif, 968c2ecf20Sopenharmony_ci isFastResponse, NULL))) { 978c2ecf20Sopenharmony_ci rx_writel(dev, 988c2ecf20Sopenharmony_ci MUnit.OutboundQueue, 998c2ecf20Sopenharmony_ci Index); 1008c2ecf20Sopenharmony_ci rx_writel(dev, 1018c2ecf20Sopenharmony_ci MUnit.ODR, 1028c2ecf20Sopenharmony_ci DoorBellAdapterNormRespReady); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci Index = rx_readl(dev, MUnit.OutboundQueue); 1068c2ecf20Sopenharmony_ci } while (Index != 0xFFFFFFFFL); 1078c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci return IRQ_NONE; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/** 1138c2ecf20Sopenharmony_ci * aac_rx_disable_interrupt - Disable interrupts 1148c2ecf20Sopenharmony_ci * @dev: Adapter 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void aac_rx_disable_interrupt(struct aac_dev *dev) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/** 1238c2ecf20Sopenharmony_ci * aac_rx_enable_interrupt_producer - Enable interrupts 1248c2ecf20Sopenharmony_ci * @dev: Adapter 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic void aac_rx_enable_interrupt_producer(struct aac_dev *dev) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/** 1338c2ecf20Sopenharmony_ci * aac_rx_enable_interrupt_message - Enable interrupts 1348c2ecf20Sopenharmony_ci * @dev: Adapter 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void aac_rx_enable_interrupt_message(struct aac_dev *dev) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/** 1438c2ecf20Sopenharmony_ci * rx_sync_cmd - send a command and wait 1448c2ecf20Sopenharmony_ci * @dev: Adapter 1458c2ecf20Sopenharmony_ci * @command: Command to execute 1468c2ecf20Sopenharmony_ci * @p1: first parameter 1478c2ecf20Sopenharmony_ci * @p2: second parameter 1488c2ecf20Sopenharmony_ci * @p3: third parameter 1498c2ecf20Sopenharmony_ci * @p4: forth parameter 1508c2ecf20Sopenharmony_ci * @p5: fifth parameter 1518c2ecf20Sopenharmony_ci * @p6: sixth parameter 1528c2ecf20Sopenharmony_ci * @status: adapter status 1538c2ecf20Sopenharmony_ci * @r1: first return value 1548c2ecf20Sopenharmony_ci * @r2: second return value 1558c2ecf20Sopenharmony_ci * @r3: third return value 1568c2ecf20Sopenharmony_ci * @r4: forth return value 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci * This routine will send a synchronous command to the adapter and wait 1598c2ecf20Sopenharmony_ci * for its completion. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int rx_sync_cmd(struct aac_dev *dev, u32 command, 1638c2ecf20Sopenharmony_ci u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, 1648c2ecf20Sopenharmony_ci u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci unsigned long start; 1678c2ecf20Sopenharmony_ci int ok; 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * Write the command into Mailbox 0 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_ci writel(command, &dev->IndexRegs->Mailbox[0]); 1728c2ecf20Sopenharmony_ci /* 1738c2ecf20Sopenharmony_ci * Write the parameters into Mailboxes 1 - 6 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci writel(p1, &dev->IndexRegs->Mailbox[1]); 1768c2ecf20Sopenharmony_ci writel(p2, &dev->IndexRegs->Mailbox[2]); 1778c2ecf20Sopenharmony_ci writel(p3, &dev->IndexRegs->Mailbox[3]); 1788c2ecf20Sopenharmony_ci writel(p4, &dev->IndexRegs->Mailbox[4]); 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * Clear the synch command doorbell to start on a clean slate. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); 1838c2ecf20Sopenharmony_ci /* 1848c2ecf20Sopenharmony_ci * Disable doorbell interrupts 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); 1878c2ecf20Sopenharmony_ci /* 1888c2ecf20Sopenharmony_ci * Force the completion of the mask register write before issuing 1898c2ecf20Sopenharmony_ci * the interrupt. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci rx_readb (dev, MUnit.OIMR); 1928c2ecf20Sopenharmony_ci /* 1938c2ecf20Sopenharmony_ci * Signal that there is a new synch command 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_ci rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci ok = 0; 1988c2ecf20Sopenharmony_ci start = jiffies; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* 2018c2ecf20Sopenharmony_ci * Wait up to 30 seconds 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_ci while (time_before(jiffies, start+30*HZ)) 2048c2ecf20Sopenharmony_ci { 2058c2ecf20Sopenharmony_ci udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * Mon960 will set doorbell0 bit when it has completed the command. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) { 2108c2ecf20Sopenharmony_ci /* 2118c2ecf20Sopenharmony_ci * Clear the doorbell. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ci rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); 2148c2ecf20Sopenharmony_ci ok = 1; 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * Yield the processor in case we are slow 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci msleep(1); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci if (unlikely(ok != 1)) { 2238c2ecf20Sopenharmony_ci /* 2248c2ecf20Sopenharmony_ci * Restore interrupt mask even though we timed out 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ci aac_adapter_enable_int(dev); 2278c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci /* 2308c2ecf20Sopenharmony_ci * Pull the synch status from Mailbox 0. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci if (status) 2338c2ecf20Sopenharmony_ci *status = readl(&dev->IndexRegs->Mailbox[0]); 2348c2ecf20Sopenharmony_ci if (r1) 2358c2ecf20Sopenharmony_ci *r1 = readl(&dev->IndexRegs->Mailbox[1]); 2368c2ecf20Sopenharmony_ci if (r2) 2378c2ecf20Sopenharmony_ci *r2 = readl(&dev->IndexRegs->Mailbox[2]); 2388c2ecf20Sopenharmony_ci if (r3) 2398c2ecf20Sopenharmony_ci *r3 = readl(&dev->IndexRegs->Mailbox[3]); 2408c2ecf20Sopenharmony_ci if (r4) 2418c2ecf20Sopenharmony_ci *r4 = readl(&dev->IndexRegs->Mailbox[4]); 2428c2ecf20Sopenharmony_ci /* 2438c2ecf20Sopenharmony_ci * Clear the synch command doorbell. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * Restore interrupt mask 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_ci aac_adapter_enable_int(dev); 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/** 2558c2ecf20Sopenharmony_ci * aac_rx_interrupt_adapter - interrupt adapter 2568c2ecf20Sopenharmony_ci * @dev: Adapter 2578c2ecf20Sopenharmony_ci * 2588c2ecf20Sopenharmony_ci * Send an interrupt to the i960 and breakpoint it. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic void aac_rx_interrupt_adapter(struct aac_dev *dev) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/** 2678c2ecf20Sopenharmony_ci * aac_rx_notify_adapter - send an event to the adapter 2688c2ecf20Sopenharmony_ci * @dev: Adapter 2698c2ecf20Sopenharmony_ci * @event: Event to send 2708c2ecf20Sopenharmony_ci * 2718c2ecf20Sopenharmony_ci * Notify the i960 that something it probably cares about has 2728c2ecf20Sopenharmony_ci * happened. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void aac_rx_notify_adapter(struct aac_dev *dev, u32 event) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci switch (event) { 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci case AdapNormCmdQue: 2808c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1); 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci case HostNormRespNotFull: 2838c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4); 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci case AdapNormRespQue: 2868c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2); 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci case HostNormCmdNotFull: 2898c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3); 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci case HostShutdown: 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci case FastIo: 2948c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6); 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci case AdapPrintfDone: 2978c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5); 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci default: 3008c2ecf20Sopenharmony_ci BUG(); 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/** 3068c2ecf20Sopenharmony_ci * aac_rx_start_adapter - activate adapter 3078c2ecf20Sopenharmony_ci * @dev: Adapter 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * Start up processing on an i960 based AAC adapter 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic void aac_rx_start_adapter(struct aac_dev *dev) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci union aac_init *init; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci init = dev->init; 3178c2ecf20Sopenharmony_ci init->r7.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds()); 3188c2ecf20Sopenharmony_ci // We can only use a 32 bit address here 3198c2ecf20Sopenharmony_ci rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, 3208c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/** 3248c2ecf20Sopenharmony_ci * aac_rx_check_health 3258c2ecf20Sopenharmony_ci * @dev: device to check if healthy 3268c2ecf20Sopenharmony_ci * 3278c2ecf20Sopenharmony_ci * Will attempt to determine if the specified adapter is alive and 3288c2ecf20Sopenharmony_ci * capable of handling requests, returning 0 if alive. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_cistatic int aac_rx_check_health(struct aac_dev *dev) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci u32 status = rx_readl(dev, MUnit.OMRx[0]); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* 3358c2ecf20Sopenharmony_ci * Check to see if the board failed any self tests. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci if (unlikely(status & SELF_TEST_FAILED)) 3388c2ecf20Sopenharmony_ci return -1; 3398c2ecf20Sopenharmony_ci /* 3408c2ecf20Sopenharmony_ci * Check to see if the board panic'd. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci if (unlikely(status & KERNEL_PANIC)) { 3438c2ecf20Sopenharmony_ci char * buffer; 3448c2ecf20Sopenharmony_ci struct POSTSTATUS { 3458c2ecf20Sopenharmony_ci __le32 Post_Command; 3468c2ecf20Sopenharmony_ci __le32 Post_Address; 3478c2ecf20Sopenharmony_ci } * post; 3488c2ecf20Sopenharmony_ci dma_addr_t paddr, baddr; 3498c2ecf20Sopenharmony_ci int ret; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (likely((status & 0xFF000000L) == 0xBC000000L)) 3528c2ecf20Sopenharmony_ci return (status >> 16) & 0xFF; 3538c2ecf20Sopenharmony_ci buffer = dma_alloc_coherent(&dev->pdev->dev, 512, &baddr, 3548c2ecf20Sopenharmony_ci GFP_KERNEL); 3558c2ecf20Sopenharmony_ci ret = -2; 3568c2ecf20Sopenharmony_ci if (unlikely(buffer == NULL)) 3578c2ecf20Sopenharmony_ci return ret; 3588c2ecf20Sopenharmony_ci post = dma_alloc_coherent(&dev->pdev->dev, 3598c2ecf20Sopenharmony_ci sizeof(struct POSTSTATUS), &paddr, 3608c2ecf20Sopenharmony_ci GFP_KERNEL); 3618c2ecf20Sopenharmony_ci if (unlikely(post == NULL)) { 3628c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, 512, buffer, baddr); 3638c2ecf20Sopenharmony_ci return ret; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci memset(buffer, 0, 512); 3668c2ecf20Sopenharmony_ci post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS); 3678c2ecf20Sopenharmony_ci post->Post_Address = cpu_to_le32(baddr); 3688c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.IMRx[0], paddr); 3698c2ecf20Sopenharmony_ci rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0, 3708c2ecf20Sopenharmony_ci NULL, NULL, NULL, NULL, NULL); 3718c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, sizeof(struct POSTSTATUS), 3728c2ecf20Sopenharmony_ci post, paddr); 3738c2ecf20Sopenharmony_ci if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) { 3748c2ecf20Sopenharmony_ci ret = (hex_to_bin(buffer[2]) << 4) + 3758c2ecf20Sopenharmony_ci hex_to_bin(buffer[3]); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, 512, buffer, baddr); 3788c2ecf20Sopenharmony_ci return ret; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci /* 3818c2ecf20Sopenharmony_ci * Wait for the adapter to be up and running. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) 3848c2ecf20Sopenharmony_ci return -3; 3858c2ecf20Sopenharmony_ci /* 3868c2ecf20Sopenharmony_ci * Everything is OK 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci/** 3928c2ecf20Sopenharmony_ci * aac_rx_deliver_producer 3938c2ecf20Sopenharmony_ci * @fib: fib to issue 3948c2ecf20Sopenharmony_ci * 3958c2ecf20Sopenharmony_ci * Will send a fib, returning 0 if successful. 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ciint aac_rx_deliver_producer(struct fib * fib) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct aac_dev *dev = fib->dev; 4008c2ecf20Sopenharmony_ci struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; 4018c2ecf20Sopenharmony_ci u32 Index; 4028c2ecf20Sopenharmony_ci unsigned long nointr = 0; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib_va, 1, fib, &nointr); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci atomic_inc(&q->numpending); 4078c2ecf20Sopenharmony_ci *(q->headers.producer) = cpu_to_le32(Index + 1); 4088c2ecf20Sopenharmony_ci if (!(nointr & aac_config.irq_mod)) 4098c2ecf20Sopenharmony_ci aac_adapter_notify(dev, AdapNormCmdQueue); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/** 4158c2ecf20Sopenharmony_ci * aac_rx_deliver_message 4168c2ecf20Sopenharmony_ci * @fib: fib to issue 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * Will send a fib, returning 0 if successful. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_cistatic int aac_rx_deliver_message(struct fib * fib) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct aac_dev *dev = fib->dev; 4238c2ecf20Sopenharmony_ci struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; 4248c2ecf20Sopenharmony_ci u32 Index; 4258c2ecf20Sopenharmony_ci u64 addr; 4268c2ecf20Sopenharmony_ci volatile void __iomem *device; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci unsigned long count = 10000000L; /* 50 seconds */ 4298c2ecf20Sopenharmony_ci atomic_inc(&q->numpending); 4308c2ecf20Sopenharmony_ci for(;;) { 4318c2ecf20Sopenharmony_ci Index = rx_readl(dev, MUnit.InboundQueue); 4328c2ecf20Sopenharmony_ci if (unlikely(Index == 0xFFFFFFFFL)) 4338c2ecf20Sopenharmony_ci Index = rx_readl(dev, MUnit.InboundQueue); 4348c2ecf20Sopenharmony_ci if (likely(Index != 0xFFFFFFFFL)) 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci if (--count == 0) { 4378c2ecf20Sopenharmony_ci atomic_dec(&q->numpending); 4388c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci udelay(5); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci device = dev->base + Index; 4438c2ecf20Sopenharmony_ci addr = fib->hw_fib_pa; 4448c2ecf20Sopenharmony_ci writel((u32)(addr & 0xffffffff), device); 4458c2ecf20Sopenharmony_ci device += sizeof(u32); 4468c2ecf20Sopenharmony_ci writel((u32)(addr >> 32), device); 4478c2ecf20Sopenharmony_ci device += sizeof(u32); 4488c2ecf20Sopenharmony_ci writel(le16_to_cpu(fib->hw_fib_va->header.Size), device); 4498c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.InboundQueue, Index); 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci/** 4548c2ecf20Sopenharmony_ci * aac_rx_ioremap 4558c2ecf20Sopenharmony_ci * @dev: adapter 4568c2ecf20Sopenharmony_ci * @size: mapping resize request 4578c2ecf20Sopenharmony_ci * 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_cistatic int aac_rx_ioremap(struct aac_dev * dev, u32 size) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci if (!size) { 4628c2ecf20Sopenharmony_ci iounmap(dev->regs.rx); 4638c2ecf20Sopenharmony_ci return 0; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci dev->base = dev->regs.rx = ioremap(dev->base_start, size); 4668c2ecf20Sopenharmony_ci if (dev->base == NULL) 4678c2ecf20Sopenharmony_ci return -1; 4688c2ecf20Sopenharmony_ci dev->IndexRegs = &dev->regs.rx->IndexRegs; 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int aac_rx_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci u32 var = 0; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (!(dev->supplement_adapter_info.supported_options2 & 4778c2ecf20Sopenharmony_ci AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) { 4788c2ecf20Sopenharmony_ci if (bled) 4798c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", 4808c2ecf20Sopenharmony_ci dev->name, dev->id, bled); 4818c2ecf20Sopenharmony_ci else { 4828c2ecf20Sopenharmony_ci bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, 4838c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); 4848c2ecf20Sopenharmony_ci if (!bled && (var != 0x00000001) && (var != 0x3803000F)) 4858c2ecf20Sopenharmony_ci bled = -EINVAL; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci if (bled && (bled != -ETIMEDOUT)) 4888c2ecf20Sopenharmony_ci bled = aac_adapter_sync_cmd(dev, IOP_RESET, 4898c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (bled && (bled != -ETIMEDOUT)) 4928c2ecf20Sopenharmony_ci return -EINVAL; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci if (bled && (var == 0x3803000F)) { /* USE_OTHER_METHOD */ 4958c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.reserved2, 3); 4968c2ecf20Sopenharmony_ci msleep(5000); /* Delay 5 seconds */ 4978c2ecf20Sopenharmony_ci var = 0x00000001; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci if (bled && (var != 0x00000001)) 5008c2ecf20Sopenharmony_ci return -EINVAL; 5018c2ecf20Sopenharmony_ci ssleep(5); 5028c2ecf20Sopenharmony_ci if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) 5038c2ecf20Sopenharmony_ci return -ENODEV; 5048c2ecf20Sopenharmony_ci if (startup_timeout < 300) 5058c2ecf20Sopenharmony_ci startup_timeout = 300; 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/** 5108c2ecf20Sopenharmony_ci * aac_rx_select_comm - Select communications method 5118c2ecf20Sopenharmony_ci * @dev: Adapter 5128c2ecf20Sopenharmony_ci * @comm: communications method 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ciint aac_rx_select_comm(struct aac_dev *dev, int comm) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci switch (comm) { 5188c2ecf20Sopenharmony_ci case AAC_COMM_PRODUCER: 5198c2ecf20Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_producer; 5208c2ecf20Sopenharmony_ci dev->a_ops.adapter_intr = aac_rx_intr_producer; 5218c2ecf20Sopenharmony_ci dev->a_ops.adapter_deliver = aac_rx_deliver_producer; 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci case AAC_COMM_MESSAGE: 5248c2ecf20Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_message; 5258c2ecf20Sopenharmony_ci dev->a_ops.adapter_intr = aac_rx_intr_message; 5268c2ecf20Sopenharmony_ci dev->a_ops.adapter_deliver = aac_rx_deliver_message; 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci default: 5298c2ecf20Sopenharmony_ci return 1; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/** 5358c2ecf20Sopenharmony_ci * aac_rx_init - initialize an i960 based AAC card 5368c2ecf20Sopenharmony_ci * @dev: device to configure 5378c2ecf20Sopenharmony_ci * 5388c2ecf20Sopenharmony_ci * Allocate and set up resources for the i960 based AAC variants. The 5398c2ecf20Sopenharmony_ci * device_interface in the commregion will be allocated and linked 5408c2ecf20Sopenharmony_ci * to the comm region. 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ciint _aac_rx_init(struct aac_dev *dev) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci unsigned long start; 5468c2ecf20Sopenharmony_ci unsigned long status; 5478c2ecf20Sopenharmony_ci int restart = 0; 5488c2ecf20Sopenharmony_ci int instance = dev->id; 5498c2ecf20Sopenharmony_ci const char * name = dev->name; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (aac_adapter_ioremap(dev, dev->base_size)) { 5528c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: unable to map adapter.\n", name); 5538c2ecf20Sopenharmony_ci goto error_iounmap; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Failure to reset here is an option ... */ 5578c2ecf20Sopenharmony_ci dev->a_ops.adapter_sync_cmd = rx_sync_cmd; 5588c2ecf20Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt; 5598c2ecf20Sopenharmony_ci dev->OIMR = status = rx_readb (dev, MUnit.OIMR); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (((status & 0x0c) != 0x0c) || dev->init_reset) { 5628c2ecf20Sopenharmony_ci dev->init_reset = false; 5638c2ecf20Sopenharmony_ci if (!aac_rx_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) { 5648c2ecf20Sopenharmony_ci /* Make sure the Hardware FIFO is empty */ 5658c2ecf20Sopenharmony_ci while ((++restart < 512) && 5668c2ecf20Sopenharmony_ci (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL)); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* 5718c2ecf20Sopenharmony_ci * Check to see if the board panic'd while booting. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_ci status = rx_readl(dev, MUnit.OMRx[0]); 5748c2ecf20Sopenharmony_ci if (status & KERNEL_PANIC) { 5758c2ecf20Sopenharmony_ci if (aac_rx_restart_adapter(dev, 5768c2ecf20Sopenharmony_ci aac_rx_check_health(dev), IOP_HWSOFT_RESET)) 5778c2ecf20Sopenharmony_ci goto error_iounmap; 5788c2ecf20Sopenharmony_ci ++restart; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci /* 5818c2ecf20Sopenharmony_ci * Check to see if the board failed any self tests. 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci status = rx_readl(dev, MUnit.OMRx[0]); 5848c2ecf20Sopenharmony_ci if (status & SELF_TEST_FAILED) { 5858c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); 5868c2ecf20Sopenharmony_ci goto error_iounmap; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci /* 5898c2ecf20Sopenharmony_ci * Check to see if the monitor panic'd while booting. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci if (status & MONITOR_PANIC) { 5928c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); 5938c2ecf20Sopenharmony_ci goto error_iounmap; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci start = jiffies; 5968c2ecf20Sopenharmony_ci /* 5978c2ecf20Sopenharmony_ci * Wait for the adapter to be up and running. Wait up to 3 minutes 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_ci while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING)) 6008c2ecf20Sopenharmony_ci { 6018c2ecf20Sopenharmony_ci if ((restart && 6028c2ecf20Sopenharmony_ci (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || 6038c2ecf20Sopenharmony_ci time_after(jiffies, start+HZ*startup_timeout)) { 6048c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 6058c2ecf20Sopenharmony_ci dev->name, instance, status); 6068c2ecf20Sopenharmony_ci goto error_iounmap; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci if (!restart && 6098c2ecf20Sopenharmony_ci ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || 6108c2ecf20Sopenharmony_ci time_after(jiffies, start + HZ * 6118c2ecf20Sopenharmony_ci ((startup_timeout > 60) 6128c2ecf20Sopenharmony_ci ? (startup_timeout - 60) 6138c2ecf20Sopenharmony_ci : (startup_timeout / 2))))) { 6148c2ecf20Sopenharmony_ci if (likely(!aac_rx_restart_adapter(dev, 6158c2ecf20Sopenharmony_ci aac_rx_check_health(dev), IOP_HWSOFT_RESET))) 6168c2ecf20Sopenharmony_ci start = jiffies; 6178c2ecf20Sopenharmony_ci ++restart; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci msleep(1); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci if (restart && aac_commit) 6228c2ecf20Sopenharmony_ci aac_commit = 1; 6238c2ecf20Sopenharmony_ci /* 6248c2ecf20Sopenharmony_ci * Fill in the common function dispatch table. 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_ci dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; 6278c2ecf20Sopenharmony_ci dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; 6288c2ecf20Sopenharmony_ci dev->a_ops.adapter_notify = aac_rx_notify_adapter; 6298c2ecf20Sopenharmony_ci dev->a_ops.adapter_sync_cmd = rx_sync_cmd; 6308c2ecf20Sopenharmony_ci dev->a_ops.adapter_check_health = aac_rx_check_health; 6318c2ecf20Sopenharmony_ci dev->a_ops.adapter_restart = aac_rx_restart_adapter; 6328c2ecf20Sopenharmony_ci dev->a_ops.adapter_start = aac_rx_start_adapter; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* 6358c2ecf20Sopenharmony_ci * First clear out all interrupts. Then enable the one's that we 6368c2ecf20Sopenharmony_ci * can handle. 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_ci aac_adapter_comm(dev, AAC_COMM_PRODUCER); 6398c2ecf20Sopenharmony_ci aac_adapter_disable_int(dev); 6408c2ecf20Sopenharmony_ci rx_writel(dev, MUnit.ODR, 0xffffffff); 6418c2ecf20Sopenharmony_ci aac_adapter_enable_int(dev); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (aac_init_adapter(dev) == NULL) 6448c2ecf20Sopenharmony_ci goto error_iounmap; 6458c2ecf20Sopenharmony_ci aac_adapter_comm(dev, dev->comm_interface); 6468c2ecf20Sopenharmony_ci dev->sync_mode = 0; /* sync. mode not supported */ 6478c2ecf20Sopenharmony_ci dev->msi = aac_msi && !pci_enable_msi(dev->pdev); 6488c2ecf20Sopenharmony_ci if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, 6498c2ecf20Sopenharmony_ci IRQF_SHARED, "aacraid", dev) < 0) { 6508c2ecf20Sopenharmony_ci if (dev->msi) 6518c2ecf20Sopenharmony_ci pci_disable_msi(dev->pdev); 6528c2ecf20Sopenharmony_ci printk(KERN_ERR "%s%d: Interrupt unavailable.\n", 6538c2ecf20Sopenharmony_ci name, instance); 6548c2ecf20Sopenharmony_ci goto error_iounmap; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci dev->dbg_base = dev->base_start; 6578c2ecf20Sopenharmony_ci dev->dbg_base_mapped = dev->base; 6588c2ecf20Sopenharmony_ci dev->dbg_size = dev->base_size; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci aac_adapter_enable_int(dev); 6618c2ecf20Sopenharmony_ci /* 6628c2ecf20Sopenharmony_ci * Tell the adapter that all is configured, and it can 6638c2ecf20Sopenharmony_ci * start accepting requests 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_ci aac_rx_start_adapter(dev); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci return 0; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cierror_iounmap: 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return -1; 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ciint aac_rx_init(struct aac_dev *dev) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci /* 6778c2ecf20Sopenharmony_ci * Fill in the function dispatch table. 6788c2ecf20Sopenharmony_ci */ 6798c2ecf20Sopenharmony_ci dev->a_ops.adapter_ioremap = aac_rx_ioremap; 6808c2ecf20Sopenharmony_ci dev->a_ops.adapter_comm = aac_rx_select_comm; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci return _aac_rx_init(dev); 6838c2ecf20Sopenharmony_ci} 684