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