px_msi.c revision 269473047d747f7815af570197e4ef7322d3632c
/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* px_msi.c
*/
#include <sys/ddi_impldefs.h>
#include <sys/pci_impl.h>
#include "px_obj.h"
/*
* msi_attach()
*/
int
{
int i, ret;
/*
* Check for all MSI related properties and
* save all information.
*/
return (DDI_FAILURE);
}
}
/*
* Create IRM pool to manage interrupt allocations.
*/
} else {
}
return (ret);
}
/*
* msi_detach()
*/
void
{
if (msi_state_p->msi_pool_p)
if (msi_state_p->msi_p) {
}
}
/*
* msi_alloc()
*/
/* ARGSUSED */
int
int flag, int *actual_msi_count_p)
{
*actual_msi_count_p = 0;
/*
* MSI interrupts are allocated as contiguous ranges at
* power of 2 boundaries from the start of the MSI array.
*/
if (type == DDI_INTR_TYPE_MSI) {
/* Search for a range of available interrupts */
!= MSI_STATE_FREE) {
break;
}
}
goto found_msi;
}
}
if (count > 1) {
"Retry MSI allocation with new msi_count "
}
}
/* Set number of available interrupts */
/* Check if successful, and enforce strict behavior */
if ((count == 0) ||
return (DDI_EAGAIN);
}
/* Allocate the interrupts */
}
}
/*
* MSI-X interrupts are allocated from the end of the MSI
* array. There are no concerns about power of 2 boundaries
* and the allocated interrupts do not have to be contiguous.
*/
if (type == DDI_INTR_TYPE_MSIX) {
/* Count available interrupts, up to count requested */
if (count == 0)
first = i;
count++;
break;
}
}
/* Set number of available interrupts */
/* Check if successful, and enforce strict behavior */
if ((count == 0) ||
return (DDI_EAGAIN);
}
/* Allocate the interrupts */
continue;
inum++;
n++;
}
}
return (DDI_SUCCESS);
}
/*
* msi_free()
*/
int
{
int i, n;
/*
* Find and release the specified MSI/X numbers.
*
* Because the allocations are not always contiguous, perform
* a full linear search of the MSI/X table looking for MSI/X
* vectors owned by the device with inum values in the range
* [inum .. (inum + msi_count - 1)].
*/
n++;
}
}
/* Fail if the MSI/X numbers were not found */
if (n < msi_count)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/*
* msi_get_msinum()
*/
int
{
int i;
for (i = 0; i < msi_state_p->msi_cnt; i++) {
return (DDI_SUCCESS);
}
}
if (i >= msi_state_p->msi_cnt)
"no msi for inum 0x%x\n", inum);
return (DDI_FAILURE);
}
/*
* px_msi_get_props()
*/
static int
{
int length = sizeof (int);
/* #msi */
DDI_PROP_DONTPASS, "#msi", 0);
if (msi_state_p->msi_cnt == 0)
return (DDI_FAILURE);
/* msi-ranges: msi# field */
!= DDI_PROP_SUCCESS)
return (DDI_FAILURE);
/* msi-data-mask */
DDI_PROP_DONTPASS, "msi-data-mask", 0);
/* msi-data-width */
DDI_PROP_DONTPASS, "msix-data-width", 0);
/*
* Assume MSI is always supported, but also check if MSIX is supported
*/
if (msi_state_p->msi_data_width) {
} else {
return (DDI_FAILURE);
}
/* msi-address-ranges */
!= DDI_PROP_SUCCESS)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}