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