xref: /illumos-gate/usr/src/uts/sun4/io/px/px_msiq.c (revision 3db86aab)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * px_msiq.c
31  */
32 
33 #include <sys/types.h>
34 #include <sys/kmem.h>
35 #include <sys/conf.h>
36 #include <sys/ddi.h>
37 #include <sys/sunddi.h>
38 #include <sys/modctl.h>
39 #include <sys/disp.h>
40 #include <sys/stat.h>
41 #include <sys/ddi_impldefs.h>
42 #include "px_obj.h"
43 
44 static void px_msiq_get_props(px_t *px_p);
45 
46 /*
47  * px_msiq_attach()
48  */
49 int
50 px_msiq_attach(px_t *px_p)
51 {
52 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
53 	caddr_t		msiq_addr;
54 	size_t		msiq_size;
55 	int		i, ret = DDI_SUCCESS;
56 
57 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_attach\n");
58 
59 	/*
60 	 * Check for all MSIQ related properties and
61 	 * save all information.
62 	 *
63 	 * Avaialble MSIQs and its properties.
64 	 */
65 	px_msiq_get_props(px_p);
66 
67 	/*
68 	 * 10% of available MSIQs are reserved for the PCIe messages.
69 	 * Around 90% of available MSIQs are reserved for the MSI/Xs.
70 	 */
71 	msiq_state_p->msiq_msg_qcnt = howmany(msiq_state_p->msiq_cnt, 10);
72 	msiq_state_p->msiq_msi_qcnt = msiq_state_p->msiq_cnt -
73 	    msiq_state_p->msiq_msg_qcnt;
74 
75 	msiq_state_p->msiq_1st_msi_qid = msiq_state_p->msiq_1st_msiq_id;
76 	msiq_state_p->msiq_next_msi_qid = msiq_state_p->msiq_1st_msi_qid;
77 
78 	msiq_state_p->msiq_1st_msg_qid = msiq_state_p->msiq_1st_msiq_id +
79 	    msiq_state_p->msiq_msi_qcnt;
80 	msiq_state_p->msiq_next_msg_qid = msiq_state_p->msiq_1st_msg_qid;
81 
82 	mutex_init(&msiq_state_p->msiq_mutex, NULL, MUTEX_DRIVER, NULL);
83 	msiq_state_p->msiq_p = kmem_zalloc(msiq_state_p->msiq_cnt *
84 	    sizeof (px_msiq_t), KM_SLEEP);
85 
86 	msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
87 	msiq_state_p->msiq_buf_p = kmem_zalloc(msiq_state_p->msiq_cnt *
88 	    msiq_size, KM_SLEEP);
89 
90 	msiq_addr = (caddr_t)(((uint64_t)msiq_state_p->msiq_buf_p +
91 	    (MMU_PAGE_SIZE - 1)) >> MMU_PAGE_SHIFT << MMU_PAGE_SHIFT);
92 
93 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
94 		msiq_state_p->msiq_p[i].msiq_id =
95 		    msiq_state_p->msiq_1st_msiq_id + i;
96 		msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_FREE;
97 
98 		msiq_state_p->msiq_p[i].msiq_base = (uint64_t)
99 		    ((caddr_t)msiq_addr + (i * msiq_size));
100 		msiq_state_p->msiq_p[i].msiq_curr =
101 		    msiq_state_p->msiq_p[i].msiq_base;
102 	}
103 
104 	if ((ret = px_lib_msiq_init(px_p->px_dip)) != DDI_SUCCESS)
105 		px_msiq_detach(px_p);
106 
107 	return (ret);
108 }
109 
110 /*
111  * px_msiq_detach()
112  */
113 void
114 px_msiq_detach(px_t *px_p)
115 {
116 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
117 
118 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_detach\n");
119 
120 	(void) px_lib_msiq_fini(px_p->px_dip);
121 	kmem_free(msiq_state_p->msiq_buf_p, msiq_state_p->msiq_cnt *
122 	    msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t));
123 
124 	mutex_destroy(&msiq_state_p->msiq_mutex);
125 	kmem_free(msiq_state_p->msiq_p,
126 	    msiq_state_p->msiq_cnt * sizeof (px_msiq_t));
127 
128 	bzero(&px_p->px_ib_p->ib_msiq_state, sizeof (px_msiq_state_t));
129 }
130 
131 /*
132  * px_msiq_alloc()
133  */
134 int
135 px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type, msiqid_t *msiq_id_p)
136 {
137 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
138 	msiqid_t	first_msiq_id, *next_msiq_index;
139 	uint_t		msiq_cnt;
140 	int		i;
141 
142 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc\n");
143 
144 	mutex_enter(&msiq_state_p->msiq_mutex);
145 
146 	if (rec_type == MSG_REC) {
147 		msiq_cnt = msiq_state_p->msiq_msg_qcnt;
148 		first_msiq_id = msiq_state_p->msiq_1st_msg_qid;
149 		next_msiq_index = &msiq_state_p->msiq_next_msg_qid;
150 	} else {
151 		msiq_cnt = msiq_state_p->msiq_msi_qcnt;
152 		first_msiq_id = msiq_state_p->msiq_1st_msi_qid;
153 		next_msiq_index = &msiq_state_p->msiq_next_msi_qid;
154 	}
155 
156 	/* Allocate MSIQs */
157 	for (i = first_msiq_id; i < (first_msiq_id + msiq_cnt); i++) {
158 		if (msiq_state_p->msiq_p[i].msiq_state == MSIQ_STATE_FREE) {
159 			msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_INUSE;
160 			break;
161 		}
162 	}
163 
164 	/*
165 	 * There are no free MSIQ.
166 	 * Use next available MSIQ.
167 	 */
168 	if (i >= (first_msiq_id + msiq_cnt))
169 		i = *next_msiq_index;
170 
171 	*msiq_id_p = msiq_state_p->msiq_p[i].msiq_id;
172 	DBG(DBG_MSIQ, px_p->px_dip,
173 	    "px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p);
174 
175 	(*next_msiq_index)++;
176 
177 	if (*next_msiq_index >= (first_msiq_id + msiq_cnt))
178 		*next_msiq_index = first_msiq_id;
179 
180 	mutex_exit(&msiq_state_p->msiq_mutex);
181 	return (DDI_SUCCESS);
182 }
183 
184 /*
185  * px_msiq_free()
186  */
187 int
188 px_msiq_free(px_t *px_p, msiqid_t msiq_id)
189 {
190 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
191 	int		i, ret = DDI_SUCCESS;
192 
193 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_free: msiq_id 0x%x", msiq_id);
194 
195 	mutex_enter(&msiq_state_p->msiq_mutex);
196 
197 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
198 		if (msiq_state_p->msiq_p[i].msiq_id == msiq_id) {
199 			msiq_state_p->msiq_p[i].msiq_curr =
200 			    msiq_state_p->msiq_p[i].msiq_base;
201 			msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_FREE;
202 			break;
203 		}
204 	}
205 
206 	if (i >= msiq_state_p->msiq_cnt) {
207 		DBG(DBG_MSIQ, px_p->px_dip,
208 		    "px_msiq_free: Invalid msiq_id 0x%x", msiq_id);
209 		ret = DDI_FAILURE;
210 	}
211 
212 	mutex_exit(&msiq_state_p->msiq_mutex);
213 	return (ret);
214 }
215 
216 /*
217  * px_msiqid_to_devino()
218  */
219 devino_t
220 px_msiqid_to_devino(px_t *px_p, msiqid_t msiq_id)
221 {
222 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
223 	devino_t	devino;
224 
225 	devino = msiq_state_p->msiq_1st_devino +
226 	    msiq_id - msiq_state_p->msiq_1st_msiq_id;
227 
228 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiqid_to_devino: "
229 	    "msiq_id 0x%x devino 0x%x\n", msiq_id, devino);
230 
231 	return (devino);
232 }
233 
234 /*
235  * px_devino_to_msiqid()
236  */
237 msiqid_t
238 px_devino_to_msiqid(px_t *px_p, devino_t devino)
239 {
240 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
241 	msiqid_t	msiq_id;
242 
243 	msiq_id = msiq_state_p->msiq_1st_msiq_id +
244 	    devino - msiq_state_p->msiq_1st_devino;
245 
246 	DBG(DBG_MSIQ, px_p->px_dip, "px_devino_to_msiq: "
247 	    "devino 0x%x msiq_id 0x%x\n", devino, msiq_id);
248 
249 	return (msiq_id);
250 }
251 
252 /*
253  * px_msiq_get_props()
254  */
255 static void
256 px_msiq_get_props(px_t *px_p)
257 {
258 	px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
259 	int	ret = DDI_SUCCESS;
260 	int	length = sizeof (int);
261 	char	*valuep = NULL;
262 
263 	DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_get_props\n");
264 
265 	/* #msi-eqs */
266 	msiq_state_p->msiq_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
267 	    DDI_PROP_DONTPASS, "#msi-eqs", PX_DEFAULT_MSIQ_CNT);
268 
269 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_cnt=%d\n",
270 	    msiq_state_p->msiq_cnt);
271 
272 	/* msi-eq-size */
273 	msiq_state_p->msiq_rec_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip,
274 	    DDI_PROP_DONTPASS, "msi-eq-size", PX_DEFAULT_MSIQ_REC_CNT);
275 
276 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_rec_cnt=%d\n",
277 	    msiq_state_p->msiq_rec_cnt);
278 
279 	/* msi-eq-to-devino: msi-eq#, devino# fields */
280 	ret = ddi_prop_op(DDI_DEV_T_ANY, px_p->px_dip, PROP_LEN_AND_VAL_ALLOC,
281 	    DDI_PROP_DONTPASS, "msi-eq-to-devino", (caddr_t)&valuep,
282 	    &length);
283 
284 	if (ret == DDI_PROP_SUCCESS) {
285 		msiq_state_p->msiq_1st_msiq_id =
286 		    ((px_msi_eq_to_devino_t *)valuep)->msi_eq_no;
287 		msiq_state_p->msiq_1st_devino =
288 		    ((px_msi_eq_to_devino_t *)valuep)->devino_no;
289 		kmem_free(valuep, (size_t)length);
290 	} else {
291 		msiq_state_p->msiq_1st_msiq_id = PX_DEFAULT_MSIQ_1ST_MSIQ_ID;
292 		msiq_state_p->msiq_1st_devino = PX_DEFAULT_MSIQ_1ST_DEVINO;
293 	}
294 
295 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_msiq_id=%d\n",
296 	    msiq_state_p->msiq_1st_msiq_id);
297 
298 	DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_devino=%d\n",
299 	    msiq_state_p->msiq_1st_devino);
300 }
301