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