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