xref: /illumos-gate/usr/src/uts/sun4/io/px/px_msiq.c (revision 825ba0f20a74fd9c5d0d1ce2c195da2cc88a7f77)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * px_msiq.c
30  */
31 
32 #include <sys/types.h>
33 #include <sys/kmem.h>
34 #include <sys/conf.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
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_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
52 	size_t		msiq_size;
53 	int		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 	msiq_state_p->msiq_msi_qcnt = msiq_state_p->msiq_cnt -
71 	    msiq_state_p->msiq_msg_qcnt;
72 
73 	msiq_state_p->msiq_1st_msi_qid = msiq_state_p->msiq_1st_msiq_id;
74 	msiq_state_p->msiq_next_msi_qid = msiq_state_p->msiq_1st_msi_qid;
75 
76 	msiq_state_p->msiq_1st_msg_qid = msiq_state_p->msiq_1st_msiq_id +
77 	    msiq_state_p->msiq_msi_qcnt;
78 	msiq_state_p->msiq_next_msg_qid = msiq_state_p->msiq_1st_msg_qid;
79 
80 	mutex_init(&msiq_state_p->msiq_mutex, NULL, MUTEX_DRIVER, NULL);
81 	msiq_state_p->msiq_p = kmem_zalloc(msiq_state_p->msiq_cnt *
82 	    sizeof (px_msiq_t), KM_SLEEP);
83 	msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
84 	msiq_state_p->msiq_buf_p = kmem_zalloc(msiq_state_p->msiq_cnt *
85 	    msiq_size, KM_SLEEP);
86 
87 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
88 		msiq_state_p->msiq_p[i].msiq_id =
89 		    msiq_state_p->msiq_1st_msiq_id + i;
90 		msiq_state_p->msiq_p[i].msiq_refcnt = 0;
91 		msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_FREE;
92 
93 		msiq_state_p->msiq_p[i].msiq_base_p = (msiqhead_t *)
94 		    ((caddr_t)msiq_state_p->msiq_buf_p + (i * msiq_size));
95 	}
96 
97 	if ((ret = px_lib_msiq_init(px_p->px_dip)) != DDI_SUCCESS)
98 		px_msiq_detach(px_p);
99 
100 	return (ret);
101 }
102 
103 /*
104  * px_msiq_detach()
105  */
106 void
107 px_msiq_detach(px_t *px_p)
108 {
109 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
110 
111 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_detach\n");
112 
113 	if (px_lib_msiq_fini(px_p->px_dip) != DDI_SUCCESS) {
114 		DBG(DBG_MSIQ, px_p->px_dip,
115 		    "px_lib_msiq_fini: failed\n");
116 	}
117 	kmem_free(msiq_state_p->msiq_buf_p, msiq_state_p->msiq_cnt *
118 	    msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t));
119 
120 	mutex_destroy(&msiq_state_p->msiq_mutex);
121 	kmem_free(msiq_state_p->msiq_p,
122 	    msiq_state_p->msiq_cnt * sizeof (px_msiq_t));
123 
124 	bzero(&px_p->px_ib_p->ib_msiq_state, sizeof (px_msiq_state_t));
125 }
126 
127 /*
128  * px_msiq_detach()
129  */
130 void
131 px_msiq_resume(px_t *px_p)
132 {
133 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
134 	int		i;
135 
136 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
137 		(void) px_lib_msiq_gethead(px_p->px_dip, i,
138 		    &msiq_state_p->msiq_p[i].msiq_curr_head_index);
139 		msiq_state_p->msiq_p[i].msiq_new_head_index = 0;
140 		msiq_state_p->msiq_p[i].msiq_recs2process = 0;
141 	}
142 }
143 
144 /*
145  * px_msiq_alloc()
146  */
147 int
148 px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type, msiqid_t *msiq_id_p)
149 {
150 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
151 	msiqid_t	first_msiq_id, *next_msiq_index;
152 	uint_t		msiq_cnt;
153 	int		i;
154 
155 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc\n");
156 
157 	mutex_enter(&msiq_state_p->msiq_mutex);
158 
159 	if (rec_type == MSG_REC) {
160 		msiq_cnt = msiq_state_p->msiq_msg_qcnt;
161 		first_msiq_id = msiq_state_p->msiq_1st_msg_qid;
162 		next_msiq_index = &msiq_state_p->msiq_next_msg_qid;
163 	} else {
164 		msiq_cnt = msiq_state_p->msiq_msi_qcnt;
165 		first_msiq_id = msiq_state_p->msiq_1st_msi_qid;
166 		next_msiq_index = &msiq_state_p->msiq_next_msi_qid;
167 	}
168 
169 	/* Allocate MSIQs */
170 	for (i = first_msiq_id; i < (first_msiq_id + msiq_cnt); i++) {
171 		if (msiq_state_p->msiq_p[i].msiq_state == MSIQ_STATE_FREE) {
172 			msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_INUSE;
173 			msiq_state_p->msiq_p[i].msiq_refcnt = 1;
174 			(void) px_lib_msiq_gethead(px_p->px_dip, i,
175 			    &msiq_state_p->msiq_p[i].msiq_curr_head_index);
176 			break;
177 		}
178 	}
179 
180 	/*
181 	 * There are no free MSIQ.
182 	 * Use next available MSIQ.
183 	 */
184 	if (i >= (first_msiq_id + msiq_cnt)) {
185 		i = *next_msiq_index;
186 		msiq_state_p->msiq_p[i].msiq_refcnt++;
187 	}
188 
189 	*msiq_id_p = msiq_state_p->msiq_p[i].msiq_id;
190 	DBG(DBG_MSIQ, px_p->px_dip,
191 	    "px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p);
192 
193 	(*next_msiq_index)++;
194 
195 	if (*next_msiq_index >= (first_msiq_id + msiq_cnt))
196 		*next_msiq_index = first_msiq_id;
197 
198 	mutex_exit(&msiq_state_p->msiq_mutex);
199 	return (DDI_SUCCESS);
200 }
201 
202 /*
203  * px_msiq_free()
204  */
205 int
206 px_msiq_free(px_t *px_p, msiqid_t msiq_id)
207 {
208 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
209 
210 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_free: msiq_id 0x%x", msiq_id);
211 
212 	mutex_enter(&msiq_state_p->msiq_mutex);
213 
214 	if ((msiq_id < msiq_state_p->msiq_1st_msiq_id) || (msiq_id >=
215 	    (msiq_state_p->msiq_1st_msiq_id + msiq_state_p->msiq_cnt))) {
216 		DBG(DBG_MSIQ, px_p->px_dip,
217 		    "px_msiq_free: Invalid msiq_id 0x%x", msiq_id);
218 		return (DDI_FAILURE);
219 	}
220 
221 	if (--msiq_state_p->msiq_p[msiq_id].msiq_refcnt == 0)
222 		msiq_state_p->msiq_p[msiq_id].msiq_state = MSIQ_STATE_FREE;
223 
224 	mutex_exit(&msiq_state_p->msiq_mutex);
225 	return (DDI_SUCCESS);
226 }
227 
228 /*
229  * px_msiqid_to_devino()
230  */
231 devino_t
232 px_msiqid_to_devino(px_t *px_p, msiqid_t msiq_id)
233 {
234 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
235 	devino_t	devino;
236 
237 	devino = msiq_state_p->msiq_1st_devino +
238 	    msiq_id - msiq_state_p->msiq_1st_msiq_id;
239 
240 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiqid_to_devino: "
241 	    "msiq_id 0x%x devino 0x%x\n", msiq_id, devino);
242 
243 	return (devino);
244 }
245 
246 /*
247  * px_devino_to_msiqid()
248  */
249 msiqid_t
250 px_devino_to_msiqid(px_t *px_p, devino_t devino)
251 {
252 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
253 	msiqid_t	msiq_id;
254 
255 	msiq_id = msiq_state_p->msiq_1st_msiq_id +
256 	    devino - msiq_state_p->msiq_1st_devino;
257 
258 	DBG(DBG_MSIQ, px_p->px_dip, "px_devino_to_msiq: "
259 	    "devino 0x%x msiq_id 0x%x\n", devino, msiq_id);
260 
261 	return (msiq_id);
262 }
263 
264 /*
265  * px_msiq_get_props()
266  */
267 static void
268 px_msiq_get_props(px_t *px_p)
269 {
270 	px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
271 	int	ret = DDI_SUCCESS;
272 	int	length = sizeof (int);
273 	char	*valuep = NULL;
274 
275 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_get_props\n");
276 
277 	/* #msi-eqs */
278 	msiq_state_p->msiq_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
279 	    DDI_PROP_DONTPASS, "#msi-eqs", PX_DEFAULT_MSIQ_CNT);
280 
281 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_cnt=%d\n",
282 	    msiq_state_p->msiq_cnt);
283 
284 	/* msi-eq-size */
285 	msiq_state_p->msiq_rec_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
286 	    DDI_PROP_DONTPASS, "msi-eq-size", PX_DEFAULT_MSIQ_REC_CNT);
287 
288 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_rec_cnt=%d\n",
289 	    msiq_state_p->msiq_rec_cnt);
290 
291 	/* msi-eq-to-devino: msi-eq#, devino# fields */
292 	ret = ddi_prop_op(DDI_DEV_T_ANY, px_p->px_dip, PROP_LEN_AND_VAL_ALLOC,
293 	    DDI_PROP_DONTPASS, "msi-eq-to-devino", (caddr_t)&valuep,
294 	    &length);
295 
296 	if (ret == DDI_PROP_SUCCESS) {
297 		msiq_state_p->msiq_1st_msiq_id =
298 		    ((px_msi_eq_to_devino_t *)valuep)->msi_eq_no;
299 		msiq_state_p->msiq_1st_devino =
300 		    ((px_msi_eq_to_devino_t *)valuep)->devino_no;
301 		kmem_free(valuep, (size_t)length);
302 	} else {
303 		msiq_state_p->msiq_1st_msiq_id = PX_DEFAULT_MSIQ_1ST_MSIQ_ID;
304 		msiq_state_p->msiq_1st_devino = PX_DEFAULT_MSIQ_1ST_DEVINO;
305 	}
306 
307 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_msiq_id=%d\n",
308 	    msiq_state_p->msiq_1st_msiq_id);
309 
310 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_devino=%d\n",
311 	    msiq_state_p->msiq_1st_devino);
312 }
313