1*fc256490SJason Beloro /* 2*fc256490SJason Beloro * CDDL HEADER START 3*fc256490SJason Beloro * 4*fc256490SJason Beloro * The contents of this file are subject to the terms of the 5*fc256490SJason Beloro * Common Development and Distribution License (the "License"). 6*fc256490SJason Beloro * You may not use this file except in compliance with the License. 7*fc256490SJason Beloro * 8*fc256490SJason Beloro * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*fc256490SJason Beloro * or http://www.opensolaris.org/os/licensing. 10*fc256490SJason Beloro * See the License for the specific language governing permissions 11*fc256490SJason Beloro * and limitations under the License. 12*fc256490SJason Beloro * 13*fc256490SJason Beloro * When distributing Covered Code, include this CDDL HEADER in each 14*fc256490SJason Beloro * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*fc256490SJason Beloro * If applicable, add the following below this CDDL HEADER, with the 16*fc256490SJason Beloro * fields enclosed by brackets "[]" replaced with your own identifying 17*fc256490SJason Beloro * information: Portions Copyright [yyyy] [name of copyright owner] 18*fc256490SJason Beloro * 19*fc256490SJason Beloro * CDDL HEADER END 20*fc256490SJason Beloro */ 21*fc256490SJason Beloro /* 22*fc256490SJason Beloro * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23*fc256490SJason Beloro * Use is subject to license terms. 24*fc256490SJason Beloro */ 25*fc256490SJason Beloro 26*fc256490SJason Beloro #include <sys/types.h> 27*fc256490SJason Beloro #include <sys/ddi.h> 28*fc256490SJason Beloro #include <sys/dditypes.h> 29*fc256490SJason Beloro #include <sys/ddifm.h> 30*fc256490SJason Beloro #include <sys/sunndi.h> 31*fc256490SJason Beloro #include <sys/devops.h> 32*fc256490SJason Beloro #include <sys/pcie.h> 33*fc256490SJason Beloro #include <sys/pci_cap.h> 34*fc256490SJason Beloro #include <sys/pcie_impl.h> 35*fc256490SJason Beloro #include <sys/pathname.h> 36*fc256490SJason Beloro 37*fc256490SJason Beloro /* 38*fc256490SJason Beloro * The below 2 global variables are for PCIe IOV Error Handling. They must only 39*fc256490SJason Beloro * be accessed during error handling under the protection of a error mutex. 40*fc256490SJason Beloro */ 41*fc256490SJason Beloro static pcie_domains_t *pcie_faulty_domains = NULL; 42*fc256490SJason Beloro static boolean_t pcie_faulty_all = B_FALSE; 43*fc256490SJason Beloro 44*fc256490SJason Beloro static void pcie_domain_list_destroy(pcie_domains_t *domain_ids); 45*fc256490SJason Beloro static void pcie_bdf_list_add(pcie_req_id_t bdf, 46*fc256490SJason Beloro pcie_req_id_list_t **rlist_p); 47*fc256490SJason Beloro static void pcie_bdf_list_remove(pcie_req_id_t bdf, 48*fc256490SJason Beloro pcie_req_id_list_t **rlist_p); 49*fc256490SJason Beloro static void pcie_cache_domain_info(pcie_bus_t *bus_p); 50*fc256490SJason Beloro static void pcie_uncache_domain_info(pcie_bus_t *bus_p); 51*fc256490SJason Beloro 52*fc256490SJason Beloro static void pcie_faulty_list_clear(); 53*fc256490SJason Beloro static void pcie_faulty_list_update(pcie_domains_t *pd, 54*fc256490SJason Beloro pcie_domains_t **headp); 55*fc256490SJason Beloro 56*fc256490SJason Beloro dev_info_t * 57*fc256490SJason Beloro pcie_find_dip_by_bdf(dev_info_t *rootp, pcie_req_id_t bdf) 58*fc256490SJason Beloro { 59*fc256490SJason Beloro dev_info_t *dip; 60*fc256490SJason Beloro pcie_bus_t *bus_p; 61*fc256490SJason Beloro int bus_num; 62*fc256490SJason Beloro 63*fc256490SJason Beloro dip = ddi_get_child(rootp); 64*fc256490SJason Beloro while (dip) { 65*fc256490SJason Beloro bus_p = PCIE_DIP2BUS(dip); 66*fc256490SJason Beloro if (bus_p && (bus_p->bus_bdf == bdf)) 67*fc256490SJason Beloro return (dip); 68*fc256490SJason Beloro if (bus_p) { 69*fc256490SJason Beloro bus_num = (bdf >> 8) & 0xff; 70*fc256490SJason Beloro if ((bus_num >= bus_p->bus_bus_range.lo && 71*fc256490SJason Beloro bus_num <= bus_p->bus_bus_range.hi) || 72*fc256490SJason Beloro bus_p->bus_bus_range.hi == 0) 73*fc256490SJason Beloro return (pcie_find_dip_by_bdf(dip, bdf)); 74*fc256490SJason Beloro } 75*fc256490SJason Beloro dip = ddi_get_next_sibling(dip); 76*fc256490SJason Beloro } 77*fc256490SJason Beloro return (NULL); 78*fc256490SJason Beloro } 79*fc256490SJason Beloro 80*fc256490SJason Beloro /* 81*fc256490SJason Beloro * Add a device bdf to the bdf list. 82*fc256490SJason Beloro */ 83*fc256490SJason Beloro static void 84*fc256490SJason Beloro pcie_bdf_list_add(pcie_req_id_t bdf, pcie_req_id_list_t **rlist_p) 85*fc256490SJason Beloro { 86*fc256490SJason Beloro pcie_req_id_list_t *rl = PCIE_ZALLOC(pcie_req_id_list_t); 87*fc256490SJason Beloro 88*fc256490SJason Beloro rl->bdf = bdf; 89*fc256490SJason Beloro rl->next = *rlist_p; 90*fc256490SJason Beloro *rlist_p = rl; 91*fc256490SJason Beloro } 92*fc256490SJason Beloro 93*fc256490SJason Beloro /* 94*fc256490SJason Beloro * Remove a bdf from the bdf list. 95*fc256490SJason Beloro */ 96*fc256490SJason Beloro static void 97*fc256490SJason Beloro pcie_bdf_list_remove(pcie_req_id_t bdf, pcie_req_id_list_t **rlist_p) 98*fc256490SJason Beloro { 99*fc256490SJason Beloro pcie_req_id_list_t *rl_pre, *rl_next; 100*fc256490SJason Beloro 101*fc256490SJason Beloro rl_pre = *rlist_p; 102*fc256490SJason Beloro if (rl_pre->bdf == bdf) { 103*fc256490SJason Beloro *rlist_p = rl_pre->next; 104*fc256490SJason Beloro kmem_free(rl_pre, sizeof (pcie_req_id_list_t)); 105*fc256490SJason Beloro return; 106*fc256490SJason Beloro } 107*fc256490SJason Beloro 108*fc256490SJason Beloro while (rl_pre->next) { 109*fc256490SJason Beloro rl_next = rl_pre->next; 110*fc256490SJason Beloro if (rl_next->bdf == bdf) { 111*fc256490SJason Beloro rl_pre->next = rl_next->next; 112*fc256490SJason Beloro kmem_free(rl_next, sizeof (pcie_req_id_list_t)); 113*fc256490SJason Beloro break; 114*fc256490SJason Beloro } else 115*fc256490SJason Beloro rl_pre = rl_next; 116*fc256490SJason Beloro } 117*fc256490SJason Beloro } 118*fc256490SJason Beloro 119*fc256490SJason Beloro /* 120*fc256490SJason Beloro * Cache IOV domain info in all it's parent's pcie_domain_t 121*fc256490SJason Beloro * 122*fc256490SJason Beloro * The leaf devices's domain info must be set before calling this function. 123*fc256490SJason Beloro */ 124*fc256490SJason Beloro void 125*fc256490SJason Beloro pcie_cache_domain_info(pcie_bus_t *bus_p) 126*fc256490SJason Beloro { 127*fc256490SJason Beloro boolean_t assigned = PCIE_IS_ASSIGNED(bus_p); 128*fc256490SJason Beloro boolean_t fma_dom = PCIE_ASSIGNED_TO_FMA_DOM(bus_p); 129*fc256490SJason Beloro uint_t domain_id = PCIE_DOMAIN_ID_GET(bus_p); 130*fc256490SJason Beloro pcie_req_id_t bdf = bus_p->bus_bdf; 131*fc256490SJason Beloro dev_info_t *pdip; 132*fc256490SJason Beloro pcie_bus_t *pbus_p; 133*fc256490SJason Beloro pcie_domain_t *pdom_p; 134*fc256490SJason Beloro 135*fc256490SJason Beloro ASSERT(!PCIE_IS_BDG(bus_p)); 136*fc256490SJason Beloro 137*fc256490SJason Beloro for (pdip = ddi_get_parent(PCIE_BUS2DIP(bus_p)); PCIE_DIP2BUS(pdip); 138*fc256490SJason Beloro pdip = ddi_get_parent(pdip)) { 139*fc256490SJason Beloro pbus_p = PCIE_DIP2BUS(pdip); 140*fc256490SJason Beloro pdom_p = PCIE_BUS2DOM(pbus_p); 141*fc256490SJason Beloro 142*fc256490SJason Beloro if (assigned) { 143*fc256490SJason Beloro if (domain_id) 144*fc256490SJason Beloro PCIE_DOMAIN_LIST_ADD(pbus_p, domain_id); 145*fc256490SJason Beloro 146*fc256490SJason Beloro if (fma_dom) 147*fc256490SJason Beloro pdom_p->fmadom_count++; 148*fc256490SJason Beloro else { 149*fc256490SJason Beloro PCIE_BDF_LIST_ADD(pbus_p, bdf); 150*fc256490SJason Beloro pdom_p->nfmadom_count++; 151*fc256490SJason Beloro } 152*fc256490SJason Beloro } else 153*fc256490SJason Beloro pdom_p->rootdom_count++; 154*fc256490SJason Beloro } 155*fc256490SJason Beloro } 156*fc256490SJason Beloro 157*fc256490SJason Beloro /* 158*fc256490SJason Beloro * Clear the leaf device's domain info and uncache IOV domain info in all it's 159*fc256490SJason Beloro * parent's pcie_domain_t 160*fc256490SJason Beloro * 161*fc256490SJason Beloro * The leaf devices's domain info is also cleared by calling this function. 162*fc256490SJason Beloro */ 163*fc256490SJason Beloro void 164*fc256490SJason Beloro pcie_uncache_domain_info(pcie_bus_t *bus_p) 165*fc256490SJason Beloro { 166*fc256490SJason Beloro boolean_t assigned = PCIE_IS_ASSIGNED(bus_p); 167*fc256490SJason Beloro boolean_t fma_dom = PCIE_ASSIGNED_TO_FMA_DOM(bus_p); 168*fc256490SJason Beloro uint_t domain_id = PCIE_DOMAIN_ID_GET(bus_p); 169*fc256490SJason Beloro pcie_domain_t *dom_p = PCIE_BUS2DOM(bus_p), *pdom_p; 170*fc256490SJason Beloro pcie_bus_t *pbus_p; 171*fc256490SJason Beloro dev_info_t *pdip; 172*fc256490SJason Beloro 173*fc256490SJason Beloro ASSERT(!PCIE_IS_BDG(bus_p)); 174*fc256490SJason Beloro ASSERT((dom_p->fmadom_count + dom_p->nfmadom_count + 175*fc256490SJason Beloro dom_p->rootdom_count) == 1); 176*fc256490SJason Beloro 177*fc256490SJason Beloro /* Clear the domain information */ 178*fc256490SJason Beloro if (domain_id) { 179*fc256490SJason Beloro PCIE_DOMAIN_ID_SET(bus_p, NULL); 180*fc256490SJason Beloro PCIE_DOMAIN_ID_DECR_REF_COUNT(bus_p); 181*fc256490SJason Beloro } 182*fc256490SJason Beloro 183*fc256490SJason Beloro dom_p->fmadom_count = 0; 184*fc256490SJason Beloro dom_p->nfmadom_count = 0; 185*fc256490SJason Beloro dom_p->rootdom_count = 0; 186*fc256490SJason Beloro 187*fc256490SJason Beloro for (pdip = ddi_get_parent(PCIE_BUS2DIP(bus_p)); PCIE_DIP2BUS(pdip); 188*fc256490SJason Beloro pdip = ddi_get_parent(pdip)) { 189*fc256490SJason Beloro pbus_p = PCIE_DIP2BUS(pdip); 190*fc256490SJason Beloro pdom_p = PCIE_BUS2DOM(pbus_p); 191*fc256490SJason Beloro 192*fc256490SJason Beloro if (assigned) { 193*fc256490SJason Beloro if (domain_id) 194*fc256490SJason Beloro PCIE_DOMAIN_LIST_REMOVE(pbus_p, domain_id); 195*fc256490SJason Beloro 196*fc256490SJason Beloro if (fma_dom) 197*fc256490SJason Beloro pdom_p->fmadom_count--; 198*fc256490SJason Beloro else { 199*fc256490SJason Beloro pdom_p->nfmadom_count--; 200*fc256490SJason Beloro PCIE_BDF_LIST_REMOVE(pbus_p, bus_p->bus_bdf); 201*fc256490SJason Beloro } 202*fc256490SJason Beloro } else 203*fc256490SJason Beloro pdom_p->rootdom_count--; 204*fc256490SJason Beloro } 205*fc256490SJason Beloro } 206*fc256490SJason Beloro 207*fc256490SJason Beloro 208*fc256490SJason Beloro /* 209*fc256490SJason Beloro * Initialize private data structure for IOV environments. 210*fc256490SJason Beloro * o Allocate memory for iov data 211*fc256490SJason Beloro * o Cache Domain ids. 212*fc256490SJason Beloro */ 213*fc256490SJason Beloro void 214*fc256490SJason Beloro pcie_init_dom(dev_info_t *dip) 215*fc256490SJason Beloro { 216*fc256490SJason Beloro pcie_domain_t *dom_p = PCIE_ZALLOC(pcie_domain_t); 217*fc256490SJason Beloro pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 218*fc256490SJason Beloro 219*fc256490SJason Beloro PCIE_BUS2DOM(bus_p) = dom_p; 220*fc256490SJason Beloro 221*fc256490SJason Beloro /* Only leaf devices are assignable to IO Domains */ 222*fc256490SJason Beloro if (PCIE_IS_BDG(bus_p)) 223*fc256490SJason Beloro return; 224*fc256490SJason Beloro 225*fc256490SJason Beloro /* 226*fc256490SJason Beloro * At the time of init_dom in the root domain a device may or may not 227*fc256490SJason Beloro * have been assigned to an IO Domain. 228*fc256490SJason Beloro * 229*fc256490SJason Beloro * LDOMS: the property "ddi-assigned" will be set for devices that is 230*fc256490SJason Beloro * assignable to an IO domain and unusable in the root domain. If the 231*fc256490SJason Beloro * property exist assume it has been assigned to a non-fma domain until 232*fc256490SJason Beloro * otherwise notified. The domain id is unknown on LDOMS. 233*fc256490SJason Beloro * 234*fc256490SJason Beloro * Xen: the "ddi-assigned" property won't be set until Xen store calls 235*fc256490SJason Beloro * pcie_loan_device is called. In this function this will always look 236*fc256490SJason Beloro * like the device is assigned to the root domain. Domain ID caching 237*fc256490SJason Beloro * will occur in pcie_loan_device function. 238*fc256490SJason Beloro */ 239*fc256490SJason Beloro if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 240*fc256490SJason Beloro "ddi-assigned", -1) != -1) { 241*fc256490SJason Beloro dom_p->nfmadom_count = 1; 242*fc256490SJason Beloro 243*fc256490SJason Beloro /* Prevent "assigned" device from detaching */ 244*fc256490SJason Beloro ndi_hold_devi(dip); 245*fc256490SJason Beloro } else 246*fc256490SJason Beloro dom_p->rootdom_count = 1; 247*fc256490SJason Beloro (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "ddi-assigned"); 248*fc256490SJason Beloro 249*fc256490SJason Beloro pcie_cache_domain_info(bus_p); 250*fc256490SJason Beloro } 251*fc256490SJason Beloro 252*fc256490SJason Beloro void 253*fc256490SJason Beloro pcie_fini_dom(dev_info_t *dip) 254*fc256490SJason Beloro { 255*fc256490SJason Beloro pcie_domain_t *dom_p = PCIE_DIP2DOM(dip); 256*fc256490SJason Beloro pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 257*fc256490SJason Beloro 258*fc256490SJason Beloro if (PCIE_IS_BDG(bus_p)) 259*fc256490SJason Beloro pcie_domain_list_destroy(PCIE_DOMAIN_LIST_GET(bus_p)); 260*fc256490SJason Beloro else 261*fc256490SJason Beloro pcie_uncache_domain_info(bus_p); 262*fc256490SJason Beloro 263*fc256490SJason Beloro kmem_free(dom_p, sizeof (pcie_domain_t)); 264*fc256490SJason Beloro } 265*fc256490SJason Beloro 266*fc256490SJason Beloro /* 267*fc256490SJason Beloro * PCIe Severity: 268*fc256490SJason Beloro * 269*fc256490SJason Beloro * PF_ERR_NO_ERROR : no IOV Action 270*fc256490SJason Beloro * PF_ERR_CE : no IOV Action 271*fc256490SJason Beloro * PF_ERR_NO_PANIC : contains error telemetry, log domain info 272*fc256490SJason Beloro * PF_ERR_MATCHED_DEVICE: contains error telemetry, log domain info 273*fc256490SJason Beloro * PF_ERR_MATCHED_RC : Error already taken care of, no further IOV Action 274*fc256490SJason Beloro * PF_ERR_MATCHED_PARENT: Error already taken care of, no further IOV Action 275*fc256490SJason Beloro * PF_ERR_PANIC : contains error telemetry, log domain info 276*fc256490SJason Beloro * 277*fc256490SJason Beloro * For NO_PANIC, MATCHED_DEVICE and PANIC, IOV wants to look at the affected 278*fc256490SJason Beloro * devices and find the domains involved. 279*fc256490SJason Beloro * 280*fc256490SJason Beloro * If root domain does not own an affected device, IOV EH should change 281*fc256490SJason Beloro * PF_ERR_PANIC to PF_ERR_MATCH_DOM. 282*fc256490SJason Beloro */ 283*fc256490SJason Beloro int 284*fc256490SJason Beloro pciev_eh(pf_data_t *pfd_p, pf_impl_t *impl) 285*fc256490SJason Beloro { 286*fc256490SJason Beloro int severity = pfd_p->pe_severity_flags; 287*fc256490SJason Beloro int iov_severity = severity; 288*fc256490SJason Beloro pcie_bus_t *a_bus_p; /* Affected device's pcie_bus_t */ 289*fc256490SJason Beloro pf_data_t *root_pfd_p = impl->pf_dq_head_p; 290*fc256490SJason Beloro pcie_bus_t *root_bus_p; 291*fc256490SJason Beloro 292*fc256490SJason Beloro /* 293*fc256490SJason Beloro * check if all devices under the root device are unassigned. 294*fc256490SJason Beloro * this function should quickly return in non-IOV environment. 295*fc256490SJason Beloro */ 296*fc256490SJason Beloro ASSERT(root_pfd_p != NULL); 297*fc256490SJason Beloro root_bus_p = PCIE_PFD2BUS(root_pfd_p); 298*fc256490SJason Beloro if (PCIE_BDG_IS_UNASSIGNED(root_bus_p)) 299*fc256490SJason Beloro return (severity); 300*fc256490SJason Beloro 301*fc256490SJason Beloro if (severity & PF_ERR_PANIC_DEADLOCK) { 302*fc256490SJason Beloro pcie_faulty_all = B_TRUE; 303*fc256490SJason Beloro 304*fc256490SJason Beloro } else if (severity & (PF_ERR_NO_PANIC | PF_ERR_MATCHED_DEVICE | 305*fc256490SJason Beloro PF_ERR_PANIC | PF_ERR_PANIC_BAD_RESPONSE)) { 306*fc256490SJason Beloro 307*fc256490SJason Beloro uint16_t affected_flag, dev_affected_flags; 308*fc256490SJason Beloro uint_t is_panic = 0, is_aff_dev_found = 0; 309*fc256490SJason Beloro 310*fc256490SJason Beloro dev_affected_flags = PFD_AFFECTED_DEV(pfd_p)->pe_affected_flags; 311*fc256490SJason Beloro /* adjust affected flags to leverage cached domain ids */ 312*fc256490SJason Beloro if (dev_affected_flags & PF_AFFECTED_CHILDREN) { 313*fc256490SJason Beloro dev_affected_flags |= PF_AFFECTED_SELF; 314*fc256490SJason Beloro dev_affected_flags &= ~PF_AFFECTED_CHILDREN; 315*fc256490SJason Beloro } 316*fc256490SJason Beloro 317*fc256490SJason Beloro for (affected_flag = 1; 318*fc256490SJason Beloro affected_flag <= PF_MAX_AFFECTED_FLAG; 319*fc256490SJason Beloro affected_flag <<= 1) { 320*fc256490SJason Beloro a_bus_p = pciev_get_affected_dev(impl, pfd_p, 321*fc256490SJason Beloro affected_flag, dev_affected_flags); 322*fc256490SJason Beloro 323*fc256490SJason Beloro if (a_bus_p == NULL) 324*fc256490SJason Beloro continue; 325*fc256490SJason Beloro 326*fc256490SJason Beloro is_aff_dev_found++; 327*fc256490SJason Beloro PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = 328*fc256490SJason Beloro a_bus_p->bus_bdf; 329*fc256490SJason Beloro 330*fc256490SJason Beloro /* 331*fc256490SJason Beloro * If a leaf device is assigned to the root domain or if 332*fc256490SJason Beloro * a bridge has children assigned to a root domain 333*fc256490SJason Beloro * panic. 334*fc256490SJason Beloro * 335*fc256490SJason Beloro * If a leaf device or a child of a bridge is assigned 336*fc256490SJason Beloro * to NFMA domain mark it for panic. If assigned to FMA 337*fc256490SJason Beloro * domain save the domain id. 338*fc256490SJason Beloro */ 339*fc256490SJason Beloro if (!PCIE_IS_BDG(a_bus_p) && 340*fc256490SJason Beloro !PCIE_IS_ASSIGNED(a_bus_p)) { 341*fc256490SJason Beloro if (severity & PF_ERR_FATAL_FLAGS) 342*fc256490SJason Beloro is_panic++; 343*fc256490SJason Beloro continue; 344*fc256490SJason Beloro } 345*fc256490SJason Beloro 346*fc256490SJason Beloro if (PCIE_BDG_HAS_CHILDREN_ROOT_DOM(a_bus_p)) { 347*fc256490SJason Beloro if (severity & PF_ERR_FATAL_FLAGS) 348*fc256490SJason Beloro is_panic++; 349*fc256490SJason Beloro } 350*fc256490SJason Beloro 351*fc256490SJason Beloro if ((PCIE_ASSIGNED_TO_NFMA_DOM(a_bus_p) || 352*fc256490SJason Beloro PCIE_BDG_HAS_CHILDREN_NFMA_DOM(a_bus_p)) && 353*fc256490SJason Beloro (severity & PF_ERR_FATAL_FLAGS)) { 354*fc256490SJason Beloro PCIE_BUS2DOM(a_bus_p)->nfma_panic = B_TRUE; 355*fc256490SJason Beloro iov_severity |= PF_ERR_MATCH_DOM; 356*fc256490SJason Beloro } 357*fc256490SJason Beloro 358*fc256490SJason Beloro if (PCIE_ASSIGNED_TO_FMA_DOM(a_bus_p)) { 359*fc256490SJason Beloro pcie_save_domain_id( 360*fc256490SJason Beloro &PCIE_BUS2DOM(a_bus_p)->domain.id); 361*fc256490SJason Beloro iov_severity |= PF_ERR_MATCH_DOM; 362*fc256490SJason Beloro } 363*fc256490SJason Beloro 364*fc256490SJason Beloro if (PCIE_BDG_HAS_CHILDREN_FMA_DOM(a_bus_p)) { 365*fc256490SJason Beloro pcie_save_domain_id( 366*fc256490SJason Beloro PCIE_DOMAIN_LIST_GET(a_bus_p)); 367*fc256490SJason Beloro iov_severity |= PF_ERR_MATCH_DOM; 368*fc256490SJason Beloro } 369*fc256490SJason Beloro } 370*fc256490SJason Beloro 371*fc256490SJason Beloro /* 372*fc256490SJason Beloro * Overwrite the severity only if affected device can be 373*fc256490SJason Beloro * identified and root domain does not need to panic. 374*fc256490SJason Beloro */ 375*fc256490SJason Beloro if ((!is_panic) && is_aff_dev_found) { 376*fc256490SJason Beloro iov_severity &= ~PF_ERR_FATAL_FLAGS; 377*fc256490SJason Beloro } 378*fc256490SJason Beloro } 379*fc256490SJason Beloro 380*fc256490SJason Beloro return (iov_severity); 381*fc256490SJason Beloro } 382*fc256490SJason Beloro 383*fc256490SJason Beloro /* ARGSUSED */ 384*fc256490SJason Beloro void 385*fc256490SJason Beloro pciev_eh_exit(pf_data_t *root_pfd_p, uint_t intr_type) 386*fc256490SJason Beloro { 387*fc256490SJason Beloro pcie_bus_t *root_bus_p; 388*fc256490SJason Beloro 389*fc256490SJason Beloro /* 390*fc256490SJason Beloro * check if all devices under the root device are unassigned. 391*fc256490SJason Beloro * this function should quickly return in non-IOV environment. 392*fc256490SJason Beloro */ 393*fc256490SJason Beloro root_bus_p = PCIE_PFD2BUS(root_pfd_p); 394*fc256490SJason Beloro if (PCIE_BDG_IS_UNASSIGNED(root_bus_p)) 395*fc256490SJason Beloro return; 396*fc256490SJason Beloro 397*fc256490SJason Beloro pcie_faulty_list_clear(); 398*fc256490SJason Beloro } 399*fc256490SJason Beloro 400*fc256490SJason Beloro pcie_bus_t * 401*fc256490SJason Beloro pciev_get_affected_dev(pf_impl_t *impl, pf_data_t *pfd_p, 402*fc256490SJason Beloro uint16_t affected_flag, uint16_t dev_affected_flags) 403*fc256490SJason Beloro { 404*fc256490SJason Beloro pcie_bus_t *bus_p = PCIE_PFD2BUS(pfd_p); 405*fc256490SJason Beloro uint16_t flag = affected_flag & dev_affected_flags; 406*fc256490SJason Beloro pcie_bus_t *temp_bus_p; 407*fc256490SJason Beloro pcie_req_id_t a_bdf; 408*fc256490SJason Beloro uint64_t a_addr; 409*fc256490SJason Beloro uint16_t cmd; 410*fc256490SJason Beloro 411*fc256490SJason Beloro if (!flag) 412*fc256490SJason Beloro return (NULL); 413*fc256490SJason Beloro 414*fc256490SJason Beloro switch (flag) { 415*fc256490SJason Beloro case PF_AFFECTED_ROOT: 416*fc256490SJason Beloro return (PCIE_DIP2BUS(bus_p->bus_rp_dip)); 417*fc256490SJason Beloro case PF_AFFECTED_SELF: 418*fc256490SJason Beloro return (bus_p); 419*fc256490SJason Beloro case PF_AFFECTED_PARENT: 420*fc256490SJason Beloro return (PCIE_DIP2BUS(ddi_get_parent(PCIE_BUS2DIP(bus_p)))); 421*fc256490SJason Beloro case PF_AFFECTED_BDF: /* may only be used for RC */ 422*fc256490SJason Beloro a_bdf = PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf; 423*fc256490SJason Beloro if (!PCIE_CHECK_VALID_BDF(a_bdf)) 424*fc256490SJason Beloro return (NULL); 425*fc256490SJason Beloro 426*fc256490SJason Beloro temp_bus_p = pf_find_busp_by_bdf(impl, a_bdf); 427*fc256490SJason Beloro return (temp_bus_p); 428*fc256490SJason Beloro case PF_AFFECTED_AER: 429*fc256490SJason Beloro if (pf_tlp_decode(bus_p, PCIE_ADV_REG(pfd_p)) == DDI_SUCCESS) { 430*fc256490SJason Beloro temp_bus_p = pf_find_busp_by_aer(impl, pfd_p); 431*fc256490SJason Beloro return (temp_bus_p); 432*fc256490SJason Beloro } 433*fc256490SJason Beloro break; 434*fc256490SJason Beloro case PF_AFFECTED_SAER: 435*fc256490SJason Beloro if (pf_pci_decode(pfd_p, &cmd) == DDI_SUCCESS) { 436*fc256490SJason Beloro temp_bus_p = pf_find_busp_by_saer(impl, pfd_p); 437*fc256490SJason Beloro return (temp_bus_p); 438*fc256490SJason Beloro } 439*fc256490SJason Beloro break; 440*fc256490SJason Beloro case PF_AFFECTED_ADDR: /* ROOT only */ 441*fc256490SJason Beloro a_addr = PCIE_ROOT_FAULT(pfd_p)->scan_addr; 442*fc256490SJason Beloro temp_bus_p = pf_find_busp_by_addr(impl, a_addr); 443*fc256490SJason Beloro return (temp_bus_p); 444*fc256490SJason Beloro } 445*fc256490SJason Beloro 446*fc256490SJason Beloro return (NULL); 447*fc256490SJason Beloro } 448*fc256490SJason Beloro 449*fc256490SJason Beloro /* type used for pcie_domain_list_find() function */ 450*fc256490SJason Beloro typedef enum { 451*fc256490SJason Beloro PCIE_DOM_LIST_TYPE_CACHE = 1, 452*fc256490SJason Beloro PCIE_DOM_LIST_TYPE_FAULT = 2 453*fc256490SJason Beloro } pcie_dom_list_type_t; 454*fc256490SJason Beloro 455*fc256490SJason Beloro /* 456*fc256490SJason Beloro * Check if a domain id is already in the linked list 457*fc256490SJason Beloro */ 458*fc256490SJason Beloro static pcie_domains_t * 459*fc256490SJason Beloro pcie_domain_list_find(uint_t domain_id, pcie_domains_t *pd_list_p, 460*fc256490SJason Beloro pcie_dom_list_type_t type) 461*fc256490SJason Beloro { 462*fc256490SJason Beloro while (pd_list_p) { 463*fc256490SJason Beloro if (pd_list_p->domain_id == domain_id) 464*fc256490SJason Beloro return (pd_list_p); 465*fc256490SJason Beloro 466*fc256490SJason Beloro if (type == PCIE_DOM_LIST_TYPE_CACHE) { 467*fc256490SJason Beloro pd_list_p = pd_list_p->cached_next; 468*fc256490SJason Beloro } else if (type == PCIE_DOM_LIST_TYPE_FAULT) { 469*fc256490SJason Beloro pd_list_p = pd_list_p->faulty_next; 470*fc256490SJason Beloro } else { 471*fc256490SJason Beloro return (NULL); 472*fc256490SJason Beloro } 473*fc256490SJason Beloro } 474*fc256490SJason Beloro 475*fc256490SJason Beloro return (NULL); 476*fc256490SJason Beloro } 477*fc256490SJason Beloro 478*fc256490SJason Beloro /* 479*fc256490SJason Beloro * Return true if a leaf device is assigned to a domain or a bridge device 480*fc256490SJason Beloro * has children assigned to the domain 481*fc256490SJason Beloro */ 482*fc256490SJason Beloro boolean_t 483*fc256490SJason Beloro pcie_in_domain(pcie_bus_t *bus_p, uint_t domain_id) 484*fc256490SJason Beloro { 485*fc256490SJason Beloro if (PCIE_IS_BDG(bus_p)) { 486*fc256490SJason Beloro pcie_domains_t *pd; 487*fc256490SJason Beloro pd = pcie_domain_list_find(domain_id, 488*fc256490SJason Beloro PCIE_DOMAIN_LIST_GET(bus_p), PCIE_DOM_LIST_TYPE_CACHE); 489*fc256490SJason Beloro if (pd && pd->cached_count) 490*fc256490SJason Beloro return (B_TRUE); 491*fc256490SJason Beloro return (B_FALSE); 492*fc256490SJason Beloro } else { 493*fc256490SJason Beloro return (PCIE_DOMAIN_ID_GET(bus_p) == domain_id); 494*fc256490SJason Beloro } 495*fc256490SJason Beloro } 496*fc256490SJason Beloro 497*fc256490SJason Beloro /* 498*fc256490SJason Beloro * Add a domain id to a cached domain id list. 499*fc256490SJason Beloro * If the domain already exists in the list, increment the reference count. 500*fc256490SJason Beloro */ 501*fc256490SJason Beloro void 502*fc256490SJason Beloro pcie_domain_list_add(uint_t domain_id, pcie_domains_t **pd_list_p) 503*fc256490SJason Beloro { 504*fc256490SJason Beloro pcie_domains_t *pd; 505*fc256490SJason Beloro 506*fc256490SJason Beloro pd = pcie_domain_list_find(domain_id, *pd_list_p, 507*fc256490SJason Beloro PCIE_DOM_LIST_TYPE_CACHE); 508*fc256490SJason Beloro 509*fc256490SJason Beloro if (pd == NULL) { 510*fc256490SJason Beloro pd = PCIE_ZALLOC(pcie_domains_t); 511*fc256490SJason Beloro pd->domain_id = domain_id; 512*fc256490SJason Beloro pd->cached_count = 1; 513*fc256490SJason Beloro pd->cached_next = *pd_list_p; 514*fc256490SJason Beloro *pd_list_p = pd; 515*fc256490SJason Beloro } else 516*fc256490SJason Beloro pd->cached_count++; 517*fc256490SJason Beloro } 518*fc256490SJason Beloro 519*fc256490SJason Beloro /* 520*fc256490SJason Beloro * Remove a domain id from a cached domain id list. 521*fc256490SJason Beloro * Decrement the reference count. 522*fc256490SJason Beloro */ 523*fc256490SJason Beloro void 524*fc256490SJason Beloro pcie_domain_list_remove(uint_t domain_id, pcie_domains_t *pd_list_p) 525*fc256490SJason Beloro { 526*fc256490SJason Beloro pcie_domains_t *pd; 527*fc256490SJason Beloro 528*fc256490SJason Beloro pd = pcie_domain_list_find(domain_id, pd_list_p, 529*fc256490SJason Beloro PCIE_DOM_LIST_TYPE_CACHE); 530*fc256490SJason Beloro 531*fc256490SJason Beloro if (pd) { 532*fc256490SJason Beloro ASSERT((pd->cached_count)--); 533*fc256490SJason Beloro } 534*fc256490SJason Beloro } 535*fc256490SJason Beloro 536*fc256490SJason Beloro /* destroy cached domain id list */ 537*fc256490SJason Beloro static void 538*fc256490SJason Beloro pcie_domain_list_destroy(pcie_domains_t *domain_ids) 539*fc256490SJason Beloro { 540*fc256490SJason Beloro pcie_domains_t *p = domain_ids; 541*fc256490SJason Beloro pcie_domains_t *next; 542*fc256490SJason Beloro 543*fc256490SJason Beloro while (p) { 544*fc256490SJason Beloro next = p->cached_next; 545*fc256490SJason Beloro kmem_free(p, sizeof (pcie_domains_t)); 546*fc256490SJason Beloro p = next; 547*fc256490SJason Beloro } 548*fc256490SJason Beloro } 549*fc256490SJason Beloro 550*fc256490SJason Beloro static void 551*fc256490SJason Beloro pcie_faulty_list_update(pcie_domains_t *pd, 552*fc256490SJason Beloro pcie_domains_t **headp) 553*fc256490SJason Beloro { 554*fc256490SJason Beloro if (pd == NULL) 555*fc256490SJason Beloro return; 556*fc256490SJason Beloro 557*fc256490SJason Beloro if (*headp == NULL) { 558*fc256490SJason Beloro *headp = pd; 559*fc256490SJason Beloro pd->faulty_prev = NULL; 560*fc256490SJason Beloro pd->faulty_next = NULL; 561*fc256490SJason Beloro pd->faulty_count = 1; 562*fc256490SJason Beloro } else { 563*fc256490SJason Beloro pd->faulty_next = *headp; 564*fc256490SJason Beloro (*headp)->faulty_prev = pd; 565*fc256490SJason Beloro pd->faulty_prev = NULL; 566*fc256490SJason Beloro pd->faulty_count = 1; 567*fc256490SJason Beloro *headp = pd; 568*fc256490SJason Beloro } 569*fc256490SJason Beloro } 570*fc256490SJason Beloro 571*fc256490SJason Beloro static void 572*fc256490SJason Beloro pcie_faulty_list_clear() 573*fc256490SJason Beloro { 574*fc256490SJason Beloro pcie_domains_t *pd = pcie_faulty_domains; 575*fc256490SJason Beloro pcie_domains_t *next; 576*fc256490SJason Beloro 577*fc256490SJason Beloro /* unlink all domain structures from the faulty list */ 578*fc256490SJason Beloro while (pd) { 579*fc256490SJason Beloro next = pd->faulty_next; 580*fc256490SJason Beloro pd->faulty_prev = NULL; 581*fc256490SJason Beloro pd->faulty_next = NULL; 582*fc256490SJason Beloro pd->faulty_count = 0; 583*fc256490SJason Beloro pd = next; 584*fc256490SJason Beloro } 585*fc256490SJason Beloro pcie_faulty_domains = NULL; 586*fc256490SJason Beloro pcie_faulty_all = B_FALSE; 587*fc256490SJason Beloro } 588*fc256490SJason Beloro 589*fc256490SJason Beloro void 590*fc256490SJason Beloro pcie_save_domain_id(pcie_domains_t *domain_ids) 591*fc256490SJason Beloro { 592*fc256490SJason Beloro pcie_domains_t *old_list_p, *new_list_p, *pd; 593*fc256490SJason Beloro 594*fc256490SJason Beloro if (pcie_faulty_all) 595*fc256490SJason Beloro return; 596*fc256490SJason Beloro 597*fc256490SJason Beloro if (domain_ids == NULL) 598*fc256490SJason Beloro return; 599*fc256490SJason Beloro 600*fc256490SJason Beloro old_list_p = pcie_faulty_domains; 601*fc256490SJason Beloro for (new_list_p = domain_ids; new_list_p; 602*fc256490SJason Beloro new_list_p = new_list_p->cached_next) { 603*fc256490SJason Beloro if (!new_list_p->cached_count) 604*fc256490SJason Beloro continue; 605*fc256490SJason Beloro 606*fc256490SJason Beloro /* search domain id in the faulty domain list */ 607*fc256490SJason Beloro pd = pcie_domain_list_find(new_list_p->domain_id, 608*fc256490SJason Beloro old_list_p, PCIE_DOM_LIST_TYPE_FAULT); 609*fc256490SJason Beloro if (pd) 610*fc256490SJason Beloro pd->faulty_count++; 611*fc256490SJason Beloro else 612*fc256490SJason Beloro pcie_faulty_list_update(new_list_p, 613*fc256490SJason Beloro &pcie_faulty_domains); 614*fc256490SJason Beloro } 615*fc256490SJason Beloro } 616