1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /*
26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
27 */
28
29
30 /*
31 * PCI to PCI bus bridge nexus driver
32 */
33
34 #include <sys/conf.h>
35 #include <sys/kmem.h>
36 #include <sys/debug.h>
37 #include <sys/modctl.h>
38 #include <sys/autoconf.h>
39 #include <sys/ddi_impldefs.h>
40 #include <sys/ddi_subrdefs.h>
41 #include <sys/ddifm.h>
42 #include <sys/fm/util.h>
43 #include <sys/fm/protocol.h>
44 #include <sys/fm/io/pci.h>
45 #include <sys/pci.h>
46 #include <sys/pci/pci_nexus.h>
47 #include <sys/pci/pci_regs.h>
48 #include <sys/pci/pci_simba.h>
49 #include <sys/ddi.h>
50 #include <sys/sunddi.h>
51 #include <sys/sunndi.h>
52 #include <sys/promif.h> /* prom_printf */
53 #include <sys/open.h>
54 #include <sys/stat.h>
55 #include <sys/file.h>
56
57 #if defined(DEBUG) && !defined(lint)
58 static uint_t simba_debug_flags = 0;
59 #define D_IDENTIFY 0x00000001
60 #define D_ATTACH 0x00000002
61 #define D_DETACH 0x00000004
62 #define D_MAP 0x00000008
63 #define D_CTLOPS 0x00000010
64 #define D_G_ISPEC 0x00000020
65 #define D_A_ISPEC 0x00000040
66 #define D_INIT_CLD 0x00400000
67 #define D_FAULT 0x00000080
68
69 #define DEBUG0(f, s) if ((f)& simba_debug_flags) \
70 prom_printf("simba: " s "\n")
71
72 #define DEBUG1(f, s, a) if ((f)& simba_debug_flags) \
73 prom_printf("simba: " s "\n", a)
74
75 #define DEBUG2(f, s, a, b) if ((f)& simba_debug_flags) \
76 prom_printf("simba: " s "\n", a, b)
77
78 #define DEBUG3(f, s, a, b, c) if ((f)& simba_debug_flags) \
79 prom_printf("simba: " s "\n", a, b, c)
80
81 #define DEBUG4(f, s, a, b, c, d) if ((f)& simba_debug_flags) \
82 prom_printf("simba: " s "\n", a, b, c, d)
83
84 #define DEBUG5(f, s, a, b, c, d, e) if ((f)& simba_debug_flags) \
85 prom_printf("simba: " s "\n", a, b, c, d, e)
86
87 #define DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& simba_debug_flags) \
88 prom_printf("simba: " s "\n", a, b, c, d, e, ff)
89
90 #else
91
92 #define DEBUG0(f, s)
93 #define DEBUG1(f, s, a)
94 #define DEBUG2(f, s, a, b)
95 #define DEBUG3(f, s, a, b, c)
96 #define DEBUG4(f, s, a, b, c, d)
97 #define DEBUG5(f, s, a, b, c, d, e)
98 #define DEBUG6(f, s, a, b, c, d, e, ff)
99
100 #endif
101
102 /*
103 * The variable controls the default setting of the command register
104 * for pci devices. See simba_initchild() for details.
105 */
106 static ushort_t simba_command_default = PCI_COMM_SERR_ENABLE |
107 PCI_COMM_WAIT_CYC_ENAB |
108 PCI_COMM_PARITY_DETECT |
109 PCI_COMM_ME |
110 PCI_COMM_MAE |
111 PCI_COMM_IO;
112
113 static int simba_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
114 off_t, off_t, caddr_t *);
115 static int simba_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
116 void *, void *);
117 static int simba_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap,
118 ddi_iblock_cookie_t *ibc);
119 static void simba_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle);
120 static void simba_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle);
121
122 struct bus_ops simba_bus_ops = {
123 BUSO_REV,
124 simba_bus_map,
125 0,
126 0,
127 0,
128 i_ddi_map_fault,
129 0,
130 ddi_dma_allochdl,
131 ddi_dma_freehdl,
132 ddi_dma_bindhdl,
133 ddi_dma_unbindhdl,
134 ddi_dma_flush,
135 ddi_dma_win,
136 ddi_dma_mctl,
137 simba_ctlops,
138 ddi_bus_prop_op,
139 ndi_busop_get_eventcookie,
140 ndi_busop_add_eventcall,
141 ndi_busop_remove_eventcall,
142 ndi_post_event,
143 0,
144 0,
145 0,
146 simba_fm_init_child,
147 NULL,
148 simba_bus_enter,
149 simba_bus_exit,
150 0,
151 i_ddi_intr_ops
152 };
153
154 static int simba_open(dev_t *devp, int flags, int otyp, cred_t *credp);
155 static int simba_close(dev_t dev, int flags, int otyp, cred_t *credp);
156 static int simba_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
157 cred_t *credp, int *rvalp);
158
159 static struct cb_ops simba_cb_ops = {
160 simba_open, /* open */
161 simba_close, /* close */
162 nulldev, /* strategy */
163 nulldev, /* print */
164 nulldev, /* dump */
165 nulldev, /* read */
166 nulldev, /* write */
167 simba_ioctl, /* ioctl */
168 nodev, /* devmap */
169 nodev, /* mmap */
170 nodev, /* segmap */
171 nochpoll, /* poll */
172 ddi_prop_op, /* cb_prop_op */
173 NULL, /* streamtab */
174 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */
175 CB_REV, /* rev */
176 nodev, /* int (*cb_aread)() */
177 nodev /* int (*cb_awrite)() */
178 };
179
180 static int simba_probe(dev_info_t *);
181 static int simba_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
182 static int simba_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
183 static int simba_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
184 void *arg, void **result);
185
186 struct dev_ops simba_ops = {
187 DEVO_REV, /* devo_rev */
188 0, /* refcnt */
189 simba_info, /* info */
190 nulldev, /* identify */
191 simba_probe, /* probe */
192 simba_attach, /* attach */
193 simba_detach, /* detach */
194 nulldev, /* reset */
195 &simba_cb_ops, /* driver operations */
196 &simba_bus_ops, /* bus operations */
197 NULL,
198 ddi_quiesce_not_supported, /* devo_quiesce */
199 };
200
201 /*
202 * Module linkage information for the kernel.
203 */
204
205 static struct modldrv modldrv = {
206 &mod_driverops, /* Type of module */
207 "SIMBA PCI to PCI bridge nexus driver",
208 &simba_ops, /* driver ops */
209 };
210
211 static struct modlinkage modlinkage = {
212 MODREV_1,
213 (void *)&modldrv,
214 NULL
215 };
216
217 /*
218 * Simba specific error state structure
219 */
220 struct simba_errstate {
221 char *error;
222 ushort_t pci_cfg_stat;
223 ushort_t pci_cfg_sec_stat;
224 uint64_t afsr;
225 uint64_t afar;
226 int bridge_secondary;
227 };
228
229 struct simba_cfg_state {
230 dev_info_t *dip;
231 ushort_t command;
232 uchar_t cache_line_size;
233 uchar_t latency_timer;
234 uchar_t header_type;
235 uchar_t bus_number;
236 uchar_t sec_bus_number;
237 uchar_t sub_bus_number;
238 uchar_t sec_latency_timer;
239 ushort_t bridge_control;
240 };
241
242 /*
243 * soft state pointer and structure template:
244 */
245 static void *simba_state;
246
247 typedef struct {
248
249 dev_info_t *dip;
250
251 /*
252 * configuration register state for the bus:
253 */
254 ddi_acc_handle_t config_handle;
255 uchar_t simba_cache_line_size;
256 uchar_t simba_latency_timer;
257
258 /*
259 * cpr support:
260 */
261 uint_t config_state_index;
262 struct simba_cfg_state *simba_config_state_p;
263 ddi_iblock_cookie_t fm_ibc;
264 int fm_cap;
265 kmutex_t simba_mutex;
266 uint_t simba_soft_state;
267 #define SIMBA_SOFT_STATE_CLOSED 0x00
268 #define SIMBA_SOFT_STATE_OPEN 0x01
269 #define SIMBA_SOFT_STATE_OPEN_EXCL 0x02
270 } simba_devstate_t;
271
272 /*
273 * The following variable enables a workaround for the following obp bug:
274 *
275 * 1234181 - obp should set latency timer registers in pci
276 * configuration header
277 *
278 * Until this bug gets fixed in the obp, the following workaround should
279 * be enabled.
280 */
281 static uint_t simba_set_latency_timer_register = 1;
282
283 /*
284 * The following variable enables a workaround for an obp bug to be
285 * submitted. A bug requesting a workaround fof this problem has
286 * been filed:
287 *
288 * 1235094 - need workarounds on positron nexus drivers to set cache
289 * line size registers
290 *
291 * Until this bug gets fixed in the obp, the following workaround should
292 * be enabled.
293 */
294 static uint_t simba_set_cache_line_size_register = 1;
295
296
297 /*
298 * forward function declarations:
299 */
300 static void simba_uninitchild(dev_info_t *);
301 static int simba_initchild(dev_info_t *child);
302 static void simba_save_config_regs(simba_devstate_t *simba_p);
303 static void simba_restore_config_regs(simba_devstate_t *simba_p);
304 static int simba_err_callback(dev_info_t *dip, ddi_fm_error_t *derr,
305 const void *impl_data);
306
307 int
_init(void)308 _init(void)
309 {
310 int e;
311
312 DEBUG0(D_ATTACH, "_init() installing module...\n");
313 if ((e = ddi_soft_state_init(&simba_state, sizeof (simba_devstate_t),
314 1)) == 0 && (e = mod_install(&modlinkage)) != 0)
315 ddi_soft_state_fini(&simba_state);
316
317 DEBUG0(D_ATTACH, "_init() module installed\n");
318 return (e);
319 }
320
321 int
_fini(void)322 _fini(void)
323 {
324 int e;
325 DEBUG0(D_ATTACH, "_fini() removing module...\n");
326 if ((e = mod_remove(&modlinkage)) == 0)
327 ddi_soft_state_fini(&simba_state);
328 return (e);
329 }
330
331 int
_info(struct modinfo * modinfop)332 _info(struct modinfo *modinfop)
333 {
334 DEBUG0(D_ATTACH, "_info() called.\n");
335 return (mod_info(&modlinkage, modinfop));
336 }
337
338 /*ARGSUSED*/
339 static int
simba_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)340 simba_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
341 {
342 simba_devstate_t *simba_p; /* per simba state pointer */
343 int instance;
344
345 instance = getminor((dev_t)arg);
346 simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state,
347 instance);
348
349 switch (infocmd) {
350 default:
351 return (DDI_FAILURE);
352
353 case DDI_INFO_DEVT2INSTANCE:
354 *result = (void *)(uintptr_t)instance;
355 return (DDI_SUCCESS);
356
357 case DDI_INFO_DEVT2DEVINFO:
358 if (simba_p == NULL)
359 return (DDI_FAILURE);
360 *result = (void *)simba_p->dip;
361 return (DDI_SUCCESS);
362 }
363 }
364
365 /*ARGSUSED*/
366 static int
simba_probe(register dev_info_t * devi)367 simba_probe(register dev_info_t *devi)
368 {
369 DEBUG0(D_ATTACH, "simba_probe() called.\n");
370 return (DDI_PROBE_SUCCESS);
371 }
372
373 /*ARGSUSED*/
374 static int
simba_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)375 simba_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
376 {
377 int instance;
378 simba_devstate_t *simba;
379
380 switch (cmd) {
381 case DDI_ATTACH:
382
383 DEBUG1(D_ATTACH, "attach(%p) ATTACH\n", devi);
384
385 /*
386 * Make sure the "device_type" property exists.
387 */
388 (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
389 "device_type", "pci");
390
391 /*
392 * Allocate and get soft state structure.
393 */
394 instance = ddi_get_instance(devi);
395 if (ddi_soft_state_zalloc(simba_state, instance) != DDI_SUCCESS)
396 return (DDI_FAILURE);
397 simba = (simba_devstate_t *)ddi_get_soft_state(simba_state,
398 instance);
399 simba->dip = devi;
400 mutex_init(&simba->simba_mutex, NULL, MUTEX_DRIVER, NULL);
401 simba->simba_soft_state = SIMBA_SOFT_STATE_CLOSED;
402
403 /*
404 * create minor node for devctl interfaces
405 */
406 if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance,
407 DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
408 mutex_destroy(&simba->simba_mutex);
409 ddi_soft_state_free(simba_state, instance);
410 return (DDI_FAILURE);
411 }
412
413 if (pci_config_setup(devi, &simba->config_handle) !=
414 DDI_SUCCESS) {
415 ddi_remove_minor_node(devi, "devctl");
416 mutex_destroy(&simba->simba_mutex);
417 ddi_soft_state_free(simba_state, instance);
418 return (DDI_FAILURE);
419 }
420
421 /*
422 * Simba cache line size is 64 bytes and hardwired.
423 */
424 simba->simba_cache_line_size =
425 pci_config_get8(simba->config_handle,
426 PCI_CONF_CACHE_LINESZ);
427 simba->simba_latency_timer =
428 pci_config_get8(simba->config_handle,
429 PCI_CONF_LATENCY_TIMER);
430
431 /* simba specific, clears up the pri/sec status registers */
432 pci_config_put16(simba->config_handle, 0x6, 0xffff);
433 pci_config_put16(simba->config_handle, 0x1e, 0xffff);
434
435 DEBUG2(D_ATTACH, "simba_attach(): clsz=%x, lt=%x\n",
436 simba->simba_cache_line_size,
437 simba->simba_latency_timer);
438
439 /*
440 * Initialize FMA support
441 */
442 simba->fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
443 DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
444
445 /*
446 * Call parent to get it's capablity
447 */
448 ddi_fm_init(devi, &simba->fm_cap, &simba->fm_ibc);
449
450 ASSERT((simba->fm_cap & DDI_FM_ERRCB_CAPABLE) &&
451 (simba->fm_cap & DDI_FM_EREPORT_CAPABLE));
452
453 pci_ereport_setup(devi);
454
455 ddi_fm_handler_register(devi, simba_err_callback, simba);
456
457 ddi_report_dev(devi);
458 DEBUG0(D_ATTACH, "attach(): ATTACH done\n");
459 return (DDI_SUCCESS);
460
461 case DDI_RESUME:
462
463 /*
464 * Get the soft state structure for the bridge.
465 */
466 simba = (simba_devstate_t *)
467 ddi_get_soft_state(simba_state, ddi_get_instance(devi));
468 simba_restore_config_regs(simba);
469 return (DDI_SUCCESS);
470 }
471 return (DDI_FAILURE);
472 }
473
474 /*ARGSUSED*/
475 static int
simba_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)476 simba_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
477 {
478 simba_devstate_t *simba;
479 simba = (simba_devstate_t *)
480 ddi_get_soft_state(simba_state, ddi_get_instance(devi));
481
482 switch (cmd) {
483 case DDI_DETACH:
484 DEBUG0(D_DETACH, "detach() called\n");
485 ddi_fm_handler_unregister(devi);
486 pci_ereport_teardown(devi);
487 ddi_fm_fini(devi);
488 pci_config_teardown(&simba->config_handle);
489 (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
490 ddi_remove_minor_node(devi, "devctl");
491 mutex_destroy(&simba->simba_mutex);
492 ddi_soft_state_free(simba_state, ddi_get_instance(devi));
493 return (DDI_SUCCESS);
494
495 case DDI_SUSPEND:
496 simba_save_config_regs(simba);
497 return (DDI_SUCCESS);
498 }
499 return (DDI_FAILURE);
500 }
501
502 /*ARGSUSED*/
503 static int
simba_bus_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)504 simba_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
505 off_t offset, off_t len, caddr_t *vaddrp)
506 {
507 register dev_info_t *pdip;
508
509 DEBUG3(D_MAP, "simba_bus_map(): dip=%p, rdip=%p, mp=%p", dip, rdip, mp);
510 DEBUG3(D_MAP, "simba_bus_map(): offset=%lx, len=%lx, vaddrp=%p",
511 offset, len, vaddrp);
512
513 pdip = (dev_info_t *)DEVI(dip)->devi_parent;
514 return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
515 (pdip, rdip, mp, offset, len, vaddrp));
516 }
517
518 /*
519 * Registered error handling callback with our parent
520 */
521 static int
simba_err_callback(dev_info_t * dip,ddi_fm_error_t * derr,const void * impl_data)522 simba_err_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data)
523 {
524 simba_devstate_t *simba = (simba_devstate_t *)impl_data;
525 struct simba_errstate simba_err;
526 int ret = 0;
527
528 bzero(&simba_err, sizeof (struct simba_errstate));
529 simba_err.afsr = pci_config_get64(simba->config_handle, 0xe8);
530 simba_err.afar = pci_config_get64(simba->config_handle, 0xf0);
531 derr->fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
532
533 pci_ereport_post(dip, derr, NULL);
534 ret = derr->fme_status;
535
536 DEBUG6(D_FAULT, "%s-%d: cleaning up fault bits %x %x %x.%8x\n",
537 ddi_driver_name(simba->dip), ddi_get_instance(simba->dip),
538 simba_err.pci_cfg_stat, simba_err.pci_cfg_sec_stat,
539 (uint_t)(simba_err.afsr >> 32), (uint_t)simba_err.afsr);
540 pci_config_put64(simba->config_handle, 0xe8, simba_err.afsr);
541
542 return (ret);
543 }
544
545 #if defined(DEBUG) && !defined(lint)
546 static char *ops[] =
547 {
548 "DDI_CTLOPS_DMAPMAPC",
549 "DDI_CTLOPS_INITCHILD",
550 "DDI_CTLOPS_UNINITCHILD",
551 "DDI_CTLOPS_REPORTDEV",
552 "DDI_CTLOPS_REPORTINT",
553 "DDI_CTLOPS_REGSIZE",
554 "DDI_CTLOPS_NREGS",
555 "DDI_CTLOPS_RESERVED0",
556 "DDI_CTLOPS_SIDDEV",
557 "DDI_CTLOPS_SLAVEONLY",
558 "DDI_CTLOPS_AFFINITY",
559 "DDI_CTLOPS_IOMIN",
560 "DDI_CTLOPS_PTOB",
561 "DDI_CTLOPS_BTOP",
562 "DDI_CTLOPS_BTOPR",
563 "DDI_CTLOPS_RESERVED1",
564 "DDI_CTLOPS_RESERVED2",
565 "DDI_CTLOPS_RESERVED3",
566 "DDI_CTLOPS_RESERVED4",
567 "DDI_CTLOPS_RESERVED5",
568 "DDI_CTLOPS_DVMAPAGESIZE",
569 "DDI_CTLOPS_POWER",
570 "DDI_CTLOPS_ATTACH",
571 "DDI_CTLOPS_DETACH",
572 "DDI_CTLOPS_POKE",
573 "DDI_CTLOPS_PEEK"
574 };
575 #endif
576
577 /*ARGSUSED*/
578 static int
simba_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)579 simba_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
580 void *arg, void *result)
581 {
582 int reglen;
583 int rn;
584 int totreg;
585 pci_regspec_t *drv_regp;
586
587 DEBUG6(D_CTLOPS,
588 "simba_ctlops(): dip=%p rdip=%p ctlop=%x-%s arg=%p result=%p",
589 dip, rdip, ctlop, ctlop < (sizeof (ops) / sizeof (ops[0])) ?
590 ops[ctlop] : "Unknown", arg, result);
591
592 switch (ctlop) {
593 case DDI_CTLOPS_REPORTDEV:
594 if (rdip == (dev_info_t *)0)
595 return (DDI_FAILURE);
596 cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n",
597 ddi_node_name(rdip), ddi_get_name_addr(rdip),
598 ddi_driver_name(rdip),
599 ddi_get_instance(rdip));
600 return (DDI_SUCCESS);
601
602 case DDI_CTLOPS_INITCHILD:
603 return (simba_initchild((dev_info_t *)arg));
604
605 case DDI_CTLOPS_UNINITCHILD:
606 simba_uninitchild((dev_info_t *)arg);
607 return (DDI_SUCCESS);
608
609 case DDI_CTLOPS_SIDDEV:
610 return (DDI_SUCCESS);
611
612 case DDI_CTLOPS_REGSIZE:
613 case DDI_CTLOPS_NREGS:
614 if (rdip == (dev_info_t *)0)
615 return (DDI_FAILURE);
616 break;
617
618 default:
619 DEBUG0(D_CTLOPS, "simba_ctlops(): calling ddi_ctlops()");
620 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
621 }
622
623 *(int *)result = 0;
624 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip,
625 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg",
626 (caddr_t)&drv_regp, ®len) != DDI_SUCCESS)
627 return (DDI_FAILURE);
628
629 totreg = reglen / sizeof (pci_regspec_t);
630 if (ctlop == DDI_CTLOPS_NREGS)
631 *(int *)result = totreg;
632 else if (ctlop == DDI_CTLOPS_REGSIZE) {
633 rn = *(int *)arg;
634 if (rn >= totreg) {
635 kmem_free(drv_regp, reglen);
636 return (DDI_FAILURE);
637 }
638 *(off_t *)result = drv_regp[rn].pci_size_low |
639 ((uint64_t)drv_regp[rn].pci_size_hi << 32);
640 }
641
642 kmem_free(drv_regp, reglen);
643 DEBUG1(D_CTLOPS, "simba_ctlops(): *result=%lx\n", *(off_t *)result);
644 return (DDI_SUCCESS);
645 }
646
647 static int
simba_name_child(dev_info_t * child,char * name,int namelen)648 simba_name_child(dev_info_t *child, char *name, int namelen)
649 {
650 uint_t n, slot, func;
651 pci_regspec_t *pci_rp;
652
653 if (ndi_dev_is_persistent_node(child) == 0) {
654 char **unit_addr;
655
656 /* name .conf nodes by "unit-address" property" */
657 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
658 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
659 DDI_PROP_SUCCESS) {
660 cmn_err(CE_WARN, "cannot name node from %s.conf",
661 ddi_driver_name(child));
662 return (DDI_FAILURE);
663 }
664 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
665 cmn_err(CE_WARN, "unit-address property in %s.conf"
666 " not well-formed", ddi_driver_name(child));
667 ddi_prop_free(unit_addr);
668 return (DDI_FAILURE);
669 }
670
671 (void) snprintf(name, namelen, "%s", *unit_addr);
672 ddi_prop_free(unit_addr);
673 return (DDI_SUCCESS);
674 }
675
676 /* name hardware nodes by "reg" property */
677 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 0, "reg",
678 (int **)&pci_rp, &n) != DDI_SUCCESS)
679 return (DDI_FAILURE);
680
681 /* get the device identifications */
682 slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
683 func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
684
685 if (func != 0)
686 (void) snprintf(name, namelen, "%x,%x", slot, func);
687 else
688 (void) snprintf(name, namelen, "%x", slot);
689
690 ddi_prop_free(pci_rp);
691 return (DDI_SUCCESS);
692 }
693
694 static int
simba_initchild(dev_info_t * child)695 simba_initchild(dev_info_t *child)
696 {
697 char name[MAXNAMELEN];
698 int i;
699 ddi_acc_handle_t config_handle;
700 ushort_t command_preserve, command;
701 uchar_t header_type;
702 uchar_t min_gnt, latency_timer;
703 simba_devstate_t *simba;
704 uint_t n;
705
706 DEBUG1(D_INIT_CLD, "simba_initchild(): child=%p\n", child);
707
708 /*
709 * Pseudo nodes indicate a prototype node with per-instance
710 * properties to be merged into the real h/w device node.
711 * The interpretation of the unit-address is DD[,F]
712 * where DD is the device id and F is the function.
713 */
714 if (ndi_dev_is_persistent_node(child) == 0) {
715 extern int pci_allow_pseudo_children;
716 pci_regspec_t *pci_rp;
717
718 if (ddi_getlongprop(DDI_DEV_T_ANY, child,
719 DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, &i) ==
720 DDI_SUCCESS) {
721 cmn_err(CE_WARN,
722 "cannot merge prototype from %s.conf",
723 ddi_driver_name(child));
724 kmem_free(pci_rp, i);
725 return (DDI_NOT_WELL_FORMED);
726 }
727
728 if (simba_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
729 return (DDI_NOT_WELL_FORMED);
730
731 ddi_set_name_addr(child, name);
732 ddi_set_parent_data(child, NULL);
733
734 /*
735 * Try to merge the properties from this prototype
736 * node into real h/w nodes.
737 */
738 if (ndi_merge_node(child, simba_name_child) == DDI_SUCCESS) {
739 /*
740 * Merged ok - return failure to remove the node.
741 */
742 simba_uninitchild(child);
743 return (DDI_FAILURE);
744 }
745
746 /* workaround for ddivs to run under PCI */
747 if (pci_allow_pseudo_children)
748 return (DDI_SUCCESS);
749
750 /*
751 * The child was not merged into a h/w node,
752 * but there's not much we can do with it other
753 * than return failure to cause the node to be removed.
754 */
755 cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
756 ddi_driver_name(child), ddi_get_name_addr(child),
757 ddi_driver_name(child));
758 simba_uninitchild(child);
759 return (DDI_NOT_WELL_FORMED);
760 }
761
762 /*
763 * Initialize real h/w nodes
764 */
765 if (simba_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
766 return (DDI_FAILURE);
767
768 ddi_set_name_addr(child, name);
769 ddi_set_parent_data(child, NULL);
770
771 if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
772 simba_uninitchild(child);
773 return (DDI_FAILURE);
774 }
775
776 DEBUG0(D_INIT_CLD, "simba_initchild(): pci_config_setup success!\n");
777
778 /*
779 * Determine the configuration header type.
780 */
781 header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
782
783 /*
784 * Support for the "command-preserve" property.
785 */
786 command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
787 DDI_PROP_DONTPASS, "command-preserve", 0);
788 command = pci_config_get16(config_handle, PCI_CONF_COMM);
789 command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
790 command |= (simba_command_default & ~command_preserve);
791 pci_config_put16(config_handle, PCI_CONF_COMM, command);
792
793 /* clean up all PCI child devices status register */
794 pci_config_put16(config_handle, PCI_CONF_STAT, 0xffff);
795
796 /*
797 * If the device has a primary bus control register then program it
798 * based on the settings in the command register.
799 */
800 if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
801 ushort_t bcr =
802 pci_config_get16(config_handle, PCI_BCNF_BCNTRL);
803 if (simba_command_default & PCI_COMM_PARITY_DETECT)
804 bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
805 if (simba_command_default & PCI_COMM_SERR_ENABLE)
806 bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
807 bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
808 pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
809 }
810
811 simba = (simba_devstate_t *)ddi_get_soft_state(simba_state,
812 ddi_get_instance(ddi_get_parent(child)));
813 /*
814 * Initialize cache-line-size configuration register if needed.
815 */
816 if (simba_set_cache_line_size_register &&
817 ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
818 "cache-line-size", 0) == 0) {
819 pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
820 simba->simba_cache_line_size);
821 n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
822 if (n != 0)
823 (void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
824 "cache-line-size", n);
825 }
826
827 /*
828 * Initialize latency timer configuration registers if needed.
829 */
830 if (simba_set_latency_timer_register &&
831 ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
832 "latency-timer", 0) == 0) {
833
834 if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
835 latency_timer = simba->simba_latency_timer;
836 pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
837 simba->simba_latency_timer);
838 } else {
839 min_gnt = pci_config_get8(config_handle,
840 PCI_CONF_MIN_G);
841 latency_timer = min_gnt * 8;
842 }
843 pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
844 latency_timer);
845 n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
846 if (n != 0)
847 (void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
848 "latency-timer", n);
849 }
850
851 pci_config_teardown(&config_handle);
852 DEBUG0(D_INIT_CLD, "simba_initchild(): pci_config_teardown called\n");
853 return (DDI_SUCCESS);
854 }
855
856 static void
simba_uninitchild(dev_info_t * dip)857 simba_uninitchild(dev_info_t *dip)
858 {
859 ddi_set_name_addr(dip, NULL);
860
861 /*
862 * Strip the node to properly convert it back to prototype form
863 */
864 impl_rem_dev_props(dip);
865 }
866
867 /*
868 * simba_save_config_regs
869 *
870 * This routine saves the state of the configuration registers of all
871 * the child nodes of each PBM.
872 *
873 * used by: simba_detach() on suspends
874 *
875 * return value: none
876 */
877 static void
simba_save_config_regs(simba_devstate_t * simba_p)878 simba_save_config_regs(simba_devstate_t *simba_p)
879 {
880 int i;
881 dev_info_t *dip;
882 ddi_acc_handle_t ch;
883 struct simba_cfg_state *statep;
884
885 for (i = 0, dip = ddi_get_child(simba_p->dip); dip != NULL;
886 dip = ddi_get_next_sibling(dip)) {
887 if (i_ddi_devi_attached(dip))
888 i++;
889 }
890 if (!i)
891 return;
892 simba_p->simba_config_state_p =
893 kmem_zalloc(i * sizeof (struct simba_cfg_state), KM_NOSLEEP);
894 if (!simba_p->simba_config_state_p) {
895 cmn_err(CE_WARN, "not enough memrory to save simba child\n");
896 return;
897 }
898 simba_p->config_state_index = i;
899
900 for (statep = simba_p->simba_config_state_p,
901 dip = ddi_get_child(simba_p->dip);
902 dip != NULL;
903 dip = ddi_get_next_sibling(dip)) {
904
905 if (!i_ddi_devi_attached(dip)) {
906 DEBUG4(D_DETACH, "%s%d: skipping unattached %s%d\n",
907 ddi_driver_name(simba_p->dip),
908 ddi_get_instance(simba_p->dip),
909 ddi_driver_name(dip),
910 ddi_get_instance(dip));
911 continue;
912 }
913
914 DEBUG4(D_DETACH, "%s%d: saving regs for %s%d\n",
915 ddi_driver_name(simba_p->dip),
916 ddi_get_instance(simba_p->dip),
917 ddi_driver_name(dip),
918 ddi_get_instance(dip));
919
920 if (pci_config_setup(dip, &ch) != DDI_SUCCESS) {
921 DEBUG4(D_DETACH, "%s%d: can't config space for %s%d\n",
922 ddi_driver_name(simba_p->dip),
923 ddi_get_instance(simba_p->dip),
924 ddi_driver_name(dip),
925 ddi_get_instance(dip));
926 continue;
927 }
928
929 DEBUG3(D_DETACH, "%s%d: saving child dip=%p\n",
930 ddi_driver_name(simba_p->dip),
931 ddi_get_instance(simba_p->dip),
932 dip);
933
934 statep->dip = dip;
935 statep->command = pci_config_get16(ch, PCI_CONF_COMM);
936 statep->header_type = pci_config_get8(ch, PCI_CONF_HEADER);
937 if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
938 statep->bridge_control =
939 pci_config_get16(ch, PCI_BCNF_BCNTRL);
940 statep->cache_line_size =
941 pci_config_get8(ch, PCI_CONF_CACHE_LINESZ);
942 statep->latency_timer =
943 pci_config_get8(ch, PCI_CONF_LATENCY_TIMER);
944 if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
945 statep->sec_latency_timer =
946 pci_config_get8(ch, PCI_BCNF_LATENCY_TIMER);
947 /*
948 * Simba specific.
949 */
950 if (pci_config_get16(ch, PCI_CONF_VENID) == PCI_SIMBA_VENID &&
951 pci_config_get16(ch, PCI_CONF_DEVID) == PCI_SIMBA_DEVID) {
952
953 statep->bus_number =
954 pci_config_get8(ch, PCI_BCNF_PRIBUS);
955 statep->sec_bus_number =
956 pci_config_get8(ch, PCI_BCNF_SECBUS);
957 statep->sub_bus_number =
958 pci_config_get8(ch, PCI_BCNF_SUBBUS);
959 statep->bridge_control =
960 pci_config_get16(ch, PCI_BCNF_BCNTRL);
961 }
962 pci_config_teardown(&ch);
963 statep++;
964 }
965 }
966
967
968 /*
969 * simba_restore_config_regs
970 *
971 * This routine restores the state of the configuration registers of all
972 * the child nodes of each PBM.
973 *
974 * used by: simba_attach() on resume
975 *
976 * return value: none
977 */
978 static void
simba_restore_config_regs(simba_devstate_t * simba_p)979 simba_restore_config_regs(simba_devstate_t *simba_p)
980 {
981 int i;
982 dev_info_t *dip;
983 ddi_acc_handle_t ch;
984 struct simba_cfg_state *statep = simba_p->simba_config_state_p;
985 if (!simba_p->config_state_index)
986 return;
987
988 for (i = 0; i < simba_p->config_state_index; i++, statep++) {
989 dip = statep->dip;
990 if (!dip) {
991 cmn_err(CE_WARN,
992 "%s%d: skipping bad dev info (%d)\n",
993 ddi_driver_name(simba_p->dip),
994 ddi_get_instance(simba_p->dip),
995 i);
996 continue;
997 }
998
999 DEBUG5(D_ATTACH, "%s%d: restoring regs for %p-%s%d\n",
1000 ddi_driver_name(simba_p->dip),
1001 ddi_get_instance(simba_p->dip),
1002 dip,
1003 ddi_driver_name(dip),
1004 ddi_get_instance(dip));
1005
1006 if (pci_config_setup(dip, &ch) != DDI_SUCCESS) {
1007 DEBUG4(D_ATTACH, "%s%d: can't config space for %s%d\n",
1008 ddi_driver_name(simba_p->dip),
1009 ddi_get_instance(simba_p->dip),
1010 ddi_driver_name(dip),
1011 ddi_get_instance(dip));
1012 continue;
1013 }
1014 pci_config_put16(ch, PCI_CONF_COMM, statep->command);
1015 if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
1016 pci_config_put16(ch, PCI_BCNF_BCNTRL,
1017 statep->bridge_control);
1018 /*
1019 * Simba specific.
1020 */
1021 if (pci_config_get16(ch, PCI_CONF_VENID) == PCI_SIMBA_VENID &&
1022 pci_config_get16(ch, PCI_CONF_DEVID) == PCI_SIMBA_DEVID) {
1023 pci_config_put8(ch, PCI_BCNF_PRIBUS,
1024 statep->bus_number);
1025 pci_config_put8(ch, PCI_BCNF_SECBUS,
1026 statep->sec_bus_number);
1027 pci_config_put8(ch, PCI_BCNF_SUBBUS,
1028 statep->sub_bus_number);
1029 pci_config_put16(ch, PCI_BCNF_BCNTRL,
1030 statep->bridge_control);
1031 }
1032
1033 pci_config_put8(ch, PCI_CONF_CACHE_LINESZ,
1034 statep->cache_line_size);
1035 pci_config_put8(ch, PCI_CONF_LATENCY_TIMER,
1036 statep->latency_timer);
1037 if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
1038 pci_config_put8(ch, PCI_BCNF_LATENCY_TIMER,
1039 statep->sec_latency_timer);
1040 pci_config_teardown(&ch);
1041 }
1042
1043 kmem_free(simba_p->simba_config_state_p,
1044 simba_p->config_state_index * sizeof (struct simba_cfg_state));
1045 simba_p->simba_config_state_p = NULL;
1046 simba_p->config_state_index = 0;
1047 }
1048
1049 /* ARGSUSED */
1050 static int
simba_open(dev_t * devp,int flags,int otyp,cred_t * credp)1051 simba_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1052 {
1053 simba_devstate_t *simba_p;
1054
1055 /*
1056 * Make sure the open is for the right file type.
1057 */
1058 if (otyp != OTYP_CHR)
1059 return (EINVAL);
1060
1061 /*
1062 * Get the soft state structure for the device.
1063 */
1064 simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state,
1065 getminor(*devp));
1066 if (simba_p == NULL)
1067 return (ENXIO);
1068
1069 /*
1070 * Handle the open by tracking the device state.
1071 */
1072 mutex_enter(&simba_p->simba_mutex);
1073 if (flags & FEXCL) {
1074 if (simba_p->simba_soft_state != SIMBA_SOFT_STATE_CLOSED) {
1075 mutex_exit(&simba_p->simba_mutex);
1076 return (EBUSY);
1077 }
1078 simba_p->simba_soft_state = SIMBA_SOFT_STATE_OPEN_EXCL;
1079 } else {
1080 if (simba_p->simba_soft_state == SIMBA_SOFT_STATE_OPEN_EXCL) {
1081 mutex_exit(&simba_p->simba_mutex);
1082 return (EBUSY);
1083 }
1084 simba_p->simba_soft_state = SIMBA_SOFT_STATE_OPEN;
1085 }
1086 mutex_exit(&simba_p->simba_mutex);
1087 return (0);
1088 }
1089
1090
1091 /* ARGSUSED */
1092 static int
simba_close(dev_t dev,int flags,int otyp,cred_t * credp)1093 simba_close(dev_t dev, int flags, int otyp, cred_t *credp)
1094 {
1095 simba_devstate_t *simba_p;
1096
1097 if (otyp != OTYP_CHR)
1098 return (EINVAL);
1099
1100 simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state,
1101 getminor(dev));
1102 if (simba_p == NULL)
1103 return (ENXIO);
1104
1105 mutex_enter(&simba_p->simba_mutex);
1106 simba_p->simba_soft_state = SIMBA_SOFT_STATE_CLOSED;
1107 mutex_exit(&simba_p->simba_mutex);
1108 return (0);
1109 }
1110
1111
1112 /*
1113 * simba_ioctl: devctl hotplug controls
1114 */
1115 /* ARGSUSED */
1116 static int
simba_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1117 simba_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1118 int *rvalp)
1119 {
1120 simba_devstate_t *simba_p;
1121 dev_info_t *self;
1122 struct devctl_iocdata *dcp;
1123 uint_t bus_state;
1124 int rv = 0;
1125
1126 simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state,
1127 getminor(dev));
1128 if (simba_p == NULL)
1129 return (ENXIO);
1130
1131 self = simba_p->dip;
1132
1133 /*
1134 * We can use the generic implementation for these ioctls
1135 */
1136 switch (cmd) {
1137 case DEVCTL_DEVICE_GETSTATE:
1138 case DEVCTL_DEVICE_ONLINE:
1139 case DEVCTL_DEVICE_OFFLINE:
1140 case DEVCTL_BUS_GETSTATE:
1141 return (ndi_devctl_ioctl(self, cmd, arg, mode, 0));
1142 }
1143
1144 /*
1145 * read devctl ioctl data
1146 */
1147 if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
1148 return (EFAULT);
1149
1150 switch (cmd) {
1151
1152 case DEVCTL_DEVICE_RESET:
1153 rv = ENOTSUP;
1154 break;
1155
1156
1157 case DEVCTL_BUS_QUIESCE:
1158 if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1159 if (bus_state == BUS_QUIESCED)
1160 break;
1161 (void) ndi_set_bus_state(self, BUS_QUIESCED);
1162 break;
1163
1164 case DEVCTL_BUS_UNQUIESCE:
1165 if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1166 if (bus_state == BUS_ACTIVE)
1167 break;
1168 (void) ndi_set_bus_state(self, BUS_ACTIVE);
1169 break;
1170
1171 case DEVCTL_BUS_RESET:
1172 rv = ENOTSUP;
1173 break;
1174
1175 case DEVCTL_BUS_RESETALL:
1176 rv = ENOTSUP;
1177 break;
1178
1179 default:
1180 rv = ENOTTY;
1181 }
1182
1183 ndi_dc_freehdl(dcp);
1184 return (rv);
1185 }
1186
1187 /*
1188 * Initialize FMA resources for children devices. Called when
1189 * child calls ddi_fm_init().
1190 */
1191 /*ARGSUSED*/
1192 static int
simba_fm_init_child(dev_info_t * dip,dev_info_t * tdip,int cap,ddi_iblock_cookie_t * ibc)1193 simba_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap,
1194 ddi_iblock_cookie_t *ibc)
1195 {
1196 simba_devstate_t *simba_p = ddi_get_soft_state(simba_state,
1197 ddi_get_instance(dip));
1198
1199 *ibc = simba_p->fm_ibc;
1200 return (simba_p->fm_cap);
1201 }
1202
1203 static void
simba_bus_enter(dev_info_t * dip,ddi_acc_handle_t handle)1204 simba_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle)
1205 {
1206 i_ndi_busop_access_enter(dip, handle);
1207 }
1208
1209 /* ARGSUSED */
1210 static void
simba_bus_exit(dev_info_t * dip,ddi_acc_handle_t handle)1211 simba_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle)
1212 {
1213 i_ndi_busop_access_exit(dip, handle);
1214 }
1215