Print this page
8368 remove warlock leftovers from usr/src/uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ib/adapters/tavor/tavor.c
+++ new/usr/src/uts/common/io/ib/adapters/tavor/tavor.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * tavor.c
28 28 * Tavor (InfiniBand) HCA Driver attach/detach Routines
29 29 *
30 30 * Implements all the routines necessary for the attach, setup,
31 31 * initialization (and subsequent possible teardown and detach) of the
32 32 * Tavor InfiniBand HCA driver.
33 33 */
34 34
35 35 #include <sys/types.h>
36 36 #include <sys/file.h>
37 37 #include <sys/open.h>
38 38 #include <sys/conf.h>
39 39 #include <sys/ddi.h>
40 40 #include <sys/sunddi.h>
41 41 #include <sys/modctl.h>
42 42 #include <sys/stat.h>
43 43 #include <sys/pci.h>
44 44 #include <sys/pci_cap.h>
45 45 #include <sys/bitmap.h>
46 46 #include <sys/policy.h>
47 47
48 48 #include <sys/ib/adapters/tavor/tavor.h>
49 49 #include <sys/pci.h>
50 50
51 51 /* Tavor HCA State Pointer */
52 52 void *tavor_statep;
53 53
54 54 /*
55 55 * The Tavor "userland resource database" is common to instances of the
56 56 * Tavor HCA driver. This structure "tavor_userland_rsrc_db" contains all
57 57 * the necessary information to maintain it.
58 58 */
59 59 tavor_umap_db_t tavor_userland_rsrc_db;
60 60
61 61 static int tavor_attach(dev_info_t *, ddi_attach_cmd_t);
62 62 static int tavor_detach(dev_info_t *, ddi_detach_cmd_t);
63 63 static int tavor_open(dev_t *, int, int, cred_t *);
64 64 static int tavor_close(dev_t, int, int, cred_t *);
65 65 static int tavor_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
66 66 static int tavor_drv_init(tavor_state_t *state, dev_info_t *dip, int instance);
67 67 static void tavor_drv_fini(tavor_state_t *state);
68 68 static void tavor_drv_fini2(tavor_state_t *state);
69 69 static int tavor_isr_init(tavor_state_t *state);
70 70 static void tavor_isr_fini(tavor_state_t *state);
71 71 static int tavor_hw_init(tavor_state_t *state);
72 72 static void tavor_hw_fini(tavor_state_t *state,
73 73 tavor_drv_cleanup_level_t cleanup);
74 74 static int tavor_soft_state_init(tavor_state_t *state);
75 75 static void tavor_soft_state_fini(tavor_state_t *state);
76 76 static int tavor_hca_port_init(tavor_state_t *state);
77 77 static int tavor_hca_ports_shutdown(tavor_state_t *state, uint_t num_init);
78 78 static void tavor_hca_config_setup(tavor_state_t *state,
79 79 tavor_hw_initqueryhca_t *inithca);
80 80 static int tavor_internal_uarpgs_init(tavor_state_t *state);
81 81 static void tavor_internal_uarpgs_fini(tavor_state_t *state);
82 82 static int tavor_special_qp_contexts_reserve(tavor_state_t *state);
83 83 static void tavor_special_qp_contexts_unreserve(tavor_state_t *state);
84 84 static int tavor_sw_reset(tavor_state_t *state);
85 85 static int tavor_mcg_init(tavor_state_t *state);
86 86 static void tavor_mcg_fini(tavor_state_t *state);
87 87 static int tavor_fw_version_check(tavor_state_t *state);
88 88 static void tavor_device_info_report(tavor_state_t *state);
89 89 static void tavor_pci_capability_list(tavor_state_t *state,
90 90 ddi_acc_handle_t hdl);
91 91 static void tavor_pci_capability_vpd(tavor_state_t *state,
92 92 ddi_acc_handle_t hdl, uint_t offset);
93 93 static int tavor_pci_read_vpd(ddi_acc_handle_t hdl, uint_t offset,
94 94 uint32_t addr, uint32_t *data);
95 95 static void tavor_pci_capability_pcix(tavor_state_t *state,
96 96 ddi_acc_handle_t hdl, uint_t offset);
97 97 static int tavor_intr_or_msi_init(tavor_state_t *state);
98 98 static int tavor_add_intrs(tavor_state_t *state, int intr_type);
99 99 static int tavor_intr_or_msi_fini(tavor_state_t *state);
100 100
101 101 /* X86 fastreboot support */
102 102 static int tavor_intr_disable(tavor_state_t *);
103 103 static int tavor_quiesce(dev_info_t *);
104 104
105 105 /* Character/Block Operations */
106 106 static struct cb_ops tavor_cb_ops = {
107 107 tavor_open, /* open */
108 108 tavor_close, /* close */
109 109 nodev, /* strategy (block) */
110 110 nodev, /* print (block) */
111 111 nodev, /* dump (block) */
112 112 nodev, /* read */
113 113 nodev, /* write */
114 114 tavor_ioctl, /* ioctl */
115 115 tavor_devmap, /* devmap */
116 116 NULL, /* mmap */
117 117 nodev, /* segmap */
118 118 nochpoll, /* chpoll */
119 119 ddi_prop_op, /* prop_op */
120 120 NULL, /* streams */
121 121 D_NEW | D_MP |
122 122 D_64BIT | D_HOTPLUG |
123 123 D_DEVMAP, /* flags */
124 124 CB_REV /* rev */
125 125 };
126 126
127 127 /* Driver Operations */
128 128 static struct dev_ops tavor_ops = {
129 129 DEVO_REV, /* struct rev */
130 130 0, /* refcnt */
131 131 tavor_getinfo, /* getinfo */
132 132 nulldev, /* identify */
133 133 nulldev, /* probe */
134 134 tavor_attach, /* attach */
135 135 tavor_detach, /* detach */
136 136 nodev, /* reset */
137 137 &tavor_cb_ops, /* cb_ops */
138 138 NULL, /* bus_ops */
139 139 nodev, /* power */
140 140 tavor_quiesce, /* devo_quiesce */
141 141 };
142 142
143 143 /* Module Driver Info */
144 144 static struct modldrv tavor_modldrv = {
145 145 &mod_driverops,
146 146 "Tavor InfiniBand HCA Driver",
147 147 &tavor_ops
148 148 };
149 149
150 150 /* Module Linkage */
151 151 static struct modlinkage tavor_modlinkage = {
152 152 MODREV_1,
153 153 &tavor_modldrv,
154 154 NULL
155 155 };
156 156
157 157 /*
158 158 * This extern refers to the ibc_operations_t function vector that is defined
159 159 * in the tavor_ci.c file.
160 160 */
161 161 extern ibc_operations_t tavor_ibc_ops;
162 162
163 163 #ifndef NPROBE
164 164 extern int tnf_mod_load(void);
165 165 extern int tnf_mod_unload(struct modlinkage *mlp);
166 166 #endif
167 167
168 168
169 169 /*
170 170 * _init()
171 171 */
172 172 int
173 173 _init()
174 174 {
175 175 int status;
176 176
177 177 #ifndef NPROBE
178 178 (void) tnf_mod_load();
179 179 #endif
180 180 TAVOR_TNF_ENTER(tavor_init);
181 181
182 182 status = ddi_soft_state_init(&tavor_statep, sizeof (tavor_state_t),
183 183 (size_t)TAVOR_INITIAL_STATES);
184 184 if (status != 0) {
185 185 TNF_PROBE_0(tavor_init_ssi_fail, TAVOR_TNF_ERROR, "");
186 186 TAVOR_TNF_EXIT(tavor_init);
187 187 #ifndef NPROBE
188 188 (void) tnf_mod_unload(&tavor_modlinkage);
189 189 #endif
190 190 return (status);
191 191 }
192 192
193 193 status = ibc_init(&tavor_modlinkage);
194 194 if (status != 0) {
195 195 TNF_PROBE_0(tavor_init_ibc_init_fail, TAVOR_TNF_ERROR, "");
196 196 ddi_soft_state_fini(&tavor_statep);
197 197 TAVOR_TNF_EXIT(tavor_init);
198 198 #ifndef NPROBE
199 199 (void) tnf_mod_unload(&tavor_modlinkage);
200 200 #endif
201 201 return (status);
202 202 }
203 203 status = mod_install(&tavor_modlinkage);
204 204 if (status != 0) {
205 205 TNF_PROBE_0(tavor_init_modi_fail, TAVOR_TNF_ERROR, "");
206 206 ibc_fini(&tavor_modlinkage);
207 207 ddi_soft_state_fini(&tavor_statep);
208 208 TAVOR_TNF_EXIT(tavor_init);
209 209 #ifndef NPROBE
210 210 (void) tnf_mod_unload(&tavor_modlinkage);
211 211 #endif
212 212 return (status);
213 213 }
214 214
215 215 /* Initialize the Tavor "userland resources database" */
216 216 tavor_umap_db_init();
217 217
218 218 TAVOR_TNF_EXIT(tavor_init);
219 219 return (status);
220 220 }
221 221
222 222
223 223 /*
224 224 * _info()
225 225 */
226 226 int
227 227 _info(struct modinfo *modinfop)
228 228 {
229 229 int status;
230 230
231 231 TAVOR_TNF_ENTER(tavor_info);
232 232 status = mod_info(&tavor_modlinkage, modinfop);
233 233 TAVOR_TNF_EXIT(tavor_info);
234 234 return (status);
235 235 }
236 236
237 237
238 238 /*
239 239 * _fini()
240 240 */
241 241 int
242 242 _fini()
243 243 {
244 244 int status;
245 245
246 246 TAVOR_TNF_ENTER(tavor_fini);
247 247
248 248 status = mod_remove(&tavor_modlinkage);
249 249 if (status != 0) {
250 250 TNF_PROBE_0(tavor_fini_modr_fail, TAVOR_TNF_ERROR, "");
251 251 TAVOR_TNF_EXIT(tavor_fini);
252 252 return (status);
253 253 }
254 254
255 255 /* Destroy the Tavor "userland resources database" */
256 256 tavor_umap_db_fini();
257 257
258 258 ibc_fini(&tavor_modlinkage);
259 259 ddi_soft_state_fini(&tavor_statep);
260 260 #ifndef NPROBE
261 261 (void) tnf_mod_unload(&tavor_modlinkage);
262 262 #endif
263 263 TAVOR_TNF_EXIT(tavor_fini);
264 264 return (status);
265 265 }
266 266
267 267
268 268 /*
269 269 * tavor_getinfo()
270 270 */
271 271 /* ARGSUSED */
272 272 static int
273 273 tavor_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
274 274 {
275 275 dev_t dev;
276 276 tavor_state_t *state;
277 277 minor_t instance;
278 278
279 279 TAVOR_TNF_ENTER(tavor_getinfo);
280 280
281 281 switch (cmd) {
282 282 case DDI_INFO_DEVT2DEVINFO:
283 283 dev = (dev_t)arg;
284 284 instance = TAVOR_DEV_INSTANCE(dev);
285 285 state = ddi_get_soft_state(tavor_statep, instance);
286 286 if (state == NULL) {
287 287 TNF_PROBE_0(tavor_getinfo_gss_fail,
288 288 TAVOR_TNF_ERROR, "");
289 289 TAVOR_TNF_EXIT(tavor_getinfo);
290 290 return (DDI_FAILURE);
291 291 }
292 292 *result = (void *)state->ts_dip;
293 293 return (DDI_SUCCESS);
294 294
295 295 case DDI_INFO_DEVT2INSTANCE:
296 296 dev = (dev_t)arg;
297 297 instance = TAVOR_DEV_INSTANCE(dev);
298 298 *result = (void *)(uintptr_t)instance;
299 299 return (DDI_SUCCESS);
300 300
301 301 default:
302 302 TNF_PROBE_0(tavor_getinfo_default_fail, TAVOR_TNF_ERROR, "");
303 303 break;
304 304 }
305 305
306 306 TAVOR_TNF_EXIT(tavor_getinfo);
307 307 return (DDI_FAILURE);
308 308 }
309 309
310 310
311 311 /*
312 312 * tavor_open()
313 313 */
314 314 /* ARGSUSED */
315 315 static int
316 316 tavor_open(dev_t *devp, int flag, int otyp, cred_t *credp)
317 317 {
318 318 tavor_state_t *state;
319 319 tavor_rsrc_t *rsrcp;
320 320 tavor_umap_db_entry_t *umapdb, *umapdb2;
321 321 minor_t instance;
322 322 uint64_t key, value;
323 323 uint_t tr_indx;
324 324 dev_t dev;
325 325 int status;
326 326
327 327 TAVOR_TNF_ENTER(tavor_open);
328 328
329 329 instance = TAVOR_DEV_INSTANCE(*devp);
330 330 state = ddi_get_soft_state(tavor_statep, instance);
331 331 if (state == NULL) {
332 332 TNF_PROBE_0(tavor_open_gss_fail, TAVOR_TNF_ERROR, "");
333 333 TAVOR_TNF_EXIT(tavor_open);
334 334 return (ENXIO);
335 335 }
336 336
337 337 /*
338 338 * Only allow driver to be opened for character access, and verify
339 339 * whether exclusive access is allowed.
340 340 */
341 341 if ((otyp != OTYP_CHR) || ((flag & FEXCL) &&
342 342 secpolicy_excl_open(credp) != 0)) {
343 343 TNF_PROBE_0(tavor_open_invflags_fail, TAVOR_TNF_ERROR, "");
344 344 TAVOR_TNF_EXIT(tavor_open);
345 345 return (EINVAL);
346 346 }
347 347
348 348 /*
349 349 * Search for the current process PID in the "userland resources
350 350 * database". If it is not found, then attempt to allocate a UAR
351 351 * page and add the ("key", "value") pair to the database.
352 352 * Note: As a last step we always return a devp appropriate for
353 353 * the open. Either we return a new minor number (based on the
354 354 * instance and the UAR page index) or we return the current minor
355 355 * number for the given client process.
356 356 *
357 357 * We also add an entry to the database to allow for lookup from
358 358 * "dev_t" to the current process PID. This is necessary because,
359 359 * under certain circumstance, the process PID that calls the Tavor
360 360 * close() entry point may not be the same as the one who called
361 361 * open(). Specifically, this can happen if a child process calls
362 362 * the Tavor's open() entry point, gets a UAR page, maps it out (using
363 363 * mmap()), and then exits without calling munmap(). Because mmap()
364 364 * adds a reference to the file descriptor, at the exit of the child
365 365 * process the file descriptor is "inherited" by the parent (and will
366 366 * be close()'d by the parent's PID only when it exits).
367 367 *
368 368 * Note: We use the tavor_umap_db_find_nolock() and
369 369 * tavor_umap_db_add_nolock() database access routines below (with
370 370 * an explicit mutex_enter of the database lock - "tdl_umapdb_lock")
371 371 * to ensure that the multiple accesses (in this case searching for,
372 372 * and then adding _two_ database entries) can be done atomically.
373 373 */
374 374 key = ddi_get_pid();
375 375 mutex_enter(&tavor_userland_rsrc_db.tdl_umapdb_lock);
376 376 status = tavor_umap_db_find_nolock(instance, key,
377 377 MLNX_UMAP_UARPG_RSRC, &value, 0, NULL);
378 378 if (status != DDI_SUCCESS) {
379 379 /*
380 380 * If we are in 'maintenance mode', we cannot alloc a UAR page.
381 381 * But we still need some rsrcp value, and a mostly unique
382 382 * tr_indx value. So we set rsrcp to NULL for maintenance
383 383 * mode, and use a rolling count for tr_indx. The field
384 384 * 'ts_open_tr_indx' is used only in this maintenance mode
385 385 * condition.
386 386 *
387 387 * Otherwise, if we are in operational mode then we allocate
388 388 * the UAR page as normal, and use the rsrcp value and tr_indx
389 389 * value from that allocation.
390 390 */
391 391 if (!TAVOR_IS_OPERATIONAL(state->ts_operational_mode)) {
392 392 rsrcp = NULL;
393 393 tr_indx = state->ts_open_tr_indx++;
394 394 } else {
395 395 /* Allocate a new UAR page for this process */
396 396 status = tavor_rsrc_alloc(state, TAVOR_UARPG, 1,
397 397 TAVOR_NOSLEEP, &rsrcp);
398 398 if (status != DDI_SUCCESS) {
399 399 mutex_exit(
400 400 &tavor_userland_rsrc_db.tdl_umapdb_lock);
401 401 TNF_PROBE_0(tavor_open_rsrcalloc_uarpg_fail,
402 402 TAVOR_TNF_ERROR, "");
403 403 TAVOR_TNF_EXIT(tavor_open);
404 404 return (EAGAIN);
405 405 }
406 406
407 407 tr_indx = rsrcp->tr_indx;
408 408 }
409 409
410 410 /*
411 411 * Allocate an entry to track the UAR page resource in the
412 412 * "userland resources database".
413 413 */
414 414 umapdb = tavor_umap_db_alloc(instance, key,
415 415 MLNX_UMAP_UARPG_RSRC, (uint64_t)(uintptr_t)rsrcp);
416 416 if (umapdb == NULL) {
417 417 mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
418 418 /* If in "maintenance mode", don't free the rsrc */
419 419 if (TAVOR_IS_OPERATIONAL(state->ts_operational_mode)) {
420 420 tavor_rsrc_free(state, &rsrcp);
421 421 }
422 422 TNF_PROBE_0(tavor_open_umap_db_alloc_fail,
423 423 TAVOR_TNF_ERROR, "");
424 424 TAVOR_TNF_EXIT(tavor_open);
425 425 return (EAGAIN);
426 426 }
427 427
428 428 /*
429 429 * Create a new device number. Minor number is a function of
430 430 * the UAR page index (15 bits) and the device instance number
431 431 * (3 bits).
432 432 */
433 433 dev = makedevice(getmajor(*devp), (tr_indx <<
434 434 TAVOR_MINORNUM_SHIFT) | instance);
435 435
436 436 /*
437 437 * Allocate another entry in the "userland resources database"
438 438 * to track the association of the device number (above) to
439 439 * the current process ID (in "key").
440 440 */
441 441 umapdb2 = tavor_umap_db_alloc(instance, dev,
442 442 MLNX_UMAP_PID_RSRC, (uint64_t)key);
443 443 if (umapdb2 == NULL) {
444 444 mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
445 445 tavor_umap_db_free(umapdb);
446 446 /* If in "maintenance mode", don't free the rsrc */
447 447 if (TAVOR_IS_OPERATIONAL(state->ts_operational_mode)) {
448 448 tavor_rsrc_free(state, &rsrcp);
449 449 }
450 450 TNF_PROBE_0(tavor_open_umap_db_alloc_fail,
451 451 TAVOR_TNF_ERROR, "");
452 452 TAVOR_TNF_EXIT(tavor_open);
453 453 return (EAGAIN);
454 454 }
455 455
456 456 /* Add the entries to the database */
457 457 tavor_umap_db_add_nolock(umapdb);
458 458 tavor_umap_db_add_nolock(umapdb2);
459 459
460 460 } else {
461 461 /*
462 462 * Return the same device number as on the original open()
463 463 * call. This was calculated as a function of the UAR page
464 464 * index (top 16 bits) and the device instance number
465 465 */
466 466 rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
467 467 dev = makedevice(getmajor(*devp), (rsrcp->tr_indx <<
468 468 TAVOR_MINORNUM_SHIFT) | instance);
469 469 }
470 470 mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
471 471
472 472 *devp = dev;
473 473
474 474 TAVOR_TNF_EXIT(tavor_open);
475 475 return (0);
476 476 }
477 477
478 478
479 479 /*
480 480 * tavor_close()
481 481 */
482 482 /* ARGSUSED */
483 483 static int
484 484 tavor_close(dev_t dev, int flag, int otyp, cred_t *credp)
485 485 {
486 486 tavor_state_t *state;
487 487 tavor_rsrc_t *rsrcp;
488 488 tavor_umap_db_entry_t *umapdb;
489 489 tavor_umap_db_priv_t *priv;
490 490 minor_t instance;
491 491 uint64_t key, value;
492 492 int status;
493 493
494 494 TAVOR_TNF_ENTER(tavor_close);
495 495
496 496 instance = TAVOR_DEV_INSTANCE(dev);
497 497 state = ddi_get_soft_state(tavor_statep, instance);
498 498 if (state == NULL) {
499 499 TNF_PROBE_0(tavor_close_gss_fail, TAVOR_TNF_ERROR, "");
500 500 TAVOR_TNF_EXIT(tavor_close);
501 501 return (ENXIO);
502 502 }
503 503
504 504 /*
505 505 * Search for "dev_t" in the "userland resources database". As
506 506 * explained above in tavor_open(), we can't depend on using the
507 507 * current process ID here to do the lookup because the process
508 508 * that ultimately closes may not be the same one who opened
509 509 * (because of inheritance).
510 510 * So we lookup the "dev_t" (which points to the PID of the process
511 511 * that opened), and we remove the entry from the database (and free
512 512 * it up). Then we do another query based on the PID value. And when
513 513 * we find that database entry, we free it up too and then free the
514 514 * Tavor UAR page resource.
515 515 *
516 516 * Note: We use the tavor_umap_db_find_nolock() database access
517 517 * routine below (with an explicit mutex_enter of the database lock)
518 518 * to ensure that the multiple accesses (which attempt to remove the
519 519 * two database entries) can be done atomically.
520 520 *
521 521 * This works the same in both maintenance mode and HCA mode, except
522 522 * for the call to tavor_rsrc_free(). In the case of maintenance mode,
523 523 * this call is not needed, as it was not allocated in tavor_open()
524 524 * above.
525 525 */
526 526 key = dev;
527 527 mutex_enter(&tavor_userland_rsrc_db.tdl_umapdb_lock);
528 528 status = tavor_umap_db_find_nolock(instance, key, MLNX_UMAP_PID_RSRC,
529 529 &value, TAVOR_UMAP_DB_REMOVE, &umapdb);
530 530 if (status == DDI_SUCCESS) {
531 531 /*
532 532 * If the "tdb_priv" field is non-NULL, it indicates that
533 533 * some "on close" handling is still necessary. Call
534 534 * tavor_umap_db_handle_onclose_cb() to do the handling (i.e.
535 535 * to invoke all the registered callbacks). Then free up
536 536 * the resources associated with "tdb_priv" and continue
537 537 * closing.
538 538 */
539 539 priv = (tavor_umap_db_priv_t *)umapdb->tdbe_common.tdb_priv;
540 540 if (priv != NULL) {
541 541 tavor_umap_db_handle_onclose_cb(priv);
542 542 kmem_free(priv, sizeof (tavor_umap_db_priv_t));
543 543 umapdb->tdbe_common.tdb_priv = (void *)NULL;
544 544 }
545 545
546 546 tavor_umap_db_free(umapdb);
547 547
548 548 /*
549 549 * Now do another lookup using PID as the key (copy it from
550 550 * "value"). When this lookup is complete, the "value" field
551 551 * will contain the tavor_rsrc_t pointer for the UAR page
552 552 * resource.
553 553 */
554 554 key = value;
555 555 status = tavor_umap_db_find_nolock(instance, key,
556 556 MLNX_UMAP_UARPG_RSRC, &value, TAVOR_UMAP_DB_REMOVE,
557 557 &umapdb);
558 558 if (status == DDI_SUCCESS) {
559 559 tavor_umap_db_free(umapdb);
560 560 /* If in "maintenance mode", don't free the rsrc */
561 561 if (TAVOR_IS_OPERATIONAL(state->ts_operational_mode)) {
562 562 rsrcp = (tavor_rsrc_t *)(uintptr_t)value;
563 563 tavor_rsrc_free(state, &rsrcp);
564 564 }
565 565 }
566 566 }
567 567 mutex_exit(&tavor_userland_rsrc_db.tdl_umapdb_lock);
568 568
569 569 TAVOR_TNF_EXIT(tavor_close);
570 570 return (0);
571 571 }
572 572
573 573
574 574 /*
575 575 * tavor_attach()
576 576 * Context: Only called from attach() path context
577 577 */
578 578 static int
↓ open down ↓ |
578 lines elided |
↑ open up ↑ |
579 579 tavor_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
580 580 {
581 581 tavor_state_t *state;
582 582 ibc_clnt_hdl_t tmp_ibtfpriv;
583 583 ibc_status_t ibc_status;
584 584 int instance;
585 585 int status;
586 586
587 587 TAVOR_TNF_ENTER(tavor_attach);
588 588
589 -#ifdef __lock_lint
590 - (void) tavor_quiesce(dip);
591 -#endif
592 -
593 589 switch (cmd) {
594 590 case DDI_ATTACH:
595 591 instance = ddi_get_instance(dip);
596 592 status = ddi_soft_state_zalloc(tavor_statep, instance);
597 593 if (status != DDI_SUCCESS) {
598 594 TNF_PROBE_0(tavor_attach_ssz_fail, TAVOR_TNF_ERROR, "");
599 595 cmn_err(CE_NOTE, "tavor%d: driver failed to attach: "
600 596 "attach_ssz_fail", instance);
601 597 goto fail_attach_nomsg;
602 598
603 599 }
604 600 state = ddi_get_soft_state(tavor_statep, instance);
605 601 if (state == NULL) {
606 602 ddi_soft_state_free(tavor_statep, instance);
607 603 TNF_PROBE_0(tavor_attach_gss_fail, TAVOR_TNF_ERROR, "");
608 604 cmn_err(CE_NOTE, "tavor%d: driver failed to attach: "
609 605 "attach_gss_fail", instance);
610 606 goto fail_attach_nomsg;
611 607 }
612 608
613 609 /* clear the attach error buffer */
614 610 TAVOR_ATTACH_MSG_INIT(state->ts_attach_buf);
615 611
616 612 /*
617 613 * Initialize Tavor driver and hardware.
618 614 *
619 615 * Note: If this initialization fails we may still wish to
620 616 * create a device node and remain operational so that Tavor
621 617 * firmware can be updated/flashed (i.e. "maintenance mode").
622 618 * If this is the case, then "ts_operational_mode" will be
623 619 * equal to TAVOR_MAINTENANCE_MODE. We will not attempt to
624 620 * attach to the IBTF or register with the IBMF (i.e. no
625 621 * InfiniBand interfaces will be enabled).
626 622 */
627 623 status = tavor_drv_init(state, dip, instance);
628 624 if ((status != DDI_SUCCESS) &&
629 625 (TAVOR_IS_OPERATIONAL(state->ts_operational_mode))) {
630 626 TNF_PROBE_0(tavor_attach_drvinit_fail,
631 627 TAVOR_TNF_ERROR, "");
632 628 goto fail_attach;
633 629 }
634 630
635 631 /* Create the minor node for device */
636 632 status = ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
637 633 DDI_PSEUDO, 0);
638 634 if (status != DDI_SUCCESS) {
639 635 tavor_drv_fini(state);
640 636 TAVOR_ATTACH_MSG(state->ts_attach_buf,
641 637 "attach_create_mn_fail");
642 638 TNF_PROBE_0(tavor_attach_create_mn_fail,
643 639 TAVOR_TNF_ERROR, "");
644 640 goto fail_attach;
645 641 }
646 642
647 643 /*
648 644 * If we are in "maintenance mode", then we don't want to
649 645 * register with the IBTF. All InfiniBand interfaces are
650 646 * uninitialized, and the device is only capable of handling
651 647 * requests to update/flash firmware (or test/debug requests).
652 648 */
653 649 if (TAVOR_IS_OPERATIONAL(state->ts_operational_mode)) {
654 650
655 651 /* Attach to InfiniBand Transport Framework (IBTF) */
656 652 ibc_status = ibc_attach(&tmp_ibtfpriv,
657 653 &state->ts_ibtfinfo);
658 654 if (ibc_status != IBC_SUCCESS) {
659 655 ddi_remove_minor_node(dip, "devctl");
660 656 tavor_drv_fini(state);
661 657 TNF_PROBE_0(tavor_attach_ibcattach_fail,
662 658 TAVOR_TNF_ERROR, "");
663 659 TAVOR_ATTACH_MSG(state->ts_attach_buf,
664 660 "attach_ibcattach_fail");
665 661 goto fail_attach;
666 662 }
667 663
668 664 /*
669 665 * Now that we've successfully attached to the IBTF,
670 666 * we enable all appropriate asynch and CQ events to
671 667 * be forwarded to the IBTF.
672 668 */
673 669 TAVOR_ENABLE_IBTF_CALLB(state, tmp_ibtfpriv);
674 670
675 671 ibc_post_attach(state->ts_ibtfpriv);
676 672
677 673 /* Register agents with IB Mgmt Framework (IBMF) */
678 674 status = tavor_agent_handlers_init(state);
679 675 if (status != DDI_SUCCESS) {
680 676 (void) ibc_pre_detach(tmp_ibtfpriv, DDI_DETACH);
681 677 TAVOR_QUIESCE_IBTF_CALLB(state);
682 678 if (state->ts_in_evcallb != 0) {
683 679 TAVOR_WARNING(state, "unable to "
684 680 "quiesce Tavor IBTF callbacks");
685 681 }
686 682 ibc_detach(tmp_ibtfpriv);
687 683 ddi_remove_minor_node(dip, "devctl");
688 684 tavor_drv_fini(state);
689 685 TNF_PROBE_0(tavor_attach_agentinit_fail,
690 686 TAVOR_TNF_ERROR, "");
691 687 TAVOR_ATTACH_MSG(state->ts_attach_buf,
692 688 "attach_agentinit_fail");
693 689 goto fail_attach;
694 690 }
695 691 }
696 692
697 693 /* Report that driver was loaded */
698 694 ddi_report_dev(dip);
699 695
700 696 /* Send device information to log file */
701 697 tavor_device_info_report(state);
702 698
703 699 /* Report attach in maintenance mode, if appropriate */
704 700 if (!(TAVOR_IS_OPERATIONAL(state->ts_operational_mode))) {
705 701 cmn_err(CE_NOTE, "tavor%d: driver attached "
706 702 "(for maintenance mode only)", state->ts_instance);
707 703 }
708 704
709 705 TAVOR_TNF_EXIT(tavor_attach);
710 706 return (DDI_SUCCESS);
711 707
712 708 case DDI_RESUME:
713 709 /* Add code here for DDI_RESUME XXX */
714 710 TAVOR_TNF_EXIT(tavor_attach);
715 711 return (DDI_FAILURE);
716 712
717 713 default:
718 714 TNF_PROBE_0(tavor_attach_default_fail, TAVOR_TNF_ERROR, "");
719 715 break;
720 716 }
721 717
722 718 fail_attach:
723 719 cmn_err(CE_NOTE, "tavor%d: driver failed to attach: %s", instance,
724 720 state->ts_attach_buf);
725 721 tavor_drv_fini2(state);
726 722 ddi_soft_state_free(tavor_statep, instance);
727 723 fail_attach_nomsg:
728 724 TAVOR_TNF_EXIT(tavor_attach);
729 725 return (DDI_FAILURE);
730 726 }
731 727
732 728
733 729 /*
734 730 * tavor_detach()
735 731 * Context: Only called from detach() path context
736 732 */
737 733 static int
738 734 tavor_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
739 735 {
740 736 tavor_state_t *state;
741 737 ibc_clnt_hdl_t tmp_ibtfpriv;
742 738 ibc_status_t ibc_status;
743 739 int instance, status;
744 740
745 741 TAVOR_TNF_ENTER(tavor_detach);
746 742
747 743 instance = ddi_get_instance(dip);
748 744 state = ddi_get_soft_state(tavor_statep, instance);
749 745 if (state == NULL) {
750 746 TNF_PROBE_0(tavor_detach_gss_fail, TAVOR_TNF_ERROR, "");
751 747 TAVOR_TNF_EXIT(tavor_detach);
752 748 return (DDI_FAILURE);
753 749 }
754 750
755 751 switch (cmd) {
756 752 case DDI_DETACH:
757 753 /*
758 754 * If we are in "maintenance mode", then we do not want to
759 755 * do teardown for any of the InfiniBand interfaces.
760 756 * Specifically, this means not detaching from IBTF (we never
761 757 * attached to begin with) and not deregistering from IBMF.
762 758 */
763 759 if (TAVOR_IS_OPERATIONAL(state->ts_operational_mode)) {
764 760 /* Unregister agents from IB Mgmt Framework (IBMF) */
765 761 status = tavor_agent_handlers_fini(state);
766 762 if (status != DDI_SUCCESS) {
767 763 TNF_PROBE_0(tavor_detach_agentfini_fail,
768 764 TAVOR_TNF_ERROR, "");
769 765 TAVOR_TNF_EXIT(tavor_detach);
770 766 return (DDI_FAILURE);
771 767 }
772 768
773 769 /*
774 770 * Attempt the "pre-detach" from InfiniBand Transport
775 771 * Framework (IBTF). At this point the IBTF is still
776 772 * capable of handling incoming asynch and completion
777 773 * events. This "pre-detach" is primarily a mechanism
778 774 * to notify the appropriate IBTF clients that the
779 775 * HCA is being removed/offlined.
780 776 */
781 777 ibc_status = ibc_pre_detach(state->ts_ibtfpriv, cmd);
782 778 if (ibc_status != IBC_SUCCESS) {
783 779 status = tavor_agent_handlers_init(state);
784 780 if (status != DDI_SUCCESS) {
785 781 TAVOR_WARNING(state, "failed to "
786 782 "restart Tavor agents");
787 783 }
788 784 TNF_PROBE_0(tavor_detach_ibcpredetach_fail,
789 785 TAVOR_TNF_ERROR, "");
790 786 TAVOR_TNF_EXIT(tavor_detach);
791 787 return (DDI_FAILURE);
792 788 }
793 789
794 790 /*
795 791 * Before we can fully detach from the IBTF we need to
796 792 * ensure that we have handled all outstanding event
797 793 * callbacks. This is accomplished by quiescing the
798 794 * event callback mechanism. Note: if we are unable
799 795 * to successfully quiesce the callbacks, then this is
800 796 * an indication that something has probably gone
801 797 * seriously wrong. We print out a warning, but
802 798 * continue.
803 799 */
804 800 tmp_ibtfpriv = state->ts_ibtfpriv;
805 801 TAVOR_QUIESCE_IBTF_CALLB(state);
806 802 if (state->ts_in_evcallb != 0) {
807 803 TAVOR_WARNING(state, "unable to quiesce Tavor "
808 804 "IBTF callbacks");
809 805 }
810 806
811 807 /* Complete the detach from the IBTF */
812 808 ibc_detach(tmp_ibtfpriv);
813 809 }
814 810
815 811 /* Remove the minor node for device */
816 812 ddi_remove_minor_node(dip, "devctl");
817 813
818 814 /*
819 815 * Only call tavor_drv_fini() if we are in Tavor HCA mode.
820 816 * (Because if we are in "maintenance mode", then we never
821 817 * successfully finished init.) Only report successful
822 818 * detach for normal HCA mode.
823 819 */
824 820 if (TAVOR_IS_OPERATIONAL(state->ts_operational_mode)) {
825 821 /* Cleanup driver resources and shutdown hardware */
826 822 tavor_drv_fini(state);
827 823 cmn_err(CE_CONT, "Tavor driver successfully "
828 824 "detached\n");
829 825 }
830 826
831 827 tavor_drv_fini2(state);
832 828 ddi_soft_state_free(tavor_statep, instance);
833 829
834 830 TAVOR_TNF_EXIT(tavor_detach);
835 831 return (DDI_SUCCESS);
836 832
837 833 case DDI_SUSPEND:
838 834 /* Add code here for DDI_SUSPEND XXX */
839 835 TAVOR_TNF_EXIT(tavor_detach);
840 836 return (DDI_FAILURE);
841 837
842 838 default:
843 839 TNF_PROBE_0(tavor_detach_default_fail, TAVOR_TNF_ERROR, "");
844 840 break;
845 841 }
846 842
847 843 TAVOR_TNF_EXIT(tavor_detach);
848 844 return (DDI_FAILURE);
849 845 }
850 846
851 847
852 848 /*
853 849 * tavor_drv_init()
854 850 * Context: Only called from attach() path context
855 851 */
856 852 static int
857 853 tavor_drv_init(tavor_state_t *state, dev_info_t *dip, int instance)
858 854 {
859 855 int status;
860 856
861 857 TAVOR_TNF_ENTER(tavor_drv_init);
862 858
863 859 /* Save away devinfo and instance */
864 860 state->ts_dip = dip;
865 861 state->ts_instance = instance;
866 862
867 863 /*
868 864 * Check and set the operational mode of the device. If the driver is
869 865 * bound to the Tavor device in "maintenance mode", then this generally
870 866 * means that either the device has been specifically jumpered to
871 867 * start in this mode or the firmware boot process has failed to
872 868 * successfully load either the primary or the secondary firmware
873 869 * image.
874 870 */
875 871 if (TAVOR_IS_HCA_MODE(state->ts_dip)) {
876 872 state->ts_operational_mode = TAVOR_HCA_MODE;
877 873
878 874 } else if (TAVOR_IS_COMPAT_MODE(state->ts_dip)) {
879 875 state->ts_operational_mode = TAVOR_COMPAT_MODE;
880 876
881 877 } else if (TAVOR_IS_MAINTENANCE_MODE(state->ts_dip)) {
882 878 state->ts_operational_mode = TAVOR_MAINTENANCE_MODE;
883 879 return (DDI_FAILURE);
884 880
885 881 } else {
886 882 state->ts_operational_mode = 0; /* invalid operational mode */
887 883 TAVOR_WARNING(state, "unexpected device type detected");
888 884 TNF_PROBE_0(tavor_hw_init_unexpected_dev_fail,
889 885 TAVOR_TNF_ERROR, "");
890 886 TAVOR_TNF_EXIT(tavor_hw_init);
891 887 return (DDI_FAILURE);
892 888 }
893 889
894 890 /*
895 891 * Initialize the Tavor hardware.
896 892 * Note: If this routine returns an error, it is often an reasonably
897 893 * good indication that something Tavor firmware-related has caused
898 894 * the failure. In order to give the user an opportunity (if desired)
899 895 * to update or reflash the Tavor firmware image, we set
900 896 * "ts_operational_mode" flag (described above) to indicate that we
901 897 * wish to enter maintenance mode.
902 898 */
903 899 status = tavor_hw_init(state);
904 900 if (status != DDI_SUCCESS) {
905 901 state->ts_operational_mode = TAVOR_MAINTENANCE_MODE;
906 902 cmn_err(CE_NOTE, "tavor%d: error during attach: %s", instance,
907 903 state->ts_attach_buf);
908 904 TNF_PROBE_0(tavor_drv_init_hwinit_fail, TAVOR_TNF_ERROR, "");
909 905 TAVOR_TNF_EXIT(tavor_drv_init);
910 906 return (DDI_FAILURE);
911 907 }
912 908
913 909 /* Setup Tavor interrupt handler */
914 910 status = tavor_isr_init(state);
915 911 if (status != DDI_SUCCESS) {
916 912 tavor_hw_fini(state, TAVOR_DRV_CLEANUP_ALL);
917 913 TNF_PROBE_0(tavor_drv_init_isrinit_fail, TAVOR_TNF_ERROR, "");
918 914 TAVOR_TNF_EXIT(tavor_drv_init);
919 915 return (DDI_FAILURE);
920 916 }
921 917
922 918 /* Initialize Tavor softstate */
923 919 status = tavor_soft_state_init(state);
924 920 if (status != DDI_SUCCESS) {
925 921 tavor_isr_fini(state);
926 922 tavor_hw_fini(state, TAVOR_DRV_CLEANUP_ALL);
927 923 TNF_PROBE_0(tavor_drv_init_ssiinit_fail, TAVOR_TNF_ERROR, "");
928 924 TAVOR_TNF_EXIT(tavor_drv_init);
929 925 return (DDI_FAILURE);
930 926 }
931 927
932 928 TAVOR_TNF_EXIT(tavor_drv_init);
933 929 return (DDI_SUCCESS);
934 930 }
935 931
936 932
937 933 /*
938 934 * tavor_drv_fini()
939 935 * Context: Only called from attach() and/or detach() path contexts
940 936 */
941 937 static void
942 938 tavor_drv_fini(tavor_state_t *state)
943 939 {
944 940 TAVOR_TNF_ENTER(tavor_drv_fini);
945 941
946 942 /* Cleanup Tavor softstate */
947 943 tavor_soft_state_fini(state);
948 944
949 945 /* Teardown Tavor interrupts */
950 946 tavor_isr_fini(state);
951 947
952 948 /* Cleanup Tavor resources and shutdown hardware */
953 949 tavor_hw_fini(state, TAVOR_DRV_CLEANUP_ALL);
954 950
955 951 TAVOR_TNF_EXIT(tavor_drv_fini);
956 952 }
957 953
958 954 /*
959 955 * tavor_drv_fini2()
960 956 * Context: Only called from attach() and/or detach() path contexts
961 957 */
962 958 static void
963 959 tavor_drv_fini2(tavor_state_t *state)
964 960 {
965 961 TAVOR_TNF_ENTER(tavor_drv_fini2);
966 962
967 963 /* TAVOR_DRV_CLEANUP_LEVEL1 */
968 964 if (state->ts_reg_cmdhdl) {
969 965 ddi_regs_map_free(&state->ts_reg_cmdhdl);
970 966 state->ts_reg_cmdhdl = NULL;
971 967 }
972 968
973 969 /* TAVOR_DRV_CLEANUP_LEVEL0 */
974 970 if (state->ts_pci_cfghdl) {
975 971 pci_config_teardown(&state->ts_pci_cfghdl);
976 972 state->ts_pci_cfghdl = NULL;
977 973 }
978 974
979 975 TAVOR_TNF_EXIT(tavor_drv_fini2);
980 976 }
981 977
982 978 /*
983 979 * tavor_isr_init()
984 980 * Context: Only called from attach() path context
985 981 */
986 982 static int
987 983 tavor_isr_init(tavor_state_t *state)
988 984 {
989 985 int status;
990 986
991 987 TAVOR_TNF_ENTER(tavor_isr_init);
992 988
993 989 /*
994 990 * Add a handler for the interrupt or MSI
995 991 */
996 992 status = ddi_intr_add_handler(state->ts_intrmsi_hdl, tavor_isr,
997 993 (caddr_t)state, NULL);
998 994 if (status != DDI_SUCCESS) {
999 995 TNF_PROBE_0(tavor_isr_init_addhndlr_fail, TAVOR_TNF_ERROR, "");
1000 996 TAVOR_TNF_EXIT(tavor_isr_init);
1001 997 return (DDI_FAILURE);
1002 998 }
1003 999
1004 1000 /*
1005 1001 * Enable the software interrupt. Note: Even though we are only
1006 1002 * using one (1) interrupt/MSI, depending on the value returned in
1007 1003 * the capability flag, we have to call either ddi_intr_block_enable()
1008 1004 * or ddi_intr_enable().
1009 1005 */
1010 1006 if (state->ts_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
1011 1007 status = ddi_intr_block_enable(&state->ts_intrmsi_hdl, 1);
1012 1008 if (status != DDI_SUCCESS) {
1013 1009 TNF_PROBE_0(tavor_isr_init_blockenable_fail,
1014 1010 TAVOR_TNF_ERROR, "");
1015 1011 TAVOR_TNF_EXIT(tavor_isr_init);
1016 1012 return (DDI_FAILURE);
1017 1013 }
1018 1014 } else {
1019 1015 status = ddi_intr_enable(state->ts_intrmsi_hdl);
1020 1016 if (status != DDI_SUCCESS) {
1021 1017 TNF_PROBE_0(tavor_isr_init_intrenable_fail,
1022 1018 TAVOR_TNF_ERROR, "");
1023 1019 TAVOR_TNF_EXIT(tavor_isr_init);
1024 1020 return (DDI_FAILURE);
1025 1021 }
1026 1022 }
1027 1023
1028 1024 /*
1029 1025 * Now that the ISR has been setup, arm all the EQs for event
1030 1026 * generation.
1031 1027 */
1032 1028 tavor_eq_arm_all(state);
1033 1029
1034 1030 TAVOR_TNF_EXIT(tavor_isr_init);
1035 1031 return (DDI_SUCCESS);
1036 1032 }
1037 1033
1038 1034
1039 1035 /*
1040 1036 * tavor_isr_fini()
1041 1037 * Context: Only called from attach() and/or detach() path contexts
1042 1038 */
1043 1039 static void
1044 1040 tavor_isr_fini(tavor_state_t *state)
1045 1041 {
1046 1042 TAVOR_TNF_ENTER(tavor_isr_fini);
1047 1043
1048 1044 /* Disable the software interrupt */
1049 1045 if (state->ts_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
1050 1046 (void) ddi_intr_block_disable(&state->ts_intrmsi_hdl, 1);
1051 1047 } else {
1052 1048 (void) ddi_intr_disable(state->ts_intrmsi_hdl);
1053 1049 }
1054 1050
1055 1051 /*
1056 1052 * Remove the software handler for the interrupt or MSI
1057 1053 */
1058 1054 (void) ddi_intr_remove_handler(state->ts_intrmsi_hdl);
1059 1055
1060 1056 TAVOR_TNF_EXIT(tavor_isr_fini);
1061 1057 }
1062 1058
1063 1059
1064 1060 /*
1065 1061 * tavor_fix_error_buf()
1066 1062 * Context: Only called from attach().
1067 1063 *
1068 1064 * The error_buf_addr returned from QUERY_FW is a PCI address.
1069 1065 * We need to convert it to an offset from the base address,
1070 1066 * which is stored in the assigned-addresses property.
1071 1067 */
1072 1068 static int
1073 1069 tavor_fix_error_buf(tavor_state_t *state)
1074 1070 {
1075 1071 int assigned_addr_len;
1076 1072 pci_regspec_t *assigned_addr;
1077 1073
1078 1074 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, state->ts_dip,
1079 1075 DDI_PROP_DONTPASS, "assigned-addresses", (int **)&assigned_addr,
1080 1076 (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
1081 1077 return (DDI_FAILURE);
1082 1078
1083 1079 state->ts_fw.error_buf_addr -= assigned_addr[0].pci_phys_low +
1084 1080 ((uint64_t)(assigned_addr[0].pci_phys_mid) << 32);
1085 1081 ddi_prop_free(assigned_addr);
1086 1082 return (DDI_SUCCESS);
1087 1083 }
1088 1084
1089 1085 /*
1090 1086 * tavor_hw_init()
1091 1087 * Context: Only called from attach() path context
1092 1088 */
1093 1089 static int
1094 1090 tavor_hw_init(tavor_state_t *state)
1095 1091 {
1096 1092 tavor_drv_cleanup_level_t cleanup;
1097 1093 sm_nodeinfo_t nodeinfo;
1098 1094 uint64_t errorcode;
1099 1095 off_t ddr_size;
1100 1096 int status;
1101 1097 int retries;
1102 1098
1103 1099 TAVOR_TNF_ENTER(tavor_hw_init);
1104 1100
1105 1101 /* This is where driver initialization begins */
1106 1102 cleanup = TAVOR_DRV_CLEANUP_LEVEL0;
1107 1103
1108 1104 /* Setup device access attributes */
1109 1105 state->ts_reg_accattr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1110 1106 state->ts_reg_accattr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
1111 1107 state->ts_reg_accattr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1112 1108
1113 1109 /* Setup for PCI config read/write of HCA device */
1114 1110 status = pci_config_setup(state->ts_dip, &state->ts_pci_cfghdl);
1115 1111 if (status != DDI_SUCCESS) {
1116 1112 tavor_hw_fini(state, cleanup);
1117 1113 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1118 1114 "hw_init_PCI_config_space_regmap_fail");
1119 1115 /* This case is not the degraded one */
1120 1116 return (DDI_FAILURE);
1121 1117 }
1122 1118
1123 1119 /* Map in Tavor registers (CMD, UAR, DDR) and setup offsets */
1124 1120 status = ddi_regs_map_setup(state->ts_dip, TAVOR_CMD_BAR,
1125 1121 &state->ts_reg_cmd_baseaddr, 0, 0, &state->ts_reg_accattr,
1126 1122 &state->ts_reg_cmdhdl);
1127 1123 if (status != DDI_SUCCESS) {
1128 1124 tavor_hw_fini(state, cleanup);
1129 1125 TNF_PROBE_0(tavor_hw_init_CMD_ddirms_fail, TAVOR_TNF_ERROR, "");
1130 1126 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1131 1127 "hw_init_CMD_ddirms_fail");
1132 1128 TAVOR_TNF_EXIT(tavor_hw_init);
1133 1129 return (DDI_FAILURE);
1134 1130 }
1135 1131 cleanup = TAVOR_DRV_CLEANUP_LEVEL1;
1136 1132
1137 1133 status = ddi_regs_map_setup(state->ts_dip, TAVOR_UAR_BAR,
1138 1134 &state->ts_reg_uar_baseaddr, 0, 0, &state->ts_reg_accattr,
1139 1135 &state->ts_reg_uarhdl);
1140 1136 if (status != DDI_SUCCESS) {
1141 1137 tavor_hw_fini(state, cleanup);
1142 1138 TNF_PROBE_0(tavor_hw_init_UAR_ddirms_fail, TAVOR_TNF_ERROR, "");
1143 1139 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1144 1140 "hw_init_UAR_ddirms_fail");
1145 1141 TAVOR_TNF_EXIT(tavor_hw_init);
1146 1142 return (DDI_FAILURE);
1147 1143 }
1148 1144 cleanup = TAVOR_DRV_CLEANUP_LEVEL2;
1149 1145
1150 1146 status = ddi_dev_regsize(state->ts_dip, TAVOR_DDR_BAR, &ddr_size);
1151 1147 if (status != DDI_SUCCESS) {
1152 1148 cmn_err(CE_CONT, "Tavor: ddi_dev_regsize() failed "
1153 1149 "(check HCA-attached DIMM memory?)\n");
1154 1150 tavor_hw_fini(state, cleanup);
1155 1151 TNF_PROBE_0(tavor_hw_init_DDR_ddi_regsize_fail,
1156 1152 TAVOR_TNF_ERROR, "");
1157 1153 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1158 1154 "hw_init_DDR_ddi_regsize_fail");
1159 1155 TAVOR_TNF_EXIT(tavor_hw_init);
1160 1156 return (DDI_FAILURE);
1161 1157 }
1162 1158
1163 1159 #if !defined(_ELF64) && !defined(__sparc)
1164 1160 /*
1165 1161 * For 32 bit x86/x64 kernels, where there is limited kernel virtual
1166 1162 * memory available, define a minimal memory footprint. This is
1167 1163 * specified in order to not take up too much resources, thus starving
1168 1164 * out others. Only specified if the HCA DIMM is equal to or greater
1169 1165 * than 256MB.
1170 1166 *
1171 1167 * Note: x86/x64 install and safemode boot are both 32bit.
1172 1168 */
1173 1169 ddr_size = TAVOR_DDR_SIZE_MIN;
1174 1170 #endif /* !(_ELF64) && !(__sparc) */
1175 1171
1176 1172 state->ts_cfg_profile_setting = ddr_size;
1177 1173
1178 1174 status = ddi_regs_map_setup(state->ts_dip, TAVOR_DDR_BAR,
1179 1175 &state->ts_reg_ddr_baseaddr, 0, ddr_size, &state->ts_reg_accattr,
1180 1176 &state->ts_reg_ddrhdl);
1181 1177
1182 1178 /*
1183 1179 * On 32-bit platform testing (primarily x86), it was seen that the
1184 1180 * ddi_regs_map_setup() call would fail because there wasn't enough
1185 1181 * kernel virtual address space available to map in the entire 256MB
1186 1182 * DDR. So we add this check in here, so that if the 256 (or other
1187 1183 * larger value of DDR) map in fails, that we fallback to try the lower
1188 1184 * size of 128MB.
1189 1185 *
1190 1186 * Note: If we only have 128MB of DDR in the system in the first place,
1191 1187 * we don't try another ddi_regs_map_setup(), and just skip over this
1192 1188 * check and return failures.
1193 1189 */
1194 1190 if (status == DDI_ME_NORESOURCES && ddr_size > TAVOR_DDR_SIZE_128) {
1195 1191 /* Try falling back to 128MB DDR mapping */
1196 1192 status = ddi_regs_map_setup(state->ts_dip, TAVOR_DDR_BAR,
1197 1193 &state->ts_reg_ddr_baseaddr, 0, TAVOR_DDR_SIZE_128,
1198 1194 &state->ts_reg_accattr, &state->ts_reg_ddrhdl);
1199 1195
1200 1196 /*
1201 1197 * 128MB DDR mapping worked.
1202 1198 * Set the updated config profile setting here.
1203 1199 */
1204 1200 if (status == DDI_SUCCESS) {
1205 1201 TNF_PROBE_0(tavor_hw_init_DDR_128mb_fallback_success,
1206 1202 TAVOR_TNF_TRACE, "");
1207 1203 state->ts_cfg_profile_setting = TAVOR_DDR_SIZE_128;
1208 1204 }
1209 1205 }
1210 1206
1211 1207 if (status != DDI_SUCCESS) {
1212 1208 if (status == DDI_ME_RNUMBER_RANGE) {
1213 1209 cmn_err(CE_CONT, "Tavor: ddi_regs_map_setup() failed "
1214 1210 "(check HCA-attached DIMM memory?)\n");
1215 1211 }
1216 1212 tavor_hw_fini(state, cleanup);
1217 1213 TNF_PROBE_0(tavor_hw_init_DDR_ddirms_fail, TAVOR_TNF_ERROR, "");
1218 1214 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1219 1215 "hw_init_DDR_ddirms_fail");
1220 1216 TAVOR_TNF_EXIT(tavor_hw_init);
1221 1217 return (DDI_FAILURE);
1222 1218 }
1223 1219 cleanup = TAVOR_DRV_CLEANUP_LEVEL3;
1224 1220
1225 1221 /* Setup Tavor Host Command Register (HCR) */
1226 1222 state->ts_cmd_regs.hcr = (tavor_hw_hcr_t *)
1227 1223 ((uintptr_t)state->ts_reg_cmd_baseaddr + TAVOR_CMD_HCR_OFFSET);
1228 1224
1229 1225 /* Setup Tavor Event Cause Register (ecr and clr_ecr) */
1230 1226 state->ts_cmd_regs.ecr = (uint64_t *)
1231 1227 ((uintptr_t)state->ts_reg_cmd_baseaddr + TAVOR_CMD_ECR_OFFSET);
1232 1228 state->ts_cmd_regs.clr_ecr = (uint64_t *)
1233 1229 ((uintptr_t)state->ts_reg_cmd_baseaddr + TAVOR_CMD_CLR_ECR_OFFSET);
1234 1230
1235 1231 /* Setup Tavor Software Reset register (sw_reset) */
1236 1232 state->ts_cmd_regs.sw_reset = (uint32_t *)
1237 1233 ((uintptr_t)state->ts_reg_cmd_baseaddr + TAVOR_CMD_SW_RESET_OFFSET);
1238 1234
1239 1235 /* Setup Tavor Clear Interrupt register (clr_int) */
1240 1236 state->ts_cmd_regs.clr_int = (uint64_t *)
1241 1237 ((uintptr_t)state->ts_reg_cmd_baseaddr + TAVOR_CMD_CLR_INT_OFFSET);
1242 1238
1243 1239 /* Initialize the Phase1 Tavor configuration profile */
1244 1240 status = tavor_cfg_profile_init_phase1(state);
1245 1241 if (status != DDI_SUCCESS) {
1246 1242 tavor_hw_fini(state, cleanup);
1247 1243 TNF_PROBE_0(tavor_hw_init_cfginit_fail, TAVOR_TNF_ERROR, "");
1248 1244 TAVOR_ATTACH_MSG(state->ts_attach_buf, "hw_init_cfginit_fail");
1249 1245 TAVOR_TNF_EXIT(tavor_hw_init);
1250 1246 return (DDI_FAILURE);
1251 1247 }
1252 1248 cleanup = TAVOR_DRV_CLEANUP_LEVEL4;
1253 1249
1254 1250 /* Do a software reset of the Tavor HW to ensure proper state */
1255 1251 status = tavor_sw_reset(state);
1256 1252 if (status != TAVOR_CMD_SUCCESS) {
1257 1253 tavor_hw_fini(state, cleanup);
1258 1254 TNF_PROBE_0(tavor_hw_init_sw_reset_fail, TAVOR_TNF_ERROR, "");
1259 1255 TAVOR_ATTACH_MSG(state->ts_attach_buf, "hw_init_sw_reset_fail");
1260 1256 TAVOR_TNF_EXIT(tavor_hw_init);
1261 1257 return (DDI_FAILURE);
1262 1258 }
1263 1259
1264 1260 /* Post the SYS_EN command to start the hardware */
1265 1261 status = tavor_sys_en_cmd_post(state, TAVOR_CMD_SYS_EN_NORMAL,
1266 1262 &errorcode, TAVOR_CMD_NOSLEEP_SPIN);
1267 1263 if (status != TAVOR_CMD_SUCCESS) {
1268 1264 if ((status == TAVOR_CMD_BAD_NVMEM) ||
1269 1265 (status == TAVOR_CMD_DDR_MEM_ERR)) {
1270 1266 cmn_err(CE_CONT, "Tavor: SYS_EN command failed: 0x%x "
1271 1267 "0x%" PRIx64 " (invalid firmware image?)\n",
1272 1268 status, errorcode);
1273 1269 } else {
1274 1270 cmn_err(CE_CONT, "Tavor: SYS_EN command failed: 0x%x "
1275 1271 "0x%" PRIx64 "\n", status, errorcode);
1276 1272 }
1277 1273 tavor_hw_fini(state, cleanup);
1278 1274 TNF_PROBE_0(tavor_hw_init_sys_en_cmd_fail,
1279 1275 TAVOR_TNF_ERROR, "");
1280 1276 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1281 1277 "hw_init_sys_en_cmd_fail");
1282 1278 TAVOR_TNF_EXIT(tavor_hw_init);
1283 1279 return (DDI_FAILURE);
1284 1280 }
1285 1281 cleanup = TAVOR_DRV_CLEANUP_LEVEL5;
1286 1282
1287 1283 /* First phase of init for Tavor configuration/resources */
1288 1284 status = tavor_rsrc_init_phase1(state);
1289 1285 if (status != DDI_SUCCESS) {
1290 1286 tavor_hw_fini(state, cleanup);
1291 1287 TNF_PROBE_0(tavor_hw_init_rsrcinit1_fail, TAVOR_TNF_ERROR, "");
1292 1288 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1293 1289 "hw_init_rsrcinit1_fail");
1294 1290 TAVOR_TNF_EXIT(tavor_hw_init);
1295 1291 return (DDI_FAILURE);
1296 1292 }
1297 1293 cleanup = TAVOR_DRV_CLEANUP_LEVEL6;
1298 1294
1299 1295 /* Query the DDR properties (e.g. total DDR size) */
1300 1296 status = tavor_cmn_query_cmd_post(state, QUERY_DDR, 0,
1301 1297 &state->ts_ddr, sizeof (tavor_hw_queryddr_t),
1302 1298 TAVOR_CMD_NOSLEEP_SPIN);
1303 1299 if (status != TAVOR_CMD_SUCCESS) {
1304 1300 cmn_err(CE_CONT, "Tavor: QUERY_DDR command failed: %08x\n",
1305 1301 status);
1306 1302 tavor_hw_fini(state, cleanup);
1307 1303 TNF_PROBE_0(tavor_hw_init_query_ddr_cmd_fail,
1308 1304 TAVOR_TNF_ERROR, "");
1309 1305 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1310 1306 "hw_init_query_ddr_cmd_fail");
1311 1307 TAVOR_TNF_EXIT(tavor_hw_init);
1312 1308 return (DDI_FAILURE);
1313 1309 }
1314 1310
1315 1311 /* Figure out how big the firmware image (in DDR) is */
1316 1312 status = tavor_cmn_query_cmd_post(state, QUERY_FW, 0, &state->ts_fw,
1317 1313 sizeof (tavor_hw_queryfw_t), TAVOR_CMD_NOSLEEP_SPIN);
1318 1314 if (status != TAVOR_CMD_SUCCESS) {
1319 1315 cmn_err(CE_CONT, "Tavor: QUERY_FW command failed: %08x\n",
1320 1316 status);
1321 1317 tavor_hw_fini(state, cleanup);
1322 1318 TNF_PROBE_0(tavor_hw_init_query_fw_cmd_fail,
1323 1319 TAVOR_TNF_ERROR, "");
1324 1320 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1325 1321 "hw_init_query_fw_cmd_fail");
1326 1322 TAVOR_TNF_EXIT(tavor_hw_init);
1327 1323 return (DDI_FAILURE);
1328 1324 }
1329 1325
1330 1326 if (tavor_fix_error_buf(state) != DDI_SUCCESS) {
1331 1327 tavor_hw_fini(state, cleanup);
1332 1328 TNF_PROBE_0(tavor_hw_init_fixerrorbuf_fail,
1333 1329 TAVOR_TNF_ERROR, "");
1334 1330 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1335 1331 "hw_init_fixerrorbuf_fail");
1336 1332 TAVOR_TNF_EXIT(tavor_hw_init);
1337 1333 return (DDI_FAILURE);
1338 1334 }
1339 1335
1340 1336 /* Validate that the FW version is appropriate */
1341 1337 status = tavor_fw_version_check(state);
1342 1338 if (status != DDI_SUCCESS) {
1343 1339 if (state->ts_operational_mode == TAVOR_HCA_MODE) {
1344 1340 cmn_err(CE_CONT, "Unsupported Tavor FW version: "
1345 1341 "expected: %04d.%04d.%04d, "
1346 1342 "actual: %04d.%04d.%04d\n",
1347 1343 TAVOR_FW_VER_MAJOR,
1348 1344 TAVOR_FW_VER_MINOR,
1349 1345 TAVOR_FW_VER_SUBMINOR,
1350 1346 state->ts_fw.fw_rev_major,
1351 1347 state->ts_fw.fw_rev_minor,
1352 1348 state->ts_fw.fw_rev_subminor);
1353 1349 } else if (state->ts_operational_mode == TAVOR_COMPAT_MODE) {
1354 1350 cmn_err(CE_CONT, "Unsupported Tavor Compat FW version: "
1355 1351 "expected: %04d.%04d.%04d, "
1356 1352 "actual: %04d.%04d.%04d\n",
1357 1353 TAVOR_COMPAT_FW_VER_MAJOR,
1358 1354 TAVOR_COMPAT_FW_VER_MINOR,
1359 1355 TAVOR_COMPAT_FW_VER_SUBMINOR,
1360 1356 state->ts_fw.fw_rev_major,
1361 1357 state->ts_fw.fw_rev_minor,
1362 1358 state->ts_fw.fw_rev_subminor);
1363 1359 } else {
1364 1360 cmn_err(CE_CONT, "Unsupported FW version: "
1365 1361 "%04d.%04d.%04d\n",
1366 1362 state->ts_fw.fw_rev_major,
1367 1363 state->ts_fw.fw_rev_minor,
1368 1364 state->ts_fw.fw_rev_subminor);
1369 1365 }
1370 1366 tavor_hw_fini(state, cleanup);
1371 1367 TNF_PROBE_0(tavor_hw_init_checkfwver_fail,
1372 1368 TAVOR_TNF_ERROR, "");
1373 1369 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1374 1370 "hw_init_checkfwver_fail");
1375 1371 TAVOR_TNF_EXIT(tavor_hw_init);
1376 1372 return (DDI_FAILURE);
1377 1373 }
1378 1374
1379 1375 drv_usecwait(10);
1380 1376 retries = 1000; /* retry up to 1 second before giving up */
1381 1377 retry:
1382 1378 /* Call MOD_STAT_CFG to setup SRQ support (or disable) */
1383 1379 status = tavor_mod_stat_cfg_cmd_post(state);
1384 1380 if (status != DDI_SUCCESS) {
1385 1381 if (retries > 0) {
1386 1382 drv_usecwait(1000);
1387 1383 retries--;
1388 1384 goto retry;
1389 1385 }
1390 1386 cmn_err(CE_CONT, "Tavor: MOD_STAT_CFG command failed: %08x\n",
1391 1387 status);
1392 1388 tavor_hw_fini(state, cleanup);
1393 1389 TNF_PROBE_0(tavor_hw_init_mod_stat_cfg_cmd_fail,
1394 1390 TAVOR_TNF_ERROR, "");
1395 1391 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1396 1392 "hw_init_mod_stat_cfg_cmd_fail");
1397 1393 TAVOR_TNF_EXIT(tavor_hw_init);
1398 1394 return (DDI_FAILURE);
1399 1395 }
1400 1396
1401 1397 /* Figure out Tavor device limits */
1402 1398 status = tavor_cmn_query_cmd_post(state, QUERY_DEV_LIM, 0,
1403 1399 &state->ts_devlim, sizeof (tavor_hw_querydevlim_t),
1404 1400 TAVOR_CMD_NOSLEEP_SPIN);
1405 1401 if (status != TAVOR_CMD_SUCCESS) {
1406 1402 cmn_err(CE_CONT, "Tavor: QUERY_DEV_LIM command failed: %08x\n",
1407 1403 status);
1408 1404 tavor_hw_fini(state, cleanup);
1409 1405 TNF_PROBE_0(tavor_hw_init_query_devlim_cmd_fail,
1410 1406 TAVOR_TNF_ERROR, "");
1411 1407 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1412 1408 "hw_init_query_devlim_cmd_fail");
1413 1409 TAVOR_TNF_EXIT(tavor_hw_init);
1414 1410 return (DDI_FAILURE);
1415 1411 }
1416 1412
1417 1413 /* Initialize the Phase2 Tavor configuration profile */
1418 1414 status = tavor_cfg_profile_init_phase2(state);
1419 1415 if (status != DDI_SUCCESS) {
1420 1416 tavor_hw_fini(state, cleanup);
1421 1417 TNF_PROBE_0(tavor_hw_init_cfginit2_fail, TAVOR_TNF_ERROR, "");
1422 1418 TAVOR_ATTACH_MSG(state->ts_attach_buf, "hw_init_cfginit2_fail");
1423 1419 TAVOR_TNF_EXIT(tavor_hw_init);
1424 1420 return (DDI_FAILURE);
1425 1421 }
1426 1422
1427 1423 /* Second phase of init for Tavor configuration/resources */
1428 1424 status = tavor_rsrc_init_phase2(state);
1429 1425 if (status != DDI_SUCCESS) {
1430 1426 tavor_hw_fini(state, cleanup);
1431 1427 TNF_PROBE_0(tavor_hw_init_rsrcinit2_fail, TAVOR_TNF_ERROR, "");
1432 1428 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1433 1429 "hw_init_rsrcinit2_fail");
1434 1430 TAVOR_TNF_EXIT(tavor_hw_init);
1435 1431 return (DDI_FAILURE);
1436 1432 }
1437 1433 cleanup = TAVOR_DRV_CLEANUP_LEVEL7;
1438 1434
1439 1435 /* Miscellaneous query information */
1440 1436 status = tavor_cmn_query_cmd_post(state, QUERY_ADAPTER, 0,
1441 1437 &state->ts_adapter, sizeof (tavor_hw_queryadapter_t),
1442 1438 TAVOR_CMD_NOSLEEP_SPIN);
1443 1439 if (status != TAVOR_CMD_SUCCESS) {
1444 1440 cmn_err(CE_CONT, "Tavor: QUERY_ADAPTER command failed: %08x\n",
1445 1441 status);
1446 1442 tavor_hw_fini(state, cleanup);
1447 1443 TNF_PROBE_0(tavor_hw_init_query_adapter_cmd_fail,
1448 1444 TAVOR_TNF_ERROR, "");
1449 1445 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1450 1446 "hw_init_query_adapter_cmd_fail");
1451 1447 TAVOR_TNF_EXIT(tavor_hw_init);
1452 1448 return (DDI_FAILURE);
1453 1449 }
1454 1450
1455 1451 /* Prepare configuration for Tavor INIT_HCA command */
1456 1452 tavor_hca_config_setup(state, &state->ts_hcaparams);
1457 1453
1458 1454 /* Post command to init Tavor HCA */
1459 1455 status = tavor_init_hca_cmd_post(state, &state->ts_hcaparams,
1460 1456 TAVOR_CMD_NOSLEEP_SPIN);
1461 1457 if (status != TAVOR_CMD_SUCCESS) {
1462 1458 cmn_err(CE_CONT, "Tavor: INIT_HCA command failed: %08x\n",
1463 1459 status);
1464 1460 tavor_hw_fini(state, cleanup);
1465 1461 TNF_PROBE_0(tavor_hw_init_init_hca_cmd_fail,
1466 1462 TAVOR_TNF_ERROR, "");
1467 1463 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1468 1464 "hw_init_init_hca_cmd_fail");
1469 1465 TAVOR_TNF_EXIT(tavor_hw_init);
1470 1466 return (DDI_FAILURE);
1471 1467 }
1472 1468 cleanup = TAVOR_DRV_CLEANUP_LEVEL8;
1473 1469
1474 1470 /* Allocate protection domain (PD) for Tavor internal use */
1475 1471 status = tavor_pd_alloc(state, &state->ts_pdhdl_internal, TAVOR_SLEEP);
1476 1472 if (status != DDI_SUCCESS) {
1477 1473 tavor_hw_fini(state, cleanup);
1478 1474 TNF_PROBE_0(tavor_hw_init_internal_pd_alloc_fail,
1479 1475 TAVOR_TNF_ERROR, "");
1480 1476 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1481 1477 "hw_init_internal_pd_alloc_fail");
1482 1478 TAVOR_TNF_EXIT(tavor_hw_init);
1483 1479 return (DDI_FAILURE);
1484 1480 }
1485 1481 cleanup = TAVOR_DRV_CLEANUP_LEVEL9;
1486 1482
1487 1483 /* Setup Tavor internal UAR pages (0 and 1) */
1488 1484 status = tavor_internal_uarpgs_init(state);
1489 1485 if (status != DDI_SUCCESS) {
1490 1486 tavor_hw_fini(state, cleanup);
1491 1487 TNF_PROBE_0(tavor_hw_init_internal_uarpgs_alloc_fail,
1492 1488 TAVOR_TNF_ERROR, "");
1493 1489 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1494 1490 "hw_init_internal_uarpgs_alloc_fail");
1495 1491 TAVOR_TNF_EXIT(tavor_hw_init);
1496 1492 return (DDI_FAILURE);
1497 1493 }
1498 1494 cleanup = TAVOR_DRV_CLEANUP_LEVEL10;
1499 1495
1500 1496 /* Query and initialize the Tavor interrupt/MSI information */
1501 1497 status = tavor_intr_or_msi_init(state);
1502 1498 if (status != DDI_SUCCESS) {
1503 1499 tavor_hw_fini(state, cleanup);
1504 1500 TNF_PROBE_0(tavor_intr_or_msi_init_fail,
1505 1501 TAVOR_TNF_ERROR, "");
1506 1502 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1507 1503 "intr_or_msi_init_fail");
1508 1504 TAVOR_TNF_EXIT(tavor_hw_init);
1509 1505 return (DDI_FAILURE);
1510 1506 }
1511 1507 cleanup = TAVOR_DRV_CLEANUP_LEVEL11;
1512 1508
1513 1509 /* Setup all of the Tavor EQs */
1514 1510 status = tavor_eq_init_all(state);
1515 1511 if (status != DDI_SUCCESS) {
1516 1512 tavor_hw_fini(state, cleanup);
1517 1513 TNF_PROBE_0(tavor_hw_init_eqinitall_fail, TAVOR_TNF_ERROR, "");
1518 1514 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1519 1515 "hw_init_eqinitall_fail");
1520 1516 TAVOR_TNF_EXIT(tavor_hw_init);
1521 1517 return (DDI_FAILURE);
1522 1518 }
1523 1519 cleanup = TAVOR_DRV_CLEANUP_LEVEL12;
1524 1520
1525 1521 /* Set aside contexts for QP0 and QP1 */
1526 1522 status = tavor_special_qp_contexts_reserve(state);
1527 1523 if (status != DDI_SUCCESS) {
1528 1524 tavor_hw_fini(state, cleanup);
1529 1525 TNF_PROBE_0(tavor_hw_init_reserve_special_qp_fail,
1530 1526 TAVOR_TNF_ERROR, "");
1531 1527 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1532 1528 "hw_init_reserve_special_qp_fail");
1533 1529 TAVOR_TNF_EXIT(tavor_hw_init);
1534 1530 return (DDI_FAILURE);
1535 1531 }
1536 1532 cleanup = TAVOR_DRV_CLEANUP_LEVEL13;
1537 1533
1538 1534 /* Initialize for multicast group handling */
1539 1535 status = tavor_mcg_init(state);
1540 1536 if (status != DDI_SUCCESS) {
1541 1537 tavor_hw_fini(state, cleanup);
1542 1538 TNF_PROBE_0(tavor_hw_init_mcg_init_fail, TAVOR_TNF_ERROR, "");
1543 1539 TAVOR_ATTACH_MSG(state->ts_attach_buf, "hw_init_mcg_init_fail");
1544 1540 TAVOR_TNF_EXIT(tavor_hw_init);
1545 1541 return (DDI_FAILURE);
1546 1542 }
1547 1543 cleanup = TAVOR_DRV_CLEANUP_LEVEL14;
1548 1544
1549 1545 /* Initialize the Tavor IB port(s) */
1550 1546 status = tavor_hca_port_init(state);
1551 1547 if (status != DDI_SUCCESS) {
1552 1548 tavor_hw_fini(state, cleanup);
1553 1549 TNF_PROBE_0(tavor_hw_init_hca_port_init_fail,
1554 1550 TAVOR_TNF_ERROR, "");
1555 1551 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1556 1552 "hw_init_hca_port_init_fail");
1557 1553 TAVOR_TNF_EXIT(tavor_hw_init);
1558 1554 return (DDI_FAILURE);
1559 1555 }
1560 1556 cleanup = TAVOR_DRV_CLEANUP_ALL;
1561 1557
1562 1558 /* Determine NodeGUID and SystemImageGUID */
1563 1559 status = tavor_getnodeinfo_cmd_post(state, TAVOR_CMD_NOSLEEP_SPIN,
1564 1560 &nodeinfo);
1565 1561 if (status != TAVOR_CMD_SUCCESS) {
1566 1562 cmn_err(CE_CONT, "Tavor: GetNodeInfo command failed: %08x\n",
1567 1563 status);
1568 1564 tavor_hw_fini(state, cleanup);
1569 1565 TNF_PROBE_0(tavor_hw_init_getnodeinfo_cmd_fail,
1570 1566 TAVOR_TNF_ERROR, "");
1571 1567 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1572 1568 "hw_init_getnodeinfo_cmd_fail");
1573 1569 TAVOR_TNF_EXIT(tavor_hw_init);
1574 1570 return (DDI_FAILURE);
1575 1571 }
1576 1572
1577 1573 /*
1578 1574 * If the NodeGUID value was set in OBP properties, then we use that
1579 1575 * value. But we still print a message if the value we queried from
1580 1576 * firmware does not match this value.
1581 1577 *
1582 1578 * Otherwise if OBP value is not set then we use the value from
1583 1579 * firmware unconditionally.
1584 1580 */
1585 1581 if (state->ts_cfg_profile->cp_nodeguid) {
1586 1582 state->ts_nodeguid = state->ts_cfg_profile->cp_nodeguid;
1587 1583 } else {
1588 1584 state->ts_nodeguid = nodeinfo.NodeGUID;
1589 1585 }
1590 1586
1591 1587 if (state->ts_nodeguid != nodeinfo.NodeGUID) {
1592 1588 cmn_err(CE_NOTE, "!NodeGUID value queried from firmware "
1593 1589 "does not match value set by device property");
1594 1590 }
1595 1591
1596 1592 /*
1597 1593 * If the SystemImageGUID value was set in OBP properties, then we use
1598 1594 * that value. But we still print a message if the value we queried
1599 1595 * from firmware does not match this value.
1600 1596 *
1601 1597 * Otherwise if OBP value is not set then we use the value from
1602 1598 * firmware unconditionally.
1603 1599 */
1604 1600 if (state->ts_cfg_profile->cp_sysimgguid) {
1605 1601 state->ts_sysimgguid = state->ts_cfg_profile->cp_sysimgguid;
1606 1602 } else {
1607 1603 state->ts_sysimgguid = nodeinfo.SystemImageGUID;
1608 1604 }
1609 1605
1610 1606 if (state->ts_sysimgguid != nodeinfo.SystemImageGUID) {
1611 1607 cmn_err(CE_NOTE, "!SystemImageGUID value queried from firmware "
1612 1608 "does not match value set by device property");
1613 1609 }
1614 1610
1615 1611 /* Get NodeDescription */
1616 1612 status = tavor_getnodedesc_cmd_post(state, TAVOR_CMD_NOSLEEP_SPIN,
1617 1613 (sm_nodedesc_t *)&state->ts_nodedesc);
1618 1614 if (status != TAVOR_CMD_SUCCESS) {
1619 1615 cmn_err(CE_CONT, "Tavor: GetNodeDesc command failed: %08x\n",
1620 1616 status);
1621 1617 tavor_hw_fini(state, cleanup);
1622 1618 TNF_PROBE_0(tavor_hw_init_getnodedesc_cmd_fail,
1623 1619 TAVOR_TNF_ERROR, "");
1624 1620 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1625 1621 "hw_init_getnodedesc_cmd_fail");
1626 1622 TAVOR_TNF_EXIT(tavor_hw_init);
1627 1623 return (DDI_FAILURE);
1628 1624 }
1629 1625
1630 1626 TAVOR_TNF_EXIT(tavor_hw_init);
1631 1627 return (DDI_SUCCESS);
1632 1628 }
1633 1629
1634 1630
1635 1631 /*
1636 1632 * tavor_hw_fini()
1637 1633 * Context: Only called from attach() and/or detach() path contexts
1638 1634 */
1639 1635 static void
1640 1636 tavor_hw_fini(tavor_state_t *state, tavor_drv_cleanup_level_t cleanup)
1641 1637 {
1642 1638 uint_t num_ports;
1643 1639 int status;
1644 1640
1645 1641 TAVOR_TNF_ENTER(tavor_hw_fini);
1646 1642
1647 1643 switch (cleanup) {
1648 1644 /*
1649 1645 * If we add more driver initialization steps that should be cleaned
1650 1646 * up here, we need to ensure that TAVOR_DRV_CLEANUP_ALL is still the
1651 1647 * first entry (i.e. corresponds to the last init step).
1652 1648 */
1653 1649 case TAVOR_DRV_CLEANUP_ALL:
1654 1650 /* Shutdown the Tavor IB port(s) */
1655 1651 num_ports = state->ts_cfg_profile->cp_num_ports;
1656 1652 (void) tavor_hca_ports_shutdown(state, num_ports);
1657 1653 /* FALLTHROUGH */
1658 1654
1659 1655 case TAVOR_DRV_CLEANUP_LEVEL14:
1660 1656 /* Teardown resources used for multicast group handling */
1661 1657 tavor_mcg_fini(state);
1662 1658 /* FALLTHROUGH */
1663 1659
1664 1660 case TAVOR_DRV_CLEANUP_LEVEL13:
1665 1661 /* Unreserve the special QP contexts */
1666 1662 tavor_special_qp_contexts_unreserve(state);
1667 1663 /* FALLTHROUGH */
1668 1664
1669 1665 case TAVOR_DRV_CLEANUP_LEVEL12:
1670 1666 /*
1671 1667 * Attempt to teardown all event queues (EQ). If we fail
1672 1668 * here then print a warning message and return. Something
1673 1669 * (either in HW or SW) has gone seriously wrong.
1674 1670 */
1675 1671 status = tavor_eq_fini_all(state);
1676 1672 if (status != DDI_SUCCESS) {
1677 1673 TAVOR_WARNING(state, "failed to teardown EQs");
1678 1674 TNF_PROBE_0(tavor_hw_fini_eqfiniall_fail,
1679 1675 TAVOR_TNF_ERROR, "");
1680 1676 TAVOR_TNF_EXIT(tavor_hw_fini);
1681 1677 return;
1682 1678 }
1683 1679 /* FALLTHROUGH */
1684 1680
1685 1681 case TAVOR_DRV_CLEANUP_LEVEL11:
1686 1682 status = tavor_intr_or_msi_fini(state);
1687 1683 if (status != DDI_SUCCESS) {
1688 1684 TAVOR_WARNING(state, "failed to free intr/MSI");
1689 1685 TNF_PROBE_0(tavor_hw_fini_intrmsifini_fail,
1690 1686 TAVOR_TNF_ERROR, "");
1691 1687 TAVOR_TNF_EXIT(tavor_hw_fini);
1692 1688 return;
1693 1689 }
1694 1690 /* FALLTHROUGH */
1695 1691
1696 1692 case TAVOR_DRV_CLEANUP_LEVEL10:
1697 1693 /* Free the resources for the Tavor internal UAR pages */
1698 1694 tavor_internal_uarpgs_fini(state);
1699 1695 /* FALLTHROUGH */
1700 1696
1701 1697 case TAVOR_DRV_CLEANUP_LEVEL9:
1702 1698 /*
1703 1699 * Free the PD that was used internally by Tavor software. If
1704 1700 * we fail here then print a warning and return. Something
1705 1701 * (probably software-related, but perhaps HW) has gone wrong.
1706 1702 */
1707 1703 status = tavor_pd_free(state, &state->ts_pdhdl_internal);
1708 1704 if (status != DDI_SUCCESS) {
1709 1705 TAVOR_WARNING(state, "failed to free internal PD");
1710 1706 TNF_PROBE_0(tavor_hw_fini_internal_pd_free_fail,
1711 1707 TAVOR_TNF_ERROR, "");
1712 1708 TAVOR_TNF_EXIT(tavor_hw_fini);
1713 1709 return;
1714 1710 }
1715 1711 /* FALLTHROUGH */
1716 1712
1717 1713 case TAVOR_DRV_CLEANUP_LEVEL8:
1718 1714 /*
1719 1715 * Post the CLOSE_HCA command to Tavor firmware. If we fail
1720 1716 * here then print a warning and return. Something (either in
1721 1717 * HW or SW) has gone seriously wrong.
1722 1718 */
1723 1719 status = tavor_close_hca_cmd_post(state,
1724 1720 TAVOR_CMD_NOSLEEP_SPIN);
1725 1721 if (status != TAVOR_CMD_SUCCESS) {
1726 1722 TAVOR_WARNING(state, "failed to shutdown HCA");
1727 1723 TNF_PROBE_0(tavor_hw_fini_closehcacmd_fail,
1728 1724 TAVOR_TNF_ERROR, "");
1729 1725 TAVOR_TNF_EXIT(tavor_hw_fini);
1730 1726 return;
1731 1727 }
1732 1728 /* FALLTHROUGH */
1733 1729
1734 1730 case TAVOR_DRV_CLEANUP_LEVEL7:
1735 1731 /* Cleanup all the phase2 resources first */
1736 1732 tavor_rsrc_fini(state, TAVOR_RSRC_CLEANUP_ALL);
1737 1733 /* FALLTHROUGH */
1738 1734
1739 1735 case TAVOR_DRV_CLEANUP_LEVEL6:
1740 1736 /* Then cleanup the phase1 resources */
1741 1737 tavor_rsrc_fini(state, TAVOR_RSRC_CLEANUP_PHASE1_COMPLETE);
1742 1738 /* FALLTHROUGH */
1743 1739
1744 1740 case TAVOR_DRV_CLEANUP_LEVEL5:
1745 1741 /*
1746 1742 * Post the SYS_DIS command to Tavor firmware to shut
1747 1743 * everything down again. If we fail here then print a
1748 1744 * warning and return. Something (probably in HW, but maybe
1749 1745 * in SW) has gone seriously wrong.
1750 1746 */
1751 1747 status = tavor_sys_dis_cmd_post(state, TAVOR_CMD_NOSLEEP_SPIN);
1752 1748 if (status != TAVOR_CMD_SUCCESS) {
1753 1749 TAVOR_WARNING(state, "failed to shutdown hardware");
1754 1750 TNF_PROBE_0(tavor_hw_fini_sys_dis_fail,
1755 1751 TAVOR_TNF_ERROR, "");
1756 1752 TAVOR_TNF_EXIT(tavor_hw_fini);
1757 1753 return;
1758 1754 }
1759 1755 /* FALLTHROUGH */
1760 1756
1761 1757 case TAVOR_DRV_CLEANUP_LEVEL4:
1762 1758 /* Teardown any resources allocated for the config profile */
1763 1759 tavor_cfg_profile_fini(state);
1764 1760 /* FALLTHROUGH */
1765 1761
1766 1762 case TAVOR_DRV_CLEANUP_LEVEL3:
1767 1763 ddi_regs_map_free(&state->ts_reg_ddrhdl);
1768 1764 /* FALLTHROUGH */
1769 1765
1770 1766 case TAVOR_DRV_CLEANUP_LEVEL2:
1771 1767 ddi_regs_map_free(&state->ts_reg_uarhdl);
1772 1768 /* FALLTHROUGH */
1773 1769
1774 1770 case TAVOR_DRV_CLEANUP_LEVEL1:
1775 1771 case TAVOR_DRV_CLEANUP_LEVEL0:
1776 1772 /*
1777 1773 * LEVEL1 and LEVEL0 resources are freed in
1778 1774 * tavor_drv_fini2().
1779 1775 */
1780 1776 break;
1781 1777
1782 1778 default:
1783 1779 TAVOR_WARNING(state, "unexpected driver cleanup level");
1784 1780 TNF_PROBE_0(tavor_hw_fini_default_fail, TAVOR_TNF_ERROR, "");
1785 1781 TAVOR_TNF_EXIT(tavor_hw_fini);
1786 1782 return;
1787 1783 }
1788 1784
1789 1785 TAVOR_TNF_EXIT(tavor_hw_fini);
1790 1786 }
1791 1787
1792 1788
1793 1789 /*
1794 1790 * tavor_soft_state_init()
1795 1791 * Context: Only called from attach() path context
1796 1792 */
1797 1793 static int
1798 1794 tavor_soft_state_init(tavor_state_t *state)
1799 1795 {
1800 1796 ibt_hca_attr_t *hca_attr;
1801 1797 uint64_t maxval, val;
1802 1798 ibt_hca_flags_t caps = IBT_HCA_NO_FLAGS;
1803 1799 int status;
1804 1800
1805 1801 TAVOR_TNF_ENTER(tavor_soft_state_init);
1806 1802
1807 1803 /*
1808 1804 * The ibc_hca_info_t struct is passed to the IBTF. This is the
1809 1805 * routine where we initialize it. Many of the init values come from
1810 1806 * either configuration variables or successful queries of the Tavor
1811 1807 * hardware abilities
1812 1808 */
1813 1809 state->ts_ibtfinfo.hca_ci_vers = IBCI_V4;
1814 1810 state->ts_ibtfinfo.hca_handle = (ibc_hca_hdl_t)state;
1815 1811 state->ts_ibtfinfo.hca_ops = &tavor_ibc_ops;
1816 1812
1817 1813 hca_attr = kmem_zalloc(sizeof (ibt_hca_attr_t), KM_SLEEP);
1818 1814 state->ts_ibtfinfo.hca_attr = hca_attr;
1819 1815
1820 1816 hca_attr->hca_dip = state->ts_dip;
1821 1817 hca_attr->hca_fw_major_version = state->ts_fw.fw_rev_major;
1822 1818 hca_attr->hca_fw_minor_version = state->ts_fw.fw_rev_minor;
1823 1819 hca_attr->hca_fw_micro_version = state->ts_fw.fw_rev_subminor;
1824 1820
1825 1821 /*
1826 1822 * Determine HCA capabilities:
1827 1823 * No default support for IBT_HCA_RD, IBT_HCA_RAW_MULTICAST,
1828 1824 * IBT_HCA_ATOMICS_GLOBAL, IBT_HCA_RESIZE_CHAN, IBT_HCA_INIT_TYPE,
1829 1825 * or IBT_HCA_SHUTDOWN_PORT
1830 1826 * But IBT_HCA_AH_PORT_CHECK, IBT_HCA_SQD_RTS_PORT, IBT_HCA_SI_GUID,
1831 1827 * IBT_HCA_RNR_NAK, and IBT_HCA_CURRENT_QP_STATE are always
1832 1828 * supported
1833 1829 * All other features are conditionally supported, depending on the
1834 1830 * status return by the Tavor HCA (in QUERY_DEV_LIM)
1835 1831 */
1836 1832 if (state->ts_devlim.ud_multi) {
1837 1833 caps |= IBT_HCA_UD_MULTICAST;
1838 1834 }
1839 1835 if (state->ts_devlim.atomic) {
1840 1836 caps |= IBT_HCA_ATOMICS_HCA;
1841 1837 }
1842 1838 if (state->ts_devlim.apm) {
1843 1839 caps |= IBT_HCA_AUTO_PATH_MIG;
1844 1840 }
1845 1841 if (state->ts_devlim.pkey_v) {
1846 1842 caps |= IBT_HCA_PKEY_CNTR;
1847 1843 }
1848 1844 if (state->ts_devlim.qkey_v) {
1849 1845 caps |= IBT_HCA_QKEY_CNTR;
1850 1846 }
1851 1847 if (state->ts_cfg_profile->cp_srq_enable) {
1852 1848 caps |= IBT_HCA_SRQ | IBT_HCA_RESIZE_SRQ;
1853 1849 }
1854 1850 caps |= (IBT_HCA_AH_PORT_CHECK | IBT_HCA_SQD_SQD_PORT |
1855 1851 IBT_HCA_SI_GUID | IBT_HCA_RNR_NAK | IBT_HCA_CURRENT_QP_STATE |
1856 1852 IBT_HCA_PORT_UP | IBT_HCA_SQD_STATE);
1857 1853 hca_attr->hca_flags = caps;
1858 1854 hca_attr->hca_flags2 = IBT_HCA2_DMA_MR;
1859 1855
1860 1856 /* Determine VendorID, DeviceID, and revision ID */
1861 1857 hca_attr->hca_vendor_id = state->ts_adapter.vendor_id;
1862 1858 hca_attr->hca_device_id = state->ts_adapter.device_id;
1863 1859 hca_attr->hca_version_id = state->ts_adapter.rev_id;
1864 1860
1865 1861 /*
1866 1862 * Determine number of available QPs and max QP size. Number of
1867 1863 * available QPs is determined by subtracting the number of
1868 1864 * "reserved QPs" (i.e. reserved for firmware use) from the
1869 1865 * total number configured.
1870 1866 */
1871 1867 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_num_qp);
1872 1868 hca_attr->hca_max_qp = val - ((uint64_t)1 <<
1873 1869 state->ts_devlim.log_rsvd_qp);
1874 1870 maxval = ((uint64_t)1 << state->ts_devlim.log_max_qp_sz);
1875 1871 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_max_qp_sz);
1876 1872 if (val > maxval) {
1877 1873 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
1878 1874 TNF_PROBE_2(tavor_soft_state_init_maxqpsz_toobig_fail,
1879 1875 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "max QP size "
1880 1876 "exceeds device maximum", tnf_uint, maxsz, maxval);
1881 1877 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1882 1878 "soft_state_init_maxqpsz_toobig_fail");
1883 1879 TAVOR_TNF_EXIT(tavor_soft_state_init);
1884 1880 return (DDI_FAILURE);
1885 1881 }
1886 1882 hca_attr->hca_max_qp_sz = val;
1887 1883
1888 1884 /* Determine max scatter-gather size in WQEs */
1889 1885 maxval = state->ts_devlim.max_sg;
1890 1886 val = state->ts_cfg_profile->cp_wqe_max_sgl;
1891 1887 if (val > maxval) {
1892 1888 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
1893 1889 TNF_PROBE_2(tavor_soft_state_init_toomanysgl_fail,
1894 1890 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "number of sgl "
1895 1891 "exceeds device maximum", tnf_uint, maxsgl, maxval);
1896 1892 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1897 1893 "soft_state_init_toomanysgl_fail");
1898 1894 TAVOR_TNF_EXIT(tavor_soft_state_init);
1899 1895 return (DDI_FAILURE);
1900 1896 }
1901 1897 /* If the rounded value for max SGL is too large, cap it */
1902 1898 if (state->ts_cfg_profile->cp_wqe_real_max_sgl > maxval) {
1903 1899 state->ts_cfg_profile->cp_wqe_real_max_sgl = maxval;
1904 1900 val = maxval;
1905 1901 } else {
1906 1902 val = state->ts_cfg_profile->cp_wqe_real_max_sgl;
1907 1903 }
1908 1904
1909 1905 hca_attr->hca_max_sgl = val;
1910 1906 hca_attr->hca_max_rd_sgl = 0; /* zero because RD is unsupported */
1911 1907
1912 1908 /*
1913 1909 * Determine number of available CQs and max CQ size. Number of
1914 1910 * available CQs is determined by subtracting the number of
1915 1911 * "reserved CQs" (i.e. reserved for firmware use) from the
1916 1912 * total number configured.
1917 1913 */
1918 1914 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_num_cq);
1919 1915 hca_attr->hca_max_cq = val - ((uint64_t)1 <<
1920 1916 state->ts_devlim.log_rsvd_cq);
1921 1917 maxval = ((uint64_t)1 << state->ts_devlim.log_max_cq_sz);
1922 1918 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_max_cq_sz) - 1;
1923 1919 if (val > maxval) {
1924 1920 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
1925 1921 TNF_PROBE_2(tavor_soft_state_init_maxcqsz_toobig_fail,
1926 1922 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "max CQ size "
1927 1923 "exceeds device maximum", tnf_uint, maxsz, maxval);
1928 1924 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1929 1925 "soft_state_init_maxcqsz_toobig_fail");
1930 1926 TAVOR_TNF_EXIT(tavor_soft_state_init);
1931 1927 return (DDI_FAILURE);
1932 1928 }
1933 1929 hca_attr->hca_max_cq_sz = val;
1934 1930
1935 1931 /*
1936 1932 * Determine number of available SRQs and max SRQ size. Number of
1937 1933 * available SRQs is determined by subtracting the number of
1938 1934 * "reserved SRQs" (i.e. reserved for firmware use) from the
1939 1935 * total number configured.
1940 1936 */
1941 1937 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_num_srq);
1942 1938 hca_attr->hca_max_srqs = val - ((uint64_t)1 <<
1943 1939 state->ts_devlim.log_rsvd_srq);
1944 1940 maxval = ((uint64_t)1 << state->ts_devlim.log_max_srq_sz);
1945 1941 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_max_srq_sz);
1946 1942
1947 1943 if (val > maxval) {
1948 1944 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
1949 1945 TNF_PROBE_2(tavor_soft_state_init_maxsrqsz_toobig_fail,
1950 1946 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "max SRQ size "
1951 1947 "exceeds device maximum", tnf_uint, maxsz, maxval);
1952 1948 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1953 1949 "soft_state_init_maxsrqsz_toobig_fail");
1954 1950 TAVOR_TNF_EXIT(tavor_soft_state_init);
1955 1951 return (DDI_FAILURE);
1956 1952 }
1957 1953 hca_attr->hca_max_srqs_sz = val;
1958 1954
1959 1955 val = state->ts_cfg_profile->cp_srq_max_sgl;
1960 1956 maxval = state->ts_devlim.max_sg;
1961 1957 if (val > maxval) {
1962 1958 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
1963 1959 TNF_PROBE_2(tavor_soft_state_init_toomanysrqsgl_fail,
1964 1960 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "number of srq "
1965 1961 "sgl exceeds device maximum", tnf_uint, maxsgl, maxval);
1966 1962 TAVOR_ATTACH_MSG(state->ts_attach_buf,
1967 1963 "soft_state_init_toomanysrqsgl_fail");
1968 1964 TAVOR_TNF_EXIT(tavor_soft_state_init);
1969 1965 return (DDI_FAILURE);
1970 1966 }
1971 1967 hca_attr->hca_max_srq_sgl = val;
1972 1968
1973 1969 /*
1974 1970 * Determine supported HCA page sizes
1975 1971 * XXX
1976 1972 * For now we simply return the system pagesize as the only supported
1977 1973 * pagesize
1978 1974 */
1979 1975 hca_attr->hca_page_sz = ((PAGESIZE == (1 << 13)) ? IBT_PAGE_8K :
1980 1976 IBT_PAGE_4K);
1981 1977
1982 1978 /*
1983 1979 * Determine number of available MemReg, MemWin, and their max size.
1984 1980 * Number of available MRs and MWs is determined by subtracting
1985 1981 * the number of "reserved MPTs" (i.e. reserved for firmware use)
1986 1982 * from the total number configured for each.
1987 1983 */
1988 1984 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_num_mpt);
1989 1985 hca_attr->hca_max_memr = val - ((uint64_t)1 <<
1990 1986 state->ts_devlim.log_rsvd_mpt);
1991 1987 hca_attr->hca_max_mem_win = val - ((uint64_t)1 <<
1992 1988 state->ts_devlim.log_rsvd_mpt);
1993 1989 maxval = state->ts_devlim.log_max_mrw_sz;
1994 1990 val = state->ts_cfg_profile->cp_log_max_mrw_sz;
1995 1991 if (val > maxval) {
1996 1992 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
1997 1993 TNF_PROBE_2(tavor_soft_state_init_maxmrwsz_toobig_fail,
1998 1994 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "max mrw size "
1999 1995 "exceeds device maximum", tnf_uint, maxsz, maxval);
2000 1996 TAVOR_ATTACH_MSG(state->ts_attach_buf,
2001 1997 "soft_state_init_maxmrwsz_toobig_fail");
2002 1998 TAVOR_TNF_EXIT(tavor_soft_state_init);
2003 1999 return (DDI_FAILURE);
2004 2000 }
2005 2001 hca_attr->hca_max_memr_len = ((uint64_t)1 << val);
2006 2002
2007 2003 /* Determine RDMA/Atomic properties */
2008 2004 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_num_rdb);
2009 2005 hca_attr->hca_max_rsc = val;
2010 2006 val = state->ts_cfg_profile->cp_hca_max_rdma_in_qp;
2011 2007 hca_attr->hca_max_rdma_in_qp = val;
2012 2008 val = state->ts_cfg_profile->cp_hca_max_rdma_out_qp;
2013 2009 hca_attr->hca_max_rdma_out_qp = val;
2014 2010 hca_attr->hca_max_rdma_in_ee = 0;
2015 2011 hca_attr->hca_max_rdma_out_ee = 0;
2016 2012
2017 2013 /*
2018 2014 * Determine maximum number of raw IPv6 and Ether QPs. Set to 0
2019 2015 * because neither type of raw QP is supported
2020 2016 */
2021 2017 hca_attr->hca_max_ipv6_qp = 0;
2022 2018 hca_attr->hca_max_ether_qp = 0;
2023 2019
2024 2020 /* Determine max number of MCGs and max QP-per-MCG */
2025 2021 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_num_qp);
2026 2022 hca_attr->hca_max_mcg_qps = val;
2027 2023 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_num_mcg);
2028 2024 hca_attr->hca_max_mcg = val;
2029 2025 val = state->ts_cfg_profile->cp_num_qp_per_mcg;
2030 2026 hca_attr->hca_max_qp_per_mcg = val;
2031 2027
2032 2028 /* Determine max number partitions (i.e. PKeys) */
2033 2029 maxval = ((uint64_t)1 << state->ts_devlim.log_max_pkey);
2034 2030 val = ((uint64_t)state->ts_cfg_profile->cp_num_ports <<
2035 2031 state->ts_cfg_profile->cp_log_max_pkeytbl);
2036 2032
2037 2033 if (val > maxval) {
2038 2034 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
2039 2035 TNF_PROBE_2(tavor_soft_state_init_toomanypkey_fail,
2040 2036 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "number of PKeys "
2041 2037 "exceeds device maximum", tnf_uint, maxpkey, maxval);
2042 2038 TAVOR_ATTACH_MSG(state->ts_attach_buf,
2043 2039 "soft_state_init_toomanypkey_fail");
2044 2040 TAVOR_TNF_EXIT(tavor_soft_state_init);
2045 2041 return (DDI_FAILURE);
2046 2042 }
2047 2043 hca_attr->hca_max_partitions = val;
2048 2044
2049 2045 /* Determine number of ports */
2050 2046 maxval = state->ts_devlim.num_ports;
2051 2047 val = state->ts_cfg_profile->cp_num_ports;
2052 2048 if ((val > maxval) || (val == 0)) {
2053 2049 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
2054 2050 TNF_PROBE_2(tavor_soft_state_init_toomanyports_fail,
2055 2051 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "number of ports "
2056 2052 "exceeds device maximum", tnf_uint, maxports, maxval);
2057 2053 TAVOR_ATTACH_MSG(state->ts_attach_buf,
2058 2054 "soft_state_init_toomanyports_fail");
2059 2055 TAVOR_TNF_EXIT(tavor_soft_state_init);
2060 2056 return (DDI_FAILURE);
2061 2057 }
2062 2058 hca_attr->hca_nports = val;
2063 2059
2064 2060 /* Copy NodeGUID and SystemImageGUID from softstate */
2065 2061 hca_attr->hca_node_guid = state->ts_nodeguid;
2066 2062 hca_attr->hca_si_guid = state->ts_sysimgguid;
2067 2063
2068 2064 /*
2069 2065 * Determine local ACK delay. Use the value suggested by the Tavor
2070 2066 * hardware (from the QUERY_DEV_LIM command)
2071 2067 */
2072 2068 hca_attr->hca_local_ack_delay = state->ts_devlim.ca_ack_delay;
2073 2069
2074 2070 /* Determine max SGID table and PKey table sizes */
2075 2071 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_max_gidtbl);
2076 2072 hca_attr->hca_max_port_sgid_tbl_sz = val;
2077 2073 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
2078 2074 hca_attr->hca_max_port_pkey_tbl_sz = val;
2079 2075
2080 2076 /* Determine max number of PDs */
2081 2077 maxval = ((uint64_t)1 << state->ts_devlim.log_max_pd);
2082 2078 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_num_pd);
2083 2079 if (val > maxval) {
2084 2080 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
2085 2081 TNF_PROBE_2(tavor_soft_state_init_toomanypd_fail,
2086 2082 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "number of PD "
2087 2083 "exceeds device maximum", tnf_uint, maxpd, maxval);
2088 2084 TAVOR_ATTACH_MSG(state->ts_attach_buf,
2089 2085 "soft_state_init_toomanypd_fail");
2090 2086 TAVOR_TNF_EXIT(tavor_soft_state_init);
2091 2087 return (DDI_FAILURE);
2092 2088 }
2093 2089 hca_attr->hca_max_pd = val;
2094 2090
2095 2091 /* Determine max number of Address Handles */
2096 2092 maxval = ((uint64_t)1 << state->ts_devlim.log_max_av);
2097 2093 val = ((uint64_t)1 << state->ts_cfg_profile->cp_log_num_ah);
2098 2094 if (val > maxval) {
2099 2095 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
2100 2096 TNF_PROBE_2(tavor_soft_state_init_toomanyah_fail,
2101 2097 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "number of AH "
2102 2098 "exceeds device maximum", tnf_uint, maxah, maxval);
2103 2099 TAVOR_ATTACH_MSG(state->ts_attach_buf,
2104 2100 "soft_state_init_toomanyah_fail");
2105 2101 TAVOR_TNF_EXIT(tavor_soft_state_init);
2106 2102 return (DDI_FAILURE);
2107 2103 }
2108 2104 hca_attr->hca_max_ah = val;
2109 2105
2110 2106 /* No RDDs or EECs (since Reliable Datagram is not supported) */
2111 2107 hca_attr->hca_max_rdd = 0;
2112 2108 hca_attr->hca_max_eec = 0;
2113 2109
2114 2110 /* Initialize lock for reserved UAR page access */
2115 2111 mutex_init(&state->ts_uar_lock, NULL, MUTEX_DRIVER,
2116 2112 DDI_INTR_PRI(state->ts_intrmsi_pri));
2117 2113
2118 2114 /* Initialize the flash fields */
2119 2115 state->ts_fw_flashstarted = 0;
2120 2116 mutex_init(&state->ts_fw_flashlock, NULL, MUTEX_DRIVER,
2121 2117 DDI_INTR_PRI(state->ts_intrmsi_pri));
2122 2118
2123 2119 /* Initialize the lock for the info ioctl */
2124 2120 mutex_init(&state->ts_info_lock, NULL, MUTEX_DRIVER,
2125 2121 DDI_INTR_PRI(state->ts_intrmsi_pri));
2126 2122
2127 2123 /* Initialize the AVL tree for QP number support */
2128 2124 tavor_qpn_avl_init(state);
2129 2125
2130 2126 /* Initialize the kstat info structure */
2131 2127 status = tavor_kstat_init(state);
2132 2128 if (status != DDI_SUCCESS) {
2133 2129 tavor_qpn_avl_fini(state);
2134 2130 mutex_destroy(&state->ts_info_lock);
2135 2131 mutex_destroy(&state->ts_fw_flashlock);
2136 2132 mutex_destroy(&state->ts_uar_lock);
2137 2133 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
2138 2134 TNF_PROBE_0(tavor_soft_state_init_kstatinit_fail,
2139 2135 TAVOR_TNF_ERROR, "");
2140 2136 TAVOR_ATTACH_MSG(state->ts_attach_buf,
2141 2137 "soft_state_init_kstatinit_fail");
2142 2138 TAVOR_TNF_EXIT(tavor_soft_state_init);
2143 2139 return (DDI_FAILURE);
2144 2140 }
2145 2141
2146 2142 TAVOR_TNF_EXIT(tavor_soft_state_init);
2147 2143 return (DDI_SUCCESS);
2148 2144 }
2149 2145
2150 2146
2151 2147 /*
2152 2148 * tavor_soft_state_fini()
2153 2149 * Context: Called only from detach() path context
2154 2150 */
2155 2151 static void
2156 2152 tavor_soft_state_fini(tavor_state_t *state)
2157 2153 {
2158 2154 TAVOR_TNF_ENTER(tavor_soft_state_fini);
2159 2155
2160 2156 /* Teardown the kstat info */
2161 2157 tavor_kstat_fini(state);
2162 2158
2163 2159 /* Teardown the AVL tree for QP number support */
2164 2160 tavor_qpn_avl_fini(state);
2165 2161
2166 2162 /* Free up info ioctl mutex */
2167 2163 mutex_destroy(&state->ts_info_lock);
2168 2164
2169 2165 /* Free up flash mutex */
2170 2166 mutex_destroy(&state->ts_fw_flashlock);
2171 2167
2172 2168 /* Free up the UAR page access mutex */
2173 2169 mutex_destroy(&state->ts_uar_lock);
2174 2170
2175 2171 /* Free up the hca_attr struct */
2176 2172 kmem_free(state->ts_ibtfinfo.hca_attr, sizeof (ibt_hca_attr_t));
2177 2173
2178 2174 TAVOR_TNF_EXIT(tavor_soft_state_fini);
2179 2175 }
2180 2176
2181 2177
2182 2178 /*
2183 2179 * tavor_hca_config_setup()
2184 2180 * Context: Only called from attach() path context
2185 2181 */
2186 2182 static void
2187 2183 tavor_hca_config_setup(tavor_state_t *state,
2188 2184 tavor_hw_initqueryhca_t *inithca)
2189 2185 {
2190 2186 tavor_rsrc_pool_info_t *rsrc_pool;
2191 2187 uint64_t ddr_baseaddr, ddr_base_map_addr;
2192 2188 uint64_t offset, addr;
2193 2189 uint_t mcg_size;
2194 2190
2195 2191 TAVOR_TNF_ENTER(tavor_hca_config_setup);
2196 2192
2197 2193 /* Set "host endianness". Default is big endian */
2198 2194 #ifdef _LITTLE_ENDIAN
2199 2195 inithca->big_endian = 0;
2200 2196 #else
2201 2197 inithca->big_endian = 1;
2202 2198 #endif
2203 2199 /* No Address Vector Protection, but Port Checking on by default */
2204 2200 inithca->udav_chk = TAVOR_UDAV_PROTECT_DISABLED;
2205 2201 inithca->udav_port_chk = TAVOR_UDAV_PORTCHK_ENABLED;
2206 2202
2207 2203 ddr_baseaddr = (uint64_t)(uintptr_t)state->ts_reg_ddr_baseaddr;
2208 2204 ddr_base_map_addr = (uint64_t)state->ts_ddr.ddr_baseaddr;
2209 2205
2210 2206 /* Setup QPC table */
2211 2207 rsrc_pool = &state->ts_rsrc_hdl[TAVOR_QPC];
2212 2208 offset = (uint64_t)(uintptr_t)rsrc_pool->rsrc_start - ddr_baseaddr;
2213 2209 addr = ddr_base_map_addr + offset;
2214 2210 inithca->context.qpc_baseaddr_h = (addr >> 32);
2215 2211 inithca->context.qpc_baseaddr_l = (addr & 0xFFFFFFFF) >> 7;
2216 2212 inithca->context.log_num_qp = state->ts_cfg_profile->cp_log_num_qp;
2217 2213
2218 2214 /* Setup EEC table (initialize to zero - RD unsupported) */
2219 2215 inithca->context.eec_baseaddr_h = 0;
2220 2216 inithca->context.eec_baseaddr_l = 0;
2221 2217 inithca->context.log_num_ee = 0;
2222 2218
2223 2219 /* Setup CQC table */
2224 2220 rsrc_pool = &state->ts_rsrc_hdl[TAVOR_CQC];
2225 2221 offset = (uint64_t)(uintptr_t)rsrc_pool->rsrc_start - ddr_baseaddr;
2226 2222 addr = ddr_base_map_addr + offset;
2227 2223 inithca->context.cqc_baseaddr_h = (addr >> 32);
2228 2224 inithca->context.cqc_baseaddr_l = (addr & 0xFFFFFFFF) >> 6;
2229 2225 inithca->context.log_num_cq = state->ts_cfg_profile->cp_log_num_cq;
2230 2226
2231 2227 /* Setup SRQC table */
2232 2228 rsrc_pool = &state->ts_rsrc_hdl[TAVOR_SRQC];
2233 2229 offset = (uint64_t)(uintptr_t)rsrc_pool->rsrc_start - ddr_baseaddr;
2234 2230 addr = ddr_base_map_addr + offset;
2235 2231 inithca->context.srqc_baseaddr_h = (addr >> 32);
2236 2232 inithca->context.srqc_baseaddr_l = (addr & 0xFFFFFFFF) >> 6;
2237 2233 inithca->context.log_num_srq =
2238 2234 state->ts_cfg_profile->cp_log_num_srq;
2239 2235
2240 2236 /* Setup EQPC table */
2241 2237 rsrc_pool = &state->ts_rsrc_hdl[TAVOR_EQPC];
2242 2238 offset = (uint64_t)(uintptr_t)rsrc_pool->rsrc_start - ddr_baseaddr;
2243 2239 addr = ddr_base_map_addr + offset;
2244 2240 inithca->context.eqpc_baseaddr = addr;
2245 2241
2246 2242 /* Setup EEEC table (initialize to zero - RD unsupported) */
2247 2243 inithca->context.eeec_baseaddr = 0;
2248 2244
2249 2245 /* Setup EQC table */
2250 2246 rsrc_pool = &state->ts_rsrc_hdl[TAVOR_EQC];
2251 2247 offset = (uint64_t)(uintptr_t)rsrc_pool->rsrc_start - ddr_baseaddr;
2252 2248 addr = ddr_base_map_addr + offset;
2253 2249 inithca->context.eqc_baseaddr_h = (addr >> 32);
2254 2250 inithca->context.eqc_baseaddr_l = (addr & 0xFFFFFFFF) >> 6;
2255 2251 inithca->context.log_num_eq = TAVOR_NUM_EQ_SHIFT;
2256 2252
2257 2253 /* Setup RDB table */
2258 2254 rsrc_pool = &state->ts_rsrc_hdl[TAVOR_RDB];
2259 2255 offset = (uint64_t)(uintptr_t)rsrc_pool->rsrc_start - ddr_baseaddr;
2260 2256 addr = ddr_base_map_addr + offset;
2261 2257 inithca->context.rdb_baseaddr_h = (addr >> 32);
2262 2258 inithca->context.rdb_baseaddr_l = 0;
2263 2259
2264 2260 /* Setup Multicast */
2265 2261 rsrc_pool = &state->ts_rsrc_hdl[TAVOR_MCG];
2266 2262 offset = (uint64_t)(uintptr_t)rsrc_pool->rsrc_start - ddr_baseaddr;
2267 2263 addr = ddr_base_map_addr + offset;
2268 2264 inithca->multi.mc_baseaddr = addr;
2269 2265 mcg_size = TAVOR_MCGMEM_SZ(state);
2270 2266 inithca->multi.log_mc_tbl_ent = highbit(mcg_size) - 1;
2271 2267 inithca->multi.mc_tbl_hash_sz =
2272 2268 (1 << state->ts_cfg_profile->cp_log_num_mcg_hash);
2273 2269 inithca->multi.mc_hash_fn = TAVOR_MCG_DEFAULT_HASH_FN;
2274 2270 inithca->multi.log_mc_tbl_sz = state->ts_cfg_profile->cp_log_num_mcg;
2275 2271
2276 2272
2277 2273 /* Setup TPT */
2278 2274 rsrc_pool = &state->ts_rsrc_hdl[TAVOR_MPT];
2279 2275 offset = (uint64_t)(uintptr_t)rsrc_pool->rsrc_start - ddr_baseaddr;
2280 2276 addr = ddr_base_map_addr + offset;
2281 2277 inithca->tpt.mpt_baseaddr = addr;
2282 2278 inithca->tpt.mttseg_sz = TAVOR_MTTSEG_SIZE_SHIFT;
2283 2279 inithca->tpt.log_mpt_sz = state->ts_cfg_profile->cp_log_num_mpt;
2284 2280 inithca->tpt.mtt_version = TAVOR_MTT_PG_WALK_VER;
2285 2281
2286 2282 rsrc_pool = &state->ts_rsrc_hdl[TAVOR_MTT];
2287 2283 offset = (uint64_t)(uintptr_t)rsrc_pool->rsrc_start - ddr_baseaddr;
2288 2284 addr = ddr_base_map_addr + offset;
2289 2285 inithca->tpt.mtt_baseaddr = addr;
2290 2286
2291 2287 /* Setup UAR */
2292 2288 rsrc_pool = &state->ts_rsrc_hdl[TAVOR_UAR_SCR];
2293 2289 offset = (uint64_t)(uintptr_t)rsrc_pool->rsrc_start - ddr_baseaddr;
2294 2290 addr = ddr_base_map_addr + offset;
2295 2291 inithca->uar.uarscr_baseaddr = addr;
2296 2292
2297 2293 inithca->uar.uar_pg_sz = PAGESHIFT - 0xC;
2298 2294
2299 2295 TAVOR_TNF_EXIT(tavor_hca_config_setup);
2300 2296 }
2301 2297
2302 2298
2303 2299 /*
2304 2300 * tavor_hca_port_init()
2305 2301 * Context: Only called from attach() path context
2306 2302 */
2307 2303 static int
2308 2304 tavor_hca_port_init(tavor_state_t *state)
2309 2305 {
2310 2306 tavor_hw_initib_t *portinits, *initib;
2311 2307 tavor_cfg_profile_t *cfgprof;
2312 2308 uint_t num_ports;
2313 2309 int i, status;
2314 2310 uint64_t maxval, val;
2315 2311 uint64_t sysimgguid, nodeguid, portguid;
2316 2312
2317 2313 TAVOR_TNF_ENTER(tavor_hca_port_init);
2318 2314
2319 2315 cfgprof = state->ts_cfg_profile;
2320 2316
2321 2317 /* Get number of HCA ports */
2322 2318 num_ports = cfgprof->cp_num_ports;
2323 2319
2324 2320 /* Allocate space for Tavor port init struct(s) */
2325 2321 portinits = (tavor_hw_initib_t *)kmem_zalloc(num_ports *
2326 2322 sizeof (tavor_hw_initib_t), KM_SLEEP);
2327 2323
2328 2324 /* Post command to initialize Tavor HCA port */
2329 2325 for (i = 0; i < num_ports; i++) {
2330 2326 initib = &portinits[i];
2331 2327
2332 2328 /*
2333 2329 * Determine whether we need to override the firmware's
2334 2330 * default SystemImageGUID setting.
2335 2331 */
2336 2332 sysimgguid = cfgprof->cp_sysimgguid;
2337 2333 if (sysimgguid != 0) {
2338 2334 initib->set_sysimg_guid = 1;
2339 2335 initib->sysimg_guid = sysimgguid;
2340 2336 }
2341 2337
2342 2338 /*
2343 2339 * Determine whether we need to override the firmware's
2344 2340 * default NodeGUID setting.
2345 2341 */
2346 2342 nodeguid = cfgprof->cp_nodeguid;
2347 2343 if (nodeguid != 0) {
2348 2344 initib->set_node_guid = 1;
2349 2345 initib->node_guid = nodeguid;
2350 2346 }
2351 2347
2352 2348 /*
2353 2349 * Determine whether we need to override the firmware's
2354 2350 * default PortGUID setting.
2355 2351 */
2356 2352 portguid = cfgprof->cp_portguid[i];
2357 2353 if (portguid != 0) {
2358 2354 initib->set_port_guid0 = 1;
2359 2355 initib->guid0 = portguid;
2360 2356 }
2361 2357
2362 2358 /* Validate max MTU size */
2363 2359 maxval = state->ts_devlim.max_mtu;
2364 2360 val = cfgprof->cp_max_mtu;
2365 2361 if (val > maxval) {
2366 2362 TNF_PROBE_2(tavor_hca_port_init_maxmtu_fail,
2367 2363 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "max "
2368 2364 "MTU size exceeds device maximum", tnf_uint,
2369 2365 maxmtu, maxval);
2370 2366 TAVOR_TNF_EXIT(tavor_hca_port_init);
2371 2367 goto init_ports_fail;
2372 2368 }
2373 2369 initib->mtu_cap = val;
2374 2370
2375 2371 /* Validate the max port width */
2376 2372 maxval = state->ts_devlim.max_port_width;
2377 2373 val = cfgprof->cp_max_port_width;
2378 2374 if (val > maxval) {
2379 2375 TNF_PROBE_2(tavor_hca_port_init_maxportwidth_fail,
2380 2376 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "max "
2381 2377 "port width exceeds device maximum", tnf_uint,
2382 2378 maxportwidth, maxval);
2383 2379 TAVOR_TNF_EXIT(tavor_hca_port_init);
2384 2380 goto init_ports_fail;
2385 2381 }
2386 2382 initib->port_width_cap = val;
2387 2383
2388 2384 /* Validate max VL cap size */
2389 2385 maxval = state->ts_devlim.max_vl;
2390 2386 val = cfgprof->cp_max_vlcap;
2391 2387 if (val > maxval) {
2392 2388 TNF_PROBE_2(tavor_hca_port_init_maxvlcap_fail,
2393 2389 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "max "
2394 2390 "VLcap size exceeds device maximum", tnf_uint,
2395 2391 maxvlcap, maxval);
2396 2392 TAVOR_TNF_EXIT(tavor_hca_port_init);
2397 2393 goto init_ports_fail;
2398 2394 }
2399 2395 initib->vl_cap = val;
2400 2396
2401 2397 /* Validate max GID table size */
2402 2398 maxval = ((uint64_t)1 << state->ts_devlim.log_max_gid);
2403 2399 val = ((uint64_t)1 << cfgprof->cp_log_max_gidtbl);
2404 2400 if (val > maxval) {
2405 2401 TNF_PROBE_2(tavor_hca_port_init_gidtable_fail,
2406 2402 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "max "
2407 2403 "GID table size exceeds device maximum", tnf_uint,
2408 2404 maxgidtbl, maxval);
2409 2405 TAVOR_TNF_EXIT(tavor_hca_port_init);
2410 2406 goto init_ports_fail;
2411 2407 }
2412 2408 initib->max_gid = val;
2413 2409
2414 2410 /* Validate max PKey table size */
2415 2411 maxval = ((uint64_t)1 << state->ts_devlim.log_max_pkey);
2416 2412 val = ((uint64_t)1 << cfgprof->cp_log_max_pkeytbl);
2417 2413 if (val > maxval) {
2418 2414 TNF_PROBE_2(tavor_hca_port_init_pkeytable_fail,
2419 2415 TAVOR_TNF_ERROR, "", tnf_string, errmsg, "max "
2420 2416 "PKey table size exceeds device maximum", tnf_uint,
2421 2417 maxpkeytbl, maxval);
2422 2418 TAVOR_TNF_EXIT(tavor_hca_port_init);
2423 2419 goto init_ports_fail;
2424 2420 }
2425 2421 initib->max_pkey = val;
2426 2422
2427 2423 /*
2428 2424 * Post the INIT_IB command to Tavor firmware. When this
2429 2425 * command completes, the corresponding Tavor port will be
2430 2426 * physically "Up" and initialized.
2431 2427 */
2432 2428 status = tavor_init_ib_cmd_post(state, initib, i + 1,
2433 2429 TAVOR_CMD_NOSLEEP_SPIN);
2434 2430 if (status != TAVOR_CMD_SUCCESS) {
2435 2431 cmn_err(CE_CONT, "Tavor: INIT_IB (port %02d) command "
2436 2432 "failed: %08x\n", i + 1, status);
2437 2433 TNF_PROBE_2(tavor_hca_port_init_init_ib_cmd_fail,
2438 2434 TAVOR_TNF_ERROR, "", tnf_uint, cmd_status, status,
2439 2435 tnf_uint, port, i + 1);
2440 2436 TAVOR_TNF_EXIT(tavor_hca_port_init);
2441 2437 goto init_ports_fail;
2442 2438 }
2443 2439 }
2444 2440
2445 2441 /* Free up the memory for Tavor port init struct(s), return success */
2446 2442 kmem_free(portinits, num_ports * sizeof (tavor_hw_initib_t));
2447 2443 TAVOR_TNF_EXIT(tavor_hca_port_init);
2448 2444 return (DDI_SUCCESS);
2449 2445
2450 2446 init_ports_fail:
2451 2447 /*
2452 2448 * Free up the memory for Tavor port init struct(s), shutdown any
2453 2449 * successfully initialized ports, and return failure
2454 2450 */
2455 2451 kmem_free(portinits, num_ports * sizeof (tavor_hw_initib_t));
2456 2452 (void) tavor_hca_ports_shutdown(state, i);
2457 2453
2458 2454 TAVOR_TNF_EXIT(tavor_hca_port_init);
2459 2455 return (DDI_FAILURE);
2460 2456 }
2461 2457
2462 2458
2463 2459 /*
2464 2460 * tavor_hca_ports_shutdown()
2465 2461 * Context: Only called from attach() and/or detach() path contexts
2466 2462 */
2467 2463 static int
2468 2464 tavor_hca_ports_shutdown(tavor_state_t *state, uint_t num_init)
2469 2465 {
2470 2466 int i, status;
2471 2467
2472 2468 TAVOR_TNF_ENTER(tavor_hca_ports_shutdown);
2473 2469
2474 2470 /*
2475 2471 * Post commands to shutdown all init'd Tavor HCA ports. Note: if
2476 2472 * any of these commands fail for any reason, it would be entirely
2477 2473 * unexpected and probably indicative a serious problem (HW or SW).
2478 2474 * Although we do return void from this function, this type of failure
2479 2475 * should not go unreported. That is why we have the warning message
2480 2476 * and the detailed TNF information.
2481 2477 */
2482 2478 for (i = 0; i < num_init; i++) {
2483 2479 status = tavor_close_ib_cmd_post(state, i + 1,
2484 2480 TAVOR_CMD_NOSLEEP_SPIN);
2485 2481 if (status != TAVOR_CMD_SUCCESS) {
2486 2482 TAVOR_WARNING(state, "failed to shutdown HCA port");
2487 2483 TNF_PROBE_2(tavor_hca_ports_shutdown_close_ib_cmd_fail,
2488 2484 TAVOR_TNF_ERROR, "", tnf_uint, cmd_status, status,
2489 2485 tnf_uint, port, i + 1);
2490 2486 TAVOR_TNF_EXIT(tavor_hca_ports_shutdown);
2491 2487 return (status);
2492 2488 }
2493 2489 }
2494 2490
2495 2491 TAVOR_TNF_EXIT(tavor_hca_ports_shutdown);
2496 2492
2497 2493 return (TAVOR_CMD_SUCCESS);
2498 2494 }
2499 2495
2500 2496
2501 2497 /*
2502 2498 * tavor_internal_uarpgs_init
2503 2499 * Context: Only called from attach() path context
2504 2500 */
2505 2501 static int
2506 2502 tavor_internal_uarpgs_init(tavor_state_t *state)
2507 2503 {
2508 2504 int status;
2509 2505
2510 2506 TAVOR_TNF_ENTER(tavor_internal_uarpgs_init);
2511 2507
2512 2508 /*
2513 2509 * Save away reserved Tavor UAR page #0. This UAR page is not to
2514 2510 * be used by software.
2515 2511 */
2516 2512 status = tavor_rsrc_alloc(state, TAVOR_UARPG, 1, TAVOR_SLEEP,
2517 2513 &state->ts_uarpg0_rsrc_rsrvd);
2518 2514 if (status != DDI_SUCCESS) {
2519 2515 TNF_PROBE_0(tavor_uarpg0_rsrcalloc_fail, TAVOR_TNF_ERROR, "");
2520 2516 TAVOR_TNF_EXIT(tavor_internal_uarpgs_init);
2521 2517 return (DDI_FAILURE);
2522 2518 }
2523 2519
2524 2520 /*
2525 2521 * Save away Tavor UAR page #1 (for internal use). This UAR page is
2526 2522 * the privileged UAR page through which all kernel generated
2527 2523 * doorbells will be rung.
2528 2524 */
2529 2525 status = tavor_rsrc_alloc(state, TAVOR_UARPG, 1, TAVOR_SLEEP,
2530 2526 &state->ts_uarpg1_rsrc);
2531 2527 if (status != DDI_SUCCESS) {
2532 2528 tavor_rsrc_free(state, &state->ts_uarpg0_rsrc_rsrvd);
2533 2529 TNF_PROBE_0(tavor_uarpg1_rsrcalloc_fail, TAVOR_TNF_ERROR, "");
2534 2530 TAVOR_TNF_EXIT(tavor_internal_uarpgs_init);
2535 2531 return (DDI_FAILURE);
2536 2532 }
2537 2533
2538 2534 /* Setup pointer to UAR page #1 doorbells */
2539 2535 state->ts_uar = (tavor_hw_uar_t *)state->ts_uarpg1_rsrc->tr_addr;
2540 2536
2541 2537 TAVOR_TNF_EXIT(tavor_internal_uarpgs_init);
2542 2538 return (DDI_SUCCESS);
2543 2539 }
2544 2540
2545 2541
2546 2542 /*
2547 2543 * tavor_internal_uarpgs_fini
2548 2544 * Context: Only called from attach() and/or detach() path contexts
2549 2545 */
2550 2546 static void
2551 2547 tavor_internal_uarpgs_fini(tavor_state_t *state)
2552 2548 {
2553 2549 TAVOR_TNF_ENTER(tavor_internal_uarpgs_fini);
2554 2550
2555 2551 /* Free up Tavor UAR page #1 (kernel driver doorbells) */
2556 2552 tavor_rsrc_free(state, &state->ts_uarpg1_rsrc);
2557 2553
2558 2554 /* Free up Tavor UAR page #0 (reserved) */
2559 2555 tavor_rsrc_free(state, &state->ts_uarpg0_rsrc_rsrvd);
2560 2556
2561 2557 TAVOR_TNF_EXIT(tavor_internal_uarpgs_fini);
2562 2558 }
2563 2559
2564 2560
2565 2561 /*
2566 2562 * tavor_special_qp_contexts_reserve()
2567 2563 * Context: Only called from attach() path context
2568 2564 */
2569 2565 static int
2570 2566 tavor_special_qp_contexts_reserve(tavor_state_t *state)
2571 2567 {
2572 2568 tavor_rsrc_t *qp0_rsrc, *qp1_rsrc;
2573 2569 int status;
2574 2570
2575 2571 TAVOR_TNF_ENTER(tavor_special_qp_contexts_reserve);
2576 2572
2577 2573 /* Initialize the lock used for special QP rsrc management */
2578 2574 mutex_init(&state->ts_spec_qplock, NULL, MUTEX_DRIVER,
2579 2575 DDI_INTR_PRI(state->ts_intrmsi_pri));
2580 2576
2581 2577 /*
2582 2578 * Reserve contexts for QP0. These QP contexts will be setup to
2583 2579 * act as aliases for the real QP0. Note: We are required to grab
2584 2580 * two QPs (one per port) even if we are operating in single-port
2585 2581 * mode.
2586 2582 */
2587 2583 status = tavor_rsrc_alloc(state, TAVOR_QPC, 2, TAVOR_SLEEP, &qp0_rsrc);
2588 2584 if (status != DDI_SUCCESS) {
2589 2585 mutex_destroy(&state->ts_spec_qplock);
2590 2586 TNF_PROBE_0(tavor_special_qp_contexts_reserve_qp0_fail,
2591 2587 TAVOR_TNF_ERROR, "");
2592 2588 TAVOR_TNF_EXIT(tavor_special_qp_contexts_reserve);
2593 2589 return (DDI_FAILURE);
2594 2590 }
2595 2591 state->ts_spec_qp0 = qp0_rsrc;
2596 2592
2597 2593 /*
2598 2594 * Reserve contexts for QP1. These QP contexts will be setup to
2599 2595 * act as aliases for the real QP1. Note: We are required to grab
2600 2596 * two QPs (one per port) even if we are operating in single-port
2601 2597 * mode.
2602 2598 */
2603 2599 status = tavor_rsrc_alloc(state, TAVOR_QPC, 2, TAVOR_SLEEP, &qp1_rsrc);
2604 2600 if (status != DDI_SUCCESS) {
2605 2601 tavor_rsrc_free(state, &qp0_rsrc);
2606 2602 mutex_destroy(&state->ts_spec_qplock);
2607 2603 TNF_PROBE_0(tavor_special_qp_contexts_reserve_qp1_fail,
2608 2604 TAVOR_TNF_ERROR, "");
2609 2605 TAVOR_TNF_EXIT(tavor_special_qp_contexts_reserve);
2610 2606 return (DDI_FAILURE);
2611 2607 }
2612 2608 state->ts_spec_qp1 = qp1_rsrc;
2613 2609
2614 2610 TAVOR_TNF_EXIT(tavor_special_qp_contexts_reserve);
2615 2611 return (DDI_SUCCESS);
2616 2612 }
2617 2613
2618 2614
2619 2615 /*
2620 2616 * tavor_special_qp_contexts_unreserve()
2621 2617 * Context: Only called from attach() and/or detach() path contexts
2622 2618 */
2623 2619 static void
2624 2620 tavor_special_qp_contexts_unreserve(tavor_state_t *state)
2625 2621 {
2626 2622 TAVOR_TNF_ENTER(tavor_special_qp_contexts_unreserve);
2627 2623
2628 2624 /* Unreserve contexts for QP1 */
2629 2625 tavor_rsrc_free(state, &state->ts_spec_qp1);
2630 2626
2631 2627 /* Unreserve contexts for QP0 */
2632 2628 tavor_rsrc_free(state, &state->ts_spec_qp0);
2633 2629
2634 2630 /* Destroy the lock used for special QP rsrc management */
2635 2631 mutex_destroy(&state->ts_spec_qplock);
2636 2632
2637 2633 TAVOR_TNF_EXIT(tavor_special_qp_contexts_unreserve);
2638 2634 }
2639 2635
2640 2636
2641 2637 /*
2642 2638 * tavor_sw_reset()
2643 2639 * Context: Currently called only from attach() path context
2644 2640 */
2645 2641 static int
2646 2642 tavor_sw_reset(tavor_state_t *state)
2647 2643 {
2648 2644 dev_info_t *dip, *pdip;
2649 2645 ddi_acc_handle_t hdl = state->ts_pci_cfghdl, phdl;
2650 2646 uint32_t reset_delay;
2651 2647 int status, i;
2652 2648
2653 2649 TAVOR_TNF_ENTER(tavor_sw_reset);
2654 2650
2655 2651 /*
2656 2652 * If the configured software reset delay is set to zero, then we
2657 2653 * will not attempt a software reset of the Tavor device.
2658 2654 */
2659 2655 reset_delay = state->ts_cfg_profile->cp_sw_reset_delay;
2660 2656 if (reset_delay == 0) {
2661 2657 TAVOR_TNF_EXIT(tavor_sw_reset);
2662 2658 return (DDI_SUCCESS);
2663 2659 }
2664 2660
2665 2661 /*
2666 2662 * Get dip for HCA device _and_ parent device as well. Parent access
2667 2663 * is necessary here because software reset of the Tavor hardware
2668 2664 * will reinitialize both the config registers of the PCI bridge
2669 2665 * (parent, if it exists) and the IB HCA (self)
2670 2666 */
2671 2667 dip = state->ts_dip;
2672 2668 pdip = ddi_get_parent(dip);
2673 2669
2674 2670 /* Query the PCI capabilities of the HCA device */
2675 2671 tavor_pci_capability_list(state, hdl);
2676 2672
2677 2673 /*
2678 2674 * Read all PCI config info (reg0...reg63). Note: According to the
2679 2675 * Tavor software reset application note, we should not read or
2680 2676 * restore the values in reg22 and reg23.
2681 2677 */
2682 2678 for (i = 0; i < TAVOR_SW_RESET_NUMREGS; i++) {
2683 2679 if ((i != TAVOR_SW_RESET_REG22_RSVD) &&
2684 2680 (i != TAVOR_SW_RESET_REG23_RSVD)) {
2685 2681 state->ts_cfg_data[i] = pci_config_get32(hdl, i << 2);
2686 2682 }
2687 2683 }
2688 2684
2689 2685 if (TAVOR_PARENT_IS_BRIDGE(pdip)) {
2690 2686 /*
2691 2687 * Setup for PCI config read/write of bridge device
2692 2688 */
2693 2689 status = pci_config_setup(pdip, &phdl);
2694 2690 if (status != DDI_SUCCESS) {
2695 2691 TNF_PROBE_0(tavor_sw_reset_pcicfg_p_fail,
2696 2692 TAVOR_TNF_ERROR, "");
2697 2693 TAVOR_TNF_EXIT(tavor_sw_reset);
2698 2694 return (DDI_FAILURE);
2699 2695 }
2700 2696
2701 2697 /*
2702 2698 * Read all PCI config info (reg0...reg63). Note: According to
2703 2699 * the Tavor software reset application note, we should not
2704 2700 * read or restore the values in reg22 and reg23.
2705 2701 */
2706 2702 for (i = 0; i < TAVOR_SW_RESET_NUMREGS; i++) {
2707 2703 if ((i != TAVOR_SW_RESET_REG22_RSVD) &&
2708 2704 (i != TAVOR_SW_RESET_REG23_RSVD)) {
2709 2705 state->ts_cfg_pdata[i] =
2710 2706 pci_config_get32(phdl, i << 2);
2711 2707 }
2712 2708 }
2713 2709 }
2714 2710
2715 2711 /*
2716 2712 * Perform the software reset (by writing 1 at offset 0xF0010)
2717 2713 */
2718 2714 ddi_put32(state->ts_reg_cmdhdl, state->ts_cmd_regs.sw_reset,
2719 2715 TAVOR_SW_RESET_START);
2720 2716
2721 2717 drv_usecwait(reset_delay);
2722 2718
2723 2719 if (TAVOR_PARENT_IS_BRIDGE(pdip)) {
2724 2720 /*
2725 2721 * Bridge exists, so wait for the bridge to become ready.
2726 2722 *
2727 2723 * The above delay is necessary to avoid system panic from
2728 2724 * Master Abort. If the device is accessed before this delay,
2729 2725 * device will not respond to config cycles and they will be
2730 2726 * terminate with a Master Abort which will panic the system.
2731 2727 * Below is the loop we use to poll status from the device to
2732 2728 * determine if it is OK to proceed.
2733 2729 */
2734 2730 i = 0;
2735 2731 while (pci_config_get32(phdl, 0) == TAVOR_SW_RESET_NOTDONE) {
2736 2732 drv_usecwait(TAVOR_SW_RESET_POLL_DELAY);
2737 2733 }
2738 2734
2739 2735 /*
2740 2736 * Write all the PCI config registers back into each device
2741 2737 * (except for reg22 and reg23 - see above)
2742 2738 */
2743 2739 for (i = 0; i < TAVOR_SW_RESET_NUMREGS; i++) {
2744 2740 if ((i != TAVOR_SW_RESET_REG22_RSVD) &&
2745 2741 (i != TAVOR_SW_RESET_REG23_RSVD)) {
2746 2742 pci_config_put32(phdl, i << 2,
2747 2743 state->ts_cfg_pdata[i]);
2748 2744 }
2749 2745 }
2750 2746
2751 2747 /*
2752 2748 * Tear down the config setup (for bridge device)
2753 2749 */
2754 2750 pci_config_teardown(&phdl);
2755 2751
2756 2752 /* No Bridge Device */
2757 2753 } else {
2758 2754 /*
2759 2755 * Bridge does not exist, so instead wait for the device itself
2760 2756 * to become ready.
2761 2757 *
2762 2758 * The above delay is necessary to avoid system panic from
2763 2759 * Master Abort. If the device is accessed before this delay,
2764 2760 * device will not respond to config cycles and they will be
2765 2761 * terminate with a Master Abort which will panic the system.
2766 2762 * Below is the loop we use to poll status from the device to
2767 2763 * determine if it is OK to proceed.
2768 2764 */
2769 2765 i = 0;
2770 2766 while (pci_config_get32(hdl, 0) == TAVOR_SW_RESET_NOTDONE) {
2771 2767 drv_usecwait(TAVOR_SW_RESET_POLL_DELAY);
2772 2768 }
2773 2769 }
2774 2770
2775 2771 for (i = 0; i < TAVOR_SW_RESET_NUMREGS; i++) {
2776 2772 if ((i != TAVOR_SW_RESET_REG22_RSVD) &&
2777 2773 (i != TAVOR_SW_RESET_REG23_RSVD)) {
2778 2774 pci_config_put32(hdl, i << 2, state->ts_cfg_data[i]);
2779 2775 }
2780 2776 }
2781 2777
2782 2778 TAVOR_TNF_EXIT(tavor_sw_reset);
2783 2779 return (DDI_SUCCESS);
2784 2780 }
2785 2781
2786 2782
2787 2783 /*
2788 2784 * tavor_mcg_init()
2789 2785 * Context: Only called from attach() path context
2790 2786 */
2791 2787 static int
2792 2788 tavor_mcg_init(tavor_state_t *state)
2793 2789 {
2794 2790 uint_t mcg_tmp_sz;
2795 2791
2796 2792 TAVOR_TNF_ENTER(tavor_mcg_init);
2797 2793
2798 2794 /*
2799 2795 * Allocate space for the MCG temporary copy buffer. This is
2800 2796 * used by the Attach/Detach Multicast Group code
2801 2797 */
2802 2798 mcg_tmp_sz = TAVOR_MCGMEM_SZ(state);
2803 2799 state->ts_mcgtmp = kmem_zalloc(mcg_tmp_sz, KM_SLEEP);
2804 2800
2805 2801 /*
2806 2802 * Initialize the multicast group mutex. This ensures atomic
2807 2803 * access to add, modify, and remove entries in the multicast
2808 2804 * group hash lists.
2809 2805 */
2810 2806 mutex_init(&state->ts_mcglock, NULL, MUTEX_DRIVER,
2811 2807 DDI_INTR_PRI(state->ts_intrmsi_pri));
2812 2808
2813 2809 TAVOR_TNF_EXIT(tavor_mcg_init);
2814 2810 return (DDI_SUCCESS);
2815 2811 }
2816 2812
2817 2813
2818 2814 /*
2819 2815 * tavor_mcg_fini()
2820 2816 * Context: Only called from attach() and/or detach() path contexts
2821 2817 */
2822 2818 static void
2823 2819 tavor_mcg_fini(tavor_state_t *state)
2824 2820 {
2825 2821 uint_t mcg_tmp_sz;
2826 2822
2827 2823 TAVOR_TNF_ENTER(tavor_mcg_fini);
2828 2824
2829 2825 /* Free up the space used for the MCG temporary copy buffer */
2830 2826 mcg_tmp_sz = TAVOR_MCGMEM_SZ(state);
2831 2827 kmem_free(state->ts_mcgtmp, mcg_tmp_sz);
2832 2828
2833 2829 /* Destroy the multicast group mutex */
2834 2830 mutex_destroy(&state->ts_mcglock);
2835 2831
2836 2832 TAVOR_TNF_EXIT(tavor_mcg_fini);
2837 2833 }
2838 2834
2839 2835
2840 2836 /*
2841 2837 * tavor_fw_version_check()
2842 2838 * Context: Only called from attach() path context
2843 2839 */
2844 2840 static int
2845 2841 tavor_fw_version_check(tavor_state_t *state)
2846 2842 {
2847 2843 uint_t tavor_fw_ver_major;
2848 2844 uint_t tavor_fw_ver_minor;
2849 2845 uint_t tavor_fw_ver_subminor;
2850 2846
2851 2847 /*
2852 2848 * Depending on which version of driver we have attached, the firmware
2853 2849 * version checks will be different. We set up the comparison values
2854 2850 * for both HCA Mode (Tavor hardware) or COMPAT Mode (Arbel hardware
2855 2851 * running in tavor mode).
2856 2852 */
2857 2853 switch (state->ts_operational_mode) {
2858 2854 case TAVOR_HCA_MODE:
2859 2855 tavor_fw_ver_major = TAVOR_FW_VER_MAJOR;
2860 2856 tavor_fw_ver_minor = TAVOR_FW_VER_MINOR;
2861 2857 tavor_fw_ver_subminor = TAVOR_FW_VER_SUBMINOR;
2862 2858 break;
2863 2859
2864 2860 case TAVOR_COMPAT_MODE:
2865 2861 tavor_fw_ver_major = TAVOR_COMPAT_FW_VER_MAJOR;
2866 2862 tavor_fw_ver_minor = TAVOR_COMPAT_FW_VER_MINOR;
2867 2863 tavor_fw_ver_subminor = TAVOR_COMPAT_FW_VER_SUBMINOR;
2868 2864 break;
2869 2865
2870 2866 default:
2871 2867 return (DDI_FAILURE);
2872 2868 }
2873 2869
2874 2870 /*
2875 2871 * If FW revision major number is less than acceptable,
2876 2872 * return failure, else if greater return success. If
2877 2873 * the major numbers are equal than check the minor number
2878 2874 */
2879 2875 if (state->ts_fw.fw_rev_major < tavor_fw_ver_major) {
2880 2876 return (DDI_FAILURE);
2881 2877 } else if (state->ts_fw.fw_rev_major > tavor_fw_ver_major) {
2882 2878 return (DDI_SUCCESS);
2883 2879 }
2884 2880 /*
2885 2881 * Do the same check as above, except for minor revision numbers
2886 2882 * If the minor numbers are equal than check the subminor number
2887 2883 */
2888 2884 if (state->ts_fw.fw_rev_minor < tavor_fw_ver_minor) {
2889 2885 return (DDI_FAILURE);
2890 2886 } else if (state->ts_fw.fw_rev_minor > tavor_fw_ver_minor) {
2891 2887 return (DDI_SUCCESS);
2892 2888 }
2893 2889
2894 2890 /*
2895 2891 * Once again we do the same check as above, except for the subminor
2896 2892 * revision number. If the subminor numbers are equal here, then
2897 2893 * these are the same firmware version, return success
2898 2894 */
2899 2895 if (state->ts_fw.fw_rev_subminor < tavor_fw_ver_subminor) {
2900 2896 return (DDI_FAILURE);
2901 2897 } else if (state->ts_fw.fw_rev_subminor > tavor_fw_ver_subminor) {
2902 2898 return (DDI_SUCCESS);
2903 2899 }
2904 2900
2905 2901 return (DDI_SUCCESS);
2906 2902 }
2907 2903
2908 2904
2909 2905 /*
2910 2906 * tavor_device_info_report()
2911 2907 * Context: Only called from attach() path context
2912 2908 */
2913 2909 static void
2914 2910 tavor_device_info_report(tavor_state_t *state)
2915 2911 {
2916 2912 cmn_err(CE_CONT, "?tavor%d: FW ver: %04d.%04d.%04d, "
2917 2913 "HW rev: %02x\n", state->ts_instance, state->ts_fw.fw_rev_major,
2918 2914 state->ts_fw.fw_rev_minor, state->ts_fw.fw_rev_subminor,
2919 2915 state->ts_adapter.rev_id);
2920 2916 cmn_err(CE_CONT, "?tavor%d: %64s (0x%016" PRIx64 ")\n",
2921 2917 state->ts_instance, state->ts_nodedesc, state->ts_nodeguid);
2922 2918 }
2923 2919
2924 2920
2925 2921 /*
2926 2922 * tavor_pci_capability_list()
2927 2923 * Context: Only called from attach() path context
2928 2924 */
2929 2925 static void
2930 2926 tavor_pci_capability_list(tavor_state_t *state, ddi_acc_handle_t hdl)
2931 2927 {
2932 2928 uint_t offset, data;
2933 2929
2934 2930 TAVOR_TNF_ENTER(tavor_pci_capability_list);
2935 2931
2936 2932 /*
2937 2933 * Check for the "PCI Capabilities" bit in the "Status Register".
2938 2934 * Bit 4 in this register indicates the presence of a "PCI
2939 2935 * Capabilities" list.
2940 2936 */
2941 2937 data = pci_config_get16(hdl, 0x6);
2942 2938 if ((data & 0x10) == 0) {
2943 2939 TNF_PROBE_0(tavor_pci_capab_list_fail, TAVOR_TNF_ERROR, "");
2944 2940 TAVOR_TNF_EXIT(tavor_pci_capability_list);
2945 2941 return;
2946 2942 }
2947 2943
2948 2944 /*
2949 2945 * Starting from offset 0x34 in PCI config space, find the
2950 2946 * head of "PCI capabilities" list, and walk the list. If
2951 2947 * capabilities of a known type are encountered (e.g.
2952 2948 * "PCI-X Capability"), then call the appropriate handler
2953 2949 * function.
2954 2950 */
2955 2951 offset = pci_config_get8(hdl, 0x34);
2956 2952 while (offset != 0x0) {
2957 2953 data = pci_config_get8(hdl, offset);
2958 2954
2959 2955 /*
2960 2956 * Check for known capability types. Tavor has the
2961 2957 * following:
2962 2958 * o VPD Capability (0x03)
2963 2959 * o PCI-X Capability (0x07)
2964 2960 * o MSI Capability (0x05)
2965 2961 * o MSIX Capability (0x11)
2966 2962 */
2967 2963 switch (data) {
2968 2964 case 0x03:
2969 2965 tavor_pci_capability_vpd(state, hdl, offset);
2970 2966 break;
2971 2967 case 0x07:
2972 2968 tavor_pci_capability_pcix(state, hdl, offset);
2973 2969 break;
2974 2970 case 0x05:
2975 2971 break;
2976 2972 default:
2977 2973 break;
2978 2974 }
2979 2975
2980 2976 /* Get offset of next entry in list */
2981 2977 offset = pci_config_get8(hdl, offset + 1);
2982 2978 }
2983 2979
2984 2980 TAVOR_TNF_EXIT(tavor_pci_capability_list);
2985 2981 }
2986 2982
2987 2983 /*
2988 2984 * tavor_pci_read_vpd()
2989 2985 * Context: Only called from attach() path context
2990 2986 * utility routine for tavor_pci_capability_vpd()
2991 2987 */
2992 2988 static int
2993 2989 tavor_pci_read_vpd(ddi_acc_handle_t hdl, uint_t offset, uint32_t addr,
2994 2990 uint32_t *data)
2995 2991 {
2996 2992 int retry = 4; /* retry counter for EEPROM poll */
2997 2993 uint32_t val;
2998 2994 int vpd_addr = offset + 2;
2999 2995 int vpd_data = offset + 4;
3000 2996
3001 2997 TAVOR_TNF_ENTER(tavor_pci_read_vpd);
3002 2998
3003 2999 /*
3004 3000 * In order to read a 32-bit value from VPD, we are to write down
3005 3001 * the address (offset in the VPD itself) to the address register.
3006 3002 * To signal the read, we also clear bit 31. We then poll on bit 31
3007 3003 * and when it is set, we can then read our 4 bytes from the data
3008 3004 * register.
3009 3005 */
3010 3006 (void) pci_config_put32(hdl, offset, addr << 16);
3011 3007 do {
3012 3008 drv_usecwait(1000);
3013 3009 val = pci_config_get16(hdl, vpd_addr);
3014 3010 if ((val >> 15) & 0x01) {
3015 3011 *data = pci_config_get32(hdl, vpd_data);
3016 3012 TAVOR_TNF_EXIT(tavor_pci_read_vpd);
3017 3013 return (DDI_SUCCESS);
3018 3014 }
3019 3015 } while (--retry);
3020 3016
3021 3017 TNF_PROBE_0(tavor_pci_read_vpd_fail, TAVOR_TNF_ERROR, "");
3022 3018 TAVOR_TNF_EXIT(tavor_pci_read_vpd);
3023 3019 return (DDI_FAILURE);
3024 3020 }
3025 3021
3026 3022
3027 3023 /*
3028 3024 * tavor_pci_capability_vpd()
3029 3025 * Context: Only called from attach() path context
3030 3026 */
3031 3027 static void
3032 3028 tavor_pci_capability_vpd(tavor_state_t *state, ddi_acc_handle_t hdl,
3033 3029 uint_t offset)
3034 3030 {
3035 3031 uint8_t name_length;
3036 3032 uint8_t pn_length;
3037 3033 int i, err = 0;
3038 3034 int vpd_str_id = 0;
3039 3035 int vpd_ro_desc;
3040 3036 int vpd_ro_pn_desc;
3041 3037 #ifndef _LITTLE_ENDIAN
3042 3038 uint32_t data32;
3043 3039 #endif /* _LITTLE_ENDIAN */
3044 3040 union {
3045 3041 uint32_t vpd_int[TAVOR_VPD_HDR_DWSIZE];
3046 3042 uchar_t vpd_char[TAVOR_VPD_HDR_BSIZE];
3047 3043 } vpd;
3048 3044
3049 3045 TAVOR_TNF_ENTER(tavor_pci_capability_vpd);
3050 3046
3051 3047 /*
3052 3048 * Read Vital Product Data (VPD) from PCI-X capability.
3053 3049 */
3054 3050 for (i = 0; i < TAVOR_VPD_HDR_DWSIZE; i++) {
3055 3051 err = tavor_pci_read_vpd(hdl, offset, i << 2, &vpd.vpd_int[i]);
3056 3052 if (err != DDI_SUCCESS) {
3057 3053 cmn_err(CE_NOTE, "!VPD read failed\n");
3058 3054 goto out;
3059 3055 }
3060 3056 }
3061 3057
3062 3058 #ifndef _LITTLE_ENDIAN
3063 3059 /*
3064 3060 * Need to swap bytes for big endian.
3065 3061 */
3066 3062 for (i = 0; i < TAVOR_VPD_HDR_DWSIZE; i++) {
3067 3063 data32 = vpd.vpd_int[i];
3068 3064 vpd.vpd_char[(i << 2) + 3] =
3069 3065 (uchar_t)((data32 & 0xFF000000) >> 24);
3070 3066 vpd.vpd_char[(i << 2) + 2] =
3071 3067 (uchar_t)((data32 & 0x00FF0000) >> 16);
3072 3068 vpd.vpd_char[(i << 2) + 1] =
3073 3069 (uchar_t)((data32 & 0x0000FF00) >> 8);
3074 3070 vpd.vpd_char[i << 2] = (uchar_t)(data32 & 0x000000FF);
3075 3071 }
3076 3072 #endif /* _LITTLE_ENDIAN */
3077 3073
3078 3074 /* Check for VPD String ID Tag */
3079 3075 if (vpd.vpd_char[vpd_str_id] == 0x82) {
3080 3076 /* get the product name */
3081 3077 name_length = (uint8_t)vpd.vpd_char[vpd_str_id + 1];
3082 3078 if (name_length > sizeof (state->ts_hca_name)) {
3083 3079 cmn_err(CE_NOTE, "!VPD name too large (0x%x)\n",
3084 3080 name_length);
3085 3081 goto out;
3086 3082 }
3087 3083 (void) memcpy(state->ts_hca_name, &vpd.vpd_char[vpd_str_id + 3],
3088 3084 name_length);
3089 3085 state->ts_hca_name[name_length] = 0;
3090 3086
3091 3087 /* get the part number */
3092 3088 vpd_ro_desc = name_length + 3; /* read-only tag location */
3093 3089 vpd_ro_pn_desc = vpd_ro_desc + 3; /* P/N keyword location */
3094 3090 /*
3095 3091 * Verify read-only tag and Part Number keyword.
3096 3092 */
3097 3093 if (vpd.vpd_char[vpd_ro_desc] != 0x90 ||
3098 3094 (vpd.vpd_char[vpd_ro_pn_desc] != 'P' &&
3099 3095 vpd.vpd_char[vpd_ro_pn_desc + 1] != 'N')) {
3100 3096 cmn_err(CE_NOTE, "!VPD Part Number not found\n");
3101 3097 goto out;
3102 3098 }
3103 3099
3104 3100 pn_length = (uint8_t)vpd.vpd_char[vpd_ro_pn_desc + 2];
3105 3101 if (pn_length > sizeof (state->ts_hca_pn)) {
3106 3102 cmn_err(CE_NOTE, "!VPD part number too large (0x%x)\n",
3107 3103 name_length);
3108 3104 goto out;
3109 3105 }
3110 3106 (void) memcpy(state->ts_hca_pn,
3111 3107 &vpd.vpd_char[vpd_ro_pn_desc + 3],
3112 3108 pn_length);
3113 3109 state->ts_hca_pn[pn_length] = 0;
3114 3110 state->ts_hca_pn_len = pn_length;
3115 3111 } else {
3116 3112 /* Wrong VPD String ID Tag */
3117 3113 cmn_err(CE_NOTE, "!VPD String ID Tag not found, tag: %02x\n",
3118 3114 vpd.vpd_char[0]);
3119 3115 goto out;
3120 3116 }
3121 3117 TAVOR_TNF_EXIT(tavor_pci_capability_vpd);
3122 3118 return;
3123 3119 out:
3124 3120 state->ts_hca_pn_len = 0;
3125 3121 TNF_PROBE_0(tavor_pci_capability_vpd_fail, TAVOR_TNF_ERROR, "");
3126 3122 TAVOR_TNF_EXIT(tavor_pci_capability_vpd);
3127 3123 }
3128 3124
3129 3125 /*
3130 3126 * tavor_pci_capability_pcix()
3131 3127 * Context: Only called from attach() path context
3132 3128 */
3133 3129 static void
3134 3130 tavor_pci_capability_pcix(tavor_state_t *state, ddi_acc_handle_t hdl,
3135 3131 uint_t offset)
3136 3132 {
3137 3133 uint_t command, status;
3138 3134 int max_out_splt_trans, max_mem_rd_byte_cnt;
3139 3135 int designed_max_out_splt_trans, designed_max_mem_rd_byte_cnt;
3140 3136
3141 3137 TAVOR_TNF_ENTER(tavor_pci_capability_pcix);
3142 3138
3143 3139 /*
3144 3140 * Query the current values for the PCI-X Command Register and
3145 3141 * the PCI-X Status Register.
3146 3142 */
3147 3143 command = pci_config_get16(hdl, offset + 2);
3148 3144 status = pci_config_get32(hdl, offset + 4);
3149 3145
3150 3146 /*
3151 3147 * Check for config property specifying "maximum outstanding
3152 3148 * split transactions". If the property is defined and valid
3153 3149 * (i.e. no larger than the so-called "designed maximum"),
3154 3150 * then use the specified value to update the PCI-X Command Register.
3155 3151 * Otherwise, extract the value from the Tavor config profile.
3156 3152 */
3157 3153 designed_max_out_splt_trans = ((status >> 23) & 7);
3158 3154 max_out_splt_trans = ddi_prop_get_int(DDI_DEV_T_ANY, state->ts_dip,
3159 3155 DDI_PROP_DONTPASS, "pcix-max-outstanding-split-trans", -1);
3160 3156 if ((max_out_splt_trans != -1) &&
3161 3157 ((max_out_splt_trans < 0) ||
3162 3158 (max_out_splt_trans > designed_max_out_splt_trans))) {
3163 3159 cmn_err(CE_NOTE, "!tavor%d: property \"pcix-max-outstanding-"
3164 3160 "split-trans\" (%d) invalid or exceeds device maximum"
3165 3161 " (%d), using default value (%d)\n", state->ts_instance,
3166 3162 max_out_splt_trans, designed_max_out_splt_trans,
3167 3163 state->ts_cfg_profile->cp_max_out_splt_trans);
3168 3164 max_out_splt_trans =
3169 3165 state->ts_cfg_profile->cp_max_out_splt_trans;
3170 3166 } else if (max_out_splt_trans == -1) {
3171 3167 max_out_splt_trans =
3172 3168 state->ts_cfg_profile->cp_max_out_splt_trans;
3173 3169 }
3174 3170
3175 3171 /*
3176 3172 * The config profile setting for max_out_splt_trans is determined
3177 3173 * based on arch. Check tavor_cfg.c for more information. A value of
3178 3174 * '-1' in the patchable variable means "do not change". A value of
3179 3175 * '0' means 1 outstanding splt trans and other values as defined by
3180 3176 * PCI. So we do one more check here, that if 'max_out_splt_trans' is
3181 3177 * -1 (ie: < 0) we do not set the PCI command and leave it at the
3182 3178 * default.
3183 3179 */
3184 3180 if (max_out_splt_trans >= 0) {
3185 3181 command = ((command & 0xFF8F) | max_out_splt_trans << 4);
3186 3182 }
3187 3183
3188 3184 /*
3189 3185 * Check for config property specifying "maximum memory read
3190 3186 * byte count. If the property is defined and valid
3191 3187 * (i.e. no larger than the so-called "designed maximum"),
3192 3188 * then use the specified value to update the PCI-X Command Register.
3193 3189 * Otherwise, extract the value from the Tavor config profile.
3194 3190 */
3195 3191 designed_max_mem_rd_byte_cnt = ((status >> 21) & 3);
3196 3192 max_mem_rd_byte_cnt = ddi_prop_get_int(DDI_DEV_T_ANY, state->ts_dip,
3197 3193 DDI_PROP_DONTPASS, "pcix-max-read-byte-count", -1);
3198 3194 if ((max_mem_rd_byte_cnt != -1) &&
3199 3195 ((max_mem_rd_byte_cnt < 0) ||
3200 3196 (max_mem_rd_byte_cnt > designed_max_mem_rd_byte_cnt))) {
3201 3197 cmn_err(CE_NOTE, "!tavor%d: property \"pcix-max-read-byte-"
3202 3198 "count\" (%d) invalid or exceeds device maximum"
3203 3199 " (%d), using default value (%d)\n", state->ts_instance,
3204 3200 max_mem_rd_byte_cnt, designed_max_mem_rd_byte_cnt,
3205 3201 state->ts_cfg_profile->cp_max_mem_rd_byte_cnt);
3206 3202 max_mem_rd_byte_cnt =
3207 3203 state->ts_cfg_profile->cp_max_mem_rd_byte_cnt;
3208 3204 } else if (max_mem_rd_byte_cnt == -1) {
3209 3205 max_mem_rd_byte_cnt =
3210 3206 state->ts_cfg_profile->cp_max_mem_rd_byte_cnt;
3211 3207 }
3212 3208
3213 3209 /*
3214 3210 * The config profile setting for max_mem_rd_byte_cnt is determined
3215 3211 * based on arch. Check tavor_cfg.c for more information. A value of
3216 3212 * '-1' in the patchable variable means "do not change". A value of
3217 3213 * '0' means minimum (512B) read, and other values as defined by
3218 3214 * PCI. So we do one more check here, that if 'max_mem_rd_byte_cnt' is
3219 3215 * -1 (ie: < 0) we do not set the PCI command and leave it at the
3220 3216 * default.
3221 3217 */
3222 3218 if (max_mem_rd_byte_cnt >= 0) {
3223 3219 command = ((command & 0xFFF3) | max_mem_rd_byte_cnt << 2);
3224 3220 }
3225 3221
3226 3222 /*
3227 3223 * Update the PCI-X Command Register with the newly configured
3228 3224 * values.
3229 3225 */
3230 3226 pci_config_put16(hdl, offset + 2, command);
3231 3227
3232 3228 TAVOR_TNF_EXIT(tavor_pci_capability_pcix);
3233 3229 }
3234 3230
3235 3231
3236 3232 /*
3237 3233 * tavor_intr_or_msi_init()
3238 3234 * Context: Only called from attach() path context
3239 3235 */
3240 3236 static int
3241 3237 tavor_intr_or_msi_init(tavor_state_t *state)
3242 3238 {
3243 3239 int status;
3244 3240
3245 3241 TAVOR_TNF_ENTER(tavor_intr_or_msi_init);
3246 3242
3247 3243 /* Query for the list of supported interrupt event types */
3248 3244 status = ddi_intr_get_supported_types(state->ts_dip,
3249 3245 &state->ts_intr_types_avail);
3250 3246 if (status != DDI_SUCCESS) {
3251 3247 TNF_PROBE_0(tavor_intr_or_msi_init_gettypes_fail,
3252 3248 TAVOR_TNF_ERROR, "");
3253 3249 TAVOR_TNF_EXIT(tavor_intr_or_msi_init);
3254 3250 return (DDI_FAILURE);
3255 3251 }
3256 3252
3257 3253 /*
3258 3254 * If Tavor/Arbel supports MSI in this system (and, if it
3259 3255 * hasn't been overridden by a configuration variable), then
3260 3256 * the default behavior is to use a single MSI. Otherwise,
3261 3257 * fallback to using legacy interrupts. Also, if MSI allocatis chosen,
3262 3258 * but fails for whatever reasons, then fallback to using legacy
3263 3259 * interrupts.
3264 3260 */
3265 3261 if ((state->ts_cfg_profile->cp_use_msi_if_avail != 0) &&
3266 3262 (state->ts_intr_types_avail & DDI_INTR_TYPE_MSI)) {
3267 3263 status = tavor_add_intrs(state, DDI_INTR_TYPE_MSI);
3268 3264 if (status == DDI_SUCCESS) {
3269 3265 state->ts_intr_type_chosen = DDI_INTR_TYPE_MSI;
3270 3266 TAVOR_TNF_EXIT(tavor_intr_or_msi_init);
3271 3267 return (DDI_SUCCESS);
3272 3268 }
3273 3269 }
3274 3270
3275 3271 /*
3276 3272 * MSI interrupt allocation failed, or was not available. Fallback to
3277 3273 * legacy interrupt support.
3278 3274 */
3279 3275 if (state->ts_intr_types_avail & DDI_INTR_TYPE_FIXED) {
3280 3276 status = tavor_add_intrs(state, DDI_INTR_TYPE_FIXED);
3281 3277 if (status == DDI_SUCCESS) {
3282 3278 state->ts_intr_type_chosen = DDI_INTR_TYPE_FIXED;
3283 3279 TAVOR_TNF_EXIT(tavor_intr_or_msi_init);
3284 3280 return (DDI_SUCCESS);
3285 3281 }
3286 3282 }
3287 3283
3288 3284 /*
3289 3285 * Neither MSI or legacy interrupts were successful. return failure.
3290 3286 */
3291 3287 TAVOR_TNF_EXIT(tavor_intr_or_msi_setup);
3292 3288 return (DDI_FAILURE);
3293 3289 }
3294 3290
3295 3291 /*
3296 3292 * tavor_add_intrs()
3297 3293 * Context: Only called from attach() patch context
3298 3294 */
3299 3295 static int
3300 3296 tavor_add_intrs(tavor_state_t *state, int intr_type)
3301 3297 {
3302 3298 int status;
3303 3299
3304 3300 TAVOR_TNF_ENTER(tavor_add_intrs);
3305 3301
3306 3302 /* Get number of interrupts/MSI supported */
3307 3303 status = ddi_intr_get_nintrs(state->ts_dip, intr_type,
3308 3304 &state->ts_intrmsi_count);
3309 3305 if (status != DDI_SUCCESS) {
3310 3306 TNF_PROBE_0(tavor_add_intrs_getnintrs_fail,
3311 3307 TAVOR_TNF_ERROR, "");
3312 3308 TAVOR_TNF_EXIT(tavor_add_intrs);
3313 3309 return (DDI_FAILURE);
3314 3310 }
3315 3311
3316 3312 /* Get number of available interrupts/MSI */
3317 3313 status = ddi_intr_get_navail(state->ts_dip, intr_type,
3318 3314 &state->ts_intrmsi_avail);
3319 3315 if (status != DDI_SUCCESS) {
3320 3316 TNF_PROBE_0(tavor_add_intrs_getnavail_fail,
3321 3317 TAVOR_TNF_ERROR, "");
3322 3318 TAVOR_TNF_EXIT(tavor_add_intrs);
3323 3319 return (DDI_FAILURE);
3324 3320 }
3325 3321
3326 3322 /* Ensure that we have at least one (1) usable MSI or interrupt */
3327 3323 if ((state->ts_intrmsi_avail < 1) || (state->ts_intrmsi_count < 1)) {
3328 3324 TNF_PROBE_0(tavor_add_intrs_notenoughts_intrmsi_fail,
3329 3325 TAVOR_TNF_ERROR, "");
3330 3326 TAVOR_TNF_EXIT(tavor_add_intrs);
3331 3327 return (DDI_FAILURE);
3332 3328 }
3333 3329
3334 3330 /* Attempt to allocate a single interrupt/MSI handle */
3335 3331 status = ddi_intr_alloc(state->ts_dip, &state->ts_intrmsi_hdl,
3336 3332 intr_type, 0, 1, &state->ts_intrmsi_allocd,
3337 3333 DDI_INTR_ALLOC_STRICT);
3338 3334 if (status != DDI_SUCCESS) {
3339 3335 TNF_PROBE_0(tavor_add_intrs_intralloc_fail,
3340 3336 TAVOR_TNF_ERROR, "");
3341 3337 TAVOR_TNF_EXIT(tavor_add_intrs);
3342 3338 return (DDI_FAILURE);
3343 3339 }
3344 3340
3345 3341 /* Ensure that we have allocated at least one (1) MSI or interrupt */
3346 3342 if (state->ts_intrmsi_allocd < 1) {
3347 3343 TNF_PROBE_0(tavor_add_intrs_noallocts_intrmsi_fail,
3348 3344 TAVOR_TNF_ERROR, "");
3349 3345 TAVOR_TNF_EXIT(tavor_add_intrs);
3350 3346 return (DDI_FAILURE);
3351 3347 }
3352 3348
3353 3349 /*
3354 3350 * Extract the priority for the allocated interrupt/MSI. This
3355 3351 * will be used later when initializing certain mutexes.
3356 3352 */
3357 3353 status = ddi_intr_get_pri(state->ts_intrmsi_hdl,
3358 3354 &state->ts_intrmsi_pri);
3359 3355 if (status != DDI_SUCCESS) {
3360 3356 /* Free the allocated interrupt/MSI handle */
3361 3357 (void) ddi_intr_free(state->ts_intrmsi_hdl);
3362 3358
3363 3359 TNF_PROBE_0(tavor_add_intrs_getpri_fail,
3364 3360 TAVOR_TNF_ERROR, "");
3365 3361 TAVOR_TNF_EXIT(tavor_add_intrs);
3366 3362 return (DDI_FAILURE);
3367 3363 }
3368 3364
3369 3365 /* Make sure the interrupt/MSI priority is below 'high level' */
3370 3366 if (state->ts_intrmsi_pri >= ddi_intr_get_hilevel_pri()) {
3371 3367 /* Free the allocated interrupt/MSI handle */
3372 3368 (void) ddi_intr_free(state->ts_intrmsi_hdl);
3373 3369
3374 3370 TNF_PROBE_0(tavor_add_intrs_hilevelpri_fail,
3375 3371 TAVOR_TNF_ERROR, "");
3376 3372 TAVOR_TNF_EXIT(tavor_add_intrs);
3377 3373 return (DDI_FAILURE);
3378 3374 }
3379 3375
3380 3376 /* Get add'l capability information regarding interrupt/MSI */
3381 3377 status = ddi_intr_get_cap(state->ts_intrmsi_hdl,
3382 3378 &state->ts_intrmsi_cap);
3383 3379 if (status != DDI_SUCCESS) {
3384 3380 /* Free the allocated interrupt/MSI handle */
3385 3381 (void) ddi_intr_free(state->ts_intrmsi_hdl);
3386 3382
3387 3383 TNF_PROBE_0(tavor_add_intrs_getcap_fail,
3388 3384 TAVOR_TNF_ERROR, "");
3389 3385 TAVOR_TNF_EXIT(tavor_add_intrs);
3390 3386 return (DDI_FAILURE);
3391 3387 }
3392 3388
3393 3389 TAVOR_TNF_EXIT(tavor_add_intrs);
3394 3390 return (DDI_SUCCESS);
3395 3391 }
3396 3392
3397 3393
3398 3394 /*
3399 3395 * tavor_intr_or_msi_fini()
3400 3396 * Context: Only called from attach() and/or detach() path contexts
3401 3397 */
3402 3398 static int
3403 3399 tavor_intr_or_msi_fini(tavor_state_t *state)
3404 3400 {
3405 3401 int status;
3406 3402
3407 3403 TAVOR_TNF_ENTER(tavor_intr_or_msi_fini);
3408 3404
3409 3405 /* Free the allocated interrupt/MSI handle */
3410 3406 status = ddi_intr_free(state->ts_intrmsi_hdl);
3411 3407 if (status != DDI_SUCCESS) {
3412 3408 TNF_PROBE_0(tavor_intr_or_msi_fini_freehdl_fail,
3413 3409 TAVOR_TNF_ERROR, "");
3414 3410 TAVOR_TNF_EXIT(tavor_intr_or_msi_fini);
3415 3411 return (DDI_FAILURE);
3416 3412 }
3417 3413
3418 3414 TAVOR_TNF_EXIT(tavor_intr_or_msi_fini);
3419 3415 return (DDI_SUCCESS);
3420 3416 }
3421 3417
3422 3418
3423 3419 /* Disable Tavor interrupts */
3424 3420 static int
3425 3421 tavor_intr_disable(tavor_state_t *state)
3426 3422 {
3427 3423 ushort_t msi_ctrl = 0, caps_ctrl = 0;
3428 3424 ddi_acc_handle_t pci_cfg_hdl = state->ts_pci_cfghdl;
3429 3425 ASSERT(pci_cfg_hdl != NULL);
3430 3426 ASSERT(state->ts_intr_types_avail &
3431 3427 (DDI_INTR_TYPE_FIXED | DDI_INTR_TYPE_MSI));
3432 3428
3433 3429 /*
3434 3430 * Check if MSI interrupts are used. If so, disable MSI interupts.
3435 3431 * If not, since Tavor doesn't support MSI-X interrupts, assuming the
3436 3432 * legacy interrupt is used instead, disable the legacy interrupt.
3437 3433 */
3438 3434 if ((state->ts_cfg_profile->cp_use_msi_if_avail != 0) &&
3439 3435 (state->ts_intr_types_avail & DDI_INTR_TYPE_MSI)) {
3440 3436
3441 3437 if ((PCI_CAP_LOCATE(pci_cfg_hdl, PCI_CAP_ID_MSI,
3442 3438 &caps_ctrl) == DDI_SUCCESS)) {
3443 3439 if ((msi_ctrl = PCI_CAP_GET16(pci_cfg_hdl, NULL,
3444 3440 caps_ctrl, PCI_MSI_CTRL)) == PCI_CAP_EINVAL16)
3445 3441 return (DDI_FAILURE);
3446 3442 }
3447 3443 ASSERT(msi_ctrl != 0);
3448 3444
3449 3445 if (!(msi_ctrl & PCI_MSI_ENABLE_BIT))
3450 3446 return (DDI_SUCCESS);
3451 3447
3452 3448 if (msi_ctrl & PCI_MSI_PVM_MASK) {
3453 3449 int offset = (msi_ctrl & PCI_MSI_64BIT_MASK) ?
3454 3450 PCI_MSI_64BIT_MASKBITS : PCI_MSI_32BIT_MASK;
3455 3451
3456 3452 /* Clear all inums in MSI */
3457 3453 PCI_CAP_PUT32(pci_cfg_hdl, NULL, caps_ctrl,
3458 3454 offset, 0x0);
3459 3455 }
3460 3456
3461 3457 /* Disable MSI interrupts */
3462 3458 msi_ctrl &= ~PCI_MSI_ENABLE_BIT;
3463 3459 PCI_CAP_PUT16(pci_cfg_hdl, NULL, caps_ctrl, PCI_MSI_CTRL,
3464 3460 msi_ctrl);
3465 3461
3466 3462 } else {
3467 3463 uint16_t cmdreg = pci_config_get16(pci_cfg_hdl, PCI_CONF_COMM);
3468 3464 ASSERT(state->ts_intr_types_avail & DDI_INTR_TYPE_FIXED);
3469 3465
3470 3466 /* Disable the legacy interrupts */
3471 3467 cmdreg |= PCI_COMM_INTX_DISABLE;
3472 3468 pci_config_put16(pci_cfg_hdl, PCI_CONF_COMM, cmdreg);
3473 3469 }
3474 3470
3475 3471 return (DDI_SUCCESS);
3476 3472 }
3477 3473
3478 3474 /* Tavor quiesce(9F) entry */
3479 3475 static int
3480 3476 tavor_quiesce(dev_info_t *dip)
3481 3477 {
3482 3478 tavor_state_t *state = ddi_get_soft_state(tavor_statep,
3483 3479 DEVI(dip)->devi_instance);
3484 3480 ASSERT(state != NULL);
3485 3481
3486 3482 /* start fastreboot */
3487 3483 state->ts_quiescing = B_TRUE;
3488 3484
3489 3485 /* If it's in maintenance mode, do nothing but return with SUCCESS */
3490 3486 if (!TAVOR_IS_OPERATIONAL(state->ts_operational_mode)) {
3491 3487 return (DDI_SUCCESS);
3492 3488 }
3493 3489
3494 3490 /* Shutdown HCA ports */
3495 3491 if (tavor_hca_ports_shutdown(state,
3496 3492 state->ts_cfg_profile->cp_num_ports) != TAVOR_CMD_SUCCESS) {
3497 3493 state->ts_quiescing = B_FALSE;
3498 3494 return (DDI_FAILURE);
3499 3495 }
3500 3496
3501 3497 /* Close HCA */
3502 3498 if (tavor_close_hca_cmd_post(state, TAVOR_CMD_NOSLEEP_SPIN) !=
3503 3499 TAVOR_CMD_SUCCESS) {
3504 3500 state->ts_quiescing = B_FALSE;
3505 3501 return (DDI_FAILURE);
3506 3502 }
3507 3503
3508 3504 /* Shutdown FW */
3509 3505 if (tavor_sys_dis_cmd_post(state, TAVOR_CMD_NOSLEEP_SPIN) !=
3510 3506 TAVOR_CMD_SUCCESS) {
3511 3507 state->ts_quiescing = B_FALSE;
3512 3508 return (DDI_FAILURE);
3513 3509 }
3514 3510
3515 3511 /* Disable interrupts */
3516 3512 if (tavor_intr_disable(state) != DDI_SUCCESS) {
3517 3513 state->ts_quiescing = B_FALSE;
3518 3514 return (DDI_FAILURE);
3519 3515 }
3520 3516
3521 3517 /* SW-reset */
3522 3518 if (tavor_sw_reset(state) != DDI_SUCCESS) {
3523 3519 state->ts_quiescing = B_FALSE;
3524 3520 return (DDI_FAILURE);
3525 3521 }
3526 3522
3527 3523 return (DDI_SUCCESS);
3528 3524 }
↓ open down ↓ |
2926 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX