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 2009 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/sysmacros.h> 36 #include <sys/machsystm.h> /* intr_dist_add */ 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_ib_t *ib_p = px_p->px_ib_p; 52 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state; 53 int qcnt, 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 71 qcnt = MIN(msiq_state_p->msiq_msg_qcnt, px_max_msiq_msgs); 72 msiq_state_p->msiq_msg_qcnt = qcnt = MAX(qcnt, px_min_msiq_msgs); 73 msiq_state_p->msiq_msi_qcnt = msiq_state_p->msiq_cnt - qcnt; 74 75 msiq_state_p->msiq_1st_msi_qid = msiq_state_p->msiq_1st_msiq_id; 76 msiq_state_p->msiq_1st_msg_qid = msiq_state_p->msiq_1st_msiq_id + 77 msiq_state_p->msiq_msi_qcnt; 78 79 mutex_init(&msiq_state_p->msiq_mutex, NULL, MUTEX_DRIVER, NULL); 80 msiq_state_p->msiq_p = kmem_zalloc(msiq_state_p->msiq_cnt * 81 sizeof (px_msiq_t), KM_SLEEP); 82 83 for (i = 0; i < msiq_state_p->msiq_cnt; i++) { 84 msiq_state_p->msiq_p[i].msiq_id = 85 msiq_state_p->msiq_1st_msiq_id + i; 86 msiq_state_p->msiq_p[i].msiq_refcnt = 0; 87 msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_FREE; 88 (void) px_ib_alloc_ino(ib_p, px_msiqid_to_devino(px_p, 89 msiq_state_p->msiq_p[i].msiq_id)); 90 } 91 92 if ((ret = px_lib_msiq_init(px_p->px_dip)) != DDI_SUCCESS) 93 px_msiq_detach(px_p); 94 95 msiq_state_p->msiq_redist_flag = B_TRUE; 96 return (ret); 97 } 98 99 /* 100 * px_msiq_detach() 101 */ 102 void 103 px_msiq_detach(px_t *px_p) 104 { 105 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 106 107 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_detach\n"); 108 109 if (px_lib_msiq_fini(px_p->px_dip) != DDI_SUCCESS) { 110 DBG(DBG_MSIQ, px_p->px_dip, 111 "px_lib_msiq_fini: failed\n"); 112 } 113 114 mutex_destroy(&msiq_state_p->msiq_mutex); 115 kmem_free(msiq_state_p->msiq_p, 116 msiq_state_p->msiq_cnt * sizeof (px_msiq_t)); 117 118 bzero(msiq_state_p, sizeof (px_msiq_state_t)); 119 } 120 121 /* 122 * px_msiq_resume() 123 */ 124 void 125 px_msiq_resume(px_t *px_p) 126 { 127 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 128 int i; 129 130 for (i = 0; i < msiq_state_p->msiq_cnt; i++) { 131 (void) px_lib_msiq_gethead(px_p->px_dip, 132 msiq_state_p->msiq_p[i].msiq_id, 133 &msiq_state_p->msiq_p[i].msiq_curr_head_index); 134 msiq_state_p->msiq_p[i].msiq_new_head_index = 0; 135 msiq_state_p->msiq_p[i].msiq_recs2process = 0; 136 } 137 } 138 139 /* 140 * px_msiq_alloc() 141 */ 142 int 143 px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type, msgcode_t msg_code, 144 msiqid_t *msiq_id_p) 145 { 146 px_ib_t *ib_p = px_p->px_ib_p; 147 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state; 148 msiqid_t first_msiq_id; 149 uint_t msiq_cnt; 150 ushort_t least_refcnt; 151 int i; 152 153 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc\n"); 154 155 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 156 mutex_enter(&msiq_state_p->msiq_mutex); 157 158 if (rec_type == MSG_REC) { 159 /* 160 * The first MSG EQ is dedicated to PCIE_MSG_CODE_ERR_COR 161 * messages. All other messages will be spread across 162 * the remaining MSG EQs. 163 */ 164 first_msiq_id = msiq_state_p->msiq_1st_msg_qid; 165 166 if (msg_code == PCIE_MSG_CODE_ERR_COR) { 167 msiq_state_p->msiq_p[first_msiq_id].msiq_state = 168 MSIQ_STATE_INUSE; 169 170 (void) px_lib_msiq_gethead(px_p->px_dip, first_msiq_id, 171 &msiq_state_p->msiq_p[first_msiq_id]. 172 msiq_curr_head_index); 173 174 *msiq_id_p = 175 msiq_state_p->msiq_p[first_msiq_id].msiq_id; 176 177 msiq_state_p->msiq_p[first_msiq_id].msiq_refcnt++; 178 179 DBG(DBG_MSIQ, px_p->px_dip, 180 "px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p); 181 182 mutex_exit(&msiq_state_p->msiq_mutex); 183 return (DDI_SUCCESS); 184 } 185 186 /* Jump past the first/dedicated EQ */ 187 first_msiq_id++; 188 msiq_cnt = msiq_state_p->msiq_msg_qcnt - 1; 189 } else { 190 msiq_cnt = msiq_state_p->msiq_msi_qcnt; 191 first_msiq_id = msiq_state_p->msiq_1st_msi_qid; 192 } 193 194 *msiq_id_p = first_msiq_id; 195 least_refcnt = msiq_state_p->msiq_p[first_msiq_id].msiq_refcnt; 196 197 /* Allocate MSIQs */ 198 for (i = first_msiq_id; i < (first_msiq_id + msiq_cnt); i++) { 199 if (msiq_state_p->msiq_p[i].msiq_state == MSIQ_STATE_FREE) { 200 msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_INUSE; 201 (void) px_lib_msiq_gethead(px_p->px_dip, i, 202 &msiq_state_p->msiq_p[i].msiq_curr_head_index); 203 *msiq_id_p = msiq_state_p->msiq_p[i].msiq_id; 204 break; 205 } 206 207 if (least_refcnt > msiq_state_p->msiq_p[i].msiq_refcnt) { 208 *msiq_id_p = msiq_state_p->msiq_p[i].msiq_id; 209 least_refcnt = msiq_state_p->msiq_p[i].msiq_refcnt; 210 } 211 } 212 213 msiq_state_p->msiq_p[*msiq_id_p].msiq_refcnt++; 214 215 DBG(DBG_MSIQ, px_p->px_dip, 216 "px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p); 217 218 mutex_exit(&msiq_state_p->msiq_mutex); 219 return (DDI_SUCCESS); 220 } 221 222 /* 223 * px_msiq_alloc_based_on_cpuid() 224 */ 225 int 226 px_msiq_alloc_based_on_cpuid(px_t *px_p, msiq_rec_type_t rec_type, 227 cpuid_t cpuid, msiqid_t *msiq_id_p) 228 { 229 px_ib_t *ib_p = px_p->px_ib_p; 230 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state; 231 msiqid_t first_msiq_id, free_msiq_id; 232 uint_t msiq_cnt; 233 ushort_t least_refcnt; 234 px_ino_t *ino_p; 235 int i; 236 237 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc_based_on_cpuid: " 238 "cpuid 0x%x\n", cpuid); 239 240 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 241 242 mutex_enter(&msiq_state_p->msiq_mutex); 243 244 if (rec_type == MSG_REC) { 245 msiq_cnt = msiq_state_p->msiq_msg_qcnt; 246 first_msiq_id = msiq_state_p->msiq_1st_msg_qid; 247 } else { 248 msiq_cnt = msiq_state_p->msiq_msi_qcnt; 249 first_msiq_id = msiq_state_p->msiq_1st_msi_qid; 250 } 251 252 *msiq_id_p = free_msiq_id = (msiqid_t)-1; 253 least_refcnt = (ushort_t)-1; 254 255 /* Allocate MSIQs */ 256 for (i = first_msiq_id; i < (first_msiq_id + msiq_cnt); i++) { 257 ino_p = px_ib_locate_ino(ib_p, px_msiqid_to_devino(px_p, i)); 258 259 if ((ino_p->ino_cpuid == cpuid) && 260 (least_refcnt > msiq_state_p->msiq_p[i].msiq_refcnt)) { 261 *msiq_id_p = msiq_state_p->msiq_p[i].msiq_id; 262 least_refcnt = msiq_state_p->msiq_p[i].msiq_refcnt; 263 } 264 265 if ((*msiq_id_p == -1) && (free_msiq_id == -1) && 266 (msiq_state_p->msiq_p[i].msiq_state == MSIQ_STATE_FREE)) 267 free_msiq_id = msiq_state_p->msiq_p[i].msiq_id; 268 } 269 270 if (*msiq_id_p == -1) { 271 if (free_msiq_id == -1) { 272 DBG(DBG_MSIQ, px_p->px_dip, 273 "px_msiq_alloc_based_on_cpuid: No EQ is available " 274 "for CPU 0x%x\n", cpuid); 275 276 mutex_exit(&msiq_state_p->msiq_mutex); 277 return (DDI_EINVAL); 278 } 279 280 *msiq_id_p = free_msiq_id; 281 ino_p = px_ib_locate_ino(ib_p, 282 px_msiqid_to_devino(px_p, *msiq_id_p)); 283 ino_p->ino_cpuid = ino_p->ino_default_cpuid = cpuid; 284 } 285 286 if (msiq_state_p->msiq_p[*msiq_id_p].msiq_state == MSIQ_STATE_FREE) { 287 msiq_state_p->msiq_p[*msiq_id_p].msiq_state = MSIQ_STATE_INUSE; 288 (void) px_lib_msiq_gethead(px_p->px_dip, *msiq_id_p, 289 &msiq_state_p->msiq_p[*msiq_id_p].msiq_curr_head_index); 290 } 291 292 msiq_state_p->msiq_p[*msiq_id_p].msiq_refcnt++; 293 294 DBG(DBG_MSIQ, px_p->px_dip, 295 "px_msiq_alloc_based_on_cpuid: msiq_id 0x%x\n", *msiq_id_p); 296 297 mutex_exit(&msiq_state_p->msiq_mutex); 298 return (DDI_SUCCESS); 299 } 300 301 /* 302 * px_msiq_free() 303 */ 304 int 305 px_msiq_free(px_t *px_p, msiqid_t msiq_id) 306 { 307 px_ib_t *ib_p = px_p->px_ib_p; 308 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state; 309 310 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_free: msiq_id 0x%x", msiq_id); 311 312 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 313 mutex_enter(&msiq_state_p->msiq_mutex); 314 315 if ((msiq_id < msiq_state_p->msiq_1st_msiq_id) || (msiq_id >= 316 (msiq_state_p->msiq_1st_msiq_id + msiq_state_p->msiq_cnt))) { 317 DBG(DBG_MSIQ, px_p->px_dip, 318 "px_msiq_free: Invalid msiq_id 0x%x", msiq_id); 319 320 mutex_exit(&msiq_state_p->msiq_mutex); 321 return (DDI_FAILURE); 322 } 323 324 if (--msiq_state_p->msiq_p[msiq_id].msiq_refcnt == 0) 325 msiq_state_p->msiq_p[msiq_id].msiq_state = MSIQ_STATE_FREE; 326 327 mutex_exit(&msiq_state_p->msiq_mutex); 328 return (DDI_SUCCESS); 329 } 330 331 /* 332 * px_msiq_redist() 333 */ 334 void 335 px_msiq_redist(px_t *px_p) 336 { 337 px_ib_t *ib_p = px_p->px_ib_p; 338 px_msiq_state_t *msiq_state_p = &ib_p->ib_msiq_state; 339 px_ino_t *ino_p; 340 int i; 341 342 ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 343 344 mutex_enter(&msiq_state_p->msiq_mutex); 345 346 if (msiq_state_p->msiq_redist_flag == B_FALSE) { 347 mutex_exit(&msiq_state_p->msiq_mutex); 348 return; 349 } 350 351 for (i = 0; i < msiq_state_p->msiq_cnt; i++) { 352 ino_p = px_ib_locate_ino(ib_p, 353 px_msiqid_to_devino(px_p, msiq_state_p->msiq_p[i].msiq_id)); 354 355 if (ino_p) { 356 ino_p->ino_cpuid = ino_p->ino_default_cpuid = 357 intr_dist_cpuid(); 358 359 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_redist: " 360 "sysino 0x%llx current cpuid 0x%x " 361 "default cpuid 0x%x\n", ino_p->ino_sysino, 362 ino_p->ino_cpuid, ino_p->ino_default_cpuid); 363 } 364 } 365 366 msiq_state_p->msiq_redist_flag = B_FALSE; 367 mutex_exit(&msiq_state_p->msiq_mutex); 368 } 369 370 /* 371 * px_msiqid_to_devino() 372 */ 373 devino_t 374 px_msiqid_to_devino(px_t *px_p, msiqid_t msiq_id) 375 { 376 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 377 devino_t devino; 378 379 devino = msiq_state_p->msiq_1st_devino + 380 msiq_id - msiq_state_p->msiq_1st_msiq_id; 381 382 DBG(DBG_MSIQ, px_p->px_dip, "px_msiqid_to_devino: " 383 "msiq_id 0x%x devino 0x%x\n", msiq_id, devino); 384 385 return (devino); 386 } 387 388 /* 389 * px_devino_to_msiqid() 390 */ 391 msiqid_t 392 px_devino_to_msiqid(px_t *px_p, devino_t devino) 393 { 394 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 395 msiqid_t msiq_id; 396 397 msiq_id = msiq_state_p->msiq_1st_msiq_id + 398 devino - msiq_state_p->msiq_1st_devino; 399 400 DBG(DBG_MSIQ, px_p->px_dip, "px_devino_to_msiq: " 401 "devino 0x%x msiq_id 0x%x\n", devino, msiq_id); 402 403 return (msiq_id); 404 } 405 406 /* 407 * px_msiq_get_props() 408 */ 409 static void 410 px_msiq_get_props(px_t *px_p) 411 { 412 px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state; 413 int ret = DDI_SUCCESS; 414 int length = sizeof (int); 415 char *valuep = NULL; 416 417 DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_get_props\n"); 418 419 /* #msi-eqs */ 420 msiq_state_p->msiq_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip, 421 DDI_PROP_DONTPASS, "#msi-eqs", PX_DEFAULT_MSIQ_CNT); 422 423 DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_cnt=%d\n", 424 msiq_state_p->msiq_cnt); 425 426 /* msi-eq-size */ 427 msiq_state_p->msiq_rec_cnt = ddi_getprop(DDI_DEV_T_ANY, px_p->px_dip, 428 DDI_PROP_DONTPASS, "msi-eq-size", PX_DEFAULT_MSIQ_REC_CNT); 429 430 DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_rec_cnt=%d\n", 431 msiq_state_p->msiq_rec_cnt); 432 433 /* msi-eq-to-devino: msi-eq#, devino# fields */ 434 ret = ddi_prop_op(DDI_DEV_T_ANY, px_p->px_dip, PROP_LEN_AND_VAL_ALLOC, 435 DDI_PROP_DONTPASS, "msi-eq-to-devino", (caddr_t)&valuep, 436 &length); 437 438 if (ret == DDI_PROP_SUCCESS) { 439 msiq_state_p->msiq_1st_msiq_id = 440 ((px_msi_eq_to_devino_t *)valuep)->msi_eq_no; 441 msiq_state_p->msiq_1st_devino = 442 ((px_msi_eq_to_devino_t *)valuep)->devino_no; 443 kmem_free(valuep, (size_t)length); 444 } else { 445 msiq_state_p->msiq_1st_msiq_id = PX_DEFAULT_MSIQ_1ST_MSIQ_ID; 446 msiq_state_p->msiq_1st_devino = PX_DEFAULT_MSIQ_1ST_DEVINO; 447 } 448 449 DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_msiq_id=%d\n", 450 msiq_state_p->msiq_1st_msiq_id); 451 452 DBG(DBG_MSIQ, px_p->px_dip, "obp: msiq_1st_devino=%d\n", 453 msiq_state_p->msiq_1st_devino); 454 } 455