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 *
pcie_find_dip_by_bdf(dev_info_t * rootp,pcie_req_id_t bdf)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
pcie_bdf_list_add(pcie_req_id_t bdf,pcie_req_id_list_t ** rlist_p)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
pcie_bdf_list_remove(pcie_req_id_t bdf,pcie_req_id_list_t ** rlist_p)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
pcie_cache_domain_info(pcie_bus_t * bus_p)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
pcie_uncache_domain_info(pcie_bus_t * bus_p)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
pcie_init_dom(dev_info_t * dip)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
pcie_fini_dom(dev_info_t * dip)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
pciev_eh(pf_data_t * pfd_p,pf_impl_t * impl)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
pciev_eh_exit(pf_data_t * root_pfd_p,uint_t intr_type)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 *
pciev_get_affected_dev(pf_impl_t * impl,pf_data_t * pfd_p,uint16_t affected_flag,uint16_t dev_affected_flags)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 *
pcie_domain_list_find(uint_t domain_id,pcie_domains_t * pd_list_p,pcie_dom_list_type_t type)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
pcie_in_domain(pcie_bus_t * bus_p,uint_t domain_id)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
pcie_domain_list_add(uint_t domain_id,pcie_domains_t ** pd_list_p)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
pcie_domain_list_remove(uint_t domain_id,pcie_domains_t * pd_list_p)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
pcie_domain_list_destroy(pcie_domains_t * domain_ids)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
pcie_faulty_list_update(pcie_domains_t * pd,pcie_domains_t ** headp)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
pcie_faulty_list_clear()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
pcie_save_domain_id(pcie_domains_t * domain_ids)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