hci1394_isr.c revision ae85eacf06af0418339ac9ae3a03449111a0ebab
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Contains the core interrupt handling logic for the hci1394 driver.
* It also contains the routine which sets up the initial interrupt
* mask during HW init.
*/
/*
* hci1394_isr_init()
* Get the iblock_cookie, make sure we are not using a high level interrupt,
* register our interrupt service routine.
*/
int
{
int status;
/* This driver does not support running at a high level interrupt */
if (status != 0) {
"High Level interrupts not supported");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* There should only be 1 1394 interrupt for an OpenHCI adapter */
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hci1394_isr_fini()
* un-register our interrupt service routine.
*/
/* ARGSUSED */
void
{
/* nothing to do right now */
}
/*
* hci1394_isr_handler_init()
* register our interrupt service routine.
*/
int
{
int status;
/* Initialize interrupt handler */
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hci1394_isr_handler_fini()
* un-register our interrupt service routine.
*/
void
{
/* Remove interrupt handler */
}
/*
* hci1394_isr_mask_setup()
* Setup the initial interrupt mask for OpenHCI. These are the interrupts
* that our interrupt handler is expected to handle.
*/
void
{
"");
/* Setup Interrupt Mask Register */
"");
}
/*
* hci1394_isr()
* Core interrupt handler. Every interrupt enabled in
* hci1394_isr_mask_setup() should be covered here. There may be other
* interrupts supported in here even if they are not initially enabled
* (like OHCI_INTR_CYC_64_SECS) since they may be enabled later (i.e. due to
* CSR register write)
*/
static uint_t
{
return (DDI_INTR_UNCLAIMED);
/*
* Get all of the enabled 1394 interrupts which are currently
* asserted.
*/
do {
/* handle the asserted interrupts */
if (interrupt_event & OHCI_INTR_BUS_RESET) {
}
if (interrupt_event & OHCI_INTR_SELFID_CMPLT) {
}
if (interrupt_event & OHCI_INTR_ISOCH_TX) {
}
if (interrupt_event & OHCI_INTR_ISOCH_RX) {
}
if (interrupt_event & OHCI_INTR_REQ_TX_CMPLT) {
}
if (interrupt_event & OHCI_INTR_RSPKT) {
}
if (interrupt_event & OHCI_INTR_RQPKT) {
}
if (interrupt_event & OHCI_INTR_RESP_TX_CMPLT) {
}
if (interrupt_event & OHCI_INTR_CYC_64_SECS) {
}
"unrecoverable error interrupt detected",
}
if (interrupt_event & OHCI_INTR_CYC_LOST) {
}
}
if (interrupt_event & OHCI_INTR_CYC_TOO_LONG) {
/* clear cycle master bit in csr state register */
}
if (interrupt_event & OHCI_INTR_POST_WR_ERR) {
}
if (interrupt_event & OHCI_INTR_PHY) {
}
if (interrupt_event & OHCI_INTR_LOCK_RESP_ERR) {
}
/*
* Check for self-id-complete interrupt disappearing. There is
* a chance in OpenHCI where it will assert the selfid
* interrupt and then take it away. We will look for this case
* and claim it just in case. We could possibly claim an
* interrupt that's not ours. We would have to be in the
* middle of a bus reset and a bunch of other weird stuff
* would have to align. It should not hurt anything if we do.
*
* This will very very rarely happen, if ever. We still have
* to handle the case, just in case. OpenHCI 1.1 should fix
* this problem.
*/
if ((status == DDI_INTR_UNCLAIMED) &&
HCI1394_TNF_HAL, "");
}
}
/*
* See if any of the enabled 1394 interrupts have been asserted
* since we first checked.
*/
soft_state->ohci);
} while (interrupt_event != 0);
return (status);
}
/*
* hci1394_isr_bus_reset()
* Process a 1394 bus reset. This signifies that a bus reset has started.
* A bus reset will not be complete until a selfid complete interrupt
* comes in.
*/
static void
{
int status;
HCI1394_TNF_HAL_STACK, "");
/*
* Set the driver state to reset. If we cannot, we have been shutdown.
* The only way we can get in this code is if we have a multi-processor
* machine and the HAL is shutdown by one processor running in base
* context while this interrupt handler runs in another processor.
* We will disable all interrupts and just return. We shouldn't have
* to disable the interrupts, but we will just in case.
*/
if (status != DDI_SUCCESS) {
return;
}
/*
* Save away reset generation count so we can detect self-id-compete
* interrupt which disappears in event register. This is discussed in
* more detail in hci1394_isr()
*/
/*
* Mask off busReset until SelfIdComplete comes in. The bus reset
* interrupt will be asserted until the SelfIdComplete interrupt
* comes in (i.e. you cannot clear the interrupt until a SelfIdComplete
* interrupt). Therefore, we disable the interrupt via its mask so we
* don't get stuck in the ISR indefinitely.
*/
/* Reset the ATREQ and ATRESP Q's */
/* Inform Services Layer about Bus Reset */
(void **)&soft_state->sl_selfid_buf);
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_isr_self_id()
* Process the selfid complete interrupt. The bus reset has completed
* and the 1394 HW has finished it's bus enumeration. The SW needs to
* see what's changed and handle any hotplug conditions.
*/
static void
{
int status;
/*
* check for the bizarre case that we got both a bus reset and self id
* complete after checking for a bus reset
*/
}
/*
* Clear any set PHY error status bits set. The PHY status bits
* may always be set (i.e. we removed cable power) so we do not want
* to clear them when we handle the interrupt. We will clear them
* every selfid complete interrupt so worst case we will get 1 PHY event
* interrupt every bus reset.
*/
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
} else {
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
} else {
/*
* Re-enable PHY interrupt. We disable the PHY interrupt
* when we get one so that we do not get stuck in the
* ISR.
*/
}
}
/* See if either AT active bit is set */
}
/* Clear busReset and selfIdComplete interrupts */
/* Read node info and test for Invalid Node ID */
if (nodeid_error == B_TRUE) {
}
/* Sync Selfid Buffer */
/* store away selfid info */
/* Test for selfid error */
if (selfid_error == B_TRUE) {
}
/*
* selfid size could be 0 if a bus reset has occurred. If this occurs,
* we should have another selfid int coming later.
*/
HCI1394_TNF_HAL_STACK, "");
return;
}
/*
* make sure generation count in buffer matches generation
* count in register.
*/
HCI1394_TNF_HAL_STACK, "");
return;
}
/*
* Skip over first quadlet in selfid buffer, this is OpenHCI specific
* data.
*/
/* Copy selfid buffer to Services Layer buffer */
}
/*
* Put our selfID info into the Services Layer's selfid buffer if we
* have a 1394-1995 PHY.
*/
selfid_buf_p = (uint32_t *)(
&selfid_buf_p[0]);
if (status != DDI_SUCCESS) {
/*
* If we fail reading from PHY, put invalid data into
* the selfid buffer so the SL will reset the bus again.
*/
HCI1394_TNF_HAL_ERROR, "");
selfid_buf_p[0] = 0xFFFFFFFF;
} else {
}
}
/* Flush out async DMA Q's */
/*
* Make sure generation count is still valid. i.e. we have not gotten
* another bus reset since the last time we checked. If we have gotten
* another bus reset, we should have another selfid interrupt coming.
*/
HCI1394_TNF_HAL_STACK, "");
return;
}
/*
* do whatever CSR register processing that needs to be done.
*/
/*
* do whatever management may be necessary for the CYCLE_LOST and
* CYCLE_INCONSISTENT interrupts.
*/
/*
* See if we saw an error. If we did, tell the services layer that we
* finished selfid processing and give them an illegal selfid buffer
* size of 0. The Services Layer will try to reset the bus again to
* see if we can recover from this problem. It will threshold after
* a finite number of errors.
*/
/*
* Take ourself out of Bus Reset processing mode
*
* Set the driver state to normal. If we cannot, we have been
* shutdown. The only way we can get in this code is if we have
* a multi-processor machine and the HAL is shutdown by one
* processor running in base context while this interrupt
* handler runs in another processor. We will disable all
* interrupts and just return. We shouldn't have to disable
* the interrupts, but we will just in case.
*/
if (status != DDI_SUCCESS) {
return;
}
/*
* Notify services layer about self-id-complete. Don't notify
* the services layer if there are too many devices on the bus.
*/
/*
* Take ourself out of Bus Reset processing mode
*
* Set the driver state to normal. If we cannot, we have been
* shutdown. The only way we can get in this code is if we have
* a multi-processor machine and the HAL is shutdown by one
* processor running in base context while this interrupt
* handler runs in another processor. We will disable all
* interrupts and just return. We shouldn't have to disable
* the interrupts, but we will just in case.
*/
if (status != DDI_SUCCESS) {
return;
}
} else {
}
/* enable bus reset interrupt */
}
/*
* hci1394_isr_isoch_ir()
* Process each isoch recv context which has its interrupt asserted. The
* interrupt will be asserted when an isoch recv descriptor with the
* interrupt bits enabled have finished being processed.
*/
static void
{
uint32_t i;
int num_ir_contexts;
HCI1394_TNF_HAL_STACK, "");
/*
* Main isochRx int is not clearable. it is automatically
* cleared by the hw when the ir_intr_event is cleared
*/
/* loop until no more IR events */
/* clear the events we just learned about */
/* for each interrupting IR context, process the interrupt */
for (i = 0; i < num_ir_contexts; i++) {
/*
* if the intr bit is on for a context,
*/
soft_state->isoch, i);
B_FALSE);
}
mask <<= 1;
}
}
}
/*
* hci1394_isr_isoch_it()
* Process each isoch transmit context which has its interrupt asserted. The
* interrupt will be asserted when an isoch transmit descriptor with the
* interrupt bit is finished being processed.
*/
static void
{
uint32_t i;
int num_it_contexts;
HCI1394_TNF_HAL_STACK, "");
/*
* Main isochTx int is not clearable. it is automatically
* cleared by the hw when the it_intr_event is cleared.
*/
/* loop until no more IT events */
/* clear the events we just learned about */
/* for each interrupting IR context, process the interrupt */
for (i = 0; i < num_it_contexts; i++) {
/*
* if the intr bit is on for a context,
*/
soft_state->isoch, i);
B_FALSE);
}
mask <<= 1;
}
}
}
/*
* hci1394_isr_atreq_complete()
* Process all completed requests that we have sent out (i.e. HW gave us
* an ack).
*/
static void
{
int status;
HCI1394_TNF_HAL_STACK, "");
/*
* Processes all ack'd AT requests. If the request is pended, it is
* considered complete relative the the atreq engine. AR response
* processing will make sure we track the response.
*/
do {
/*
* Process a single request. Do not flush Q. That is only
* done during bus reset processing.
*/
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
}
} while (request_available == B_TRUE);
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_isr_arresp()
* Process all responses that have come in off the bus and send then up to
* the services layer. We send out a request on the bus (atreq) and some time
* later a response comes in. We send this response up to the services
* layer.
*/
static void
{
int status;
/*
* Process all responses that have been received. If more responses
* come in we will stay in interrupt handler and re-run this routine.
* It is possible that we will call hci1394_async_arresp_process()
* even though there are no more AR responses to process. This would
* be because we have processed them earlier on. (i.e. we cleared
* interrupt, then got another response and processed it. The interrupt
* would still be pending.
*/
do {
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
}
} while (response_available == B_TRUE);
}
/*
* hci1394_isr_arreq()
* Process all requests that have come in off the bus and send then up to
* the services layer.
*/
static void
{
int status;
/*
* Process all requests that have been received. It is possible that we
* will call hci1394_async_arreq_process() even though there are no
* more requests to process. This would be because we have processed
* them earlier on. (i.e. we cleared interrupt, got another request
* and processed it. The interrupt would still be pending.
*/
do {
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
}
} while (request_available == B_TRUE);
}
/*
* hci1394_isr_atresp_complete()
* Process all completed responses that we have sent out (i.e. HW gave us
* an ack). We get in a request off the bus (arreq) and send it up to the
* services layer, they send down a response to that request some time
* later. This interrupt signifies that the HW is done with the response.
* (i.e. it sent it out or failed it)
*/
static void
{
int status;
HCI1394_TNF_HAL_STACK, "");
/*
* Processes all ack'd AT responses It is possible that we will call
* hci1394_async_atresp_process() even thought there are no more
* responses to process. This would be because we have processed
* them earlier on. (i.e. we cleared interrupt, then got another
* response and processed it. The interrupt would still be pending.
*/
do {
/*
* Process a single response. Do not flush Q. That is only
* done during bus reset processing.
*/
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
}
} while (response_available == B_TRUE);
HCI1394_TNF_HAL_STACK, "");
}