xref: /illumos-gate/usr/src/uts/sun4/io/px/px_msiq.c (revision b2b3ca14)
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 /*
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/modctl.h>
36 #include <sys/disp.h>
37 #include <sys/stat.h>
38 #include <sys/ddi_impldefs.h>
39 #include "px_obj.h"
40 
41 static void px_msiq_get_props(px_t *px_p);
42 
43 /*
44  * px_msiq_attach()
45  */
46 int
47 px_msiq_attach(px_t *px_p)
48 {
49 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
50 	int		i, ret = DDI_SUCCESS;
51 
52 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_attach\n");
53 
54 	/*
55 	 * Check for all MSIQ related properties and
56 	 * save all information.
57 	 *
58 	 * Avaialble MSIQs and its properties.
59 	 */
60 	px_msiq_get_props(px_p);
61 
62 	/*
63 	 * 10% of available MSIQs are reserved for the PCIe messages.
64 	 * Around 90% of available MSIQs are reserved for the MSI/Xs.
65 	 */
66 	msiq_state_p->msiq_msg_qcnt = howmany(msiq_state_p->msiq_cnt, 10);
67 	msiq_state_p->msiq_msi_qcnt = msiq_state_p->msiq_cnt -
68 	    msiq_state_p->msiq_msg_qcnt;
69 
70 	msiq_state_p->msiq_1st_msi_qid = msiq_state_p->msiq_1st_msiq_id;
71 	msiq_state_p->msiq_next_msi_qid = msiq_state_p->msiq_1st_msi_qid;
72 
73 	msiq_state_p->msiq_1st_msg_qid = msiq_state_p->msiq_1st_msiq_id +
74 	    msiq_state_p->msiq_msi_qcnt;
75 	msiq_state_p->msiq_next_msg_qid = msiq_state_p->msiq_1st_msg_qid;
76 
77 	mutex_init(&msiq_state_p->msiq_mutex, NULL, MUTEX_DRIVER, NULL);
78 	msiq_state_p->msiq_p = kmem_zalloc(msiq_state_p->msiq_cnt *
79 	    sizeof (px_msiq_t), KM_SLEEP);
80 
81 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
82 		msiq_state_p->msiq_p[i].msiq_id =
83 		    msiq_state_p->msiq_1st_msiq_id + i;
84 		msiq_state_p->msiq_p[i].msiq_refcnt = 0;
85 		msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_FREE;
86 	}
87 
88 	if ((ret = px_lib_msiq_init(px_p->px_dip)) != DDI_SUCCESS)
89 		px_msiq_detach(px_p);
90 
91 	return (ret);
92 }
93 
94 /*
95  * px_msiq_detach()
96  */
97 void
98 px_msiq_detach(px_t *px_p)
99 {
100 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
101 
102 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_detach\n");
103 
104 	if (px_lib_msiq_fini(px_p->px_dip) != DDI_SUCCESS) {
105 		DBG(DBG_MSIQ, px_p->px_dip,
106 		    "px_lib_msiq_fini: failed\n");
107 	}
108 
109 	mutex_destroy(&msiq_state_p->msiq_mutex);
110 	kmem_free(msiq_state_p->msiq_p,
111 	    msiq_state_p->msiq_cnt * sizeof (px_msiq_t));
112 
113 	bzero(&px_p->px_ib_p->ib_msiq_state, sizeof (px_msiq_state_t));
114 }
115 
116 /*
117  * px_msiq_detach()
118  */
119 void
120 px_msiq_resume(px_t *px_p)
121 {
122 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
123 	int		i;
124 
125 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
126 		(void) px_lib_msiq_gethead(px_p->px_dip, i,
127 		    &msiq_state_p->msiq_p[i].msiq_curr_head_index);
128 		msiq_state_p->msiq_p[i].msiq_new_head_index = 0;
129 		msiq_state_p->msiq_p[i].msiq_recs2process = 0;
130 	}
131 }
132 
133 /*
134  * px_msiq_alloc()
135  */
136 int
137 px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type, msiqid_t *msiq_id_p)
138 {
139 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
140 	msiqid_t	first_msiq_id, *next_msiq_index;
141 	uint_t		msiq_cnt;
142 	int		i;
143 
144 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc\n");
145 
146 	mutex_enter(&msiq_state_p->msiq_mutex);
147 
148 	if (rec_type == MSG_REC) {
149 		msiq_cnt = msiq_state_p->msiq_msg_qcnt;
150 		first_msiq_id = msiq_state_p->msiq_1st_msg_qid;
151 		next_msiq_index = &msiq_state_p->msiq_next_msg_qid;
152 	} else {
153 		msiq_cnt = msiq_state_p->msiq_msi_qcnt;
154 		first_msiq_id = msiq_state_p->msiq_1st_msi_qid;
155 		next_msiq_index = &msiq_state_p->msiq_next_msi_qid;
156 	}
157 
158 	/* Allocate MSIQs */
159 	for (i = first_msiq_id; i < (first_msiq_id + msiq_cnt); i++) {
160 		if (msiq_state_p->msiq_p[i].msiq_state == MSIQ_STATE_FREE) {
161 			msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_INUSE;
162 			msiq_state_p->msiq_p[i].msiq_refcnt = 1;
163 			(void) px_lib_msiq_gethead(px_p->px_dip, i,
164 			    &msiq_state_p->msiq_p[i].msiq_curr_head_index);
165 			break;
166 		}
167 	}
168 
169 	/*
170 	 * There are no free MSIQ.
171 	 * Use next available MSIQ.
172 	 */
173 	if (i >= (first_msiq_id + msiq_cnt)) {
174 		i = *next_msiq_index;
175 		msiq_state_p->msiq_p[i].msiq_refcnt++;
176 	}
177 
178 	*msiq_id_p = msiq_state_p->msiq_p[i].msiq_id;
179 	DBG(DBG_MSIQ, px_p->px_dip,
180 	    "px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p);
181 
182 	(*next_msiq_index)++;
183 
184 	if (*next_msiq_index >= (first_msiq_id + msiq_cnt))
185 		*next_msiq_index = first_msiq_id;
186 
187 	mutex_exit(&msiq_state_p->msiq_mutex);
188 	return (DDI_SUCCESS);
189 }
190 
191 /*
192  * px_msiq_free()
193  */
194 int
195 px_msiq_free(px_t *px_p, msiqid_t msiq_id)
196 {
197 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
198 
199 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_free: msiq_id 0x%x", msiq_id);
200 
201 	mutex_enter(&msiq_state_p->msiq_mutex);
202 
203 	if ((msiq_id < msiq_state_p->msiq_1st_msiq_id) || (msiq_id >=
204 	    (msiq_state_p->msiq_1st_msiq_id + msiq_state_p->msiq_cnt))) {
205 		DBG(DBG_MSIQ, px_p->px_dip,
206 		    "px_msiq_free: Invalid msiq_id 0x%x", msiq_id);
207 		return (DDI_FAILURE);
208 	}
209 
210 	if (--msiq_state_p->msiq_p[msiq_id].msiq_refcnt == 0)
211 		msiq_state_p->msiq_p[msiq_id].msiq_state = MSIQ_STATE_FREE;
212 
213 	mutex_exit(&msiq_state_p->msiq_mutex);
214 	return (DDI_SUCCESS);
215 }
216 
217 /*
218  * px_msiqid_to_devino()
219  */
220 devino_t
221 px_msiqid_to_devino(px_t *px_p, msiqid_t msiq_id)
222 {
223 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
224 	devino_t	devino;
225 
226 	devino = msiq_state_p->msiq_1st_devino +
227 	    msiq_id - msiq_state_p->msiq_1st_msiq_id;
228 
229 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiqid_to_devino: "
230 	    "msiq_id 0x%x devino 0x%x\n", msiq_id, devino);
231 
232 	return (devino);
233 }
234 
235 /*
236  * px_devino_to_msiqid()
237  */
238 msiqid_t
239 px_devino_to_msiqid(px_t *px_p, devino_t devino)
240 {
241 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
242 	msiqid_t	msiq_id;
243 
244 	msiq_id = msiq_state_p->msiq_1st_msiq_id +
245 	    devino - msiq_state_p->msiq_1st_devino;
246 
247 	DBG(DBG_MSIQ, px_p->px_dip, "px_devino_to_msiq: "
248 	    "devino 0x%x msiq_id 0x%x\n", devino, msiq_id);
249 
250 	return (msiq_id);
251 }
252 
253 /*
254  * px_msiq_get_props()
255  */
256 static void
257 px_msiq_get_props(px_t *px_p)
258 {
259 	px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
260 	int	ret = DDI_SUCCESS;
261 	int	length = sizeof (int);
262 	char	*valuep = NULL;
263 
264 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_get_props\n");
265 
266 	/* #msi-eqs */
267 	msiq_state_p->msiq_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
268 	    DDI_PROP_DONTPASS, "#msi-eqs", PX_DEFAULT_MSIQ_CNT);
269 
270 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_cnt=%d\n",
271 	    msiq_state_p->msiq_cnt);
272 
273 	/* msi-eq-size */
274 	msiq_state_p->msiq_rec_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
275 	    DDI_PROP_DONTPASS, "msi-eq-size", PX_DEFAULT_MSIQ_REC_CNT);
276 
277 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_rec_cnt=%d\n",
278 	    msiq_state_p->msiq_rec_cnt);
279 
280 	/* msi-eq-to-devino: msi-eq#, devino# fields */
281 	ret = ddi_prop_op(DDI_DEV_T_ANY, px_p->px_dip, PROP_LEN_AND_VAL_ALLOC,
282 	    DDI_PROP_DONTPASS, "msi-eq-to-devino", (caddr_t)&valuep,
283 	    &length);
284 
285 	if (ret == DDI_PROP_SUCCESS) {
286 		msiq_state_p->msiq_1st_msiq_id =
287 		    ((px_msi_eq_to_devino_t *)valuep)->msi_eq_no;
288 		msiq_state_p->msiq_1st_devino =
289 		    ((px_msi_eq_to_devino_t *)valuep)->devino_no;
290 		kmem_free(valuep, (size_t)length);
291 	} else {
292 		msiq_state_p->msiq_1st_msiq_id = PX_DEFAULT_MSIQ_1ST_MSIQ_ID;
293 		msiq_state_p->msiq_1st_devino = PX_DEFAULT_MSIQ_1ST_DEVINO;
294 	}
295 
296 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_msiq_id=%d\n",
297 	    msiq_state_p->msiq_1st_msiq_id);
298 
299 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_devino=%d\n",
300 	    msiq_state_p->msiq_1st_devino);
301 }
302