// SPDX-License-Identifier: GPL-2.0-or-later /* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. * * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000-2010 Adaptec, Inc. * 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * 2016-2017 Microsemi Corp. (aacraid@microsemi.com) * * Module Name: * rx.c * * Abstract: Hardware miniport for Drawbridge specific hardware functions.
*/
/** * rx_sync_cmd - send a command and wait * @dev: Adapter * @command: Command to execute * @p1: first parameter * @p2: second parameter * @p3: third parameter * @p4: forth parameter * @p5: fifth parameter * @p6: sixth parameter * @status: adapter status * @r1: first return value * @r2: second return value * @r3: third return value * @r4: forth return value * * This routine will send a synchronous command to the adapter and wait * for its completion.
*/
staticint rx_sync_cmd(struct aac_dev *dev, u32 command,
u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4)
{ unsignedlong start; int ok; /* * Write the command into Mailbox 0
*/
writel(command, &dev->IndexRegs->Mailbox[0]); /* * Write the parameters into Mailboxes 1 - 6
*/
writel(p1, &dev->IndexRegs->Mailbox[1]);
writel(p2, &dev->IndexRegs->Mailbox[2]);
writel(p3, &dev->IndexRegs->Mailbox[3]);
writel(p4, &dev->IndexRegs->Mailbox[4]); /* * Clear the synch command doorbell to start on a clean slate.
*/
rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); /* * Disable doorbell interrupts
*/
rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); /* * Force the completion of the mask register write before issuing * the interrupt.
*/
rx_readb (dev, MUnit.OIMR); /* * Signal that there is a new synch command
*/
rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
ok = 0;
start = jiffies;
/* * Wait up to 30 seconds
*/ while (time_before(jiffies, start+30*HZ))
{
udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ /* * Mon960 will set doorbell0 bit when it has completed the command.
*/ if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) { /* * Clear the doorbell.
*/
rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
ok = 1; break;
} /* * Yield the processor in case we are slow
*/
msleep(1);
} if (unlikely(ok != 1)) { /* * Restore interrupt mask even though we timed out
*/
aac_adapter_enable_int(dev); return -ETIMEDOUT;
} /* * Pull the synch status from Mailbox 0.
*/ if (status)
*status = readl(&dev->IndexRegs->Mailbox[0]); if (r1)
*r1 = readl(&dev->IndexRegs->Mailbox[1]); if (r2)
*r2 = readl(&dev->IndexRegs->Mailbox[2]); if (r3)
*r3 = readl(&dev->IndexRegs->Mailbox[3]); if (r4)
*r4 = readl(&dev->IndexRegs->Mailbox[4]); /* * Clear the synch command doorbell.
*/
rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); /* * Restore interrupt mask
*/
aac_adapter_enable_int(dev); return 0;
}
/** * aac_rx_interrupt_adapter - interrupt adapter * @dev: Adapter * * Send an interrupt to the i960 and breakpoint it.
*/
/** * aac_rx_notify_adapter - send an event to the adapter * @dev: Adapter * @event: Event to send * * Notify the i960 that something it probably cares about has * happened.
*/
case AdapNormCmdQue:
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1); break; case HostNormRespNotFull:
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4); break; case AdapNormRespQue:
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2); break; case HostNormCmdNotFull:
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3); break; case HostShutdown: break; case FastIo:
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6); break; case AdapPrintfDone:
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5); break; default:
BUG(); break;
}
}
/** * aac_rx_start_adapter - activate adapter * @dev: Adapter * * Start up processing on an i960 based AAC adapter
*/
staticvoid aac_rx_start_adapter(struct aac_dev *dev)
{ union aac_init *init;
init = dev->init;
init->r7.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds()); // We can only use a 32 bit address here
rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa,
0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
}
/** * aac_rx_check_health * @dev: device to check if healthy * * Will attempt to determine if the specified adapter is alive and * capable of handling requests, returning 0 if alive.
*/ staticint aac_rx_check_health(struct aac_dev *dev)
{
u32 status = rx_readl(dev, MUnit.OMRx[0]);
/* * Check to see if the board failed any self tests.
*/ if (unlikely(status & SELF_TEST_FAILED)) return -1; /* * Check to see if the board panic'd.
*/ if (unlikely(status & KERNEL_PANIC)) { char * buffer; struct POSTSTATUS {
__le32 Post_Command;
__le32 Post_Address;
} * post;
dma_addr_t paddr, baddr; int ret;
if (likely((status & 0xFF000000L) == 0xBC000000L)) return (status >> 16) & 0xFF;
buffer = dma_alloc_coherent(&dev->pdev->dev, 512, &baddr,
GFP_KERNEL);
ret = -2; if (unlikely(buffer == NULL)) return ret;
post = dma_alloc_coherent(&dev->pdev->dev, sizeof(struct POSTSTATUS), &paddr,
GFP_KERNEL); if (unlikely(post == NULL)) {
dma_free_coherent(&dev->pdev->dev, 512, buffer, baddr); return ret;
}
memset(buffer, 0, 512);
post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);
post->Post_Address = cpu_to_le32(baddr);
rx_writel(dev, MUnit.IMRx[0], paddr);
rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0,
NULL, NULL, NULL, NULL, NULL);
dma_free_coherent(&dev->pdev->dev, sizeof(struct POSTSTATUS),
post, paddr); if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) {
ret = (hex_to_bin(buffer[2]) << 4) +
hex_to_bin(buffer[3]);
}
dma_free_coherent(&dev->pdev->dev, 512, buffer, baddr); return ret;
} /* * Wait for the adapter to be up and running.
*/ if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) return -3; /* * Everything is OK
*/ return 0;
}
/** * aac_rx_deliver_producer * @fib: fib to issue * * Will send a fib, returning 0 if successful.
*/ int aac_rx_deliver_producer(struct fib * fib)
{ struct aac_dev *dev = fib->dev; struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];
u32 Index; unsignedlong nointr = 0;
/** * _aac_rx_init - initialize an i960 based AAC card * @dev: device to configure * * Allocate and set up resources for the i960 based AAC variants. The * device_interface in the commregion will be allocated and linked * to the comm region.
*/
int _aac_rx_init(struct aac_dev *dev)
{ unsignedlong start; unsignedlong status; int restart = 0; int instance = dev->id; constchar * name = dev->name;
if (aac_adapter_ioremap(dev, dev->base_size)) {
printk(KERN_WARNING "%s: unable to map adapter.\n", name); goto error_iounmap;
}
/* Failure to reset here is an option ... */
dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt;
dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
if (((status & 0x0c) != 0x0c) || dev->init_reset) {
dev->init_reset = false; if (!aac_rx_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) { /* Make sure the Hardware FIFO is empty */ while ((++restart < 512) &&
(rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL));
}
}
/* * Check to see if the board panic'd while booting.
*/
status = rx_readl(dev, MUnit.OMRx[0]); if (status & KERNEL_PANIC) { if (aac_rx_restart_adapter(dev,
aac_rx_check_health(dev), IOP_HWSOFT_RESET)) goto error_iounmap;
++restart;
} /* * Check to see if the board failed any self tests.
*/
status = rx_readl(dev, MUnit.OMRx[0]); if (status & SELF_TEST_FAILED) {
printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); goto error_iounmap;
} /* * Check to see if the monitor panic'd while booting.
*/ if (status & MONITOR_PANIC) {
printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); goto error_iounmap;
}
start = jiffies; /* * Wait for the adapter to be up and running. Wait up to 3 minutes
*/ while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))
{ if ((restart &&
(status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
time_after(jiffies, start+HZ*startup_timeout)) {
printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
dev->name, instance, status); goto error_iounmap;
} if (!restart &&
((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
time_after(jiffies, start + HZ *
((startup_timeout > 60)
? (startup_timeout - 60)
: (startup_timeout / 2))))) { if (likely(!aac_rx_restart_adapter(dev,
aac_rx_check_health(dev), IOP_HWSOFT_RESET)))
start = jiffies;
++restart;
}
msleep(1);
} if (restart && aac_commit)
aac_commit = 1; /* * Fill in the common function dispatch table.
*/
dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;
dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;
dev->a_ops.adapter_notify = aac_rx_notify_adapter;
dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
dev->a_ops.adapter_check_health = aac_rx_check_health;
dev->a_ops.adapter_restart = aac_rx_restart_adapter;
dev->a_ops.adapter_start = aac_rx_start_adapter;
/* * First clear out all interrupts. Then enable the one's that we * can handle.
*/
aac_adapter_comm(dev, AAC_COMM_PRODUCER);
aac_adapter_disable_int(dev);
rx_writel(dev, MUnit.ODR, 0xffffffff);
aac_adapter_enable_int(dev);
aac_adapter_enable_int(dev); /* * Tell the adapter that all is configured, and it can * start accepting requests
*/
aac_rx_start_adapter(dev);
return 0;
error_iounmap:
return -1;
}
int aac_rx_init(struct aac_dev *dev)
{ /* * Fill in the function dispatch table.
*/
dev->a_ops.adapter_ioremap = aac_rx_ioremap;
dev->a_ops.adapter_comm = aac_rx_select_comm;
return _aac_rx_init(dev);
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.