#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/sunndi.h>
#include <sys/cmn_err.h>
#include <sys/pci.h>
#include <sys/pcie.h>
#include <sys/pci_cfgspace.h>
#include <sys/pci_props.h>
#include <sys/sysmacros.h>
#include <sys/plat/pci_prd.h>
#include <pci_strings.h>
typedef struct {
uint8_t ppc_class;
uint8_t ppc_subclass;
uint8_t ppc_pi;
} pci_prop_class_t;
static boolean_t
pci_prop_class_match(const pci_prop_data_t *prop, const pci_prop_class_t *class,
const size_t nclass, boolean_t check_pi)
{
for (size_t i = 0; i < nclass; i++) {
if (prop->ppd_class == class[i].ppc_class &&
prop->ppd_subclass == class[i].ppc_subclass &&
(!check_pi || prop->ppd_pi == class[i].ppc_pi)) {
return (B_TRUE);
}
}
return (B_FALSE);
}
static const pci_prop_class_t pci_prop_vga_classes[] = {
{ PCI_CLASS_NONE, PCI_NONE_VGA, 0x00 },
{ PCI_CLASS_DISPLAY, PCI_DISPLAY_VGA, PCI_DISPLAY_IF_VGA },
{ PCI_CLASS_DISPLAY, PCI_DISPLAY_VGA, PCI_DISPLAY_IF_8514 }
};
static const pci_prop_class_t pci_prop_ioapic_classes[] = {
{ PCI_CLASS_PERIPH, PCI_PERIPH_PIC, PCI_PERIPH_PIC_IF_IO_APIC },
{ PCI_CLASS_PERIPH, PCI_PERIPH_PIC, PCI_PERIPH_PIC_IF_IOX_APIC },
};
static const pci_prop_class_t pci_prop_isa_classes[] = {
{ PCI_CLASS_BRIDGE, PCI_BRIDGE_ISA, 0 }
};
static const pci_prop_class_t pci_prop_pcibridge_classes[] = {
{ PCI_CLASS_BRIDGE, PCI_BRIDGE_PCI, 0 }
};
boolean_t
pci_prop_class_is_vga(const pci_prop_data_t *prop)
{
return (pci_prop_class_match(prop, pci_prop_vga_classes,
ARRAY_SIZE(pci_prop_vga_classes), B_TRUE));
}
boolean_t
pci_prop_class_is_ioapic(const pci_prop_data_t *prop)
{
return (pci_prop_class_match(prop, pci_prop_ioapic_classes,
ARRAY_SIZE(pci_prop_ioapic_classes), B_TRUE));
}
boolean_t
pci_prop_class_is_isa(const pci_prop_data_t *prop)
{
return (pci_prop_class_match(prop, pci_prop_isa_classes,
ARRAY_SIZE(pci_prop_isa_classes), B_FALSE));
}
boolean_t
pci_prop_class_is_pcibridge(const pci_prop_data_t *prop)
{
return (pci_prop_class_match(prop, pci_prop_pcibridge_classes,
ARRAY_SIZE(pci_prop_pcibridge_classes), B_FALSE));
}
static const char *
pci_prop_nodename_prefix(const pci_prop_data_t *prop,
pci_prd_compat_flags_t flags)
{
if ((flags & PCI_PRD_COMPAT_PCI_NODE_NAME) != 0) {
return ("pci");
}
if ((prop->ppd_flags & PCI_PROP_F_PCIE) != 0) {
return ("pciex");
} else {
return ("pci");
}
}
static boolean_t
pci_prop_use_subsystem(const pci_prop_data_t *prop,
pci_prd_compat_flags_t flags)
{
if ((flags & PCI_PRD_COMPAT_SUBSYS) != 0 &&
prop->ppd_header == PCI_HEADER_PPB) {
return (B_FALSE);
}
return (prop->ppd_subvid != 0);
}
pci_prop_failure_t
pci_prop_name_node(dev_info_t *dip, const pci_prop_data_t *prop)
{
char buf[64];
pci_prd_compat_flags_t flags = pci_prd_compat_flags();
if (pci_prop_class_is_vga(prop)) {
(void) snprintf(buf, sizeof (buf), "display");
} else if (pci_prop_class_is_isa(prop) &&
(flags & PCI_PRD_COMPAT_ISA) != 0) {
(void) snprintf(buf, sizeof (buf), "isa");
} else {
const char *prefix = pci_prop_nodename_prefix(prop, flags);
if (pci_prop_use_subsystem(prop, flags)) {
(void) snprintf(buf, sizeof (buf), "%s%x,%x", prefix,
prop->ppd_subvid, prop->ppd_subsys);
} else {
(void) snprintf(buf, sizeof (buf), "%s%x,%x", prefix,
prop->ppd_vendid, prop->ppd_devid);
}
}
if (ndi_devi_set_nodename(dip, buf, 0) != NDI_SUCCESS) {
return (PCI_PROP_E_NDI);
}
return (PCI_PROP_OK);
}
static uint8_t
pci_prop_get8(ddi_acc_handle_t acc, const pci_prop_data_t *prop, uint16_t off)
{
if (acc == NULL) {
return ((*pci_getb_func)(prop->ppd_bus, prop->ppd_dev,
prop->ppd_func, off));
} else {
return (pci_config_get8(acc, off));
}
}
static uint16_t
pci_prop_get16(ddi_acc_handle_t acc, const pci_prop_data_t *prop, uint16_t off)
{
if (acc == NULL) {
return ((*pci_getw_func)(prop->ppd_bus, prop->ppd_dev,
prop->ppd_func, off));
} else {
return (pci_config_get16(acc, off));
}
}
static uint32_t
pci_prop_get32(ddi_acc_handle_t acc, const pci_prop_data_t *prop, uint16_t off)
{
if (acc == NULL) {
return ((*pci_getl_func)(prop->ppd_bus, prop->ppd_dev,
prop->ppd_func, off));
} else {
return (pci_config_get32(acc, off));
}
}
static pci_prop_failure_t
pci_prop_data_fill_pcie(ddi_acc_handle_t acc, pci_prop_data_t *prop,
uint8_t cap_base)
{
uint16_t pciecap;
uint32_t slotcap;
uint8_t vers;
pciecap = pci_prop_get16(acc, prop, cap_base + PCIE_PCIECAP);
vers = pciecap & PCIE_PCIECAP_VER_MASK;
switch (vers) {
case PCIE_PCIECAP_VER_1_0:
case PCIE_PCIECAP_VER_2_0:
break;
default:
cmn_err(CE_WARN, "found device at b/d/f 0x%x/0x%x/0x%x with "
"PCIe capability with unsupported capability version: 0x%x",
prop->ppd_bus, prop->ppd_dev, prop->ppd_func, vers);
return (PCI_PROP_E_BAD_PCIE_CAP);
}
prop->ppd_flags |= PCI_PROP_F_PCIE;
prop->ppd_pcie_type = pciecap & PCIE_PCIECAP_DEV_TYPE_MASK;
if ((pciecap & PCIE_PCIECAP_SLOT_IMPL) == 0) {
return (PCI_PROP_OK);
}
slotcap = pci_prop_get32(acc, prop, cap_base + PCIE_SLOTCAP);
prop->ppd_slotno = PCIE_SLOTCAP_PHY_SLOT_NUM(slotcap);
prop->ppd_flags |= PCI_PROP_F_SLOT_VALID;
return (PCI_PROP_OK);
}
pci_prop_failure_t
pci_prop_data_fill(ddi_acc_handle_t acc, uint8_t bus, uint8_t dev, uint8_t func,
pci_prop_data_t *prop)
{
uint8_t htype, cap_off, max_cap = PCI_CAP_MAX_PTR;
uint16_t status;
bzero(prop, sizeof (pci_prop_data_t));
prop->ppd_bus = bus;
prop->ppd_dev = dev;
prop->ppd_func = func;
prop->ppd_vendid = pci_prop_get16(acc, prop, PCI_CONF_VENID);
if (prop->ppd_vendid == PCI_EINVAL16) {
return (PCI_PROP_E_BAD_READ);
}
prop->ppd_devid = pci_prop_get16(acc, prop, PCI_CONF_DEVID);
prop->ppd_rev = pci_prop_get8(acc, prop, PCI_CONF_REVID);
prop->ppd_class = pci_prop_get8(acc, prop, PCI_CONF_BASCLASS);
prop->ppd_subclass = pci_prop_get8(acc, prop, PCI_CONF_SUBCLASS);
prop->ppd_pi = pci_prop_get8(acc, prop, PCI_CONF_PROGCLASS);
htype = pci_prop_get8(acc, prop, PCI_CONF_HEADER);
prop->ppd_header = htype & PCI_HEADER_TYPE_M;
if ((htype & PCI_HEADER_MULTI) != 0) {
prop->ppd_flags |= PCI_PROP_F_MULT_FUNC;
}
switch (prop->ppd_header) {
case PCI_HEADER_ZERO:
prop->ppd_subvid = pci_prop_get16(acc, prop,
PCI_CONF_SUBVENID);
prop->ppd_subsys = pci_prop_get16(acc, prop,
PCI_CONF_SUBSYSID);
prop->ppd_mingrt = pci_prop_get8(acc, prop, PCI_CONF_MIN_G);
prop->ppd_maxlat = pci_prop_get8(acc, prop, PCI_CONF_MAX_L);
break;
case PCI_HEADER_CARDBUS:
prop->ppd_subvid = pci_prop_get16(acc, prop,
PCI_CBUS_SUBVENID);
prop->ppd_subsys = pci_prop_get16(acc, prop,
PCI_CBUS_SUBSYSID);
break;
case PCI_HEADER_PPB:
break;
default:
return (PCI_PROP_E_UNKNOWN_HEADER);
}
prop->ppd_ipin = pci_prop_get8(acc, prop, PCI_CONF_IPIN);
prop->ppd_status = pci_prop_get16(acc, prop, PCI_CONF_STAT);
status = pci_prop_get16(acc, prop, PCI_CONF_STAT);
if ((status & PCI_STAT_CAP) == 0)
return (PCI_PROP_OK);
cap_off = pci_prop_get8(acc, prop, PCI_CONF_CAP_PTR);
for (; max_cap > 0 && cap_off >= PCI_CAP_PTR_OFF; max_cap--) {
uint8_t cap_addr = cap_off & PCI_CAP_PTR_MASK;
uint8_t cap_id = pci_prop_get8(acc, prop, cap_addr);
uint16_t subvid, subsys;
pci_prop_failure_t ret;
if (cap_id == PCI_EINVAL8) {
return (PCI_PROP_OK);
}
switch (cap_id) {
case PCI_CAP_ID_PCI_E:
ret = pci_prop_data_fill_pcie(acc, prop, cap_addr);
if (ret != PCI_PROP_OK) {
return (ret);
}
break;
case PCI_CAP_ID_P2P_SUBSYS:
subvid = pci_prop_get16(acc, prop, cap_addr +
PCI_SUBSYSCAP_SUBVID);
subsys = pci_prop_get16(acc, prop, cap_addr +
PCI_SUBSYSCAP_SUBSYS);
if (prop->ppd_header == PCI_HEADER_PPB) {
prop->ppd_subvid = subvid;
prop->ppd_subsys = subsys;
} else if (subvid != prop->ppd_subvid ||
subsys != prop->ppd_subsys) {
cmn_err(CE_WARN, "found device at b/d/f "
"0x%x/0x%x/0x%x with PCI subsystem "
"capability, but wrong header type 0x%x "
"and mismatched subsystems: header "
"0x%x/0x%x, cap: 0x%x/0x%x, using header "
"values", bus, dev, func, prop->ppd_header,
prop->ppd_subvid, prop->ppd_subsys, subvid,
subsys);
break;
}
break;
default:
break;
}
cap_off = pci_prop_get8(acc, prop, cap_addr + PCI_CAP_NEXT_PTR);
if (cap_off == PCI_EINVAL8) {
return (PCI_PROP_OK);
}
}
return (PCI_PROP_OK);
}
static void
pci_prop_set_pciex_slot_name(dev_info_t *dip, uint16_t slotno)
{
uint32_t slot[32];
size_t len;
bzero(slot, sizeof (slot));
slot[0] = 1;
len = snprintf((char *)&slot[1], sizeof (slot) - sizeof (slot[0]),
"pcie%u", slotno) + 1;
len = P2ROUNDUP(len, sizeof (uint32_t));
len /= sizeof (uint32_t);
len += 1;
(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "slot-names",
(int *)slot, len);
}
pci_prop_failure_t
pci_prop_set_common_props(dev_info_t *dip, const pci_prop_data_t *prop)
{
int class;
char unitaddr[16];
pci_prd_compat_flags_t flags = pci_prd_compat_flags();
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "vendor-id",
prop->ppd_vendid);
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "device-id",
prop->ppd_devid);
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "revision-id",
prop->ppd_rev);
class = (prop->ppd_class << 16) | (prop->ppd_subclass << 8) |
prop->ppd_pi;
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "class-code", class);
if (prop->ppd_subvid != 0) {
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
"subsystem-vendor-id", prop->ppd_subvid);
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "subsystem-id",
prop->ppd_subsys);
}
if (prop->ppd_func > 0) {
(void) snprintf(unitaddr, sizeof (unitaddr), "%x,%x",
prop->ppd_dev, prop->ppd_func);
} else {
(void) snprintf(unitaddr, sizeof (unitaddr), "%x",
prop->ppd_dev);
}
(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "unit-address",
unitaddr);
if ((prop->ppd_flags & PCI_PROP_F_PCIE) == 0) {
if ((prop->ppd_status & PCI_STAT_FBBC) != 0) {
(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
"fast-back-to-back");
}
if ((prop->ppd_status & PCI_STAT_66MHZ) != 0) {
(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
"66mhz-capable");
}
if ((prop->ppd_status & PCI_STAT_UDF) != 0) {
(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
"udf-supported");
}
if (prop->ppd_header == PCI_HEADER_ZERO) {
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
"min-grant", prop->ppd_mingrt);
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
"max-latency", prop->ppd_maxlat);
}
} else {
if ((prop->ppd_flags & PCI_PROP_F_SLOT_VALID) != 0) {
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
"physical-slot#", prop->ppd_slotno);
if (prop->ppd_pcie_type !=
PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
pci_prop_set_pciex_slot_name(dip,
prop->ppd_slotno);
}
}
}
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "devsel-speed",
(prop->ppd_status & PCI_STAT_DEVSELT) >> 9);
if (prop->ppd_ipin != 0) {
(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, "interrupts",
prop->ppd_ipin);
}
if (pci_prop_class_is_vga(prop)) {
(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
"device_type", "display");
} else if (pci_prop_class_is_isa(prop) &&
(flags & PCI_PRD_COMPAT_ISA) != 0) {
(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
"device_type", "isa");
}
if ((prop->ppd_flags & PCI_PROP_F_PCIE) != 0 &&
prop->ppd_pcie_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
(char *)"PCIe-PCI bridge");
} else if (prop->ppd_class == PCI_CLASS_MASS &&
prop->ppd_subclass == PCI_MASS_IDE) {
(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
(char *)"IDE controller");
} else {
const char *desc = NULL;
for (int i = 0; i < class_pci_items; i++) {
if (prop->ppd_class == class_pci[i].base_class &&
prop->ppd_subclass == class_pci[i].sub_class &&
prop->ppd_pi == class_pci[i].prog_class) {
desc = class_pci[i].actual_desc;
break;
}
}
if (desc == NULL) {
desc = "Unknown class of pci/pnpbios device";
}
(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip, "model",
(char *)desc);
}
return (PCI_PROP_OK);
}
typedef enum {
PCI_ALIAS_VD_SVSI_R,
PCI_ALIAS_VD_SVSI,
PCI_ALIAS_SVSI_S,
PCI_ALIAS_SVSI,
PCI_ALIAS_VD_R,
PCI_ALIAS_VD_P,
PCI_ALIAS_VD,
PCI_ALIAS_CSPI,
PCI_ALIAS_CS,
PCI_ALIAS_MAX
} pci_alias_t;
#define PCI_MAX_ALIASES (2 * PCI_ALIAS_MAX)
typedef enum {
PCI_ALIAS_F_PCI_ONLY = 1 << 0,
PCI_ALIAS_F_SKIP_BRIDGE = 1 << 1,
PCI_ALIAS_F_COMPAT = 1 << 2,
PCI_ALIAS_F_CHECK_SUBSYS = 1 << 3
} pci_alias_flags_t;
typedef struct {
pci_alias_t pad_type;
pci_alias_flags_t pad_flags;
} pci_alias_data_t;
static const pci_alias_data_t pci_alias_table[] = {
{ PCI_ALIAS_VD_SVSI_R, 0 },
{ PCI_ALIAS_VD_SVSI, 0 },
{ PCI_ALIAS_SVSI_S, PCI_ALIAS_F_PCI_ONLY | PCI_ALIAS_F_CHECK_SUBSYS },
{ PCI_ALIAS_SVSI, PCI_ALIAS_F_PCI_ONLY | PCI_ALIAS_F_SKIP_BRIDGE |
PCI_ALIAS_F_COMPAT | PCI_ALIAS_F_CHECK_SUBSYS },
{ PCI_ALIAS_VD_R, 0 },
{ PCI_ALIAS_VD_P, PCI_ALIAS_F_PCI_ONLY },
{ PCI_ALIAS_VD, 0 },
{ PCI_ALIAS_CSPI, 0 },
{ PCI_ALIAS_CS, 0 },
};
typedef enum {
PCI_PROP_NSM_VID_CLASS,
PCI_PROP_NSM_SUBSYS
} pci_prop_no_subsys_match_t;
typedef boolean_t (*pci_prop_no_subsys_class_f)(const pci_prop_data_t *);
typedef struct pci_prop_no_subsys {
pci_prop_no_subsys_match_t ppnsm_type;
uint16_t ppnsm_vid;
uint16_t ppnsm_did;
uint16_t ppnsm_subvid;
uint16_t ppnsm_subsys;
pci_prop_no_subsys_class_f ppnsm_class;
} pci_prop_no_subsys_t;
static const pci_prop_no_subsys_t pci_prop_no_subsys[] = {
{ .ppnsm_type = PCI_PROP_NSM_VID_CLASS, .ppnsm_vid = 0x10de,
.ppnsm_class = pci_prop_class_is_vga },
{ .ppnsm_type = PCI_PROP_NSM_SUBSYS, .ppnsm_vid = 0x8086,
.ppnsm_did = 0x166, .ppnsm_subvid = 0x8086, .ppnsm_subsys = 0x2044 }
};
static boolean_t
pci_prop_skip_subsys(const pci_prop_data_t *prop)
{
for (size_t i = 0; i < ARRAY_SIZE(pci_prop_no_subsys); i++) {
const pci_prop_no_subsys_t *p = &pci_prop_no_subsys[i];
switch (p->ppnsm_type) {
case PCI_PROP_NSM_VID_CLASS:
if (prop->ppd_vendid == p->ppnsm_vid &&
p->ppnsm_class(prop)) {
return (B_TRUE);
}
break;
case PCI_PROP_NSM_SUBSYS:
if (prop->ppd_vendid == p->ppnsm_vid &&
prop->ppd_devid == p->ppnsm_did &&
prop->ppd_subvid == p->ppnsm_subvid &&
prop->ppd_subsys == p->ppnsm_subsys) {
return (B_TRUE);
}
break;
}
}
return (B_FALSE);
}
static void
pci_prop_alias_pass(const pci_prop_data_t *prop, char **alias, uint_t *nalias,
pci_prd_compat_flags_t compat, boolean_t force_pci)
{
boolean_t is_pci = force_pci ||
(prop->ppd_flags & PCI_PROP_F_PCIE) == 0;
const char *prefix = is_pci ? "pci" : "pciex";
boolean_t subsys_valid = prop->ppd_subvid != 0;
for (size_t i = 0; i < ARRAY_SIZE(pci_alias_table); i++) {
const pci_alias_data_t *a = &pci_alias_table[i];
if ((a->pad_flags & PCI_ALIAS_F_PCI_ONLY) != 0 && !is_pci) {
continue;
}
if ((a->pad_flags & PCI_ALIAS_F_SKIP_BRIDGE) != 0 &&
prop->ppd_header == PCI_HEADER_PPB) {
continue;
}
if ((a->pad_flags & PCI_ALIAS_F_COMPAT) != 0 &&
(compat & PCI_PRD_COMPAT_SUBSYS) == 0) {
continue;
}
if ((a->pad_flags & PCI_ALIAS_F_CHECK_SUBSYS) != 0 &&
pci_prop_skip_subsys(prop)) {
continue;
}
switch (a->pad_type) {
case PCI_ALIAS_VD_SVSI_R:
if (!subsys_valid)
continue;
alias[*nalias] = kmem_asprintf("%s%x,%x.%x.%x.%x",
prefix, prop->ppd_vendid, prop->ppd_devid,
prop->ppd_subvid, prop->ppd_subsys,
prop->ppd_rev);
break;
case PCI_ALIAS_VD_SVSI:
if (!subsys_valid)
continue;
alias[*nalias] = kmem_asprintf("%s%x,%x.%x.%x", prefix,
prop->ppd_vendid, prop->ppd_devid,
prop->ppd_subvid, prop->ppd_subsys);
break;
case PCI_ALIAS_SVSI_S:
if (!subsys_valid)
continue;
alias[*nalias] = kmem_asprintf("%s%x,%x,s", prefix,
prop->ppd_subvid, prop->ppd_subsys);
break;
case PCI_ALIAS_SVSI:
if (!subsys_valid)
continue;
alias[*nalias] = kmem_asprintf("%s%x,%x", prefix,
prop->ppd_subvid, prop->ppd_subsys);
break;
case PCI_ALIAS_VD_R:
alias[*nalias] = kmem_asprintf("%s%x,%x.%x", prefix,
prop->ppd_vendid, prop->ppd_devid, prop->ppd_rev);
break;
case PCI_ALIAS_VD_P:
alias[*nalias] = kmem_asprintf("%s%x,%x,p", prefix,
prop->ppd_vendid, prop->ppd_devid);
break;
case PCI_ALIAS_VD:
alias[*nalias] = kmem_asprintf("%s%x,%x", prefix,
prop->ppd_vendid, prop->ppd_devid);
break;
case PCI_ALIAS_CSPI:
alias[*nalias] = kmem_asprintf("%sclass,%02x%02x%02x",
prefix, prop->ppd_class, prop->ppd_subclass,
prop->ppd_pi);
break;
case PCI_ALIAS_CS:
alias[*nalias] = kmem_asprintf("%sclass,%02x%02x",
prefix, prop->ppd_class, prop->ppd_subclass);
break;
default:
panic("encountered unknown alias type: 0x%x",
a->pad_type);
}
*nalias = *nalias + 1;
ASSERT3U(*nalias, <=, PCI_MAX_ALIASES);
}
}
pci_prop_failure_t
pci_prop_set_compatible(dev_info_t *dip, const pci_prop_data_t *prop)
{
char *alias[PCI_MAX_ALIASES];
uint_t nalias = 0;
pci_prd_compat_flags_t compat = pci_prd_compat_flags();
boolean_t two_sets = (compat & PCI_PRD_COMPAT_PCI_NODE_NAME) != 0;
pci_prop_alias_pass(prop, alias, &nalias, compat, B_FALSE);
if (two_sets && (prop->ppd_flags & PCI_PROP_F_PCIE) != 0) {
pci_prop_alias_pass(prop, alias, &nalias, compat, B_TRUE);
}
(void) ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
alias, nalias);
for (uint_t i = 0; i < nalias; i++) {
strfree(alias[i]);
}
return (PCI_PROP_OK);
}