xref: /illumos-gate/usr/src/uts/sun4/io/px/px_msiq.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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/machsystm.h>	/* intr_dist_add */
36 #include <sys/modctl.h>
37 #include <sys/disp.h>
38 #include <sys/stat.h>
39 #include <sys/ddi_impldefs.h>
40 #include "px_obj.h"
41 
42 static void px_msiq_get_props(px_t *px_p);
43 
44 /*
45  * px_msiq_attach()
46  */
47 int
48 px_msiq_attach(px_t *px_p)
49 {
50 	px_ib_t		*ib_p = px_p->px_ib_p;
51 	px_msiq_state_t	*msiq_state_p = &ib_p->ib_msiq_state;
52 	int		i, ret = DDI_SUCCESS;
53 
54 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_attach\n");
55 
56 	/*
57 	 * Check for all MSIQ related properties and
58 	 * save all information.
59 	 *
60 	 * Avaialble MSIQs and its properties.
61 	 */
62 	px_msiq_get_props(px_p);
63 
64 	/*
65 	 * 10% of available MSIQs are reserved for the PCIe messages.
66 	 * Around 90% of available MSIQs are reserved for the MSI/Xs.
67 	 */
68 	msiq_state_p->msiq_msg_qcnt = howmany(msiq_state_p->msiq_cnt, 10);
69 	msiq_state_p->msiq_msi_qcnt = msiq_state_p->msiq_cnt -
70 	    msiq_state_p->msiq_msg_qcnt;
71 
72 	msiq_state_p->msiq_1st_msi_qid = msiq_state_p->msiq_1st_msiq_id;
73 	msiq_state_p->msiq_1st_msg_qid = msiq_state_p->msiq_1st_msiq_id +
74 	    msiq_state_p->msiq_msi_qcnt;
75 
76 	mutex_init(&msiq_state_p->msiq_mutex, NULL, MUTEX_DRIVER, NULL);
77 	msiq_state_p->msiq_p = kmem_zalloc(msiq_state_p->msiq_cnt *
78 	    sizeof (px_msiq_t), KM_SLEEP);
79 
80 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
81 		msiq_state_p->msiq_p[i].msiq_id =
82 		    msiq_state_p->msiq_1st_msiq_id + i;
83 		msiq_state_p->msiq_p[i].msiq_refcnt = 0;
84 		msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_FREE;
85 		(void) px_ib_alloc_ino(ib_p, px_msiqid_to_devino(px_p,
86 		    msiq_state_p->msiq_p[i].msiq_id));
87 	}
88 
89 	if ((ret = px_lib_msiq_init(px_p->px_dip)) != DDI_SUCCESS)
90 		px_msiq_detach(px_p);
91 
92 	msiq_state_p->msiq_redist_flag = B_TRUE;
93 	return (ret);
94 }
95 
96 /*
97  * px_msiq_detach()
98  */
99 void
100 px_msiq_detach(px_t *px_p)
101 {
102 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
103 
104 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_detach\n");
105 
106 	if (px_lib_msiq_fini(px_p->px_dip) != DDI_SUCCESS) {
107 		DBG(DBG_MSIQ, px_p->px_dip,
108 		    "px_lib_msiq_fini: failed\n");
109 	}
110 
111 	mutex_destroy(&msiq_state_p->msiq_mutex);
112 	kmem_free(msiq_state_p->msiq_p,
113 	    msiq_state_p->msiq_cnt * sizeof (px_msiq_t));
114 
115 	bzero(msiq_state_p, sizeof (px_msiq_state_t));
116 }
117 
118 /*
119  * px_msiq_resume()
120  */
121 void
122 px_msiq_resume(px_t *px_p)
123 {
124 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
125 	int		i;
126 
127 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
128 		(void) px_lib_msiq_gethead(px_p->px_dip,
129 		    msiq_state_p->msiq_p[i].msiq_id,
130 		    &msiq_state_p->msiq_p[i].msiq_curr_head_index);
131 		msiq_state_p->msiq_p[i].msiq_new_head_index = 0;
132 		msiq_state_p->msiq_p[i].msiq_recs2process = 0;
133 	}
134 }
135 
136 /*
137  * px_msiq_alloc()
138  */
139 int
140 px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type, msiqid_t *msiq_id_p)
141 {
142 	px_ib_t		*ib_p = px_p->px_ib_p;
143 	px_msiq_state_t	*msiq_state_p = &ib_p->ib_msiq_state;
144 	msiqid_t	first_msiq_id;
145 	uint_t		msiq_cnt;
146 	ushort_t	least_refcnt;
147 	int		i;
148 
149 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc\n");
150 
151 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
152 	mutex_enter(&msiq_state_p->msiq_mutex);
153 
154 	if (rec_type == MSG_REC) {
155 		msiq_cnt = msiq_state_p->msiq_msg_qcnt;
156 		first_msiq_id = msiq_state_p->msiq_1st_msg_qid;
157 	} else {
158 		msiq_cnt = msiq_state_p->msiq_msi_qcnt;
159 		first_msiq_id = msiq_state_p->msiq_1st_msi_qid;
160 	}
161 
162 	*msiq_id_p = first_msiq_id;
163 	least_refcnt = msiq_state_p->msiq_p[first_msiq_id].msiq_refcnt;
164 
165 	/* Allocate MSIQs */
166 	for (i = first_msiq_id; i < (first_msiq_id + msiq_cnt); i++) {
167 		if (msiq_state_p->msiq_p[i].msiq_state == MSIQ_STATE_FREE) {
168 			msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_INUSE;
169 			(void) px_lib_msiq_gethead(px_p->px_dip, i,
170 			    &msiq_state_p->msiq_p[i].msiq_curr_head_index);
171 			*msiq_id_p = msiq_state_p->msiq_p[i].msiq_id;
172 			break;
173 		}
174 
175 		if (least_refcnt > msiq_state_p->msiq_p[i].msiq_refcnt) {
176 			*msiq_id_p = msiq_state_p->msiq_p[i].msiq_id;
177 			least_refcnt = msiq_state_p->msiq_p[i].msiq_refcnt;
178 		}
179 	}
180 
181 	msiq_state_p->msiq_p[*msiq_id_p].msiq_refcnt++;
182 
183 	DBG(DBG_MSIQ, px_p->px_dip,
184 	    "px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p);
185 
186 	mutex_exit(&msiq_state_p->msiq_mutex);
187 	return (DDI_SUCCESS);
188 }
189 
190 /*
191  * px_msiq_alloc_based_on_cpuid()
192  */
193 int
194 px_msiq_alloc_based_on_cpuid(px_t *px_p, msiq_rec_type_t rec_type,
195     cpuid_t cpuid, msiqid_t *msiq_id_p)
196 {
197 	px_ib_t		*ib_p = px_p->px_ib_p;
198 	px_msiq_state_t	*msiq_state_p = &ib_p->ib_msiq_state;
199 	msiqid_t	first_msiq_id, free_msiq_id;
200 	uint_t		msiq_cnt;
201 	ushort_t	least_refcnt;
202 	px_ino_t	*ino_p;
203 	int		i;
204 
205 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc_based_on_cpuid: "
206 	    "cpuid 0x%x\n", cpuid);
207 
208 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
209 
210 	mutex_enter(&msiq_state_p->msiq_mutex);
211 
212 	if (rec_type == MSG_REC) {
213 		msiq_cnt = msiq_state_p->msiq_msg_qcnt;
214 		first_msiq_id = msiq_state_p->msiq_1st_msg_qid;
215 	} else {
216 		msiq_cnt = msiq_state_p->msiq_msi_qcnt;
217 		first_msiq_id = msiq_state_p->msiq_1st_msi_qid;
218 	}
219 
220 	*msiq_id_p = free_msiq_id = (msiqid_t)-1;
221 	least_refcnt = (ushort_t)-1;
222 
223 	/* Allocate MSIQs */
224 	for (i = first_msiq_id; i < (first_msiq_id + msiq_cnt); i++) {
225 		ino_p = px_ib_locate_ino(ib_p, px_msiqid_to_devino(px_p, i));
226 
227 		if ((ino_p->ino_cpuid == cpuid) &&
228 		    (least_refcnt > msiq_state_p->msiq_p[i].msiq_refcnt)) {
229 			*msiq_id_p = msiq_state_p->msiq_p[i].msiq_id;
230 			least_refcnt = msiq_state_p->msiq_p[i].msiq_refcnt;
231 		}
232 
233 		if ((*msiq_id_p == -1) && (free_msiq_id == -1) &&
234 		    (msiq_state_p->msiq_p[i].msiq_state == MSIQ_STATE_FREE))
235 			free_msiq_id = msiq_state_p->msiq_p[i].msiq_id;
236 	}
237 
238 	if (*msiq_id_p == -1) {
239 		if (free_msiq_id == -1) {
240 			DBG(DBG_MSIQ, px_p->px_dip,
241 			    "px_msiq_alloc_based_on_cpuid: No EQ is available "
242 			    "for CPU 0x%x\n", cpuid);
243 
244 			mutex_exit(&msiq_state_p->msiq_mutex);
245 			return (DDI_EINVAL);
246 		}
247 
248 		*msiq_id_p = free_msiq_id;
249 		ino_p = px_ib_locate_ino(ib_p,
250 		    px_msiqid_to_devino(px_p, *msiq_id_p));
251 		ino_p->ino_cpuid = ino_p->ino_default_cpuid = cpuid;
252 	}
253 
254 	if (msiq_state_p->msiq_p[*msiq_id_p].msiq_state == MSIQ_STATE_FREE) {
255 		msiq_state_p->msiq_p[*msiq_id_p].msiq_state = MSIQ_STATE_INUSE;
256 		(void) px_lib_msiq_gethead(px_p->px_dip, *msiq_id_p,
257 		    &msiq_state_p->msiq_p[*msiq_id_p].msiq_curr_head_index);
258 	}
259 
260 	msiq_state_p->msiq_p[*msiq_id_p].msiq_refcnt++;
261 
262 	DBG(DBG_MSIQ, px_p->px_dip,
263 	    "px_msiq_alloc_based_on_cpuid: msiq_id 0x%x\n", *msiq_id_p);
264 
265 	mutex_exit(&msiq_state_p->msiq_mutex);
266 	return (DDI_SUCCESS);
267 }
268 
269 /*
270  * px_msiq_free()
271  */
272 int
273 px_msiq_free(px_t *px_p, msiqid_t msiq_id)
274 {
275 	px_ib_t		*ib_p = px_p->px_ib_p;
276 	px_msiq_state_t	*msiq_state_p = &ib_p->ib_msiq_state;
277 
278 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_free: msiq_id 0x%x", msiq_id);
279 
280 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
281 	mutex_enter(&msiq_state_p->msiq_mutex);
282 
283 	if ((msiq_id < msiq_state_p->msiq_1st_msiq_id) || (msiq_id >=
284 	    (msiq_state_p->msiq_1st_msiq_id + msiq_state_p->msiq_cnt))) {
285 		DBG(DBG_MSIQ, px_p->px_dip,
286 		    "px_msiq_free: Invalid msiq_id 0x%x", msiq_id);
287 
288 		mutex_exit(&msiq_state_p->msiq_mutex);
289 		return (DDI_FAILURE);
290 	}
291 
292 	if (--msiq_state_p->msiq_p[msiq_id].msiq_refcnt == 0)
293 		msiq_state_p->msiq_p[msiq_id].msiq_state = MSIQ_STATE_FREE;
294 
295 	mutex_exit(&msiq_state_p->msiq_mutex);
296 	return (DDI_SUCCESS);
297 }
298 
299 /*
300  * px_msiq_redist()
301  */
302 void
303 px_msiq_redist(px_t *px_p)
304 {
305 	px_ib_t		*ib_p = px_p->px_ib_p;
306 	px_msiq_state_t	*msiq_state_p = &ib_p->ib_msiq_state;
307 	px_ino_t	*ino_p;
308 	int		i;
309 
310 	ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
311 
312 	mutex_enter(&msiq_state_p->msiq_mutex);
313 
314 	if (msiq_state_p->msiq_redist_flag == B_FALSE) {
315 		mutex_exit(&msiq_state_p->msiq_mutex);
316 		return;
317 	}
318 
319 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
320 		ino_p = px_ib_locate_ino(ib_p,
321 		    px_msiqid_to_devino(px_p, msiq_state_p->msiq_p[i].msiq_id));
322 
323 		if (ino_p) {
324 			ino_p->ino_cpuid = ino_p->ino_default_cpuid =
325 			    intr_dist_cpuid();
326 
327 			DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_redist: "
328 			    "sysino 0x%llx current cpuid 0x%x "
329 			    "default cpuid 0x%x\n", ino_p->ino_sysino,
330 			    ino_p->ino_cpuid, ino_p->ino_default_cpuid);
331 		}
332 	}
333 
334 	msiq_state_p->msiq_redist_flag = B_FALSE;
335 	mutex_exit(&msiq_state_p->msiq_mutex);
336 }
337 
338 /*
339  * px_msiqid_to_devino()
340  */
341 devino_t
342 px_msiqid_to_devino(px_t *px_p, msiqid_t msiq_id)
343 {
344 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
345 	devino_t	devino;
346 
347 	devino = msiq_state_p->msiq_1st_devino +
348 	    msiq_id - msiq_state_p->msiq_1st_msiq_id;
349 
350 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiqid_to_devino: "
351 	    "msiq_id 0x%x devino 0x%x\n", msiq_id, devino);
352 
353 	return (devino);
354 }
355 
356 /*
357  * px_devino_to_msiqid()
358  */
359 msiqid_t
360 px_devino_to_msiqid(px_t *px_p, devino_t devino)
361 {
362 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
363 	msiqid_t	msiq_id;
364 
365 	msiq_id = msiq_state_p->msiq_1st_msiq_id +
366 	    devino - msiq_state_p->msiq_1st_devino;
367 
368 	DBG(DBG_MSIQ, px_p->px_dip, "px_devino_to_msiq: "
369 	    "devino 0x%x msiq_id 0x%x\n", devino, msiq_id);
370 
371 	return (msiq_id);
372 }
373 
374 /*
375  * px_msiq_get_props()
376  */
377 static void
378 px_msiq_get_props(px_t *px_p)
379 {
380 	px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
381 	int	ret = DDI_SUCCESS;
382 	int	length = sizeof (int);
383 	char	*valuep = NULL;
384 
385 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_get_props\n");
386 
387 	/* #msi-eqs */
388 	msiq_state_p->msiq_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
389 	    DDI_PROP_DONTPASS, "#msi-eqs", PX_DEFAULT_MSIQ_CNT);
390 
391 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_cnt=%d\n",
392 	    msiq_state_p->msiq_cnt);
393 
394 	/* msi-eq-size */
395 	msiq_state_p->msiq_rec_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
396 	    DDI_PROP_DONTPASS, "msi-eq-size", PX_DEFAULT_MSIQ_REC_CNT);
397 
398 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_rec_cnt=%d\n",
399 	    msiq_state_p->msiq_rec_cnt);
400 
401 	/* msi-eq-to-devino: msi-eq#, devino# fields */
402 	ret = ddi_prop_op(DDI_DEV_T_ANY, px_p->px_dip, PROP_LEN_AND_VAL_ALLOC,
403 	    DDI_PROP_DONTPASS, "msi-eq-to-devino", (caddr_t)&valuep,
404 	    &length);
405 
406 	if (ret == DDI_PROP_SUCCESS) {
407 		msiq_state_p->msiq_1st_msiq_id =
408 		    ((px_msi_eq_to_devino_t *)valuep)->msi_eq_no;
409 		msiq_state_p->msiq_1st_devino =
410 		    ((px_msi_eq_to_devino_t *)valuep)->devino_no;
411 		kmem_free(valuep, (size_t)length);
412 	} else {
413 		msiq_state_p->msiq_1st_msiq_id = PX_DEFAULT_MSIQ_1ST_MSIQ_ID;
414 		msiq_state_p->msiq_1st_devino = PX_DEFAULT_MSIQ_1ST_DEVINO;
415 	}
416 
417 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_msiq_id=%d\n",
418 	    msiq_state_p->msiq_1st_msiq_id);
419 
420 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_devino=%d\n",
421 	    msiq_state_p->msiq_1st_devino);
422 }
423