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
27 #include <sys/types.h>
28 #include <sys/conf.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/autoconf.h>
32 #include <sys/ddi_impldefs.h>
33 #include <sys/ddi_subrdefs.h>
34 #include <sys/cmn_err.h>
35 #include <sys/errno.h>
36 #include <sys/kmem.h>
37 #include <sys/debug.h>
38 #include <sys/sysmacros.h>
39 #include <sys/spl.h>
40 #include <sys/async.h>
41 #include <sys/dvma.h>
42 #include <sys/upa64s.h>
43 #include <sys/machsystm.h>
44
45 /*
46 * driver global data:
47 */
48 static void *per_upa64s_state; /* soft state pointer */
49
50 /*
51 * function prototypes for bus ops routines:
52 */
53 static int
54 upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
55 off_t offset, off_t len, caddr_t *addrp);
56 static int
57 upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip,
58 ddi_ctl_enum_t op, void *arg, void *result);
59 static int
60 upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
61 ddi_intr_handle_impl_t *hdlp, void *result);
62 static int
63 upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
64 ddi_intr_handle_impl_t *hdlp);
65 static int
66 upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
67 ddi_intr_handle_impl_t *hdlp);
68
69 /*
70 * function prototypes for dev ops routines:
71 */
72 static int upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
73 static int upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
74 static int upa64s_power(dev_info_t *dip, int component, int level);
75
76 /*
77 * bus ops and dev ops structures:
78 */
79 static struct bus_ops upa64s_bus_ops = {
80 BUSO_REV,
81 upa64s_map,
82 0,
83 0,
84 0,
85 i_ddi_map_fault,
86 ddi_no_dma_map,
87 ddi_no_dma_allochdl,
88 ddi_no_dma_freehdl,
89 ddi_no_dma_bindhdl,
90 ddi_no_dma_unbindhdl,
91 ddi_no_dma_flush,
92 ddi_no_dma_win,
93 ddi_no_dma_mctl,
94 upa64s_ctlops,
95 ddi_bus_prop_op,
96 0,
97 0,
98 0,
99 0,
100 0,
101 0,
102 0,
103 0,
104 0,
105 0,
106 0,
107 0,
108 upa64_intr_ops
109 };
110
111 static struct dev_ops upa64s_ops = {
112 DEVO_REV,
113 0,
114 ddi_no_info,
115 nulldev,
116 0,
117 upa64s_attach,
118 upa64s_detach,
119 nodev,
120 (struct cb_ops *)0,
121 &upa64s_bus_ops,
122 upa64s_power,
123 ddi_quiesce_not_supported, /* devo_quiesce */
124 };
125
126 /*
127 * module definitions:
128 */
129 #include <sys/modctl.h>
130 extern struct mod_ops mod_driverops;
131
132 static struct modldrv modldrv = {
133 &mod_driverops, /* type of module */
134 "UPA64S nexus driver", /* name of module */
135 &upa64s_ops, /* driver ops */
136 };
137
138 static struct modlinkage modlinkage = {
139 MODREV_1, (void *)&modldrv, NULL
140 };
141
142 int
_init(void)143 _init(void)
144 {
145 int e;
146
147 /*
148 * Initialize per instance bus soft state pointer.
149 */
150 if (e = ddi_soft_state_init(&per_upa64s_state,
151 sizeof (upa64s_devstate_t), 2))
152 return (e);
153 /*
154 * Install the module.
155 */
156 if (e = mod_install(&modlinkage))
157 ddi_soft_state_fini(&per_upa64s_state);
158 return (e);
159 }
160
161 int
_fini(void)162 _fini(void)
163 {
164 int e = mod_remove(&modlinkage);
165 if (e)
166 return (e);
167 ddi_soft_state_fini(&per_upa64s_state);
168 return (e);
169 }
170
171 int
_info(struct modinfo * modinfop)172 _info(struct modinfo *modinfop)
173 {
174 return (mod_info(&modlinkage, modinfop));
175 }
176
177
178 /*
179 * forward declarations:
180 */
181 static void upa64s_intrdist(void *arg);
182 static int init_child(dev_info_t *child);
183 static int report_dev(dev_info_t *dip);
184 static int get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip);
185 static void save_state(upa64s_devstate_t *upa64s_p);
186 static void restore_state(upa64s_devstate_t *upa64s_p);
187 static int xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *upa64s_rp,
188 off_t off, off_t len, struct regspec *rp);
189 static int get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber,
190 off_t off, off_t len, struct regspec *rp);
191 static off_t get_reg_set_size(dev_info_t *child, int rnumber);
192 static uint_t get_nreg_set(dev_info_t *child);
193
194
195 /* device driver entry points */
196
197 /*
198 * attach entry point:
199 */
200 static int
upa64s_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)201 upa64s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
202 {
203 upa64s_devstate_t *upa64s_p; /* per upa64s state pointer */
204 ddi_device_acc_attr_t attr;
205 int instance;
206 char *pmc[] = { "NAME=Framebuffer Power", "0=Off", "1=On", NULL };
207
208 switch (cmd) {
209 case DDI_ATTACH:
210 /*
211 * Allocate and get the per instance soft state structure.
212 */
213 instance = ddi_get_instance(dip);
214 if (alloc_upa64s_soft_state(instance) != DDI_SUCCESS) {
215 cmn_err(CE_WARN, "%s%d: can't allocate upa64s state",
216 ddi_get_name(dip), instance);
217 return (DDI_FAILURE);
218 }
219 upa64s_p = get_upa64s_soft_state(instance);
220 upa64s_p->dip = dip;
221
222 /*
223 * Get key properties of the bridge node.
224 */
225 if (get_properties(upa64s_p, dip) != DDI_SUCCESS)
226 goto fail;
227
228 /*
229 * Create "pm-components" property for the purpose of
230 * doing Power Management.
231 */
232 if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
233 "pm-components", pmc, ((sizeof (pmc)/sizeof (char *)) - 1))
234 != DDI_PROP_SUCCESS) {
235 cmn_err(CE_WARN, "%s%d: failed to create pm-components "
236 "property.", ddi_get_name(dip), instance);
237 goto fail;
238 }
239
240 /* Map in the UPA's registers */
241 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
242 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
243 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
244 if (ddi_regs_map_setup(dip, 0,
245 (caddr_t *)&upa64s_p->config_base, 0, 0, &attr,
246 &upa64s_p->config_base_ah) != DDI_SUCCESS) {
247 cmn_err(CE_WARN, "%s%d: failed to map reg1.",
248 ddi_get_name(dip), instance);
249 goto fail;
250 }
251
252 upa64s_p->upa0_config = (uint64_t *)(upa64s_p->config_base +
253 UPA64S_UPA0_CONFIG_OFFSET);
254 upa64s_p->upa1_config = (uint64_t *)(upa64s_p->config_base +
255 UPA64S_UPA1_CONFIG_OFFSET);
256 upa64s_p->if_config = (uint64_t *)(upa64s_p->config_base +
257 UPA64S_IF_CONFIG_OFFSET);
258 upa64s_p->estar = (uint64_t *)(upa64s_p->config_base +
259 UPA64S_ESTAR_OFFSET);
260
261 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&upa64s_p->imr[0],
262 0, 0, &attr, &upa64s_p->imr_ah[0]) != DDI_SUCCESS) {
263 cmn_err(CE_WARN, "%s%d: failed to map reg2.",
264 ddi_get_name(dip), instance);
265 goto fail1;
266 }
267
268 if (ddi_regs_map_setup(dip, 2, (caddr_t *)&upa64s_p->imr[1],
269 0, 0, &attr, &upa64s_p->imr_ah[1]) != DDI_SUCCESS) {
270 cmn_err(CE_WARN, "%s%d: failed to map reg3.",
271 ddi_get_name(dip), instance);
272 goto fail2;
273 }
274
275 /*
276 * Power level of a component is unknown at attach time.
277 * Bring the power level to what is needed for normal operation.
278 */
279 upa64s_p->power_level = UPA64S_PM_UNKNOWN;
280 if (pm_raise_power(dip, UPA64S_PM_COMP, UPA64S_PM_NORMOP) !=
281 DDI_SUCCESS) {
282 cmn_err(CE_WARN, "%s%d: failed to raise the power.",
283 ddi_get_name(dip), instance);
284 goto fail3;
285 }
286
287 intr_dist_add(upa64s_intrdist, dip);
288
289 ddi_report_dev(dip);
290 return (DDI_SUCCESS);
291
292 case DDI_RESUME:
293
294 upa64s_p = get_upa64s_soft_state(ddi_get_instance(dip));
295 DBG(D_ATTACH, dip, "DDI_RESUME\n");
296 restore_state(upa64s_p);
297
298 /*
299 * Power level of a component is unknown at resume time.
300 * Bring the power level to what it was before suspend.
301 */
302 upa64s_p->power_level = UPA64S_PM_UNKNOWN;
303 if (pm_raise_power(dip, UPA64S_PM_COMP,
304 upa64s_p->saved_power_level) != DDI_SUCCESS)
305 cmn_err(CE_WARN, "%s%d: failed to change power level "
306 "during resume!", ddi_get_name(dip), instance);
307
308 return (DDI_SUCCESS);
309
310 default:
311 return (DDI_FAILURE);
312 }
313
314 fail3:
315 ddi_regs_map_free(&upa64s_p->imr_ah[1]);
316 fail2:
317 ddi_regs_map_free(&upa64s_p->imr_ah[0]);
318 fail1:
319 ddi_regs_map_free(&upa64s_p->config_base_ah);
320 fail:
321 free_upa64s_soft_state(instance);
322 return (DDI_FAILURE);
323 }
324
325
326 /*
327 * detach entry point:
328 */
329 static int
upa64s_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)330 upa64s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
331 {
332 int instance = ddi_get_instance(dip);
333 upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
334
335 switch (cmd) {
336 case DDI_DETACH:
337
338 DBG(D_DETACH, dip, "DDI_DETACH\n");
339
340 /*
341 * Power down the device.
342 */
343 if (pm_lower_power(dip, UPA64S_PM_COMP, UPA64S_PM_RESET) !=
344 DDI_SUCCESS)
345 DBG(D_DETACH, dip, "failed to power off!\n");
346
347 intr_dist_rem(upa64s_intrdist, dip);
348
349 ddi_regs_map_free(&upa64s_p->config_base_ah);
350 ddi_regs_map_free(&upa64s_p->imr_ah[0]);
351 ddi_regs_map_free(&upa64s_p->imr_ah[1]);
352 free_upa64s_soft_state(instance);
353 return (DDI_SUCCESS);
354
355 case DDI_SUSPEND:
356
357 DBG(D_DETACH, dip, "DDI_SUSPEND\n");
358 save_state(upa64s_p);
359 upa64s_p->saved_power_level = upa64s_p->power_level;
360 return (DDI_SUCCESS);
361 }
362
363 return (DDI_FAILURE);
364 }
365
366 /*
367 * power entry point:
368 *
369 * This entry point is called by Power Management framework to
370 * reset upa bus and slow down/speed up the upa interface of
371 * Schizo chip.
372 */
373 static int
upa64s_power(dev_info_t * dip,int component,int level)374 upa64s_power(dev_info_t *dip, int component, int level)
375 {
376 int instance = ddi_get_instance(dip);
377 upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
378 volatile uint64_t uint64_data;
379
380 DBG2(D_POWER, dip, "component=%d, level=%d\n", component, level);
381 if (component != UPA64S_PM_COMP ||
382 level < UPA64S_PM_RESET || level > UPA64S_PM_NORMOP)
383 return (DDI_FAILURE);
384
385 /*
386 * We can't set the hardware to the state that it is
387 * already in. So if the power state is not known, inquire the
388 * state of the hardware. If it is already in that state,
389 * record and return, otherwise make the state change.
390 */
391 if (upa64s_p->power_level == UPA64S_PM_UNKNOWN) {
392 uint64_data = ddi_get64(upa64s_p->config_base_ah,
393 upa64s_p->if_config);
394 if ((level == UPA64S_PM_RESET &&
395 uint64_data == UPA64S_NOT_POK_RST_L) ||
396 (level == UPA64S_PM_NORMOP &&
397 uint64_data == UPA64S_POK_NOT_RST_L)) {
398 upa64s_p->power_level = level;
399 return (DDI_SUCCESS);
400 }
401 }
402
403 if (level == upa64s_p->power_level) {
404 DBG1(D_POWER, dip, "device is already at power level %d\n",
405 level);
406 return (DDI_SUCCESS);
407 }
408
409
410 if (level == UPA64S_PM_RESET) {
411 /*
412 * Assert UPA64S_RESET
413 */
414 ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
415 UPA64S_POK_RST_L);
416
417 /*
418 * Deassert UPA64S_POK. Flush the store buffer.
419 */
420 ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
421 UPA64S_NOT_POK_RST_L);
422 uint64_data = ddi_get64(upa64s_p->config_base_ah,
423 upa64s_p->if_config);
424
425 /*
426 * Internal UPA clock to 1/2 speed
427 */
428 ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
429 UPA64S_1_2_SPEED);
430
431 /*
432 * Internal UPA clock to 1/64 speed. Flush the store buffer.
433 */
434 ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
435 UPA64S_1_64_SPEED);
436 uint64_data = ddi_get64(upa64s_p->config_base_ah,
437 upa64s_p->estar);
438 } else {
439 /*
440 * Internal UPA clock to 1/2 speed
441 */
442 ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
443 UPA64S_1_2_SPEED);
444
445 /*
446 * Internal UPA clock to full speed. Flush the store buffer.
447 */
448 ddi_put64(upa64s_p->config_base_ah, upa64s_p->estar,
449 UPA64S_FULL_SPEED);
450 uint64_data = ddi_get64(upa64s_p->config_base_ah,
451 upa64s_p->estar);
452
453 /*
454 * Assert UPA64S_POK. Flush the store buffer before
455 * the wait delay.
456 */
457 ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
458 UPA64S_POK_RST_L);
459 uint64_data = ddi_get64(upa64s_p->config_base_ah,
460 upa64s_p->if_config);
461
462 /*
463 * Delay 20 milliseconds for the signals to settle down.
464 */
465 delay(drv_usectohz(20*1000));
466
467 /*
468 * Deassert UPA64S_RESET. Flush the store buffer.
469 */
470 ddi_put64(upa64s_p->config_base_ah, upa64s_p->if_config,
471 UPA64S_POK_NOT_RST_L);
472 uint64_data = ddi_get64(upa64s_p->config_base_ah,
473 upa64s_p->if_config);
474 }
475 upa64s_p->power_level = level;
476
477 return (DDI_SUCCESS);
478 }
479
480 /* bus driver entry points */
481
482 /*
483 * bus map entry point:
484 *
485 * if map request is for an rnumber
486 * get the corresponding regspec from device node
487 * build a new regspec in our parent's format
488 * build a new map_req with the new regspec
489 * call up the tree to complete the mapping
490 */
491 static int
upa64s_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t off,off_t len,caddr_t * addrp)492 upa64s_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
493 off_t off, off_t len, caddr_t *addrp)
494 {
495 struct regspec regspec;
496 ddi_map_req_t p_map_request;
497 int rnumber, rval;
498
499 DBG4(D_MAP, dip, "upa64s_map() mp=%x.%x addrp=%x.%08x\n",
500 HI32(mp), LO32(mp), HI32(addrp), LO32(addrp));
501
502 /*
503 * User level mappings are not supported yet.
504 */
505 if (mp->map_flags & DDI_MF_USER_MAPPING) {
506 DBG2(D_MAP, dip, "rdip=%s%d: no user level mappings yet!\n",
507 ddi_get_name(rdip), ddi_get_instance(rdip));
508 return (DDI_ME_UNIMPLEMENTED);
509 }
510
511 /*
512 * Now handle the mapping according to its type.
513 */
514 switch (mp->map_type) {
515 case DDI_MT_REGSPEC:
516
517 /*
518 * We assume the register specification is in PCI format.
519 * We must convert it into a regspec of our parent's
520 * and pass the request to our parent.
521 */
522 DBG3(D_MAP, dip, "rdip=%s%d: REGSPEC - handlep=%x\n",
523 ddi_get_name(rdip), ddi_get_instance(rdip),
524 mp->map_handlep);
525 rval = xlate_reg_prop(dip, (upa64s_regspec_t *)mp->map_obj.rp,
526 off, len, ®spec);
527 break;
528
529 case DDI_MT_RNUMBER:
530
531 /*
532 * Get the "reg" property from the device node and convert
533 * it to our parent's format.
534 */
535 DBG4(D_MAP, dip, "rdip=%s%d: rnumber=%x handlep=%x\n",
536 ddi_get_name(rdip), ddi_get_instance(rdip),
537 mp->map_obj.rnumber, mp->map_handlep);
538 rnumber = mp->map_obj.rnumber;
539 if (rnumber < 0)
540 return (DDI_ME_RNUMBER_RANGE);
541 rval = get_reg_set(dip, rdip, rnumber, off, len, ®spec);
542 break;
543
544 default:
545 return (DDI_ME_INVAL);
546
547 }
548 if (rval != DDI_SUCCESS) {
549 DBG(D_MAP, dip, "failed on regspec\n\n");
550 return (rval);
551 }
552
553 /*
554 * Now we have a copy of the upa64s regspec converted to our parent's
555 * format. Build a new map request based on this regspec and pass
556 * it to our parent.
557 */
558 p_map_request = *mp;
559 p_map_request.map_type = DDI_MT_REGSPEC;
560 p_map_request.map_obj.rp = ®spec;
561 rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
562 DBG3(D_MAP, dip, "ddi_map returns: rval=%x addrp=%x.%08x\n\n",
563 rval, HI32(*addrp), LO32(*addrp));
564 return (rval);
565 }
566
567 /*
568 * Translate the UPA devices interrupt property. This is the only case I
569 * know of where the interrupts property is meaningless. As a result, we
570 * just use UPA_BASE_INO as our interrupt value and add to it the upa port id.
571 * UPA portid is returned too.
572 */
573 #define UPA_BASE_INO 0x2a
574
575 static int
upa64s_xlate_intr(dev_info_t * rdip,int32_t safariport,uint32_t * intr)576 upa64s_xlate_intr(dev_info_t *rdip, int32_t safariport, uint32_t *intr)
577 {
578 uint32_t ino = UPA_BASE_INO;
579 int32_t portid;
580
581 /* Clear the ffb's interrupts property, it's meaningless */
582 *intr = 0;
583
584 if ((portid = ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
585 "upa-portid", -1)) == -1)
586 return (-1);
587
588 ino += portid;
589
590 *intr = UPA64S_MAKE_MONDO(safariport, ino);
591
592 DBG5(D_A_ISPEC, rdip, "upa64s_xlate_intr: rdip=%s%d: upa portid %d "
593 "ino=%x mondo 0x%x\n", ddi_get_name(rdip), ddi_get_instance(rdip),
594 portid, ino, *intr);
595
596 return (portid);
597 }
598
599 /*
600 * bus add intrspec entry point:
601 */
602 static int
upa64s_add_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)603 upa64s_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
604 ddi_intr_handle_impl_t *hdlp)
605 {
606 int upaport, instance = ddi_get_instance(dip);
607 upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
608 #ifdef DEBUG
609 uint_t (*int_handler)(caddr_t, caddr_t) = hdlp->ih_cb_func;
610 caddr_t int_handler_arg1 = hdlp->ih_cb_arg1;
611 #endif /* DEBUG */
612 uint_t cpu_id;
613 volatile uint64_t imr_data;
614
615 upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id,
616 (uint32_t *)&hdlp->ih_vector);
617
618 if (hdlp->ih_vector == 0)
619 return (DDI_FAILURE);
620
621 DBG3(D_A_ISPEC, dip,
622 "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n",
623 ddi_driver_name(rdip), ddi_get_instance(rdip), hdlp->ih_vector);
624
625 /*
626 * Make sure an interrupt handler isn't already installed.
627 */
628 if (upa64s_p->ino_state[upaport] != INO_FREE) {
629 return (DDI_FAILURE);
630 }
631
632 /*
633 * Install the handler in the system table.
634 */
635 #ifdef DEBUG
636 DBG2(D_A_ISPEC, dip, "i_ddi_add_ivintr: hdlr=%p arg=%p\n",
637 int_handler, int_handler_arg1);
638 #endif
639 if (i_ddi_add_ivintr(hdlp) != DDI_SUCCESS)
640 return (DDI_FAILURE);
641
642 cpu_id = intr_dist_cpuid();
643
644 /*
645 * Enable the interrupt through its interrupt mapping register.
646 */
647 imr_data = UPA64S_CPUID_TO_IMR(cpu_id);
648 imr_data = UPA64S_GET_MAP_REG(hdlp->ih_vector, imr_data);
649
650 DBG4(D_A_ISPEC, dip, "IMR [upaport=%d mapping reg 0x%p] = %x.%x\n",
651 upaport, upa64s_p->imr[upaport], HI32(imr_data), LO32(imr_data));
652
653 ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], imr_data);
654 /* Read the data back to flush store buffers. */
655 imr_data = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]);
656 upa64s_p->ino_state[upaport] = INO_INUSE;
657
658 DBG(D_A_ISPEC, dip, "add_intr success!\n");
659 return (DDI_SUCCESS);
660 }
661
662
663 /*
664 * bus remove intrspec entry point
665 */
666 static int
upa64s_remove_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)667 upa64s_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
668 ddi_intr_handle_impl_t *hdlp)
669 {
670 upa64s_devstate_t *upa64s_p =
671 get_upa64s_soft_state(ddi_get_instance(dip));
672 int upaport;
673 #ifndef lint
674 volatile uint64_t tmp;
675 #endif
676
677 /*
678 * Make sure the mondo is valid.
679 */
680 upaport = upa64s_xlate_intr(rdip, upa64s_p->safari_id,
681 (uint32_t *)&hdlp->ih_vector);
682
683 if (hdlp->ih_vector == 0)
684 return (DDI_FAILURE);
685
686 DBG3(D_R_ISPEC, dip,
687 "rdip=%s%d - IDDI_INTR_TYPE_NORMAL, mondo=%x\n",
688 ddi_driver_name(rdip), ddi_get_instance(rdip), hdlp->ih_vector);
689
690 if (upa64s_p->ino_state[upaport] != INO_INUSE) {
691 return (DDI_FAILURE);
692 }
693
694 /* Call up to our parent to handle the removal */
695 i_ddi_rem_ivintr(hdlp);
696
697 ddi_put64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport], 0);
698 #ifndef lint
699 /* Flush store buffers */
700 tmp = ddi_get64(upa64s_p->imr_ah[upaport], upa64s_p->imr[upaport]);
701 #endif
702
703 upa64s_p->ino_state[upaport] = INO_FREE;
704 return (DDI_SUCCESS);
705 }
706
707
708 /* new intr_ops structure */
709 static int
upa64_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)710 upa64_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
711 ddi_intr_handle_impl_t *hdlp, void *result)
712 {
713 int ret = DDI_SUCCESS;
714
715 switch (intr_op) {
716 case DDI_INTROP_GETCAP:
717 *(int *)result = DDI_INTR_FLAG_EDGE;
718 break;
719 case DDI_INTROP_ALLOC:
720 *(int *)result = hdlp->ih_scratch1;
721 break;
722 case DDI_INTROP_FREE:
723 break;
724 case DDI_INTROP_GETPRI:
725 /*
726 * We only have slave UPA devices so force the PIL to 5.
727 * this is done since all slave UPA devices have historically
728 * had their PILs set to 5. Only do it if the PIL is not
729 * being preset.
730 */
731 *(int *)result = hdlp->ih_pri ? hdlp->ih_pri : 5;
732 break;
733 case DDI_INTROP_SETPRI:
734 break;
735 case DDI_INTROP_ADDISR:
736 ret = upa64s_add_intr_impl(dip, rdip, hdlp);
737 break;
738 case DDI_INTROP_REMISR:
739 ret = upa64s_remove_intr_impl(dip, rdip, hdlp);
740 break;
741 case DDI_INTROP_ENABLE:
742 case DDI_INTROP_DISABLE:
743 break;
744 case DDI_INTROP_NINTRS:
745 case DDI_INTROP_NAVAIL:
746 *(int *)result = i_ddi_get_intx_nintrs(rdip);
747 break;
748 case DDI_INTROP_SETCAP:
749 case DDI_INTROP_SETMASK:
750 case DDI_INTROP_CLRMASK:
751 case DDI_INTROP_GETPENDING:
752 ret = DDI_ENOTSUP;
753 break;
754 case DDI_INTROP_SUPPORTED_TYPES:
755 /* only support fixed interrupts */
756 *(int *)result = i_ddi_get_intx_nintrs(rdip) ?
757 DDI_INTR_TYPE_FIXED : 0;
758 break;
759 default:
760 ret = i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result);
761 break;
762 }
763
764 return (ret);
765 }
766
767 #ifdef DEBUG
768 uint_t upa64s_debug_flags = (uint_t)0;
769
770 extern void prom_printf(const char *, ...);
771 #endif
772
773 /*
774 * control ops entry point:
775 *
776 * Requests handled completely:
777 * DDI_CTLOPS_INITCHILD see init_child() for details
778 * DDI_CTLOPS_UNINITCHILD
779 * DDI_CTLOPS_REPORTDEV see report_dev() for details
780 * DDI_CTLOPS_REGSIZE
781 * DDI_CTLOPS_NREGS
782 *
783 * All others passed to parent.
784 */
785 static int
upa64s_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)786 upa64s_ctlops(dev_info_t *dip, dev_info_t *rdip,
787 ddi_ctl_enum_t op, void *arg, void *result)
788 {
789 DBG5(D_CTLOPS, dip, "dip=%x.%x rdip=%x.%x op=%x",
790 HI32(dip), LO32(dip), HI32(rdip), LO32(rdip), op);
791 DBG4(D_CTLOPS|D_CONT, dip, " arg=%x.%x result=%x.%x\n",
792 HI32(arg), LO32(arg), HI32(result), LO32(result));
793
794 switch (op) {
795 case DDI_CTLOPS_INITCHILD:
796 DBG2(D_CTLOPS, dip, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n",
797 ddi_get_name(rdip), ddi_get_instance(rdip));
798 return (init_child((dev_info_t *)arg));
799
800 case DDI_CTLOPS_UNINITCHILD:
801 DBG2(D_CTLOPS, dip, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n",
802 ddi_get_name(rdip), ddi_get_instance(rdip));
803 ddi_set_name_addr((dev_info_t *)arg, NULL);
804 ddi_remove_minor_node((dev_info_t *)arg, NULL);
805 impl_rem_dev_props((dev_info_t *)arg);
806 return (DDI_SUCCESS);
807
808 case DDI_CTLOPS_REPORTDEV:
809 DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n",
810 ddi_get_name(rdip), ddi_get_instance(rdip));
811 return (report_dev(rdip));
812
813 case DDI_CTLOPS_REGSIZE:
814 DBG2(D_CTLOPS, dip, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n",
815 ddi_get_name(rdip), ddi_get_instance(rdip));
816 *((off_t *)result) = get_reg_set_size(rdip, *((int *)arg));
817 return (*((off_t *)result) == -1 ? DDI_FAILURE : DDI_SUCCESS);
818
819 case DDI_CTLOPS_NREGS:
820 DBG2(D_CTLOPS, dip, "DDI_CTLOPS_NREGS: rdip=%s%d\n",
821 ddi_get_name(rdip), ddi_get_instance(rdip));
822 *((uint_t *)result) = get_nreg_set(rdip);
823 return (DDI_SUCCESS);
824 }
825
826 /*
827 * Now pass the request up to our parent.
828 */
829 DBG3(D_CTLOPS, dip, "passing request to parent: rdip=%s%d op=%x\n\n",
830 ddi_get_name(rdip), ddi_get_instance(rdip), op);
831 return (ddi_ctlops(dip, rdip, op, arg, result));
832 }
833
834
835 /* support routines */
836
837 /*
838 * get_properties
839 *
840 * This function is called from the attach routine to get the key
841 * properties of the upa64s node.
842 *
843 * used by: upa64s_attach()
844 *
845 * return value: none
846 */
847 static int
get_properties(upa64s_devstate_t * upa64s_p,dev_info_t * dip)848 get_properties(upa64s_devstate_t *upa64s_p, dev_info_t *dip)
849 {
850 int safari_id;
851
852 /*
853 * Get the device's safari id.
854 */
855 safari_id = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
856 "portid", -1);
857 if (safari_id == -1) {
858 int instance = ddi_get_instance(dip);
859 panic("%s%d: no portid property", ddi_get_name(dip), instance);
860 }
861 upa64s_p->safari_id = safari_id;
862
863 return (DDI_SUCCESS);
864 }
865
866
867 /*
868 * save_state
869 *
870 * This routine saves a copy of the upa64s register state.
871 *
872 * used by: upa64s_detach() on a suspend operation
873 */
874 static void
save_state(upa64s_devstate_t * upa64s_p)875 save_state(upa64s_devstate_t *upa64s_p)
876 {
877 upa64s_p->imr_data[0] = ddi_get64(upa64s_p->imr_ah[0],
878 upa64s_p->imr[0]);
879 upa64s_p->imr_data[1] = ddi_get64(upa64s_p->imr_ah[1],
880 upa64s_p->imr[1]);
881 }
882
883
884 /*
885 * restore_state
886 *
887 * This routine restores a copy of the upa64s register state.
888 *
889 * used by: upa64s_attach() on a resume operation
890 */
891 static void
restore_state(upa64s_devstate_t * upa64s_p)892 restore_state(upa64s_devstate_t *upa64s_p)
893 {
894 #ifndef lint
895 volatile uint64_t tmp;
896 #endif
897 ddi_put64(upa64s_p->imr_ah[0], upa64s_p->imr[0],
898 upa64s_p->imr_data[0]);
899 ddi_put64(upa64s_p->imr_ah[1], upa64s_p->imr[1],
900 upa64s_p->imr_data[1]);
901 #ifndef lint
902 /* Flush the store buffer */
903 tmp = ddi_get64(upa64s_p->imr_ah[0], upa64s_p->imr[0]);
904 tmp = ddi_get64(upa64s_p->imr_ah[1], upa64s_p->imr[1]);
905 #endif
906 }
907
908
909 /*
910 * get_reg_set
911 *
912 * This routine will get a upa64s format regspec for a given
913 * device node and register number.
914 *
915 * used by: upa64s_map()
916 *
917 * return value:
918 *
919 * DDI_SUCCESS - on success
920 * DDI_ME_INVAL - regspec is invalid
921 * DDI_ME_RNUMBER_RANGE - rnumber out of range
922 */
923 static int
get_reg_set(dev_info_t * dip,dev_info_t * child,int rnumber,off_t off,off_t len,struct regspec * rp)924 get_reg_set(dev_info_t *dip, dev_info_t *child, int rnumber,
925 off_t off, off_t len, struct regspec *rp)
926 {
927 upa64s_regspec_t *upa64s_rp;
928 int i, n, rval;
929
930 /*
931 * Get child device "reg" property
932 */
933 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
934 (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
935 return (DDI_ME_RNUMBER_RANGE);
936
937 n = i / (int)sizeof (upa64s_regspec_t);
938 if (rnumber >= n) {
939 kmem_free(upa64s_rp, i);
940 return (DDI_ME_RNUMBER_RANGE);
941 }
942
943 /*
944 * Convert each the upa64s format register specification to
945 * out parent format.
946 */
947 rval = xlate_reg_prop(dip, &upa64s_rp[rnumber], off, len, rp);
948 kmem_free(upa64s_rp, i);
949 return (rval);
950 }
951
952
953 /*
954 * xlate_reg_prop
955 *
956 * This routine converts a upa64s format regspec to a standard
957 * regspec containing the corresponding system address.
958 *
959 * used by: upa64s_map()
960 *
961 * return value:
962 *
963 * DDI_SUCCESS
964 * DDI_FAILURE - off + len is beyond device address range
965 * DDI_ME_INVAL - regspec is invalid
966 */
967 static int
xlate_reg_prop(dev_info_t * dip,upa64s_regspec_t * child_rp,off_t off,off_t len,struct regspec * rp)968 xlate_reg_prop(dev_info_t *dip, upa64s_regspec_t *child_rp, off_t off,
969 off_t len, struct regspec *rp)
970 {
971 int n_ranges, ranges_len, i;
972 uint64_t child_beg, child_end;
973 upa64s_ranges_t *range_p, *rng_p;
974
975 DBG4(D_MAP, dip, "upa64s regspec - ((%x,%x) (%x,%x))\n",
976 HI32(child_rp->upa64s_phys), LO32(child_rp->upa64s_phys),
977 HI32(child_rp->upa64s_size), LO32(child_rp->upa64s_size));
978 DBG2(D_MAP, dip, "upa64s xlate_reg_prp - off=%lx len=%lx\n", off, len);
979 #if 0
980 /*
981 * both FFB and AFB have broken "reg" properties, all mapping
982 * requests are done through reg-0 with very long offsets.
983 * Hence this safety check is always violated.
984 */
985 if (off + len > child_rp->upa64s_size) {
986 DBG(D_MAP, dip, "upa64s xlate_reg_prp: bad off + len\n");
987 return (DDI_FAILURE);
988 }
989 #endif
990 /*
991 * current "struct regspec" only supports 32-bit sizes.
992 */
993 if (child_rp->upa64s_size >= (1ull << 32))
994 panic("upa64s: reg size must be less than 4 Gb");
995
996 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
997 "ranges", (caddr_t)&range_p, &ranges_len) != DDI_SUCCESS) {
998 ranges_len = 0;
999 cmn_err(CE_WARN, "%s%d: no ranges property",
1000 ddi_get_name(dip), ddi_get_instance(dip));
1001 }
1002
1003 n_ranges = ranges_len / sizeof (upa64s_regspec_t);
1004 child_beg = child_rp->upa64s_phys;
1005 #if 0
1006 /*
1007 * again, this safety checking can not be performed.
1008 * Hack by adding a pratical max child reg bank length.
1009 */
1010 child_end = child_beg + child_rp->upa64s_size;
1011 #else
1012 #define UPA64S_MAX_CHILD_LEN 0xe000000
1013 child_end = child_beg + UPA64S_MAX_CHILD_LEN;
1014 #endif
1015 for (i = 0, rng_p = range_p; i < n_ranges; i++, rng_p++) {
1016 uint64_t rng_beg = rng_p->upa64s_child;
1017 uint64_t rng_end = rng_beg + rng_p->upa64s_size;
1018 if ((rng_beg <= child_beg) && (rng_end >= child_end)) {
1019 uint64_t addr = child_beg - rng_beg + off;
1020 addr += rng_p->upa64s_parent;
1021 rp->regspec_bustype = HI32(addr);
1022 rp->regspec_addr = LO32(addr);
1023 rp->regspec_size = len ? len : child_rp->upa64s_size;
1024 break;
1025 }
1026 }
1027 if (ranges_len)
1028 kmem_free(range_p, ranges_len);
1029 DBG4(D_MAP, dip, "regspec (%x,%x,%x) i=%x\n",
1030 rp->regspec_bustype, rp->regspec_addr, rp->regspec_size, i);
1031 return (i < n_ranges? DDI_SUCCESS : DDI_ME_INVAL);
1032 }
1033
1034
1035 /*
1036 * report_dev
1037 *
1038 * This function is called from our control ops routine on a
1039 * DDI_CTLOPS_REPORTDEV request.
1040 */
1041 static int
report_dev(dev_info_t * dip)1042 report_dev(dev_info_t *dip)
1043 {
1044 if (dip == (dev_info_t *)0)
1045 return (DDI_FAILURE);
1046 cmn_err(CE_CONT, "?UPA64S-device: %s@%s, %s #%d\n",
1047 ddi_node_name(dip), ddi_get_name_addr(dip),
1048 ddi_get_name(dip), ddi_get_instance(dip));
1049 return (DDI_SUCCESS);
1050 }
1051
1052
1053 /*
1054 * init_child
1055 *
1056 * This function is called from our control ops routine on a
1057 * DDI_CTLOPS_INITCHILD request. It builds and sets the device's
1058 * parent private data area.
1059 *
1060 * used by: upa64s_ctlops()
1061 *
1062 * return value: none
1063 */
1064 static int
init_child(dev_info_t * child)1065 init_child(dev_info_t *child)
1066 {
1067 upa64s_regspec_t *child_rp;
1068 int i;
1069 char addr[256];
1070 int32_t portid;
1071
1072 if ((portid = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
1073 "upa-portid", -1)) == -1)
1074 return (DDI_FAILURE);
1075
1076 /*
1077 * Set the address portion of the node name based on
1078 * the function and device number.
1079 */
1080 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
1081 (caddr_t)&child_rp, &i) != DDI_SUCCESS) {
1082 return (DDI_FAILURE);
1083 }
1084
1085 (void) sprintf(addr, "%x,%x", portid, LO32(child_rp->upa64s_phys));
1086 ddi_set_name_addr(child, addr);
1087
1088 ddi_set_parent_data(child, NULL);
1089 kmem_free(child_rp, i);
1090 return (DDI_SUCCESS);
1091 }
1092
1093
1094 /*
1095 * get_reg_set_size
1096 *
1097 * Given a dev info pointer to a child and a register number, this
1098 * routine returns the size element of that reg set property.
1099 *
1100 * used by: upa64s_ctlops() - DDI_CTLOPS_REGSIZE
1101 *
1102 * return value: size of reg set on success, -1 on error
1103 */
1104 static off_t
get_reg_set_size(dev_info_t * child,int rnumber)1105 get_reg_set_size(dev_info_t *child, int rnumber)
1106 {
1107 upa64s_regspec_t *upa64s_rp;
1108 uint_t size;
1109 int i;
1110
1111 if (rnumber < 0)
1112 return (-1);
1113
1114 /*
1115 * Get the reg property for the device.
1116 */
1117 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
1118 (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
1119 return (-1);
1120
1121 if (rnumber >= (i / (int)sizeof (upa64s_regspec_t))) {
1122 kmem_free(upa64s_rp, i);
1123 return (-1);
1124 }
1125
1126 /* >4G reg size not supported */
1127 size = (uint32_t)upa64s_rp[rnumber].upa64s_size;
1128 kmem_free(upa64s_rp, i);
1129 return (size);
1130 }
1131
1132
1133 /*
1134 * get_nreg_set
1135 *
1136 * Given a dev info pointer to a child, this routine returns the
1137 * number of sets in its "reg" property.
1138 *
1139 * used by: upa64s_ctlops() - DDI_CTLOPS_NREGS
1140 *
1141 * return value: # of reg sets on success, zero on error
1142 */
1143 static uint_t
get_nreg_set(dev_info_t * child)1144 get_nreg_set(dev_info_t *child)
1145 {
1146 upa64s_regspec_t *upa64s_rp;
1147 int i, n;
1148
1149 /*
1150 * Get the reg property for the device.
1151 */
1152 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
1153 (caddr_t)&upa64s_rp, &i) != DDI_SUCCESS)
1154 return (0);
1155
1156 n = i / (int)sizeof (upa64s_regspec_t);
1157 kmem_free(upa64s_rp, i);
1158 return (n);
1159 }
1160
1161
1162 /*
1163 * upa64s_intrdist
1164 *
1165 * The following routine is the callback function for this nexus driver
1166 * to support interrupt distribution on sun4u systems. When this
1167 * function is called by the interrupt distribution framework, it will
1168 * reprogram all the active the mondo registers.
1169 */
1170 static void
upa64s_intrdist(void * arg)1171 upa64s_intrdist(void *arg)
1172 {
1173 dev_info_t *dip = (dev_info_t *)arg;
1174 int instance = ddi_get_instance(dip);
1175 upa64s_devstate_t *upa64s_p = get_upa64s_soft_state(instance);
1176 uint_t upaport;
1177
1178 for (upaport = 0; upaport < UPA64S_PORTS; upaport++) {
1179 volatile uint64_t *imr;
1180 volatile uint64_t imr_dat;
1181 uint_t mondo;
1182 uint32_t cpuid;
1183
1184 if (upa64s_p->ino_state[upaport] != INO_INUSE)
1185 continue;
1186
1187 imr = upa64s_p->imr[upaport];
1188 mondo = UPA64S_IMR_TO_MONDO(*imr);
1189 cpuid = intr_dist_cpuid();
1190 imr_dat = UPA64S_CPUID_TO_IMR(cpuid);
1191 imr_dat = UPA64S_GET_MAP_REG(mondo, imr_dat);
1192
1193 /* Check and re-program cpu target if necessary */
1194 DBG2(D_INTRDIST, dip, "mondo=%x cpuid=%x\n", mondo, cpuid);
1195 if (UPA64S_IMR_TO_CPUID(*imr) == cpuid) {
1196 DBG(D_INTRDIST, dip, "same cpuid\n");
1197 continue;
1198 }
1199 ddi_put64(upa64s_p->imr_ah[upaport], (uint64_t *)imr, imr_dat);
1200 imr_dat = ddi_get64(upa64s_p->imr_ah[upaport], (uint64_t *)imr);
1201 }
1202 }
1203
1204
1205 #ifdef DEBUG
1206 static void
upa64s_debug(uint_t flag,dev_info_t * dip,char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)1207 upa64s_debug(uint_t flag, dev_info_t *dip, char *fmt,
1208 uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
1209 {
1210 char *s = NULL;
1211 uint_t cont = 0;
1212 if (flag & D_CONT) {
1213 flag &= ~D_CONT;
1214 cont = 1;
1215 }
1216 if (!(upa64s_debug_flags & flag))
1217 return;
1218
1219 switch (flag) {
1220 case D_ATTACH: s = "attach"; break;
1221 case D_DETACH: s = "detach"; break;
1222 case D_POWER: s = "power"; break;
1223 case D_MAP: s = "map"; break;
1224 case D_CTLOPS: s = "ctlops"; break;
1225 case D_G_ISPEC: s = "get_intrspec"; break;
1226 case D_A_ISPEC: s = "add_intrspec"; break;
1227 case D_R_ISPEC: s = "remove_intrspec"; break;
1228 case D_INIT_CLD: s = "init_child"; break;
1229 case D_INTRDIST: s = "intrdist"; break;
1230 }
1231
1232 if (s && cont == 0) {
1233 prom_printf("%s(%d): %s: ", ddi_get_name(dip),
1234 ddi_get_instance(dip), s);
1235 }
1236 prom_printf(fmt, a1, a2, a3, a4, a5);
1237 }
1238 #endif
1239