xref: /illumos-gate/usr/src/uts/sun4/io/px/px_msiq.c (revision 5a3c8170a75e81911cf43e0eb9ad5cdabb5f1e39)
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 2009 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 void px_msiq_get_props(px_t *px_p);
44 
45 /*
46  * px_msiq_attach()
47  */
48 int
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 	px_msiq_get_props(px_p);
64 
65 	/*
66 	 * 10% of available MSIQs are reserved for the PCIe messages.
67 	 * Around 90% of available MSIQs are reserved for the MSI/Xs.
68 	 */
69 	msiq_state_p->msiq_msg_qcnt = howmany(msiq_state_p->msiq_cnt, 10);
70 
71 	qcnt = MIN(msiq_state_p->msiq_msg_qcnt, px_max_msiq_msgs);
72 	msiq_state_p->msiq_msg_qcnt = qcnt = MAX(qcnt, px_min_msiq_msgs);
73 	msiq_state_p->msiq_msi_qcnt = msiq_state_p->msiq_cnt - qcnt;
74 
75 	msiq_state_p->msiq_1st_msi_qid = msiq_state_p->msiq_1st_msiq_id;
76 	msiq_state_p->msiq_1st_msg_qid = msiq_state_p->msiq_1st_msiq_id +
77 	    msiq_state_p->msiq_msi_qcnt;
78 
79 	mutex_init(&msiq_state_p->msiq_mutex, NULL, MUTEX_DRIVER, NULL);
80 	msiq_state_p->msiq_p = kmem_zalloc(msiq_state_p->msiq_cnt *
81 	    sizeof (px_msiq_t), KM_SLEEP);
82 
83 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
84 		msiq_state_p->msiq_p[i].msiq_id =
85 		    msiq_state_p->msiq_1st_msiq_id + i;
86 		msiq_state_p->msiq_p[i].msiq_refcnt = 0;
87 		msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_FREE;
88 		(void) px_ib_alloc_ino(ib_p, px_msiqid_to_devino(px_p,
89 		    msiq_state_p->msiq_p[i].msiq_id));
90 	}
91 
92 	if ((ret = px_lib_msiq_init(px_p->px_dip)) != DDI_SUCCESS)
93 		px_msiq_detach(px_p);
94 
95 	msiq_state_p->msiq_redist_flag = B_TRUE;
96 	return (ret);
97 }
98 
99 /*
100  * px_msiq_detach()
101  */
102 void
103 px_msiq_detach(px_t *px_p)
104 {
105 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
106 
107 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_detach\n");
108 
109 	if (px_lib_msiq_fini(px_p->px_dip) != DDI_SUCCESS) {
110 		DBG(DBG_MSIQ, px_p->px_dip,
111 		    "px_lib_msiq_fini: failed\n");
112 	}
113 
114 	mutex_destroy(&msiq_state_p->msiq_mutex);
115 	kmem_free(msiq_state_p->msiq_p,
116 	    msiq_state_p->msiq_cnt * sizeof (px_msiq_t));
117 
118 	bzero(msiq_state_p, sizeof (px_msiq_state_t));
119 }
120 
121 /*
122  * px_msiq_resume()
123  */
124 void
125 px_msiq_resume(px_t *px_p)
126 {
127 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
128 	int		i;
129 
130 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
131 		(void) px_lib_msiq_gethead(px_p->px_dip,
132 		    msiq_state_p->msiq_p[i].msiq_id,
133 		    &msiq_state_p->msiq_p[i].msiq_curr_head_index);
134 		msiq_state_p->msiq_p[i].msiq_new_head_index = 0;
135 		msiq_state_p->msiq_p[i].msiq_recs2process = 0;
136 	}
137 }
138 
139 /*
140  * px_msiq_alloc()
141  */
142 int
143 px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type, msgcode_t msg_code,
144     msiqid_t *msiq_id_p)
145 {
146 	px_ib_t		*ib_p = px_p->px_ib_p;
147 	px_msiq_state_t	*msiq_state_p = &ib_p->ib_msiq_state;
148 	msiqid_t	first_msiq_id;
149 	uint_t		msiq_cnt;
150 	ushort_t	least_refcnt;
151 	int		i;
152 
153 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc\n");
154 
155 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
156 	mutex_enter(&msiq_state_p->msiq_mutex);
157 
158 	if (rec_type == MSG_REC) {
159 		/*
160 		 * The first MSG EQ is dedicated to PCIE_MSG_CODE_ERR_COR
161 		 * messages. All other messages will be spread across
162 		 * the remaining MSG EQs.
163 		 */
164 		first_msiq_id = msiq_state_p->msiq_1st_msg_qid;
165 
166 		if (msg_code == PCIE_MSG_CODE_ERR_COR) {
167 			msiq_state_p->msiq_p[first_msiq_id].msiq_state =
168 			    MSIQ_STATE_INUSE;
169 
170 			(void) px_lib_msiq_gethead(px_p->px_dip, first_msiq_id,
171 			    &msiq_state_p->msiq_p[first_msiq_id].
172 			    msiq_curr_head_index);
173 
174 			*msiq_id_p =
175 			    msiq_state_p->msiq_p[first_msiq_id].msiq_id;
176 
177 			msiq_state_p->msiq_p[first_msiq_id].msiq_refcnt++;
178 
179 			DBG(DBG_MSIQ, px_p->px_dip,
180 			    "px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p);
181 
182 			mutex_exit(&msiq_state_p->msiq_mutex);
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 	mutex_exit(&msiq_state_p->msiq_mutex);
219 	return (DDI_SUCCESS);
220 }
221 
222 /*
223  * px_msiq_alloc_based_on_cpuid()
224  */
225 int
226 px_msiq_alloc_based_on_cpuid(px_t *px_p, msiq_rec_type_t rec_type,
227     cpuid_t cpuid, msiqid_t *msiq_id_p)
228 {
229 	px_ib_t		*ib_p = px_p->px_ib_p;
230 	px_msiq_state_t	*msiq_state_p = &ib_p->ib_msiq_state;
231 	msiqid_t	first_msiq_id, free_msiq_id;
232 	uint_t		msiq_cnt;
233 	ushort_t	least_refcnt;
234 	px_ino_t	*ino_p;
235 	int		i;
236 
237 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc_based_on_cpuid: "
238 	    "cpuid 0x%x\n", cpuid);
239 
240 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
241 
242 	mutex_enter(&msiq_state_p->msiq_mutex);
243 
244 	if (rec_type == MSG_REC) {
245 		msiq_cnt = msiq_state_p->msiq_msg_qcnt;
246 		first_msiq_id = msiq_state_p->msiq_1st_msg_qid;
247 	} else {
248 		msiq_cnt = msiq_state_p->msiq_msi_qcnt;
249 		first_msiq_id = msiq_state_p->msiq_1st_msi_qid;
250 	}
251 
252 	*msiq_id_p = free_msiq_id = (msiqid_t)-1;
253 	least_refcnt = (ushort_t)-1;
254 
255 	/* Allocate MSIQs */
256 	for (i = first_msiq_id; i < (first_msiq_id + msiq_cnt); i++) {
257 		ino_p = px_ib_locate_ino(ib_p, px_msiqid_to_devino(px_p, i));
258 
259 		if ((ino_p->ino_cpuid == cpuid) &&
260 		    (least_refcnt > msiq_state_p->msiq_p[i].msiq_refcnt)) {
261 			*msiq_id_p = msiq_state_p->msiq_p[i].msiq_id;
262 			least_refcnt = msiq_state_p->msiq_p[i].msiq_refcnt;
263 		}
264 
265 		if ((*msiq_id_p == -1) && (free_msiq_id == -1) &&
266 		    (msiq_state_p->msiq_p[i].msiq_state == MSIQ_STATE_FREE))
267 			free_msiq_id = msiq_state_p->msiq_p[i].msiq_id;
268 	}
269 
270 	if (*msiq_id_p == -1) {
271 		if (free_msiq_id == -1) {
272 			DBG(DBG_MSIQ, px_p->px_dip,
273 			    "px_msiq_alloc_based_on_cpuid: No EQ is available "
274 			    "for CPU 0x%x\n", cpuid);
275 
276 			mutex_exit(&msiq_state_p->msiq_mutex);
277 			return (DDI_EINVAL);
278 		}
279 
280 		*msiq_id_p = free_msiq_id;
281 		ino_p = px_ib_locate_ino(ib_p,
282 		    px_msiqid_to_devino(px_p, *msiq_id_p));
283 		ino_p->ino_cpuid = ino_p->ino_default_cpuid = cpuid;
284 	}
285 
286 	if (msiq_state_p->msiq_p[*msiq_id_p].msiq_state == MSIQ_STATE_FREE) {
287 		msiq_state_p->msiq_p[*msiq_id_p].msiq_state = MSIQ_STATE_INUSE;
288 		(void) px_lib_msiq_gethead(px_p->px_dip, *msiq_id_p,
289 		    &msiq_state_p->msiq_p[*msiq_id_p].msiq_curr_head_index);
290 	}
291 
292 	msiq_state_p->msiq_p[*msiq_id_p].msiq_refcnt++;
293 
294 	DBG(DBG_MSIQ, px_p->px_dip,
295 	    "px_msiq_alloc_based_on_cpuid: msiq_id 0x%x\n", *msiq_id_p);
296 
297 	mutex_exit(&msiq_state_p->msiq_mutex);
298 	return (DDI_SUCCESS);
299 }
300 
301 /*
302  * px_msiq_free()
303  */
304 int
305 px_msiq_free(px_t *px_p, msiqid_t msiq_id)
306 {
307 	px_ib_t		*ib_p = px_p->px_ib_p;
308 	px_msiq_state_t	*msiq_state_p = &ib_p->ib_msiq_state;
309 
310 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_free: msiq_id 0x%x", msiq_id);
311 
312 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
313 	mutex_enter(&msiq_state_p->msiq_mutex);
314 
315 	if ((msiq_id < msiq_state_p->msiq_1st_msiq_id) || (msiq_id >=
316 	    (msiq_state_p->msiq_1st_msiq_id + msiq_state_p->msiq_cnt))) {
317 		DBG(DBG_MSIQ, px_p->px_dip,
318 		    "px_msiq_free: Invalid msiq_id 0x%x", msiq_id);
319 
320 		mutex_exit(&msiq_state_p->msiq_mutex);
321 		return (DDI_FAILURE);
322 	}
323 
324 	if (--msiq_state_p->msiq_p[msiq_id].msiq_refcnt == 0)
325 		msiq_state_p->msiq_p[msiq_id].msiq_state = MSIQ_STATE_FREE;
326 
327 	mutex_exit(&msiq_state_p->msiq_mutex);
328 	return (DDI_SUCCESS);
329 }
330 
331 /*
332  * px_msiq_redist()
333  */
334 void
335 px_msiq_redist(px_t *px_p)
336 {
337 	px_ib_t		*ib_p = px_p->px_ib_p;
338 	px_msiq_state_t	*msiq_state_p = &ib_p->ib_msiq_state;
339 	px_ino_t	*ino_p;
340 	int		i;
341 
342 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
343 
344 	mutex_enter(&msiq_state_p->msiq_mutex);
345 
346 	if (msiq_state_p->msiq_redist_flag == B_FALSE) {
347 		mutex_exit(&msiq_state_p->msiq_mutex);
348 		return;
349 	}
350 
351 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
352 		ino_p = px_ib_locate_ino(ib_p,
353 		    px_msiqid_to_devino(px_p, msiq_state_p->msiq_p[i].msiq_id));
354 
355 		if (ino_p) {
356 			ino_p->ino_cpuid = ino_p->ino_default_cpuid =
357 			    intr_dist_cpuid();
358 
359 			DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_redist: "
360 			    "sysino 0x%llx current cpuid 0x%x "
361 			    "default cpuid 0x%x\n", ino_p->ino_sysino,
362 			    ino_p->ino_cpuid, ino_p->ino_default_cpuid);
363 		}
364 	}
365 
366 	msiq_state_p->msiq_redist_flag = B_FALSE;
367 	mutex_exit(&msiq_state_p->msiq_mutex);
368 }
369 
370 /*
371  * px_msiqid_to_devino()
372  */
373 devino_t
374 px_msiqid_to_devino(px_t *px_p, msiqid_t msiq_id)
375 {
376 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
377 	devino_t	devino;
378 
379 	devino = msiq_state_p->msiq_1st_devino +
380 	    msiq_id - msiq_state_p->msiq_1st_msiq_id;
381 
382 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiqid_to_devino: "
383 	    "msiq_id 0x%x devino 0x%x\n", msiq_id, devino);
384 
385 	return (devino);
386 }
387 
388 /*
389  * px_devino_to_msiqid()
390  */
391 msiqid_t
392 px_devino_to_msiqid(px_t *px_p, devino_t devino)
393 {
394 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
395 	msiqid_t	msiq_id;
396 
397 	msiq_id = msiq_state_p->msiq_1st_msiq_id +
398 	    devino - msiq_state_p->msiq_1st_devino;
399 
400 	DBG(DBG_MSIQ, px_p->px_dip, "px_devino_to_msiq: "
401 	    "devino 0x%x msiq_id 0x%x\n", devino, msiq_id);
402 
403 	return (msiq_id);
404 }
405 
406 /*
407  * px_msiq_get_props()
408  */
409 static void
410 px_msiq_get_props(px_t *px_p)
411 {
412 	px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
413 	int	ret = DDI_SUCCESS;
414 	int	length = sizeof (int);
415 	char	*valuep = NULL;
416 
417 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_get_props\n");
418 
419 	/* #msi-eqs */
420 	msiq_state_p->msiq_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
421 	    DDI_PROP_DONTPASS, "#msi-eqs", PX_DEFAULT_MSIQ_CNT);
422 
423 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_cnt=%d\n",
424 	    msiq_state_p->msiq_cnt);
425 
426 	/* msi-eq-size */
427 	msiq_state_p->msiq_rec_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
428 	    DDI_PROP_DONTPASS, "msi-eq-size", PX_DEFAULT_MSIQ_REC_CNT);
429 
430 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_rec_cnt=%d\n",
431 	    msiq_state_p->msiq_rec_cnt);
432 
433 	/* msi-eq-to-devino: msi-eq#, devino# fields */
434 	ret = ddi_prop_op(DDI_DEV_T_ANY, px_p->px_dip, PROP_LEN_AND_VAL_ALLOC,
435 	    DDI_PROP_DONTPASS, "msi-eq-to-devino", (caddr_t)&valuep,
436 	    &length);
437 
438 	if (ret == DDI_PROP_SUCCESS) {
439 		msiq_state_p->msiq_1st_msiq_id =
440 		    ((px_msi_eq_to_devino_t *)valuep)->msi_eq_no;
441 		msiq_state_p->msiq_1st_devino =
442 		    ((px_msi_eq_to_devino_t *)valuep)->devino_no;
443 		kmem_free(valuep, (size_t)length);
444 	} else {
445 		msiq_state_p->msiq_1st_msiq_id = PX_DEFAULT_MSIQ_1ST_MSIQ_ID;
446 		msiq_state_p->msiq_1st_devino = PX_DEFAULT_MSIQ_1ST_DEVINO;
447 	}
448 
449 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_msiq_id=%d\n",
450 	    msiq_state_p->msiq_1st_msiq_id);
451 
452 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_devino=%d\n",
453 	    msiq_state_p->msiq_1st_devino);
454 }
455