162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Adaptec AAC series RAID controller driver 462306a36Sopenharmony_ci * (c) Copyright 2001 Red Hat Inc. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * based on the old aacraid driver that is.. 762306a36Sopenharmony_ci * Adaptec aacraid device driver for Linux. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (c) 2000-2010 Adaptec, Inc. 1062306a36Sopenharmony_ci * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) 1162306a36Sopenharmony_ci * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Module Name: 1462306a36Sopenharmony_ci * rx.c 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Abstract: Hardware miniport for Drawbridge specific hardware functions. 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/types.h> 2262306a36Sopenharmony_ci#include <linux/pci.h> 2362306a36Sopenharmony_ci#include <linux/spinlock.h> 2462306a36Sopenharmony_ci#include <linux/blkdev.h> 2562306a36Sopenharmony_ci#include <linux/delay.h> 2662306a36Sopenharmony_ci#include <linux/completion.h> 2762306a36Sopenharmony_ci#include <linux/time.h> 2862306a36Sopenharmony_ci#include <linux/interrupt.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <scsi/scsi_host.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "aacraid.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic irqreturn_t aac_rx_intr_producer(int irq, void *dev_id) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct aac_dev *dev = dev_id; 3762306a36Sopenharmony_ci unsigned long bellbits; 3862306a36Sopenharmony_ci u8 intstat = rx_readb(dev, MUnit.OISR); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* 4162306a36Sopenharmony_ci * Read mask and invert because drawbridge is reversed. 4262306a36Sopenharmony_ci * This allows us to only service interrupts that have 4362306a36Sopenharmony_ci * been enabled. 4462306a36Sopenharmony_ci * Check to see if this is our interrupt. If it isn't just return 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci if (likely(intstat & ~(dev->OIMR))) { 4762306a36Sopenharmony_ci bellbits = rx_readl(dev, OutboundDoorbellReg); 4862306a36Sopenharmony_ci if (unlikely(bellbits & DoorBellPrintfReady)) { 4962306a36Sopenharmony_ci aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5])); 5062306a36Sopenharmony_ci rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); 5162306a36Sopenharmony_ci rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci else if (unlikely(bellbits & DoorBellAdapterNormCmdReady)) { 5462306a36Sopenharmony_ci rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); 5562306a36Sopenharmony_ci aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci else if (likely(bellbits & DoorBellAdapterNormRespReady)) { 5862306a36Sopenharmony_ci rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); 5962306a36Sopenharmony_ci aac_response_normal(&dev->queues->queue[HostNormRespQueue]); 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci else if (unlikely(bellbits & DoorBellAdapterNormCmdNotFull)) { 6262306a36Sopenharmony_ci rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci else if (unlikely(bellbits & DoorBellAdapterNormRespNotFull)) { 6562306a36Sopenharmony_ci rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); 6662306a36Sopenharmony_ci rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci return IRQ_HANDLED; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci return IRQ_NONE; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic irqreturn_t aac_rx_intr_message(int irq, void *dev_id) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci int isAif, isFastResponse, isSpecial; 7662306a36Sopenharmony_ci struct aac_dev *dev = dev_id; 7762306a36Sopenharmony_ci u32 Index = rx_readl(dev, MUnit.OutboundQueue); 7862306a36Sopenharmony_ci if (unlikely(Index == 0xFFFFFFFFL)) 7962306a36Sopenharmony_ci Index = rx_readl(dev, MUnit.OutboundQueue); 8062306a36Sopenharmony_ci if (likely(Index != 0xFFFFFFFFL)) { 8162306a36Sopenharmony_ci do { 8262306a36Sopenharmony_ci isAif = isFastResponse = isSpecial = 0; 8362306a36Sopenharmony_ci if (Index & 0x00000002L) { 8462306a36Sopenharmony_ci isAif = 1; 8562306a36Sopenharmony_ci if (Index == 0xFFFFFFFEL) 8662306a36Sopenharmony_ci isSpecial = 1; 8762306a36Sopenharmony_ci Index &= ~0x00000002L; 8862306a36Sopenharmony_ci } else { 8962306a36Sopenharmony_ci if (Index & 0x00000001L) 9062306a36Sopenharmony_ci isFastResponse = 1; 9162306a36Sopenharmony_ci Index >>= 2; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci if (!isSpecial) { 9462306a36Sopenharmony_ci if (unlikely(aac_intr_normal(dev, 9562306a36Sopenharmony_ci Index, isAif, 9662306a36Sopenharmony_ci isFastResponse, NULL))) { 9762306a36Sopenharmony_ci rx_writel(dev, 9862306a36Sopenharmony_ci MUnit.OutboundQueue, 9962306a36Sopenharmony_ci Index); 10062306a36Sopenharmony_ci rx_writel(dev, 10162306a36Sopenharmony_ci MUnit.ODR, 10262306a36Sopenharmony_ci DoorBellAdapterNormRespReady); 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci Index = rx_readl(dev, MUnit.OutboundQueue); 10662306a36Sopenharmony_ci } while (Index != 0xFFFFFFFFL); 10762306a36Sopenharmony_ci return IRQ_HANDLED; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci return IRQ_NONE; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/** 11362306a36Sopenharmony_ci * aac_rx_disable_interrupt - Disable interrupts 11462306a36Sopenharmony_ci * @dev: Adapter 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void aac_rx_disable_interrupt(struct aac_dev *dev) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/** 12362306a36Sopenharmony_ci * aac_rx_enable_interrupt_producer - Enable interrupts 12462306a36Sopenharmony_ci * @dev: Adapter 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic void aac_rx_enable_interrupt_producer(struct aac_dev *dev) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/** 13362306a36Sopenharmony_ci * aac_rx_enable_interrupt_message - Enable interrupts 13462306a36Sopenharmony_ci * @dev: Adapter 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void aac_rx_enable_interrupt_message(struct aac_dev *dev) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/** 14362306a36Sopenharmony_ci * rx_sync_cmd - send a command and wait 14462306a36Sopenharmony_ci * @dev: Adapter 14562306a36Sopenharmony_ci * @command: Command to execute 14662306a36Sopenharmony_ci * @p1: first parameter 14762306a36Sopenharmony_ci * @p2: second parameter 14862306a36Sopenharmony_ci * @p3: third parameter 14962306a36Sopenharmony_ci * @p4: forth parameter 15062306a36Sopenharmony_ci * @p5: fifth parameter 15162306a36Sopenharmony_ci * @p6: sixth parameter 15262306a36Sopenharmony_ci * @status: adapter status 15362306a36Sopenharmony_ci * @r1: first return value 15462306a36Sopenharmony_ci * @r2: second return value 15562306a36Sopenharmony_ci * @r3: third return value 15662306a36Sopenharmony_ci * @r4: forth return value 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * This routine will send a synchronous command to the adapter and wait 15962306a36Sopenharmony_ci * for its completion. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int rx_sync_cmd(struct aac_dev *dev, u32 command, 16362306a36Sopenharmony_ci u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, 16462306a36Sopenharmony_ci u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci unsigned long start; 16762306a36Sopenharmony_ci int ok; 16862306a36Sopenharmony_ci /* 16962306a36Sopenharmony_ci * Write the command into Mailbox 0 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci writel(command, &dev->IndexRegs->Mailbox[0]); 17262306a36Sopenharmony_ci /* 17362306a36Sopenharmony_ci * Write the parameters into Mailboxes 1 - 6 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci writel(p1, &dev->IndexRegs->Mailbox[1]); 17662306a36Sopenharmony_ci writel(p2, &dev->IndexRegs->Mailbox[2]); 17762306a36Sopenharmony_ci writel(p3, &dev->IndexRegs->Mailbox[3]); 17862306a36Sopenharmony_ci writel(p4, &dev->IndexRegs->Mailbox[4]); 17962306a36Sopenharmony_ci /* 18062306a36Sopenharmony_ci * Clear the synch command doorbell to start on a clean slate. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); 18362306a36Sopenharmony_ci /* 18462306a36Sopenharmony_ci * Disable doorbell interrupts 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); 18762306a36Sopenharmony_ci /* 18862306a36Sopenharmony_ci * Force the completion of the mask register write before issuing 18962306a36Sopenharmony_ci * the interrupt. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci rx_readb (dev, MUnit.OIMR); 19262306a36Sopenharmony_ci /* 19362306a36Sopenharmony_ci * Signal that there is a new synch command 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ok = 0; 19862306a36Sopenharmony_ci start = jiffies; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* 20162306a36Sopenharmony_ci * Wait up to 30 seconds 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci while (time_before(jiffies, start+30*HZ)) 20462306a36Sopenharmony_ci { 20562306a36Sopenharmony_ci udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * Mon960 will set doorbell0 bit when it has completed the command. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_ci if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) { 21062306a36Sopenharmony_ci /* 21162306a36Sopenharmony_ci * Clear the doorbell. 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_ci rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); 21462306a36Sopenharmony_ci ok = 1; 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci /* 21862306a36Sopenharmony_ci * Yield the processor in case we are slow 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci msleep(1); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci if (unlikely(ok != 1)) { 22362306a36Sopenharmony_ci /* 22462306a36Sopenharmony_ci * Restore interrupt mask even though we timed out 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci aac_adapter_enable_int(dev); 22762306a36Sopenharmony_ci return -ETIMEDOUT; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci /* 23062306a36Sopenharmony_ci * Pull the synch status from Mailbox 0. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci if (status) 23362306a36Sopenharmony_ci *status = readl(&dev->IndexRegs->Mailbox[0]); 23462306a36Sopenharmony_ci if (r1) 23562306a36Sopenharmony_ci *r1 = readl(&dev->IndexRegs->Mailbox[1]); 23662306a36Sopenharmony_ci if (r2) 23762306a36Sopenharmony_ci *r2 = readl(&dev->IndexRegs->Mailbox[2]); 23862306a36Sopenharmony_ci if (r3) 23962306a36Sopenharmony_ci *r3 = readl(&dev->IndexRegs->Mailbox[3]); 24062306a36Sopenharmony_ci if (r4) 24162306a36Sopenharmony_ci *r4 = readl(&dev->IndexRegs->Mailbox[4]); 24262306a36Sopenharmony_ci /* 24362306a36Sopenharmony_ci * Clear the synch command doorbell. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); 24662306a36Sopenharmony_ci /* 24762306a36Sopenharmony_ci * Restore interrupt mask 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ci aac_adapter_enable_int(dev); 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/** 25562306a36Sopenharmony_ci * aac_rx_interrupt_adapter - interrupt adapter 25662306a36Sopenharmony_ci * @dev: Adapter 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci * Send an interrupt to the i960 and breakpoint it. 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic void aac_rx_interrupt_adapter(struct aac_dev *dev) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/** 26762306a36Sopenharmony_ci * aac_rx_notify_adapter - send an event to the adapter 26862306a36Sopenharmony_ci * @dev: Adapter 26962306a36Sopenharmony_ci * @event: Event to send 27062306a36Sopenharmony_ci * 27162306a36Sopenharmony_ci * Notify the i960 that something it probably cares about has 27262306a36Sopenharmony_ci * happened. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic void aac_rx_notify_adapter(struct aac_dev *dev, u32 event) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci switch (event) { 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci case AdapNormCmdQue: 28062306a36Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1); 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci case HostNormRespNotFull: 28362306a36Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4); 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case AdapNormRespQue: 28662306a36Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci case HostNormCmdNotFull: 28962306a36Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3); 29062306a36Sopenharmony_ci break; 29162306a36Sopenharmony_ci case HostShutdown: 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci case FastIo: 29462306a36Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6); 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci case AdapPrintfDone: 29762306a36Sopenharmony_ci rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5); 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci default: 30062306a36Sopenharmony_ci BUG(); 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/** 30662306a36Sopenharmony_ci * aac_rx_start_adapter - activate adapter 30762306a36Sopenharmony_ci * @dev: Adapter 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * Start up processing on an i960 based AAC adapter 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic void aac_rx_start_adapter(struct aac_dev *dev) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci union aac_init *init; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci init = dev->init; 31762306a36Sopenharmony_ci init->r7.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds()); 31862306a36Sopenharmony_ci // We can only use a 32 bit address here 31962306a36Sopenharmony_ci rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, 32062306a36Sopenharmony_ci 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci/** 32462306a36Sopenharmony_ci * aac_rx_check_health 32562306a36Sopenharmony_ci * @dev: device to check if healthy 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci * Will attempt to determine if the specified adapter is alive and 32862306a36Sopenharmony_ci * capable of handling requests, returning 0 if alive. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_cistatic int aac_rx_check_health(struct aac_dev *dev) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci u32 status = rx_readl(dev, MUnit.OMRx[0]); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* 33562306a36Sopenharmony_ci * Check to see if the board failed any self tests. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci if (unlikely(status & SELF_TEST_FAILED)) 33862306a36Sopenharmony_ci return -1; 33962306a36Sopenharmony_ci /* 34062306a36Sopenharmony_ci * Check to see if the board panic'd. 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci if (unlikely(status & KERNEL_PANIC)) { 34362306a36Sopenharmony_ci char * buffer; 34462306a36Sopenharmony_ci struct POSTSTATUS { 34562306a36Sopenharmony_ci __le32 Post_Command; 34662306a36Sopenharmony_ci __le32 Post_Address; 34762306a36Sopenharmony_ci } * post; 34862306a36Sopenharmony_ci dma_addr_t paddr, baddr; 34962306a36Sopenharmony_ci int ret; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (likely((status & 0xFF000000L) == 0xBC000000L)) 35262306a36Sopenharmony_ci return (status >> 16) & 0xFF; 35362306a36Sopenharmony_ci buffer = dma_alloc_coherent(&dev->pdev->dev, 512, &baddr, 35462306a36Sopenharmony_ci GFP_KERNEL); 35562306a36Sopenharmony_ci ret = -2; 35662306a36Sopenharmony_ci if (unlikely(buffer == NULL)) 35762306a36Sopenharmony_ci return ret; 35862306a36Sopenharmony_ci post = dma_alloc_coherent(&dev->pdev->dev, 35962306a36Sopenharmony_ci sizeof(struct POSTSTATUS), &paddr, 36062306a36Sopenharmony_ci GFP_KERNEL); 36162306a36Sopenharmony_ci if (unlikely(post == NULL)) { 36262306a36Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, 512, buffer, baddr); 36362306a36Sopenharmony_ci return ret; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci memset(buffer, 0, 512); 36662306a36Sopenharmony_ci post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS); 36762306a36Sopenharmony_ci post->Post_Address = cpu_to_le32(baddr); 36862306a36Sopenharmony_ci rx_writel(dev, MUnit.IMRx[0], paddr); 36962306a36Sopenharmony_ci rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0, 37062306a36Sopenharmony_ci NULL, NULL, NULL, NULL, NULL); 37162306a36Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, sizeof(struct POSTSTATUS), 37262306a36Sopenharmony_ci post, paddr); 37362306a36Sopenharmony_ci if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) { 37462306a36Sopenharmony_ci ret = (hex_to_bin(buffer[2]) << 4) + 37562306a36Sopenharmony_ci hex_to_bin(buffer[3]); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, 512, buffer, baddr); 37862306a36Sopenharmony_ci return ret; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci /* 38162306a36Sopenharmony_ci * Wait for the adapter to be up and running. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) 38462306a36Sopenharmony_ci return -3; 38562306a36Sopenharmony_ci /* 38662306a36Sopenharmony_ci * Everything is OK 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci/** 39262306a36Sopenharmony_ci * aac_rx_deliver_producer 39362306a36Sopenharmony_ci * @fib: fib to issue 39462306a36Sopenharmony_ci * 39562306a36Sopenharmony_ci * Will send a fib, returning 0 if successful. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ciint aac_rx_deliver_producer(struct fib * fib) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct aac_dev *dev = fib->dev; 40062306a36Sopenharmony_ci struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; 40162306a36Sopenharmony_ci u32 Index; 40262306a36Sopenharmony_ci unsigned long nointr = 0; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib_va, 1, fib, &nointr); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci atomic_inc(&q->numpending); 40762306a36Sopenharmony_ci *(q->headers.producer) = cpu_to_le32(Index + 1); 40862306a36Sopenharmony_ci if (!(nointr & aac_config.irq_mod)) 40962306a36Sopenharmony_ci aac_adapter_notify(dev, AdapNormCmdQueue); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci/** 41562306a36Sopenharmony_ci * aac_rx_deliver_message 41662306a36Sopenharmony_ci * @fib: fib to issue 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci * Will send a fib, returning 0 if successful. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_cistatic int aac_rx_deliver_message(struct fib * fib) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct aac_dev *dev = fib->dev; 42362306a36Sopenharmony_ci struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; 42462306a36Sopenharmony_ci u32 Index; 42562306a36Sopenharmony_ci u64 addr; 42662306a36Sopenharmony_ci volatile void __iomem *device; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci unsigned long count = 10000000L; /* 50 seconds */ 42962306a36Sopenharmony_ci atomic_inc(&q->numpending); 43062306a36Sopenharmony_ci for(;;) { 43162306a36Sopenharmony_ci Index = rx_readl(dev, MUnit.InboundQueue); 43262306a36Sopenharmony_ci if (unlikely(Index == 0xFFFFFFFFL)) 43362306a36Sopenharmony_ci Index = rx_readl(dev, MUnit.InboundQueue); 43462306a36Sopenharmony_ci if (likely(Index != 0xFFFFFFFFL)) 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci if (--count == 0) { 43762306a36Sopenharmony_ci atomic_dec(&q->numpending); 43862306a36Sopenharmony_ci return -ETIMEDOUT; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci udelay(5); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci device = dev->base + Index; 44362306a36Sopenharmony_ci addr = fib->hw_fib_pa; 44462306a36Sopenharmony_ci writel((u32)(addr & 0xffffffff), device); 44562306a36Sopenharmony_ci device += sizeof(u32); 44662306a36Sopenharmony_ci writel((u32)(addr >> 32), device); 44762306a36Sopenharmony_ci device += sizeof(u32); 44862306a36Sopenharmony_ci writel(le16_to_cpu(fib->hw_fib_va->header.Size), device); 44962306a36Sopenharmony_ci rx_writel(dev, MUnit.InboundQueue, Index); 45062306a36Sopenharmony_ci return 0; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci/** 45462306a36Sopenharmony_ci * aac_rx_ioremap 45562306a36Sopenharmony_ci * @dev: adapter 45662306a36Sopenharmony_ci * @size: mapping resize request 45762306a36Sopenharmony_ci * 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_cistatic int aac_rx_ioremap(struct aac_dev * dev, u32 size) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci if (!size) { 46262306a36Sopenharmony_ci iounmap(dev->regs.rx); 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci dev->base = dev->regs.rx = ioremap(dev->base_start, size); 46662306a36Sopenharmony_ci if (dev->base == NULL) 46762306a36Sopenharmony_ci return -1; 46862306a36Sopenharmony_ci dev->IndexRegs = &dev->regs.rx->IndexRegs; 46962306a36Sopenharmony_ci return 0; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic int aac_rx_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci u32 var = 0; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (!(dev->supplement_adapter_info.supported_options2 & 47762306a36Sopenharmony_ci AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) { 47862306a36Sopenharmony_ci if (bled) 47962306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", 48062306a36Sopenharmony_ci dev->name, dev->id, bled); 48162306a36Sopenharmony_ci else { 48262306a36Sopenharmony_ci bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, 48362306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); 48462306a36Sopenharmony_ci if (!bled && (var != 0x00000001) && (var != 0x3803000F)) 48562306a36Sopenharmony_ci bled = -EINVAL; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci if (bled && (bled != -ETIMEDOUT)) 48862306a36Sopenharmony_ci bled = aac_adapter_sync_cmd(dev, IOP_RESET, 48962306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (bled && (bled != -ETIMEDOUT)) 49262306a36Sopenharmony_ci return -EINVAL; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci if (bled && (var == 0x3803000F)) { /* USE_OTHER_METHOD */ 49562306a36Sopenharmony_ci rx_writel(dev, MUnit.reserved2, 3); 49662306a36Sopenharmony_ci msleep(5000); /* Delay 5 seconds */ 49762306a36Sopenharmony_ci var = 0x00000001; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci if (bled && (var != 0x00000001)) 50062306a36Sopenharmony_ci return -EINVAL; 50162306a36Sopenharmony_ci ssleep(5); 50262306a36Sopenharmony_ci if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) 50362306a36Sopenharmony_ci return -ENODEV; 50462306a36Sopenharmony_ci if (startup_timeout < 300) 50562306a36Sopenharmony_ci startup_timeout = 300; 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci/** 51062306a36Sopenharmony_ci * aac_rx_select_comm - Select communications method 51162306a36Sopenharmony_ci * @dev: Adapter 51262306a36Sopenharmony_ci * @comm: communications method 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ciint aac_rx_select_comm(struct aac_dev *dev, int comm) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci switch (comm) { 51862306a36Sopenharmony_ci case AAC_COMM_PRODUCER: 51962306a36Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_producer; 52062306a36Sopenharmony_ci dev->a_ops.adapter_intr = aac_rx_intr_producer; 52162306a36Sopenharmony_ci dev->a_ops.adapter_deliver = aac_rx_deliver_producer; 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci case AAC_COMM_MESSAGE: 52462306a36Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_message; 52562306a36Sopenharmony_ci dev->a_ops.adapter_intr = aac_rx_intr_message; 52662306a36Sopenharmony_ci dev->a_ops.adapter_deliver = aac_rx_deliver_message; 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci default: 52962306a36Sopenharmony_ci return 1; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/** 53562306a36Sopenharmony_ci * _aac_rx_init - initialize an i960 based AAC card 53662306a36Sopenharmony_ci * @dev: device to configure 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci * Allocate and set up resources for the i960 based AAC variants. The 53962306a36Sopenharmony_ci * device_interface in the commregion will be allocated and linked 54062306a36Sopenharmony_ci * to the comm region. 54162306a36Sopenharmony_ci */ 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ciint _aac_rx_init(struct aac_dev *dev) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci unsigned long start; 54662306a36Sopenharmony_ci unsigned long status; 54762306a36Sopenharmony_ci int restart = 0; 54862306a36Sopenharmony_ci int instance = dev->id; 54962306a36Sopenharmony_ci const char * name = dev->name; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (aac_adapter_ioremap(dev, dev->base_size)) { 55262306a36Sopenharmony_ci printk(KERN_WARNING "%s: unable to map adapter.\n", name); 55362306a36Sopenharmony_ci goto error_iounmap; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* Failure to reset here is an option ... */ 55762306a36Sopenharmony_ci dev->a_ops.adapter_sync_cmd = rx_sync_cmd; 55862306a36Sopenharmony_ci dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt; 55962306a36Sopenharmony_ci dev->OIMR = status = rx_readb (dev, MUnit.OIMR); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (((status & 0x0c) != 0x0c) || dev->init_reset) { 56262306a36Sopenharmony_ci dev->init_reset = false; 56362306a36Sopenharmony_ci if (!aac_rx_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) { 56462306a36Sopenharmony_ci /* Make sure the Hardware FIFO is empty */ 56562306a36Sopenharmony_ci while ((++restart < 512) && 56662306a36Sopenharmony_ci (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL)); 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci /* 57162306a36Sopenharmony_ci * Check to see if the board panic'd while booting. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ci status = rx_readl(dev, MUnit.OMRx[0]); 57462306a36Sopenharmony_ci if (status & KERNEL_PANIC) { 57562306a36Sopenharmony_ci if (aac_rx_restart_adapter(dev, 57662306a36Sopenharmony_ci aac_rx_check_health(dev), IOP_HWSOFT_RESET)) 57762306a36Sopenharmony_ci goto error_iounmap; 57862306a36Sopenharmony_ci ++restart; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci /* 58162306a36Sopenharmony_ci * Check to see if the board failed any self tests. 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_ci status = rx_readl(dev, MUnit.OMRx[0]); 58462306a36Sopenharmony_ci if (status & SELF_TEST_FAILED) { 58562306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); 58662306a36Sopenharmony_ci goto error_iounmap; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci /* 58962306a36Sopenharmony_ci * Check to see if the monitor panic'd while booting. 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_ci if (status & MONITOR_PANIC) { 59262306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); 59362306a36Sopenharmony_ci goto error_iounmap; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci start = jiffies; 59662306a36Sopenharmony_ci /* 59762306a36Sopenharmony_ci * Wait for the adapter to be up and running. Wait up to 3 minutes 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_ci while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING)) 60062306a36Sopenharmony_ci { 60162306a36Sopenharmony_ci if ((restart && 60262306a36Sopenharmony_ci (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || 60362306a36Sopenharmony_ci time_after(jiffies, start+HZ*startup_timeout)) { 60462306a36Sopenharmony_ci printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 60562306a36Sopenharmony_ci dev->name, instance, status); 60662306a36Sopenharmony_ci goto error_iounmap; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci if (!restart && 60962306a36Sopenharmony_ci ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || 61062306a36Sopenharmony_ci time_after(jiffies, start + HZ * 61162306a36Sopenharmony_ci ((startup_timeout > 60) 61262306a36Sopenharmony_ci ? (startup_timeout - 60) 61362306a36Sopenharmony_ci : (startup_timeout / 2))))) { 61462306a36Sopenharmony_ci if (likely(!aac_rx_restart_adapter(dev, 61562306a36Sopenharmony_ci aac_rx_check_health(dev), IOP_HWSOFT_RESET))) 61662306a36Sopenharmony_ci start = jiffies; 61762306a36Sopenharmony_ci ++restart; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci msleep(1); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci if (restart && aac_commit) 62262306a36Sopenharmony_ci aac_commit = 1; 62362306a36Sopenharmony_ci /* 62462306a36Sopenharmony_ci * Fill in the common function dispatch table. 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ci dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; 62762306a36Sopenharmony_ci dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; 62862306a36Sopenharmony_ci dev->a_ops.adapter_notify = aac_rx_notify_adapter; 62962306a36Sopenharmony_ci dev->a_ops.adapter_sync_cmd = rx_sync_cmd; 63062306a36Sopenharmony_ci dev->a_ops.adapter_check_health = aac_rx_check_health; 63162306a36Sopenharmony_ci dev->a_ops.adapter_restart = aac_rx_restart_adapter; 63262306a36Sopenharmony_ci dev->a_ops.adapter_start = aac_rx_start_adapter; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* 63562306a36Sopenharmony_ci * First clear out all interrupts. Then enable the one's that we 63662306a36Sopenharmony_ci * can handle. 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_ci aac_adapter_comm(dev, AAC_COMM_PRODUCER); 63962306a36Sopenharmony_ci aac_adapter_disable_int(dev); 64062306a36Sopenharmony_ci rx_writel(dev, MUnit.ODR, 0xffffffff); 64162306a36Sopenharmony_ci aac_adapter_enable_int(dev); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (aac_init_adapter(dev) == NULL) 64462306a36Sopenharmony_ci goto error_iounmap; 64562306a36Sopenharmony_ci aac_adapter_comm(dev, dev->comm_interface); 64662306a36Sopenharmony_ci dev->sync_mode = 0; /* sync. mode not supported */ 64762306a36Sopenharmony_ci dev->msi = aac_msi && !pci_enable_msi(dev->pdev); 64862306a36Sopenharmony_ci if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, 64962306a36Sopenharmony_ci IRQF_SHARED, "aacraid", dev) < 0) { 65062306a36Sopenharmony_ci if (dev->msi) 65162306a36Sopenharmony_ci pci_disable_msi(dev->pdev); 65262306a36Sopenharmony_ci printk(KERN_ERR "%s%d: Interrupt unavailable.\n", 65362306a36Sopenharmony_ci name, instance); 65462306a36Sopenharmony_ci goto error_iounmap; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci dev->dbg_base = dev->base_start; 65762306a36Sopenharmony_ci dev->dbg_base_mapped = dev->base; 65862306a36Sopenharmony_ci dev->dbg_size = dev->base_size; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci aac_adapter_enable_int(dev); 66162306a36Sopenharmony_ci /* 66262306a36Sopenharmony_ci * Tell the adapter that all is configured, and it can 66362306a36Sopenharmony_ci * start accepting requests 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_ci aac_rx_start_adapter(dev); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cierror_iounmap: 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci return -1; 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ciint aac_rx_init(struct aac_dev *dev) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci /* 67762306a36Sopenharmony_ci * Fill in the function dispatch table. 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_ci dev->a_ops.adapter_ioremap = aac_rx_ioremap; 68062306a36Sopenharmony_ci dev->a_ops.adapter_comm = aac_rx_select_comm; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci return _aac_rx_init(dev); 68362306a36Sopenharmony_ci} 684