1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * px_msiq.c
28 */
29
30 #include <sys/types.h>
31 #include <sys/kmem.h>
32 #include <sys/conf.h>
33 #include <sys/ddi.h>
34 #include <sys/sunddi.h>
35 #include <sys/sysmacros.h>
36 #include <sys/machsystm.h> /* intr_dist_add */
37 #include <sys/modctl.h>
38 #include <sys/disp.h>
39 #include <sys/stat.h>
40 #include <sys/ddi_impldefs.h>
41 #include "px_obj.h"
42
43 static int px_msiq_get_props(px_t *px_p);
44
45 /*
46 * px_msiq_attach()
47 */
48 int
px_msiq_attach(px_t * px_p)49 px_msiq_attach(px_t *px_p)
50 {
51 px_ib_t *ib_p = px_p->px_ib_p;
52 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state;
53 int qcnt, i, ret = DDI_SUCCESS;
54
55 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_attach\n");
56
57 /*
58 * Check for all MSIQ related properties and
59 * save all information.
60 *
61 * Avaialble MSIQs and its properties.
62 */
63 if (px_msiq_get_props(px_p) != DDI_SUCCESS)
64 return (DDI_FAILURE);
65
66 /*
67 * 10% of available MSIQs are reserved for the PCIe messages.
68 * Around 90% of available MSIQs are reserved for the MSI/Xs.
69 */
70 msiq_state_p->msiq_msg_qcnt = howmany(msiq_state_p->msiq_cnt, 10);
71
72 qcnt = MIN(msiq_state_p->msiq_msg_qcnt, px_max_msiq_msgs);
73 msiq_state_p->msiq_msg_qcnt = qcnt = MAX(qcnt, px_min_msiq_msgs);
74 msiq_state_p->msiq_msi_qcnt = msiq_state_p->msiq_cnt - qcnt;
75
76 msiq_state_p->msiq_1st_msi_qid = msiq_state_p->msiq_1st_msiq_id;
77 msiq_state_p->msiq_1st_msg_qid = msiq_state_p->msiq_1st_msiq_id +
78 msiq_state_p->msiq_msi_qcnt;
79
80 msiq_state_p->msiq_p = kmem_zalloc(msiq_state_p->msiq_cnt *
81 sizeof (px_msiq_t), KM_SLEEP);
82
83 mutex_enter(&ib_p->ib_ino_lst_mutex);
84 for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
85 msiq_state_p->msiq_p[i].msiq_id =
86 msiq_state_p->msiq_1st_msiq_id + i;
87 msiq_state_p->msiq_p[i].msiq_refcnt = 0;
88 msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_FREE;
89 (void) px_ib_alloc_ino(ib_p, px_msiqid_to_devino(px_p,
90 msiq_state_p->msiq_p[i].msiq_id));
91 }
92
93 msiq_state_p->msiq_redist_flag = B_TRUE;
94 mutex_exit(&ib_p->ib_ino_lst_mutex);
95
96 if ((ret = px_lib_msiq_init(px_p->px_dip)) != DDI_SUCCESS)
97 px_msiq_detach(px_p);
98
99 return (ret);
100 }
101
102 /*
103 * px_msiq_detach()
104 */
105 void
px_msiq_detach(px_t * px_p)106 px_msiq_detach(px_t *px_p)
107 {
108 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
109
110 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_detach\n");
111
112 if (px_lib_msiq_fini(px_p->px_dip) != DDI_SUCCESS) {
113 DBG(DBG_MSIQ, px_p->px_dip,
114 "px_lib_msiq_fini: failed\n");
115 }
116
117 kmem_free(msiq_state_p->msiq_p,
118 msiq_state_p->msiq_cnt * sizeof (px_msiq_t));
119
120 bzero(msiq_state_p, sizeof (px_msiq_state_t));
121 }
122
123 /*
124 * px_msiq_resume()
125 */
126 void
px_msiq_resume(px_t * px_p)127 px_msiq_resume(px_t *px_p)
128 {
129 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
130 int i;
131
132 for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
133 (void) px_lib_msiq_gethead(px_p->px_dip,
134 msiq_state_p->msiq_p[i].msiq_id,
135 &msiq_state_p->msiq_p[i].msiq_curr_head_index);
136 msiq_state_p->msiq_p[i].msiq_new_head_index = 0;
137 msiq_state_p->msiq_p[i].msiq_recs2process = 0;
138 }
139 }
140
141 /*
142 * px_msiq_alloc()
143 */
144 int
px_msiq_alloc(px_t * px_p,msiq_rec_type_t rec_type,msgcode_t msg_code,msiqid_t * msiq_id_p)145 px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type, msgcode_t msg_code,
146 msiqid_t *msiq_id_p)
147 {
148 px_ib_t *ib_p = px_p->px_ib_p;
149 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state;
150 msiqid_t first_msiq_id;
151 uint_t msiq_cnt;
152 ushort_t least_refcnt;
153 int i;
154
155 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc\n");
156
157 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
158
159 if (rec_type == MSG_REC) {
160 /*
161 * The first MSG EQ is dedicated to PCIE_MSG_CODE_ERR_COR
162 * messages. All other messages will be spread across
163 * the remaining MSG EQs.
164 */
165 first_msiq_id = msiq_state_p->msiq_1st_msg_qid;
166
167 if (msg_code == PCIE_MSG_CODE_ERR_COR) {
168 msiq_state_p->msiq_p[first_msiq_id].msiq_state =
169 MSIQ_STATE_INUSE;
170
171 (void) px_lib_msiq_gethead(px_p->px_dip, first_msiq_id,
172 &msiq_state_p->msiq_p[first_msiq_id].
173 msiq_curr_head_index);
174
175 *msiq_id_p =
176 msiq_state_p->msiq_p[first_msiq_id].msiq_id;
177
178 msiq_state_p->msiq_p[first_msiq_id].msiq_refcnt++;
179
180 DBG(DBG_MSIQ, px_p->px_dip,
181 "px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p);
182
183 return (DDI_SUCCESS);
184 }
185
186 /* Jump past the first/dedicated EQ */
187 first_msiq_id++;
188 msiq_cnt = msiq_state_p->msiq_msg_qcnt - 1;
189 } else {
190 msiq_cnt = msiq_state_p->msiq_msi_qcnt;
191 first_msiq_id = msiq_state_p->msiq_1st_msi_qid;
192 }
193
194 *msiq_id_p = first_msiq_id;
195 least_refcnt = msiq_state_p->msiq_p[first_msiq_id].msiq_refcnt;
196
197 /* Allocate MSIQs */
198 for (i = first_msiq_id; i < (first_msiq_id + msiq_cnt); i++) {
199 if (msiq_state_p->msiq_p[i].msiq_state == MSIQ_STATE_FREE) {
200 msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_INUSE;
201 (void) px_lib_msiq_gethead(px_p->px_dip, i,
202 &msiq_state_p->msiq_p[i].msiq_curr_head_index);
203 *msiq_id_p = msiq_state_p->msiq_p[i].msiq_id;
204 break;
205 }
206
207 if (least_refcnt > msiq_state_p->msiq_p[i].msiq_refcnt) {
208 *msiq_id_p = msiq_state_p->msiq_p[i].msiq_id;
209 least_refcnt = msiq_state_p->msiq_p[i].msiq_refcnt;
210 }
211 }
212
213 msiq_state_p->msiq_p[*msiq_id_p].msiq_refcnt++;
214
215 DBG(DBG_MSIQ, px_p->px_dip,
216 "px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p);
217
218 return (DDI_SUCCESS);
219 }
220
221 /*
222 * px_msiq_alloc_based_on_cpuid()
223 */
224 int
px_msiq_alloc_based_on_cpuid(px_t * px_p,msiq_rec_type_t rec_type,cpuid_t cpuid,msiqid_t * msiq_id_p)225 px_msiq_alloc_based_on_cpuid(px_t *px_p, msiq_rec_type_t rec_type,
226 cpuid_t cpuid, msiqid_t *msiq_id_p)
227 {
228 px_ib_t *ib_p = px_p->px_ib_p;
229 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state;
230 msiqid_t first_msiq_id, free_msiq_id;
231 uint_t msiq_cnt;
232 ushort_t least_refcnt;
233 px_ino_t *ino_p;
234 int i;
235
236 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc_based_on_cpuid: "
237 "cpuid 0x%x\n", cpuid);
238
239 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
240
241 if (rec_type == MSG_REC) {
242 msiq_cnt = msiq_state_p->msiq_msg_qcnt;
243 first_msiq_id = msiq_state_p->msiq_1st_msg_qid;
244 } else {
245 msiq_cnt = msiq_state_p->msiq_msi_qcnt;
246 first_msiq_id = msiq_state_p->msiq_1st_msi_qid;
247 }
248
249 *msiq_id_p = free_msiq_id = (msiqid_t)-1;
250 least_refcnt = (ushort_t)-1;
251
252 /* Allocate MSIQs */
253 for (i = first_msiq_id; i < (first_msiq_id + msiq_cnt); i++) {
254 ino_p = px_ib_locate_ino(ib_p, px_msiqid_to_devino(px_p, i));
255
256 if ((ino_p->ino_cpuid == cpuid) &&
257 (least_refcnt > msiq_state_p->msiq_p[i].msiq_refcnt)) {
258 *msiq_id_p = msiq_state_p->msiq_p[i].msiq_id;
259 least_refcnt = msiq_state_p->msiq_p[i].msiq_refcnt;
260 }
261
262 if ((*msiq_id_p == -1) && (free_msiq_id == -1) &&
263 (msiq_state_p->msiq_p[i].msiq_state == MSIQ_STATE_FREE))
264 free_msiq_id = msiq_state_p->msiq_p[i].msiq_id;
265 }
266
267 if (*msiq_id_p == -1) {
268 if (free_msiq_id == -1) {
269 DBG(DBG_MSIQ, px_p->px_dip,
270 "px_msiq_alloc_based_on_cpuid: No EQ is available "
271 "for CPU 0x%x\n", cpuid);
272 return (DDI_EINVAL);
273 }
274
275 *msiq_id_p = free_msiq_id;
276 ino_p = px_ib_locate_ino(ib_p,
277 px_msiqid_to_devino(px_p, *msiq_id_p));
278 ino_p->ino_cpuid = ino_p->ino_default_cpuid = cpuid;
279 }
280
281 if (msiq_state_p->msiq_p[*msiq_id_p].msiq_state == MSIQ_STATE_FREE) {
282 msiq_state_p->msiq_p[*msiq_id_p].msiq_state = MSIQ_STATE_INUSE;
283 (void) px_lib_msiq_gethead(px_p->px_dip, *msiq_id_p,
284 &msiq_state_p->msiq_p[*msiq_id_p].msiq_curr_head_index);
285 }
286
287 msiq_state_p->msiq_p[*msiq_id_p].msiq_refcnt++;
288
289 DBG(DBG_MSIQ, px_p->px_dip,
290 "px_msiq_alloc_based_on_cpuid: msiq_id 0x%x\n", *msiq_id_p);
291
292 return (DDI_SUCCESS);
293 }
294
295 /*
296 * px_msiq_free()
297 */
298 int
px_msiq_free(px_t * px_p,msiqid_t msiq_id)299 px_msiq_free(px_t *px_p, msiqid_t msiq_id)
300 {
301 px_ib_t *ib_p = px_p->px_ib_p;
302 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state;
303
304 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_free: msiq_id 0x%x", msiq_id);
305
306 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
307
308 if ((msiq_id < msiq_state_p->msiq_1st_msiq_id) || (msiq_id >=
309 (msiq_state_p->msiq_1st_msiq_id + msiq_state_p->msiq_cnt))) {
310 DBG(DBG_MSIQ, px_p->px_dip,
311 "px_msiq_free: Invalid msiq_id 0x%x", msiq_id);
312 return (DDI_FAILURE);
313 }
314
315 if (--msiq_state_p->msiq_p[msiq_id].msiq_refcnt == 0)
316 msiq_state_p->msiq_p[msiq_id].msiq_state = MSIQ_STATE_FREE;
317
318 return (DDI_SUCCESS);
319 }
320
321 /*
322 * px_msiq_redist()
323 */
324 void
px_msiq_redist(px_t * px_p)325 px_msiq_redist(px_t *px_p)
326 {
327 px_ib_t *ib_p = px_p->px_ib_p;
328 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state;
329 px_ino_t *ino_p;
330 int i;
331
332 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
333
334 if (msiq_state_p->msiq_redist_flag == B_FALSE)
335 return;
336
337 for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
338 ino_p = px_ib_locate_ino(ib_p,
339 px_msiqid_to_devino(px_p, msiq_state_p->msiq_p[i].msiq_id));
340
341 if (ino_p) {
342 ino_p->ino_cpuid = ino_p->ino_default_cpuid =
343 intr_dist_cpuid();
344
345 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_redist: "
346 "sysino 0x%llx current cpuid 0x%x "
347 "default cpuid 0x%x\n", ino_p->ino_sysino,
348 ino_p->ino_cpuid, ino_p->ino_default_cpuid);
349 }
350 }
351
352 msiq_state_p->msiq_redist_flag = B_FALSE;
353 }
354
355 /*
356 * px_msiqid_to_devino()
357 */
358 devino_t
px_msiqid_to_devino(px_t * px_p,msiqid_t msiq_id)359 px_msiqid_to_devino(px_t *px_p, msiqid_t msiq_id)
360 {
361 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
362 devino_t devino;
363
364 devino = msiq_state_p->msiq_1st_devino +
365 msiq_id - msiq_state_p->msiq_1st_msiq_id;
366
367 DBG(DBG_MSIQ, px_p->px_dip, "px_msiqid_to_devino: "
368 "msiq_id 0x%x devino 0x%x\n", msiq_id, devino);
369
370 return (devino);
371 }
372
373 /*
374 * px_devino_to_msiqid()
375 */
376 msiqid_t
px_devino_to_msiqid(px_t * px_p,devino_t devino)377 px_devino_to_msiqid(px_t *px_p, devino_t devino)
378 {
379 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
380 msiqid_t msiq_id;
381
382 msiq_id = msiq_state_p->msiq_1st_msiq_id +
383 devino - msiq_state_p->msiq_1st_devino;
384
385 DBG(DBG_MSIQ, px_p->px_dip, "px_devino_to_msiq: "
386 "devino 0x%x msiq_id 0x%x\n", devino, msiq_id);
387
388 return (msiq_id);
389 }
390
391 /*
392 * px_msiq_get_props()
393 */
394 static int
px_msiq_get_props(px_t * px_p)395 px_msiq_get_props(px_t *px_p)
396 {
397 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
398 int length = sizeof (int);
399 char *valuep = NULL;
400 int ret;
401
402 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_get_props\n");
403
404 /* #msi-eqs */
405 msiq_state_p->msiq_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
406 DDI_PROP_DONTPASS, "#msi-eqs", 0);
407
408 DBG(DBG_MSIQ, px_p->px_dip, "msiq_cnt=%d\n", msiq_state_p->msiq_cnt);
409
410 /* msi-eq-size */
411 msiq_state_p->msiq_rec_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
412 DDI_PROP_DONTPASS, "msi-eq-size", 0);
413
414 DBG(DBG_MSIQ, px_p->px_dip, "msiq_rec_cnt=%d\n",
415 msiq_state_p->msiq_rec_cnt);
416
417 if ((msiq_state_p->msiq_cnt == 0) || (msiq_state_p->msiq_rec_cnt == 0))
418 return (DDI_FAILURE);
419
420 /* msi-eq-to-devino: msi-eq#, devino# fields */
421 ret = ddi_prop_op(DDI_DEV_T_ANY, px_p->px_dip, PROP_LEN_AND_VAL_ALLOC,
422 DDI_PROP_DONTPASS, "msi-eq-to-devino", (caddr_t)&valuep, &length);
423
424 /*
425 * NOTE:
426 * On sun4u PCIe systems, the msi-eq-to-devino property is broken and
427 * these systems defines this property as msi-eq-devino.
428 */
429 if (ret == DDI_PROP_NOT_FOUND) {
430 DBG(DBG_MSIQ, px_p->px_dip, "msi-eq-to-devino is not found\n");
431 ret = ddi_prop_op(DDI_DEV_T_ANY, px_p->px_dip,
432 PROP_LEN_AND_VAL_ALLOC, DDI_PROP_DONTPASS, "msi-eq-devino",
433 (caddr_t)&valuep, &length);
434 }
435
436 if (ret != DDI_PROP_SUCCESS) {
437 return (DDI_FAILURE);
438 }
439
440 msiq_state_p->msiq_1st_msiq_id =
441 ((px_msi_eq_to_devino_t *)valuep)->msi_eq_no;
442 msiq_state_p->msiq_1st_devino =
443 ((px_msi_eq_to_devino_t *)valuep)->devino_no;
444
445 DBG(DBG_MSIQ, px_p->px_dip, "msiq_1st_msiq_id=%d\n",
446 msiq_state_p->msiq_1st_msiq_id);
447
448 DBG(DBG_MSIQ, px_p->px_dip, "msiq_1st_devino=%d\n",
449 msiq_state_p->msiq_1st_devino);
450
451 kmem_free(valuep, (size_t)length);
452 return (DDI_SUCCESS);
453 }
454