110942STom.Pothier@Sun.COM /*
210942STom.Pothier@Sun.COM * CDDL HEADER START
310942STom.Pothier@Sun.COM *
410942STom.Pothier@Sun.COM * The contents of this file are subject to the terms of the
510942STom.Pothier@Sun.COM * Common Development and Distribution License (the "License").
610942STom.Pothier@Sun.COM * You may not use this file except in compliance with the License.
710942STom.Pothier@Sun.COM *
810942STom.Pothier@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910942STom.Pothier@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010942STom.Pothier@Sun.COM * See the License for the specific language governing permissions
1110942STom.Pothier@Sun.COM * and limitations under the License.
1210942STom.Pothier@Sun.COM *
1310942STom.Pothier@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410942STom.Pothier@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510942STom.Pothier@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610942STom.Pothier@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710942STom.Pothier@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810942STom.Pothier@Sun.COM *
1910942STom.Pothier@Sun.COM * CDDL HEADER END
2010942STom.Pothier@Sun.COM */
2110942STom.Pothier@Sun.COM
2210942STom.Pothier@Sun.COM /*
2312355SSean.Ye@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410942STom.Pothier@Sun.COM */
2510942STom.Pothier@Sun.COM
2610942STom.Pothier@Sun.COM /*
2710942STom.Pothier@Sun.COM * i86pc Generic hostbridge/pciex/pci enumerator
2810942STom.Pothier@Sun.COM *
2910942STom.Pothier@Sun.COM * hostbridge/pciexrc/pcibus topo nodes are created per SMBIOS type 138
3010942STom.Pothier@Sun.COM * (SUN_OEM_PCIEXRC) records. Each type 138 record can either represent
3110942STom.Pothier@Sun.COM * a hostbridge or a pciexrc/pcibus determined by whether it points to
3210942STom.Pothier@Sun.COM * a baseboard record or another type 138 record.
3310942STom.Pothier@Sun.COM *
3410942STom.Pothier@Sun.COM * x86pi_gen_hbr() is called when a new hostbridge node needs to be created..
3510942STom.Pothier@Sun.COM * It then searches all the type 138 records that connected to it. For each
3610942STom.Pothier@Sun.COM * of the records, bdf is compared to find a matching di_node. If the
3710942STom.Pothier@Sun.COM * di_node is a pciex root port, a pciexrc (bad name!) node will be created.
3810942STom.Pothier@Sun.COM * When pciexrc creation is done, or the di_node is a pcibus, in either
3910942STom.Pothier@Sun.COM * case the pcibus module will loaded to enumerate pciexbus/pcibus etc.
4010942STom.Pothier@Sun.COM *
4110942STom.Pothier@Sun.COM * The enumeration uses did routines heavily, which requires a did hash
4210942STom.Pothier@Sun.COM * pointer stored in x86pi's module-specific area.
4310942STom.Pothier@Sun.COM */
4410942STom.Pothier@Sun.COM
4510942STom.Pothier@Sun.COM #include <sys/types.h>
4610942STom.Pothier@Sun.COM #include <strings.h>
4710942STom.Pothier@Sun.COM #include <fm/topo_mod.h>
4810942STom.Pothier@Sun.COM #include <fm/topo_hc.h>
4910942STom.Pothier@Sun.COM #include <sys/systeminfo.h>
5010942STom.Pothier@Sun.COM #include <sys/smbios_impl.h>
5110942STom.Pothier@Sun.COM #include <sys/fm/protocol.h>
5210942STom.Pothier@Sun.COM #include <x86pi_impl.h>
5310942STom.Pothier@Sun.COM #include <did.h>
5410942STom.Pothier@Sun.COM #include <did_impl.h>
5510942STom.Pothier@Sun.COM #include <did_props.h>
5610942STom.Pothier@Sun.COM #include <hostbridge.h>
5710942STom.Pothier@Sun.COM
5810942STom.Pothier@Sun.COM #define PCI_ENUM "pcibus"
5910942STom.Pothier@Sun.COM #define PCI_ENUMR_VERS 1
6010942STom.Pothier@Sun.COM #define MAX_HB_BUSES 255
6110942STom.Pothier@Sun.COM
6210942STom.Pothier@Sun.COM extern txprop_t RC_common_props[], HB_common_props[], ExHB_common_props[];
6310942STom.Pothier@Sun.COM extern int RC_propcnt, HB_propcnt, ExHB_propcnt;
6410942STom.Pothier@Sun.COM
6510942STom.Pothier@Sun.COM static topo_mod_t *pcimp = NULL;
6610942STom.Pothier@Sun.COM
6710942STom.Pothier@Sun.COM int
x86pi_hbr_enum_init(topo_mod_t * mod)6810942STom.Pothier@Sun.COM x86pi_hbr_enum_init(topo_mod_t *mod)
6910942STom.Pothier@Sun.COM {
7010942STom.Pothier@Sun.COM const char *f = "x86pi_hbr_enum_init";
7110942STom.Pothier@Sun.COM
7212355SSean.Ye@Sun.COM if (did_hash_init(mod) < 0) {
7310942STom.Pothier@Sun.COM topo_mod_dprintf(mod, "%s: did_hash_init() failed.\n", f);
7410942STom.Pothier@Sun.COM return (-1);
7510942STom.Pothier@Sun.COM }
7610942STom.Pothier@Sun.COM
7712355SSean.Ye@Sun.COM if ((pcimp = topo_mod_load(mod, PCI_ENUM, PCI_ENUMR_VERS)) == NULL) {
7810942STom.Pothier@Sun.COM topo_mod_dprintf(mod,
7910942STom.Pothier@Sun.COM "%s: %s enumerator could not load %s.\n",
8010942STom.Pothier@Sun.COM f, HOSTBRIDGE, PCI_ENUM);
8110942STom.Pothier@Sun.COM did_hash_fini(mod);
8210942STom.Pothier@Sun.COM return (-1);
8310942STom.Pothier@Sun.COM }
8410942STom.Pothier@Sun.COM
8510942STom.Pothier@Sun.COM return (0);
8610942STom.Pothier@Sun.COM }
8710942STom.Pothier@Sun.COM
8810942STom.Pothier@Sun.COM void
x86pi_hbr_enum_fini(topo_mod_t * mod)8910942STom.Pothier@Sun.COM x86pi_hbr_enum_fini(topo_mod_t *mod)
9010942STom.Pothier@Sun.COM {
9110942STom.Pothier@Sun.COM did_hash_fini(mod);
9212355SSean.Ye@Sun.COM topo_mod_unload(pcimp);
9312355SSean.Ye@Sun.COM pcimp = NULL;
9410942STom.Pothier@Sun.COM }
9510942STom.Pothier@Sun.COM
9610942STom.Pothier@Sun.COM static int
pciex_process(topo_mod_t * mod,tnode_t * tn_hbr,di_node_t rcn,topo_instance_t rci)9710942STom.Pothier@Sun.COM pciex_process(topo_mod_t *mod, tnode_t *tn_hbr, di_node_t rcn,
9810942STom.Pothier@Sun.COM topo_instance_t rci)
9910942STom.Pothier@Sun.COM {
10010942STom.Pothier@Sun.COM did_t *did;
10110942STom.Pothier@Sun.COM int rv;
10210942STom.Pothier@Sun.COM tnode_t *tn_rc;
10310942STom.Pothier@Sun.COM x86pi_hcfmri_t hcfmri = {0};
10410942STom.Pothier@Sun.COM tnode_t *tn_bb = topo_node_parent(tn_hbr);
10510942STom.Pothier@Sun.COM const char *f = "pciexrc_process";
10610942STom.Pothier@Sun.COM
10710942STom.Pothier@Sun.COM if ((did = did_create(mod, rcn, topo_node_instance(tn_bb),
10810942STom.Pothier@Sun.COM topo_node_instance(tn_hbr), rci, TRUST_BDF)) == NULL)
10910942STom.Pothier@Sun.COM return (NULL);
11010942STom.Pothier@Sun.COM
11110942STom.Pothier@Sun.COM did_markrc(did);
11210942STom.Pothier@Sun.COM
11310942STom.Pothier@Sun.COM /*
11410942STom.Pothier@Sun.COM * Let did set the hostbridge properties excluding FRU and label.
11510942STom.Pothier@Sun.COM */
11610942STom.Pothier@Sun.COM (void) did_props_set(tn_hbr, did, ExHB_common_props, ExHB_propcnt - 2);
11710942STom.Pothier@Sun.COM
11810942STom.Pothier@Sun.COM if (topo_node_range_create(mod, tn_hbr, PCIEX_ROOT, 0,
11910942STom.Pothier@Sun.COM MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) {
12010942STom.Pothier@Sun.COM topo_mod_dprintf(mod,
12110942STom.Pothier@Sun.COM "%s: create child range for %s failed: %s\n",
12210942STom.Pothier@Sun.COM f, PCIEX_ROOT, topo_mod_errmsg(mod));
12310942STom.Pothier@Sun.COM return (-1);
12410942STom.Pothier@Sun.COM }
12510942STom.Pothier@Sun.COM
12610942STom.Pothier@Sun.COM hcfmri.hc_name = PCIEX_ROOT;
12710942STom.Pothier@Sun.COM hcfmri.instance = rci;
12810942STom.Pothier@Sun.COM rv = x86pi_enum_generic(mod, &hcfmri, tn_hbr, tn_hbr, &tn_rc, 0);
12910942STom.Pothier@Sun.COM if (rv != 0) {
13010942STom.Pothier@Sun.COM topo_mod_dprintf(mod, "%s: failed to create %s = %d\n",
13110942STom.Pothier@Sun.COM f, PCIEX_ROOT, rci);
13210942STom.Pothier@Sun.COM return (-1);
13310942STom.Pothier@Sun.COM }
13410942STom.Pothier@Sun.COM
13510942STom.Pothier@Sun.COM /*
13610942STom.Pothier@Sun.COM * pcibus enumerator requires di_node_t be set in node specific
13710942STom.Pothier@Sun.COM */
13810942STom.Pothier@Sun.COM topo_node_setspecific(tn_rc, rcn);
13910942STom.Pothier@Sun.COM
14010942STom.Pothier@Sun.COM /*
14110942STom.Pothier@Sun.COM * Let did set the RC properties excluding FRU, and label.
14210942STom.Pothier@Sun.COM */
14310942STom.Pothier@Sun.COM if (did_props_set(tn_rc, did, RC_common_props, RC_propcnt - 2) < 0) {
14410942STom.Pothier@Sun.COM topo_mod_dprintf(mod, "%s: did_props_set failed for %s = %d\n",
14510942STom.Pothier@Sun.COM f, PCIEX_ROOT, rci);
14610942STom.Pothier@Sun.COM topo_node_unbind(tn_rc);
14710942STom.Pothier@Sun.COM return (-1);
14810942STom.Pothier@Sun.COM }
14910942STom.Pothier@Sun.COM
15010942STom.Pothier@Sun.COM if (topo_node_range_create(mod, tn_rc, PCIEX_BUS, 0,
15110942STom.Pothier@Sun.COM MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) {
15210942STom.Pothier@Sun.COM topo_mod_dprintf(mod,
15310942STom.Pothier@Sun.COM "%s: create child range for %s failed: %s\n",
15410942STom.Pothier@Sun.COM f, PCIEX_BUS, topo_mod_errmsg(mod));
15510942STom.Pothier@Sun.COM return (-1);
15610942STom.Pothier@Sun.COM }
15710942STom.Pothier@Sun.COM
15810942STom.Pothier@Sun.COM return (topo_mod_enumerate(mod, tn_rc, PCI_BUS, PCIEX_BUS,
15910942STom.Pothier@Sun.COM 0, MAX_HB_BUSES, did));
16010942STom.Pothier@Sun.COM }
16110942STom.Pothier@Sun.COM
16210942STom.Pothier@Sun.COM static int
pci_process(topo_mod_t * mod,tnode_t * tn_hbr,di_node_t bn)16310942STom.Pothier@Sun.COM pci_process(topo_mod_t *mod, tnode_t *tn_hbr, di_node_t bn)
16410942STom.Pothier@Sun.COM {
16510942STom.Pothier@Sun.COM did_t *did;
16610942STom.Pothier@Sun.COM tnode_t *tn_bb = topo_node_parent(tn_hbr);
16710942STom.Pothier@Sun.COM
16810942STom.Pothier@Sun.COM if ((did = did_create(mod, bn, topo_node_instance(tn_bb),
16910942STom.Pothier@Sun.COM topo_node_instance(tn_hbr), NO_RC, TRUST_BDF)) == NULL)
17010942STom.Pothier@Sun.COM return (-1);
17110942STom.Pothier@Sun.COM
17210942STom.Pothier@Sun.COM /*
17310942STom.Pothier@Sun.COM * Let did set the hostbridge properties excluding FRU and label.
17410942STom.Pothier@Sun.COM */
17510942STom.Pothier@Sun.COM (void) did_props_set(tn_hbr, did, HB_common_props, HB_propcnt - 2);
17610942STom.Pothier@Sun.COM
17710942STom.Pothier@Sun.COM if (topo_node_range_create(mod, tn_hbr, PCI_BUS, 0,
17810942STom.Pothier@Sun.COM MAX_HB_BUSES) != 0 && topo_mod_errno(mod) != EMOD_NODE_DUP) {
17910942STom.Pothier@Sun.COM topo_mod_dprintf(mod, "create child range for %s failed: %s\n",
18010942STom.Pothier@Sun.COM PCI_BUS, topo_mod_errmsg(mod));
18110942STom.Pothier@Sun.COM return (-1);
18210942STom.Pothier@Sun.COM }
18310942STom.Pothier@Sun.COM
18410942STom.Pothier@Sun.COM return (topo_mod_enumerate(mod, tn_hbr, PCI_BUS, PCI_BUS,
18510942STom.Pothier@Sun.COM 0, MAX_HB_BUSES, did));
18610942STom.Pothier@Sun.COM }
18710942STom.Pothier@Sun.COM
18810942STom.Pothier@Sun.COM static int
x86pi_gen_pci_pciexrc(topo_mod_t * mod,tnode_t * tn_hbr,uint16_t bdf,topo_instance_t * rcip)18910942STom.Pothier@Sun.COM x86pi_gen_pci_pciexrc(topo_mod_t *mod, tnode_t *tn_hbr, uint16_t bdf,
19010942STom.Pothier@Sun.COM topo_instance_t *rcip)
19110942STom.Pothier@Sun.COM {
19210942STom.Pothier@Sun.COM di_node_t devtree, pnode, cnode;
19310942STom.Pothier@Sun.COM
19410942STom.Pothier@Sun.COM topo_mod_dprintf(mod, "creating pci/pciexrc node bdf = %#x\n",
19510942STom.Pothier@Sun.COM (int)bdf);
19610942STom.Pothier@Sun.COM
19710942STom.Pothier@Sun.COM devtree = topo_mod_devinfo(mod);
19810942STom.Pothier@Sun.COM if (devtree == DI_NODE_NIL) {
19910942STom.Pothier@Sun.COM topo_mod_dprintf(mod, "devinfo init failed.\n");
20010942STom.Pothier@Sun.COM return (-1);
20110942STom.Pothier@Sun.COM }
20210942STom.Pothier@Sun.COM
20310942STom.Pothier@Sun.COM for (pnode = di_drv_first_node(PCI, devtree);
20410942STom.Pothier@Sun.COM pnode != DI_NODE_NIL; pnode = di_drv_next_node(pnode))
20510942STom.Pothier@Sun.COM if (x86pi_bdf(mod, pnode) == bdf)
20610942STom.Pothier@Sun.COM return (pci_process(mod, tn_hbr, pnode));
20710942STom.Pothier@Sun.COM
20810942STom.Pothier@Sun.COM pnode = di_drv_first_node(NPE, devtree);
20910942STom.Pothier@Sun.COM while (pnode != DI_NODE_NIL) {
21010942STom.Pothier@Sun.COM for (cnode = di_child_node(pnode); cnode != DI_NODE_NIL;
21110942STom.Pothier@Sun.COM cnode = di_sibling_node(cnode)) {
21210942STom.Pothier@Sun.COM if (di_driver_name(cnode) == NULL ||
21310942STom.Pothier@Sun.COM x86pi_bdf(mod, cnode) != bdf)
21410942STom.Pothier@Sun.COM continue;
21510942STom.Pothier@Sun.COM
21610942STom.Pothier@Sun.COM if (strcmp(di_driver_name(cnode), PCI_PCI) == 0)
21710942STom.Pothier@Sun.COM return (pci_process(mod, tn_hbr, cnode));
21810942STom.Pothier@Sun.COM
21910942STom.Pothier@Sun.COM if (strcmp(di_driver_name(cnode), PCIEB) == 0)
22010942STom.Pothier@Sun.COM return (pciex_process(mod, tn_hbr,
22110942STom.Pothier@Sun.COM cnode, (*rcip)++));
22210942STom.Pothier@Sun.COM
22310942STom.Pothier@Sun.COM topo_mod_dprintf(mod, "no matching driver found: "
22410942STom.Pothier@Sun.COM "bdf = %#x\n", (int)bdf);
22510942STom.Pothier@Sun.COM }
22610942STom.Pothier@Sun.COM pnode = di_drv_next_node(pnode);
22710942STom.Pothier@Sun.COM }
22810942STom.Pothier@Sun.COM
22910942STom.Pothier@Sun.COM topo_mod_dprintf(mod, "no matching bdf found: bdf = %#x\n", (int)bdf);
23010942STom.Pothier@Sun.COM
23110942STom.Pothier@Sun.COM return (0);
23210942STom.Pothier@Sun.COM }
23310942STom.Pothier@Sun.COM
23410942STom.Pothier@Sun.COM int
x86pi_gen_hbr(topo_mod_t * mod,tnode_t * tn_bb,int hbr_smbid,topo_instance_t hbri,topo_instance_t * rcip)235*12832STrang.Do@Sun.COM x86pi_gen_hbr(topo_mod_t *mod, tnode_t *tn_bb,
23610942STom.Pothier@Sun.COM int hbr_smbid, topo_instance_t hbri, topo_instance_t *rcip)
23710942STom.Pothier@Sun.COM {
23810942STom.Pothier@Sun.COM x86pi_hcfmri_t hcfmri = {0};
23910942STom.Pothier@Sun.COM tnode_t *tn_hbr;
24010942STom.Pothier@Sun.COM smbs_cnt_t *smbc = &stypes[SUN_OEM_PCIEXRC];
24110942STom.Pothier@Sun.COM smbios_pciexrc_t smb_rc;
24210942STom.Pothier@Sun.COM int i, rv, err = 0;
24310942STom.Pothier@Sun.COM const char *f = "x86pi_gen_hbr";
244*12832STrang.Do@Sun.COM smbios_hdl_t *shp;
245*12832STrang.Do@Sun.COM
246*12832STrang.Do@Sun.COM shp = topo_mod_smbios(mod);
247*12832STrang.Do@Sun.COM if (shp == NULL)
248*12832STrang.Do@Sun.COM return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
24910942STom.Pothier@Sun.COM
25010942STom.Pothier@Sun.COM hcfmri.hc_name = HOSTBRIDGE;
25110942STom.Pothier@Sun.COM hcfmri.instance = hbri;
25210942STom.Pothier@Sun.COM
25310942STom.Pothier@Sun.COM /* create and bind the "hostbridge" node */
25410942STom.Pothier@Sun.COM rv = x86pi_enum_generic(mod, &hcfmri, tn_bb, tn_bb, &tn_hbr, 0);
25510942STom.Pothier@Sun.COM if (rv != 0) {
25610942STom.Pothier@Sun.COM topo_mod_dprintf(mod, "%s: failed to create %s = %d\n",
25710942STom.Pothier@Sun.COM f, HOSTBRIDGE, hbri);
25810942STom.Pothier@Sun.COM return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
25910942STom.Pothier@Sun.COM }
26010942STom.Pothier@Sun.COM
26110942STom.Pothier@Sun.COM /*
26210942STom.Pothier@Sun.COM * Walk the smbios records and create the pci/pciexrc nodes
26310942STom.Pothier@Sun.COM */
26410942STom.Pothier@Sun.COM for (i = 0; i < smbc->count; i++) {
26510942STom.Pothier@Sun.COM if (smbios_info_pciexrc(shp, smbc->ids[i].id, &smb_rc) != 0)
26610942STom.Pothier@Sun.COM topo_mod_dprintf(mod,
26710942STom.Pothier@Sun.COM "%s: failed: id = %d\n", f, (int)smbc->ids[i].id);
26810942STom.Pothier@Sun.COM else if (smb_rc.smbpcie_bb == hbr_smbid &&
26910942STom.Pothier@Sun.COM x86pi_gen_pci_pciexrc(mod, tn_hbr, smb_rc.smbpcie_bdf,
27010942STom.Pothier@Sun.COM rcip) != 0)
27110942STom.Pothier@Sun.COM err++;
27210942STom.Pothier@Sun.COM }
27310942STom.Pothier@Sun.COM
27410942STom.Pothier@Sun.COM return (err == 0 ? 0 : topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
27510942STom.Pothier@Sun.COM }
276