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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Daktari platform specific hotplug controller. This
28 * driver exports the same interfaces to user space
29 * as the generic hpc3130 driver. It adds specific
30 * functionality found on Daktari, such as slot button
31 * and platform specific LED displays. Placed in
32 * the daktari specific platform directory, it will
33 * be loaded instead of the generic module.
37 #include <sys/types.h>
38 #include <sys/cmn_err.h>
40 #include <sys/errno.h>
41 #include <sys/cpuvar.h>
46 #include <sys/sunddi.h>
47 #include <sys/modctl.h>
49 #include <sys/hotplug/hpctrl.h>
50 #include <sys/hotplug/hpcsvc.h>
51 #include <sys/i2c/clients/hpc3130.h>
52 #include <sys/hpc3130_events.h>
53 #include <sys/daktari.h>
54 #include <sys/hpc3130_dak.h>
57 static int hpc3130debug
= 0;
59 #define D1CMN_ERR(ARGS) if (hpc3130debug & 0x1) cmn_err ARGS;
60 #define D2CMN_ERR(ARGS) if (hpc3130debug & 0x2) cmn_err ARGS;
64 #define D1CMN_ERR(ARGS)
65 #define D2CMN_ERR(ARGS)
69 #define HPC3130_REG(offset, slot) ((offset) + ((slot)*8))
76 struct connect_command
{
81 struct tuple pci_sequence
[] =
83 {HPC3130_GCR
, HPC3130_AUTO2_SEQ
},
84 {HPC3130_INTERRUPT
, HPC3130_PWRGOOD
|
85 HPC3130_DETECT0
| HPC3130_PRSNT1
| HPC3130_PRSNT2
},
86 {HPC3130_EVENT_STATUS
, 0xff},
87 {HPC3130_NO_REGISTER
, 0},
90 struct tuple cpu_sequence
[] =
93 HPC3130_PRSNT1
| HPC3130_DETECT0
},
94 {HPC3130_EVENT_STATUS
, 0xff},
95 {HPC3130_NO_REGISTER
, 0},
98 struct connect_command connect_sequence
[] =
100 {B_TRUE
, HPC3130_SLOTREQ64
},
101 {B_FALSE
, HPC3130_SLOTRST
},
102 {B_FALSE
, HPC3130_CLKON
},
103 {B_FALSE
, HPC3130_REQ64
},
104 {B_FALSE
, HPC3130_SLOTREQ64
},
105 {B_TRUE
, HPC3130_SLOTRST
},
106 {B_FALSE
, HPC3130_BUS_CTL
},
109 #define HPC3130_CONNECT_SEQ_COUNT (sizeof (connect_sequence)/ \
110 sizeof (struct connect_command))
117 * The order here is significant. Its the order
118 * of appearance of slots from bottom to top
121 static struct xlate_entry slot_translate
[] =
123 {"/pci@8,700000", 5}, /* PCI0 */
124 {"/pci@8,700000", 4}, /* PCI1 */
125 {"/pci@8,700000", 3}, /* PCI2 */
126 {"/pci@8,700000", 2}, /* PCI3 */
128 {"/pci@9,700000", 4}, /* PCI4 */
129 {"/pci@9,700000", 3}, /* PCI5 */
130 {"/pci@9,700000", 2}, /* PCI6 */
132 {"/pci@9,600000", 2}, /* PCI7 */
133 {"/pci@9,600000", 1} /* PCI8 */
136 #define HPC3130_LOOKUP_SLOTS (sizeof (slot_translate)/ \
137 sizeof (struct xlate_entry))
139 static int control_slot_control
= HPC3130_SLOT_CONTROL_ENABLE
;
141 hpc3130_unit_t
*hpc3130soft_statep
;
143 static int hpc3130_atoi(const char *);
144 int hpc3130_lookup_slot(char *, int);
146 static int hpc3130_init(dev_info_t
*, struct tuple
*);
147 static uint_t
hpc3130_hard_intr(caddr_t
);
149 static int hpc3130_cpu_init(hpc3130_unit_t
*, int, i2c_client_hdl_t
);
150 static int hpc3130_debounce_status(i2c_client_hdl_t
, int, uint8_t *);
151 static int hpc3130_read(i2c_client_hdl_t
, uint8_t, uint8_t, uint8_t *);
152 static int hpc3130_write(i2c_client_hdl_t
, uint8_t, uint8_t, uint8_t);
153 static int hpc3130_rw(i2c_client_hdl_t
, uint8_t, boolean_t
, uint8_t *);
155 static int hpc3130_do_attach(dev_info_t
*);
156 static int hpc3130_do_detach(dev_info_t
*);
157 static int hpc3130_do_resume(void);
158 static int hpc3130_do_suspend();
159 static int hpc3130_get(intptr_t, int, hpc3130_unit_t
*, int);
160 static int hpc3130_set(intptr_t, int, hpc3130_unit_t
*, int);
162 static int hpc3130_slot_connect(caddr_t
, hpc_slot_t
, void *, uint_t
);
163 static int hpc3130_slot_disconnect(caddr_t
, hpc_slot_t
, void *, uint_t
);
164 static int hpc3130_verify_slot_power(hpc3130_unit_t
*, i2c_client_hdl_t
,
165 uint8_t, char *, boolean_t
);
166 static int hpc3130_slot_insert(caddr_t
, hpc_slot_t
, void *, uint_t
);
167 static int hpc3130_slot_remove(caddr_t
, hpc_slot_t
, void *, uint_t
);
168 static int hpc3130_slot_control(caddr_t
, hpc_slot_t
, int, caddr_t
);
172 static int hpc3130_open(dev_t
*, int, int, cred_t
*);
173 static int hpc3130_close(dev_t
, int, int, cred_t
*);
174 static int hpc3130_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
175 static int hpc3130_poll(dev_t dev
, short events
, int anyyet
, short
176 *reventsp
, struct pollhead
**phpp
);
178 static struct cb_ops hpc3130_cbops
= {
179 hpc3130_open
, /* open */
180 hpc3130_close
, /* close */
181 nodev
, /* strategy */
186 hpc3130_ioctl
, /* ioctl */
190 hpc3130_poll
, /* poll */
191 ddi_prop_op
, /* cb_prop_op */
192 NULL
, /* streamtab */
193 D_NEW
| D_MP
| D_HOTPLUG
, /* Driver compatibility flag */
195 nodev
, /* int (*cb_aread)() */
196 nodev
/* int (*cb_awrite)() */
202 static int hpc3130_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
204 static int hpc3130_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
);
205 static int hpc3130_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
);
207 static struct dev_ops hpc3130_ops
= {
219 ddi_quiesce_not_needed
, /* quiesce */
222 extern struct mod_ops mod_driverops
;
224 static struct modldrv hpc3130_modldrv
= {
225 &mod_driverops
, /* type of module - driver */
226 "Hotplug controller driver",
230 static struct modlinkage hpc3130_modlinkage
= {
241 error
= mod_install(&hpc3130_modlinkage
);
244 (void) ddi_soft_state_init((void *)&hpc3130soft_statep
,
245 sizeof (hpc3130_unit_t
), 4);
254 error
= mod_remove(&hpc3130_modlinkage
);
256 ddi_soft_state_fini((void *)&hpc3130soft_statep
);
262 _info(struct modinfo
*modinfop
)
264 return (mod_info(&hpc3130_modlinkage
, modinfop
));
268 hpc3130_open(dev_t
*devp
, int flags
, int otyp
, cred_t
*credp
)
270 _NOTE(ARGUNUSED(credp
))
271 hpc3130_unit_t
*unitp
;
275 if (otyp
!= OTYP_CHR
) {
279 instance
= MINOR_TO_INST(getminor(*devp
));
281 unitp
= (hpc3130_unit_t
*)
282 ddi_get_soft_state(hpc3130soft_statep
, instance
);
288 mutex_enter(&unitp
->hpc3130_mutex
);
291 if (unitp
->hpc3130_oflag
!= 0) {
294 unitp
->hpc3130_oflag
= FEXCL
;
297 if (unitp
->hpc3130_oflag
== FEXCL
) {
300 unitp
->hpc3130_oflag
= FOPEN
;
304 mutex_exit(&unitp
->hpc3130_mutex
);
310 hpc3130_close(dev_t dev
, int flags
, int otyp
, cred_t
*credp
)
312 _NOTE(ARGUNUSED(flags
, otyp
, credp
))
313 hpc3130_unit_t
*unitp
;
316 instance
= MINOR_TO_INST(getminor(dev
));
318 unitp
= (hpc3130_unit_t
*)
319 ddi_get_soft_state(hpc3130soft_statep
, instance
);
325 mutex_enter(&unitp
->hpc3130_mutex
);
327 unitp
->hpc3130_oflag
= 0;
329 mutex_exit(&unitp
->hpc3130_mutex
);
330 return (DDI_SUCCESS
);
334 hpc3130_get(intptr_t arg
, int reg
, hpc3130_unit_t
*unitp
, int mode
)
336 i2c_transfer_t
*i2c_tran_pointer
;
337 int err
= DDI_SUCCESS
;
340 D2CMN_ERR((CE_WARN
, "ioctl: arg passed in to "
344 (void) i2c_transfer_alloc(unitp
->hpc3130_hdl
, &i2c_tran_pointer
,
346 if (i2c_tran_pointer
== NULL
) {
347 D2CMN_ERR((CE_WARN
, "Failed in HPC3130_GET_STATUS"
348 " i2c_tran_pointer not allocated"));
352 i2c_tran_pointer
->i2c_flags
= I2C_WR_RD
;
353 i2c_tran_pointer
->i2c_wbuf
[0] = (uchar_t
)reg
;
355 err
= i2c_transfer(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
357 D2CMN_ERR((CE_WARN
, "Failed in HPC3130_GET_STATUS"
358 " i2c_trasfer routine"));
359 i2c_transfer_free(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
362 D1CMN_ERR((CE_NOTE
, "The i2c_rbuf contains %x",
363 i2c_tran_pointer
->i2c_rbuf
[0]));
365 if (ddi_copyout((caddr_t
)i2c_tran_pointer
->i2c_rbuf
,
367 sizeof (uint8_t), mode
) != DDI_SUCCESS
) {
368 D2CMN_ERR((CE_WARN
, "Failed in HPC3130_GET_STATUS"
369 " ddi_copyout routine"));
372 i2c_transfer_free(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
377 hpc3130_set(intptr_t arg
, int reg
, hpc3130_unit_t
*unitp
, int mode
)
379 i2c_transfer_t
*i2c_tran_pointer
;
380 int err
= DDI_SUCCESS
;
384 D2CMN_ERR((CE_WARN
, "ioctl: arg passed in to "
388 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&passin_byte
,
389 sizeof (uint8_t), mode
) != DDI_SUCCESS
) {
390 D2CMN_ERR((CE_WARN
, "Failed in HPC3130_SET_CONTROL "
391 "ddi_copyin routine"));
395 (void) i2c_transfer_alloc(unitp
->hpc3130_hdl
, &i2c_tran_pointer
,
397 if (i2c_tran_pointer
== NULL
) {
398 D2CMN_ERR((CE_WARN
, "Failed in "
399 "HPC3130_SET_CONTROL i2c_tran_pointer not allocated"));
404 i2c_tran_pointer
->i2c_flags
= I2C_WR
;
405 i2c_tran_pointer
->i2c_wbuf
[0] = (uchar_t
)reg
;
406 i2c_tran_pointer
->i2c_wbuf
[1] = passin_byte
;
408 err
= i2c_transfer(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
409 i2c_transfer_free(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
415 hpc3130_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
418 _NOTE(ARGUNUSED(credp
, rvalp
))
419 hpc3130_unit_t
*unitp
;
420 int err
= DDI_SUCCESS
;
421 i2c_transfer_t
*i2c_tran_pointer
;
423 int port
= MINOR_TO_PORT(getminor(dev
));
424 int instance
= MINOR_TO_INST(getminor(dev
));
425 hpc3130_slot_table_entry_t
*ste
;
427 unitp
= (hpc3130_unit_t
*)
428 ddi_get_soft_state(hpc3130soft_statep
, instance
);
431 D1CMN_ERR((CE_WARN
, "unitp not filled"));
436 * It should be the case that the port number is a valid
437 * index in the per instance slot table. If it is not
438 * then we should fail out.
440 if (!(port
>= 0 && port
< unitp
->hpc3130_slot_table_length
)) {
444 mutex_enter(&unitp
->hpc3130_mutex
);
446 ste
= &unitp
->hpc3130_slot_table
[port
];
448 D2CMN_ERR((CE_NOTE
, "ioctl: port = %d instance = %d",
452 case HPC3130_GET_STATUS
:
453 err
= hpc3130_get(arg
, HPC3130_HP_STATUS_REG(port
), unitp
,
457 case HPC3130_GET_CONTROL
:
458 err
= hpc3130_get(arg
, HPC3130_HP_CONTROL_REG(port
), unitp
,
462 case HPC3130_SET_CONTROL
:
463 if (control_slot_control
== HPC3130_SLOT_CONTROL_DISABLE
) {
464 cmn_err(CE_WARN
, "Cannot change control register.");
468 err
= hpc3130_set(arg
, HPC3130_HP_CONTROL_REG(port
), unitp
,
472 case HPC3130_GET_EVENT_STATUS
:
473 err
= hpc3130_get(arg
, HPC3130_INTERRUPT_STATUS_REG(port
),
477 case HPC3130_SET_EVENT_STATUS
:
478 err
= hpc3130_set(arg
, HPC3130_INTERRUPT_STATUS_REG(port
),
482 case HPC3130_GET_GENERAL_CONFIG
:
483 err
= hpc3130_get(arg
, HPC3130_GENERAL_CONFIG_REG(port
),
487 case HPC3130_SET_GENERAL_CONFIG
:
488 err
= hpc3130_set(arg
, HPC3130_GENERAL_CONFIG_REG(port
),
492 case HPC3130_GET_INDICATOR_CONTROL
:
493 err
= hpc3130_get(arg
, HPC3130_ATTENTION_INDICATOR(port
),
497 case HPC3130_SET_INDICATOR_CONTROL
:
498 err
= hpc3130_set(arg
, HPC3130_ATTENTION_INDICATOR(port
),
502 case HPC3130_GET_EVENT_ENABLE
:
503 err
= hpc3130_get(arg
, HPC3130_INTERRUPT_ENABLE_REG(port
),
507 case HPC3130_SET_EVENT_ENABLE
:
508 err
= hpc3130_set(arg
, HPC3130_INTERRUPT_ENABLE_REG(port
),
512 case HPC3130_ENABLE_SLOT_CONTROL
:
513 control_slot_control
= HPC3130_SLOT_CONTROL_ENABLE
;
514 D2CMN_ERR((CE_NOTE
, "Set the control_slot_control variable to"
515 "HPC3130_SLOT_CONTROL_ENABLE"));
518 case HPC3130_DISABLE_SLOT_CONTROL
:
519 control_slot_control
= HPC3130_SLOT_CONTROL_DISABLE
;
520 D2CMN_ERR((CE_NOTE
, "Set the control_slot_control variable to"
521 "HPC3130_SLOT_CONTROL_DISABLE"));
526 D2CMN_ERR((CE_WARN
, "ioctl: arg passed in to "
531 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&ioctl_reg
,
532 sizeof (i2c_reg_t
), mode
) != DDI_SUCCESS
) {
533 D2CMN_ERR((CE_WARN
, "Failed in I2C_GET_REG "
534 "ddi_copyin routine"));
538 (void) i2c_transfer_alloc(unitp
->hpc3130_hdl
, &i2c_tran_pointer
,
540 if (i2c_tran_pointer
== NULL
) {
541 D2CMN_ERR((CE_WARN
, "Failed in I2C_GET_REG "
542 "i2c_tran_pointer not allocated"));
547 i2c_tran_pointer
->i2c_flags
= I2C_WR_RD
;
548 i2c_tran_pointer
->i2c_wbuf
[0] = ioctl_reg
.reg_num
;
550 err
= i2c_transfer(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
552 D2CMN_ERR((CE_WARN
, "Failed in I2C_GET_REG "
553 "i2c_transfer routine"));
554 i2c_transfer_free(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
557 ioctl_reg
.reg_value
= i2c_tran_pointer
->i2c_rbuf
[0];
558 if (ddi_copyout((caddr_t
)&ioctl_reg
, (caddr_t
)arg
,
559 sizeof (i2c_reg_t
), mode
) != DDI_SUCCESS
) {
560 D2CMN_ERR((CE_WARN
, "Failed in I2C_GET_REG "
561 "ddi_copyout routine"));
565 i2c_transfer_free(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
570 D2CMN_ERR((CE_WARN
, "ioctl: arg passed in to "
575 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&ioctl_reg
,
576 sizeof (i2c_reg_t
), mode
) != DDI_SUCCESS
) {
577 D2CMN_ERR((CE_WARN
, "Failed in I2C_SET_REG "
578 "ddi_copyin routine"));
582 (void) i2c_transfer_alloc(unitp
->hpc3130_hdl
, &i2c_tran_pointer
,
584 if (i2c_tran_pointer
== NULL
) {
585 D2CMN_ERR((CE_WARN
, "Failed in I2C_GET_REG "
586 "i2c_tran_pointer not allocated"));
591 i2c_tran_pointer
->i2c_flags
= I2C_WR
;
592 i2c_tran_pointer
->i2c_wbuf
[0] = ioctl_reg
.reg_num
;
593 i2c_tran_pointer
->i2c_wbuf
[1] = (uchar_t
)ioctl_reg
.reg_value
;
595 err
= i2c_transfer(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
597 D2CMN_ERR((CE_WARN
, "Failed in I2C_SET_REG "
598 "i2c_transfer routine"));
599 i2c_transfer_free(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
603 i2c_transfer_free(unitp
->hpc3130_hdl
, i2c_tran_pointer
);
606 case HPC3130_GET_EVENT
: {
607 struct hpc3130_event ev
;
609 bzero(&ev
, sizeof (struct hpc3130_event
));
611 if (unitp
->slots_are
== HPC3130_SLOT_TYPE_SBD
) {
612 DAK_GET_SBD_APID(ev
.name
, sizeof (ev
.name
), port
);
614 (void) snprintf(ev
.name
, HPC3130_NAME_MAX
,
615 "/devices%s:", ste
->nexus
);
616 ASSERT(strlen(ev
.name
) < HPC3130_NAME_MAX
- 1);
617 DAK_GET_PCI_APID(ev
.name
+ strlen(ev
.name
),
618 HPC3130_NAME_MAX
- strlen(ev
.name
),
619 hpc3130_lookup_slot(ste
->nexus
,
620 ste
->hpc3130_slot_info
.pci_dev_num
));
623 if (unitp
->events
[port
] & HPC3130_IEVENT_OCCUPANCY
) {
624 unitp
->events
[port
] &= ~HPC3130_IEVENT_OCCUPANCY
;
625 ev
.id
= (unitp
->present
[port
] == B_FALSE
?
626 HPC3130_EVENT_REMOVAL
:
627 HPC3130_EVENT_INSERTION
);
628 } else if (unitp
->events
[port
] & HPC3130_IEVENT_POWER
) {
629 unitp
->events
[port
] &= ~HPC3130_IEVENT_POWER
;
630 ev
.id
= (unitp
->power
[port
] == B_TRUE
?
631 HPC3130_EVENT_POWERON
:
632 HPC3130_EVENT_POWEROFF
);
633 } else if (unitp
->events
[port
] & HPC3130_IEVENT_BUTTON
) {
634 unitp
->events
[port
] &= ~HPC3130_IEVENT_BUTTON
;
635 ev
.id
= HPC3130_EVENT_BUTTON
;
636 } else if (unitp
->events
[port
] & HPC3130_IEVENT_FAULT
) {
637 unitp
->events
[port
] &= ~HPC3130_IEVENT_FAULT
;
638 ev
.id
= (unitp
->fault_led
[port
] == HPC3130_ATTN_ON
?
639 HPC3130_LED_FAULT_ON
:
640 HPC3130_LED_FAULT_OFF
);
641 } else if (unitp
->events
[port
] & HPC3130_IEVENT_OK2REM
) {
642 unitp
->events
[port
] &= ~HPC3130_IEVENT_OK2REM
;
643 ev
.id
= (unitp
->ok2rem_led
[port
] == HPC3130_ATTN_ON
?
644 HPC3130_LED_REMOVABLE_ON
:
645 HPC3130_LED_REMOVABLE_OFF
);
649 "sending EVENT: ap_id=%s, event=%d", ev
.name
, ev
.id
));
651 if (ddi_copyout((caddr_t
)&ev
, (caddr_t
)arg
,
652 sizeof (struct hpc3130_event
), mode
) != DDI_SUCCESS
) {
653 D1CMN_ERR((CE_WARN
, "Failed in hpc3130_ioctl"
654 " ddi_copyout routine"));
659 case HPC3130_CONF_DR
: {
663 if (ddi_copyin((caddr_t
)arg
, (caddr_t
)&dr_conf
,
664 sizeof (int), mode
) != DDI_SUCCESS
) {
665 D2CMN_ERR((CE_WARN
, "Failed in HPC3130_CONF_DR "
666 "ddi_copyin routine"))
671 offset
= ste
->callback_info
.offset
;
673 unitp
->enabled
[offset
] =
674 (dr_conf
== HPC3130_DR_DISABLE
? B_FALSE
: B_TRUE
);
679 D2CMN_ERR((CE_WARN
, "Invalid IOCTL cmd: %x", cmd
));
683 mutex_exit(&unitp
->hpc3130_mutex
);
688 hpc3130_poll(dev_t dev
, short events
, int anyyet
, short
689 *reventsp
, struct pollhead
**phpp
)
691 _NOTE(ARGUNUSED(events
))
692 hpc3130_unit_t
*unitp
;
693 int port
= MINOR_TO_PORT(getminor(dev
));
694 int instance
= MINOR_TO_INST(getminor(dev
));
696 if (!(port
>= 0 && port
< HPC3130_MAX_SLOT
)) {
699 unitp
= (hpc3130_unit_t
*)
700 ddi_get_soft_state(hpc3130soft_statep
, instance
);
702 mutex_enter(&unitp
->hpc3130_mutex
);
703 if (unitp
->events
[port
]) {
708 *phpp
= &unitp
->pollhead
[port
];
710 mutex_exit(&unitp
->hpc3130_mutex
);
716 hpc3130_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
721 if (infocmd
== DDI_INFO_DEVT2INSTANCE
) {
723 instance
= MINOR_TO_INST(getminor(dev
));
724 *result
= (void *)(uintptr_t)instance
;
725 return (DDI_SUCCESS
);
727 return (DDI_FAILURE
);
731 hpc3130_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
735 return (hpc3130_do_attach(dip
));
737 return (hpc3130_do_resume());
739 return (DDI_FAILURE
);
744 hpc3130_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
748 return (hpc3130_do_detach(dip
));
750 return (hpc3130_do_suspend());
752 return (DDI_FAILURE
);
757 hpc3130_do_attach(dev_info_t
*dip
)
759 hpc3130_unit_t
*hpc3130_p
;
765 char name
[MAXNAMELEN
];
766 minor_t minor_number
;
767 int hpc3130_pil
= HPC3130_PIL
;
768 int instance
= ddi_get_instance(dip
);
771 * Allocate the soft state structure for this instance.
773 r
= ddi_soft_state_zalloc(hpc3130soft_statep
, instance
);
774 if (r
!= DDI_SUCCESS
) {
775 return (DDI_FAILURE
);
779 (hpc3130_unit_t
*)ddi_get_soft_state(hpc3130soft_statep
, instance
);
782 if (ddi_prop_create(DDI_DEV_T_NONE
, dip
, DDI_PROP_CANSLEEP
,
783 "interrupt-priorities", (caddr_t
)&hpc3130_pil
,
784 sizeof (hpc3130_pil
)) != DDI_PROP_SUCCESS
) {
788 if (ddi_intr_hilevel(dip
, 0)) {
789 cmn_err(CE_WARN
, "High level interrupt not supported");
794 * Get the "slot-table" property which defines the list of
795 * hot-pluggable slots for this controller along with the
796 * corresponding bus nexus node and device identification
799 r
= ddi_getlongprop(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
800 "slot-table", (caddr_t
)&hpc3130_p
->hpc3130_slot_table_data
,
801 &hpc3130_p
->hpc3130_slot_table_size
);
804 case DDI_PROP_SUCCESS
:
806 case DDI_PROP_NOT_FOUND
:
808 "couldn't find slot-table property");
809 return (DDI_FAILURE
);
810 case DDI_PROP_UNDEFINED
:
812 "slot-table undefined");
813 return (DDI_FAILURE
);
814 case DDI_PROP_NO_MEMORY
:
816 "can't allocate memory for slot-table");
817 return (DDI_FAILURE
);
821 * Determine the size of the slot table from the OBP property and
822 * allocate the slot table arrary..
824 for (i
= 0, n
= 0; i
< hpc3130_p
->hpc3130_slot_table_size
; i
++) {
825 if (hpc3130_p
->hpc3130_slot_table_data
[i
] == 0) {
830 D1CMN_ERR((CE_NOTE
, "hpc3130_attach(): slot table has %d entries", n
));
833 * There should be HPC3130_TABLE_COLUMNS elements per entry
835 if (n
% HPC3130_TABLE_COLUMNS
) {
836 cmn_err(CE_WARN
, "bad format in slot-table");
840 hpc3130_p
->dip
= dip
;
841 hpc3130_p
->hpc3130_slot_table_length
= n
/ HPC3130_TABLE_COLUMNS
;
843 if (ddi_get_iblock_cookie(dip
, 0, &hpc3130_p
->ic_trap_cookie
) !=
845 cmn_err(CE_WARN
, "ddi_get_iblock_cookie FAILED");
849 mutex_init(&hpc3130_p
->hpc3130_mutex
, NULL
, MUTEX_DRIVER
,
850 (void *)hpc3130_p
->ic_trap_cookie
);
852 * Create enough space for each slot table entry
853 * based on how many entries in the property
855 hpc3130_p
->hpc3130_slot_table
= (hpc3130_slot_table_entry_t
*)
856 kmem_zalloc(hpc3130_p
->hpc3130_slot_table_length
*
857 sizeof (hpc3130_slot_table_entry_t
), KM_SLEEP
);
860 * Setup to talk to the i2c nexus
862 if (i2c_client_register(dip
, &hpc3130_p
->hpc3130_hdl
) != I2C_SUCCESS
) {
863 cmn_err(CE_WARN
, "failed to register as i2c client");
867 s
= hpc3130_p
->hpc3130_slot_table_data
;
868 for (i
= 0; i
< hpc3130_p
->hpc3130_slot_table_length
; i
++) {
869 hpc3130_slot_table_entry_t
*ste
;
871 /* Pick off pointer to nexus path */
873 s
= s
+ strlen(s
) + 1;
875 /* Pick off pointer to 3130 register offset */
877 s
= s
+ strlen(s
) + 1;
879 /* Pick off pointer to the device number */
882 s
= s
+ strlen(s
) + 1;
884 j
= hpc3130_atoi(reg_offset
);
886 if (j
< 0 || j
>= HPC3130_MAX_SLOT
) {
888 "invalid register offset value");
892 ste
= &hpc3130_p
->hpc3130_slot_table
[j
];
894 (void) strcpy(ste
->nexus
, nexus
);
896 if (strncmp(ste
->nexus
, "/pci", 4) == 0) {
898 ste
->hpc3130_slot_info
.pci_dev_num
=
899 hpc3130_atoi(pcidev
);
901 DAK_GET_PCI_APID(ste
->hpc3130_slot_info
.pci_slot_name
,
903 hpc3130_lookup_slot(ste
->nexus
,
904 hpc3130_atoi(pcidev
)));
906 ste
->hpc3130_slot_info
.slot_type
= HPC_SLOT_TYPE_PCI
;
907 ste
->hpc3130_slot_info
.slot_flags
=
908 HPC_SLOT_CREATE_DEVLINK
;
909 hpc3130_p
->slots_are
= HPC3130_SLOT_TYPE_PCI
;
913 ste
->hpc3130_slot_info
.sbd_slot_num
=
914 hpc3130_atoi(reg_offset
);
916 ste
->hpc3130_slot_info
.slot_type
= HPC_SLOT_TYPE_SBD
;
918 hpc3130_p
->slots_are
= HPC3130_SLOT_TYPE_SBD
;
921 hpc3130_p
->present
[j
] = B_FALSE
;
922 hpc3130_p
->enabled
[j
] = B_TRUE
;
925 * The "callback_info" structure of the slot_table is what gets
926 * passed back in the callback routines. All that is needed
927 * at that point is the device handle and the register offset
928 * within it the chip it represents.
930 ste
->callback_info
.handle
= (caddr_t
)hpc3130_p
->hpc3130_hdl
;
932 ste
->callback_info
.offset
= hpc3130_atoi(reg_offset
);
934 ste
->callback_info
.statep
= (caddr_t
)hpc3130_p
;
937 hpc3130_p
->hpc3130_slot_ops
= hpc_alloc_slot_ops(KM_SLEEP
);
938 hpc3130_p
->hpc3130_slot_ops
->hpc_version
= 0;
940 hpc3130_p
->hpc3130_slot_ops
->hpc_op_connect
= hpc3130_slot_connect
;
941 hpc3130_p
->hpc3130_slot_ops
->hpc_op_disconnect
=
942 hpc3130_slot_disconnect
;
943 hpc3130_p
->hpc3130_slot_ops
->hpc_op_insert
= hpc3130_slot_insert
;
944 hpc3130_p
->hpc3130_slot_ops
->hpc_op_remove
= hpc3130_slot_remove
;
945 hpc3130_p
->hpc3130_slot_ops
->hpc_op_control
= hpc3130_slot_control
;
947 cv_init(&hpc3130_p
->hpc3130_cond
, NULL
, CV_DEFAULT
, NULL
);
949 if (hpc3130_init(dip
, (hpc3130_p
->slots_are
== HPC3130_SLOT_TYPE_SBD
) ?
950 cpu_sequence
: pci_sequence
) != DDI_SUCCESS
) {
954 if (ddi_add_intr(dip
, 0, &hpc3130_p
->ic_trap_cookie
,
955 NULL
, hpc3130_hard_intr
,
956 (caddr_t
)hpc3130_p
) != DDI_SUCCESS
) {
957 cmn_err(CE_WARN
, "failed to add interrupt");
962 * Register with the "services" module
964 for (i
= 0; i
< hpc3130_p
->hpc3130_slot_table_length
; i
++) {
965 hpc3130_slot_table_entry_t
*ste
=
966 &hpc3130_p
->hpc3130_slot_table
[i
];
967 hpc3130_p
->power
[i
] = B_TRUE
;
968 if (ste
->callback_info
.handle
!= NULL
) {
969 (void) hpc_slot_register(dip
, ste
->nexus
,
970 &ste
->hpc3130_slot_info
,
971 &ste
->hpc3130_slot_handle
,
972 hpc3130_p
->hpc3130_slot_ops
,
973 (caddr_t
)&ste
->callback_info
, 0);
977 (void) snprintf(hpc3130_p
->hpc3130_name
,
978 sizeof (hpc3130_p
->hpc3130_name
),
979 "%s%d", ddi_node_name(dip
), instance
);
981 for (i
= 0; i
< HPC3130_MAX_SLOT
; i
++) {
982 (void) snprintf(name
, MAXNAMELEN
, "port_%d", i
);
983 minor_number
= INST_TO_MINOR(instance
) |
984 PORT_TO_MINOR(I2C_PORT(i
));
985 if (ddi_create_minor_node(dip
, name
, S_IFCHR
, minor_number
,
986 "ddi_i2c:controller", NULL
) == DDI_FAILURE
) {
987 D1CMN_ERR((CE_WARN
, "ddi_create_minor_node failed "
989 ddi_remove_intr(dip
, 0u,
990 hpc3130_p
->ic_trap_cookie
);
995 return (DDI_SUCCESS
);
998 hpc_free_slot_ops(hpc3130_p
->hpc3130_slot_ops
);
1000 i2c_client_unregister(hpc3130_p
->hpc3130_hdl
);
1002 mutex_destroy(&hpc3130_p
->hpc3130_mutex
);
1003 kmem_free(hpc3130_p
->hpc3130_slot_table
,
1004 hpc3130_p
->hpc3130_slot_table_length
*
1005 sizeof (hpc3130_slot_table_entry_t
));
1007 kmem_free(hpc3130_p
->hpc3130_slot_table_data
,
1008 hpc3130_p
->hpc3130_slot_table_size
);
1010 ddi_soft_state_free(hpc3130soft_statep
, instance
);
1012 return (DDI_FAILURE
);
1018 return (DDI_SUCCESS
);
1022 hpc3130_do_suspend()
1024 return (DDI_SUCCESS
);
1028 hpc3130_do_detach(dev_info_t
*dip
)
1031 int instance
= ddi_get_instance(dip
);
1032 hpc3130_unit_t
*hpc3130_p
;
1034 hpc3130_p
= (hpc3130_unit_t
*)ddi_get_soft_state(hpc3130soft_statep
,
1036 if (hpc3130_p
== NULL
)
1039 i2c_client_unregister(hpc3130_p
->hpc3130_hdl
);
1041 ddi_remove_intr(dip
, 0u, hpc3130_p
->ic_trap_cookie
);
1043 cv_destroy(&hpc3130_p
->hpc3130_cond
);
1045 for (i
= 0; i
< hpc3130_p
->hpc3130_slot_table_length
; i
++) {
1046 (void) hpc_slot_unregister(
1047 &hpc3130_p
->hpc3130_slot_table
[i
].hpc3130_slot_handle
);
1050 kmem_free(hpc3130_p
->hpc3130_slot_table
,
1051 hpc3130_p
->hpc3130_slot_table_length
*
1052 sizeof (hpc3130_slot_table_entry_t
));
1054 kmem_free(hpc3130_p
->hpc3130_slot_table_data
,
1055 hpc3130_p
->hpc3130_slot_table_size
);
1057 hpc_free_slot_ops(hpc3130_p
->hpc3130_slot_ops
);
1059 mutex_destroy(&hpc3130_p
->hpc3130_mutex
);
1061 ddi_soft_state_free(hpc3130soft_statep
, instance
);
1063 return (DDI_SUCCESS
);
1067 hpc3130_set_led(hpc3130_unit_t
*unitp
, int slot
, int led
, uint8_t value
)
1069 i2c_client_hdl_t handle
= unitp
->hpc3130_hdl
;
1073 if (hpc3130_read(handle
, HPC3130_ATTEN
, slot
, &old
) != DDI_SUCCESS
) {
1074 return (DDI_FAILURE
);
1076 new = (old
& ~HPC3130_ATTN_MASK(led
)) |
1077 value
<< HPC3130_ATTN_SHIFT(led
);
1079 D1CMN_ERR((CE_NOTE
, "setting led %d to %x", led
, value
));
1081 if (hpc3130_write(handle
, HPC3130_ATTEN
, slot
, new) != DDI_SUCCESS
) {
1082 return (DDI_FAILURE
);
1085 if ((value
== HPC3130_ATTN_OFF
|| value
== HPC3130_ATTN_ON
) &&
1086 ((old
& HPC3130_ATTN_MASK(led
)) !=
1087 (new & HPC3130_ATTN_MASK(led
)))) {
1089 * We're turning a LED on or off (i.e., not blinking), and
1090 * the value actually did change.
1092 if (led
== HPC3130_LED_OK2REM
) {
1093 unitp
->events
[slot
] |= HPC3130_IEVENT_OK2REM
;
1094 unitp
->ok2rem_led
[slot
] = value
;
1096 "recording IEVENT_OK2REM slot=%d, val=%d",
1099 unitp
->events
[slot
] |= HPC3130_IEVENT_FAULT
;
1100 unitp
->fault_led
[slot
] = value
;
1102 "recording IEVENT_FAULT slot=%d, val=%d",
1105 ASSERT(MUTEX_HELD(&unitp
->hpc3130_mutex
));
1106 mutex_exit(&unitp
->hpc3130_mutex
);
1107 pollwakeup(&unitp
->pollhead
[slot
], POLLIN
);
1108 mutex_enter(&unitp
->hpc3130_mutex
);
1110 return (DDI_SUCCESS
);
1114 hpc3130_get_led(i2c_client_hdl_t handle
, int slot
,
1115 int led
, uint8_t *value
)
1119 if (hpc3130_read(handle
, HPC3130_ATTEN
, slot
, &temp
) != DDI_SUCCESS
) {
1120 return (DDI_FAILURE
);
1123 *value
= (temp
& HPC3130_ATTN_MASK(led
)) >> HPC3130_ATTN_SHIFT(led
);
1124 return (DDI_SUCCESS
);
1128 hpc3130_write(i2c_client_hdl_t handle
, uint8_t offset
,
1129 uint8_t port
, uint8_t data
)
1131 ASSERT(port
< HPC3130_MAX_SLOT
);
1134 return (hpc3130_rw(handle
,
1135 HPC3130_REG(offset
, port
), B_TRUE
, &data
));
1139 hpc3130_read(i2c_client_hdl_t handle
, uint8_t offset
,
1140 uint8_t port
, uint8_t *data
)
1142 ASSERT(port
< HPC3130_MAX_SLOT
);
1145 return (hpc3130_rw(handle
,
1146 HPC3130_REG(offset
, port
), B_FALSE
, data
));
1150 hpc3130_rw(i2c_client_hdl_t handle
, uint8_t reg
,
1151 boolean_t write
, uint8_t *data
)
1153 i2c_transfer_t
*i2c_tran_pointer
;
1158 if (write
== B_TRUE
) {
1166 (void) i2c_transfer_alloc(handle
,
1167 &i2c_tran_pointer
, wlen
, rlen
, I2C_SLEEP
);
1169 if (i2c_tran_pointer
== NULL
) {
1170 D1CMN_ERR((CE_WARN
, "Failed in hpc3130_rw: "
1171 "no transfer structure 0x%x", reg
));
1172 return (DDI_FAILURE
);
1174 i2c_tran_pointer
->i2c_wbuf
[0] = reg
;
1175 if (write
== B_TRUE
) {
1176 i2c_tran_pointer
->i2c_flags
= I2C_WR
;
1177 i2c_tran_pointer
->i2c_wbuf
[1] = *data
;
1179 i2c_tran_pointer
->i2c_flags
= I2C_WR_RD
;
1182 err
= i2c_transfer(handle
, i2c_tran_pointer
);
1184 D1CMN_ERR((CE_WARN
, "Failed in hpc3130_rw: "
1185 "no I2C data transfered 0x%x", reg
));
1186 (void) i2c_transfer_free(handle
, i2c_tran_pointer
);
1187 return (DDI_FAILURE
);
1190 if (write
== B_FALSE
)
1191 *data
= i2c_tran_pointer
->i2c_rbuf
[0];
1193 (void) i2c_transfer_free(handle
, i2c_tran_pointer
);
1195 return (DDI_SUCCESS
);
1199 * Put the hot plug controller(s) in proper mode for further
1203 hpc3130_init(dev_info_t
*dip
,
1204 struct tuple
*init_sequence
)
1208 i2c_client_hdl_t handle
;
1209 hpc3130_unit_t
*hpc3130_p
;
1210 int instance
= ddi_get_instance(dip
);
1211 int error
= DDI_FAILURE
;
1215 (hpc3130_unit_t
*)ddi_get_soft_state(hpc3130soft_statep
,
1219 mutex_enter(&hpc3130_p
->hpc3130_mutex
);
1221 handle
= hpc3130_p
->hpc3130_hdl
;
1223 for (slot
= 0; slot
< HPC3130_MAX_SLOT
; slot
++) {
1225 while (tp
->reg
!= HPC3130_NO_REGISTER
) {
1226 if (hpc3130_write(handle
, tp
->reg
, slot
,
1227 tp
->val
) != DDI_SUCCESS
) {
1233 * CPU slots need some special initialization
1236 if (hpc3130_p
->slots_are
== HPC3130_SLOT_TYPE_SBD
) {
1237 if (hpc3130_cpu_init(hpc3130_p
, slot
, handle
)
1243 error
= DDI_SUCCESS
;
1245 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
1251 * When the TI 3130 produces an interrupt,
1252 * this routine is called to sort it out.
1255 hpc3130_hard_intr(caddr_t arg
)
1260 i2c_client_hdl_t handle
;
1261 hpc3130_slot_type_t slot_type
;
1262 uint_t rc
= DDI_INTR_UNCLAIMED
;
1264 hpc3130_unit_t
*hpc3130_p
= (hpc3130_unit_t
*)arg
;
1267 mutex_enter(&hpc3130_p
->hpc3130_mutex
);
1269 slot_type
= hpc3130_p
->slots_are
;
1270 handle
= hpc3130_p
->hpc3130_hdl
;
1272 for (slot
= 0; slot
< HPC3130_MAX_SLOT
; slot
++) {
1275 * Read the interrupt event register - see
1276 * which event(s) took place.
1278 if (hpc3130_read(handle
, HPC3130_EVENT_STATUS
, slot
,
1286 rc
= DDI_INTR_CLAIMED
;
1288 if (hpc3130_debounce_status(handle
,
1289 slot
, &status
) != DDI_SUCCESS
) {
1293 if (interrupt
& HPC3130_PWRGOOD
) {
1294 hpc3130_p
->power
[slot
] = B_FALSE
;
1295 if (!(status
& HPC3130_PWRGOOD
)) {
1296 hpc3130_p
->power
[slot
] = B_TRUE
;
1298 cv_signal(&hpc3130_p
->hpc3130_cond
);
1299 hpc3130_p
->events
[slot
] |= HPC3130_IEVENT_POWER
;
1302 if (interrupt
& HPC3130_DETECT0
) {
1303 if (slot_type
== HPC3130_SLOT_TYPE_SBD
) {
1304 boolean_t present
= !(status
&HPC3130_DETECT0
);
1306 /* Turn ON/OFF OK-to-remove LED */
1307 (void) hpc3130_set_led(hpc3130_p
,
1310 (present
? HPC3130_ATTN_ON
:
1313 /* Clear the FAULT LED on removal */
1314 (void) hpc3130_set_led(hpc3130_p
,
1320 hpc3130_p
->present
[slot
] = present
;
1321 hpc3130_p
->events
[slot
] |=
1322 HPC3130_IEVENT_OCCUPANCY
;
1324 ASSERT(slot_type
== HPC3130_SLOT_TYPE_PCI
);
1326 if (!(status
& HPC3130_DETECT0
)) {
1328 * Event on the downward
1329 * stroke of the button.
1331 hpc3130_p
->events
[slot
] |=
1332 HPC3130_IEVENT_BUTTON
;
1337 if (interrupt
& (HPC3130_PRSNT1
| HPC3130_PRSNT2
)) {
1338 if (slot_type
== HPC3130_SLOT_TYPE_SBD
) {
1339 if (!(status
& HPC3130_PRSNT1
)) {
1341 * Event only on the downward
1342 * stroke of the button.
1344 hpc3130_p
->events
[slot
] |=
1345 HPC3130_IEVENT_BUTTON
;
1348 ASSERT(slot_type
== HPC3130_SLOT_TYPE_PCI
);
1349 if ((status
& (HPC3130_PRSNT1
|
1351 (HPC3130_PRSNT1
| HPC3130_PRSNT2
)) {
1353 hpc3130_p
->present
[slot
] = B_FALSE
;
1355 /* Turn OFF Fault LED */
1356 (void) hpc3130_set_led(hpc3130_p
,
1360 /* Turn OFF OK-to-remove LED */
1361 (void) hpc3130_set_led(hpc3130_p
,
1367 hpc3130_p
->present
[slot
] = B_TRUE
;
1369 /* Turn ON OK-to-remove LED */
1370 (void) hpc3130_set_led(hpc3130_p
,
1376 hpc3130_p
->events
[slot
] |=
1377 HPC3130_IEVENT_OCCUPANCY
;
1380 if (hpc3130_p
->events
[slot
] &&
1381 (hpc3130_p
->present
[slot
] == B_TRUE
)) {
1382 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
1383 pollwakeup(&hpc3130_p
->pollhead
[slot
], POLLIN
);
1384 mutex_enter(&hpc3130_p
->hpc3130_mutex
);
1386 (void) hpc3130_write(handle
, HPC3130_EVENT_STATUS
,
1390 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
1396 hpc3130_cpu_init(hpc3130_unit_t
*hpc3130_p
, int slot
, i2c_client_hdl_t handle
)
1398 uint8_t slot_status
;
1399 uint8_t control_reg
;
1401 int result
= HPC_ERR_FAILED
;
1403 if (hpc3130_read(handle
, HPC3130_STATUS
, slot
,
1408 if (hpc3130_read(handle
, HPC3130_CONTROL
, slot
,
1414 * For the CPU slots, the DETECT[0] pin on the HPC3130
1415 * goes low when a CPU module is in the slot. Pulled
1418 if (slot_status
& HPC3130_DETECT0
) {
1419 D1CMN_ERR((CE_NOTE
, "hpc3130_cpu_init(): "
1420 "[0x%x]Power off....[%d]",
1421 slot_status
, slot
));
1422 control_reg
= control_reg
& ~HPC3130_SLTPWRCTL
;
1424 D1CMN_ERR((CE_NOTE
, "hpc3130_cpu_init(): "
1425 "[0x%x]Power LEFT on!!!....[%d]",
1426 slot_status
, slot
));
1427 hpc3130_p
->present
[slot
] = B_TRUE
;
1428 control_reg
= control_reg
| HPC3130_SLTPWRCTL
;
1433 * Set the control register accordingly
1435 if (hpc3130_write(handle
, HPC3130_CONTROL
,
1436 slot
, control_reg
) != DDI_SUCCESS
) {
1440 result
= DDI_SUCCESS
;
1447 hpc3130_debounce_status(i2c_client_hdl_t handle
,
1448 int slot
, uint8_t *status
)
1456 * Get HPC3130_DEBOUNCE_COUNT consecutive equal
1457 * readings from the status register
1460 count
= 0; limit
= 0; old
= 0xff;
1462 if (hpc3130_read(handle
, HPC3130_STATUS
,
1464 return (DDI_FAILURE
);
1466 if (old
!= *status
) {
1475 } while (count
< HPC3130_DEBOUNCE_COUNT
&&
1476 limit
< HPC3130_DEBOUNCE_LIMIT
);
1478 if (limit
== HPC3130_DEBOUNCE_LIMIT
) {
1479 return (DDI_FAILURE
);
1482 return (DDI_SUCCESS
);
1486 hpc3130_slot_connect(caddr_t ops_arg
, hpc_slot_t slot_hdl
,
1487 void *data
, uint_t flags
)
1489 _NOTE(ARGUNUSED(slot_hdl
, data
, flags
))
1494 hpc3130_unit_t
*hpc3130_p
;
1495 i2c_client_hdl_t handle
;
1497 int result
= HPC_ERR_FAILED
;
1498 hpc3130_slot_type_t slot_type
;
1499 hpc3130_slot_table_entry_t
*ste
;
1500 char phys_slot
[MAXPATHLEN
];
1501 boolean_t needs_to_be_powered_off
= B_FALSE
;
1503 hpc3130_callback_arg_t
*info_p
= (hpc3130_callback_arg_t
*)ops_arg
;
1506 * Callback parameter has specific device handle and offset
1507 * information in it.
1510 hpc3130_p
= (hpc3130_unit_t
*)info_p
->statep
;
1513 mutex_enter(&hpc3130_p
->hpc3130_mutex
);
1515 handle
= (i2c_client_hdl_t
)info_p
->handle
;
1516 offset
= info_p
->offset
;
1518 ste
= &hpc3130_p
->hpc3130_slot_table
[offset
];
1520 if (hpc3130_p
->slots_are
== HPC3130_SLOT_TYPE_SBD
) {
1521 DAK_GET_SBD_APID(phys_slot
, MAXPATHLEN
, offset
);
1523 DAK_GET_PCI_APID(phys_slot
, MAXPATHLEN
,
1524 hpc3130_lookup_slot(ste
->nexus
,
1525 ste
->hpc3130_slot_info
.pci_dev_num
));
1528 ASSERT(ste
->hpc3130_slot_handle
!= NULL
);
1530 slot_type
= hpc3130_p
->slots_are
;
1532 if (hpc3130_p
->enabled
[offset
] == B_FALSE
) {
1533 cmn_err(CE_WARN
, "hot-plug disabled on %s", phys_slot
);
1537 /* Return (do nothing) if power already applied */
1538 if (hpc3130_p
->power
[offset
] == B_TRUE
) {
1539 D1CMN_ERR((CE_NOTE
, "Slot power already on %s", phys_slot
));
1540 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
1541 return (HPC_SUCCESS
);
1544 if (hpc3130_read(handle
, HPC3130_STATUS
, offset
,
1549 /* Read the slot control register to get current value */
1550 if (hpc3130_read(handle
, HPC3130_CONTROL
, offset
,
1555 if (slot_type
== HPC3130_SLOT_TYPE_SBD
) {
1557 D1CMN_ERR((CE_NOTE
, "CPU connect %d control=%x status=%x",
1558 offset
, control
, status
));
1560 control
= control
| HPC3130_SLTPWRCTL
;
1561 if (hpc3130_write(handle
, HPC3130_CONTROL
, offset
,
1562 control
) != DDI_SUCCESS
) {
1568 D1CMN_ERR((CE_NOTE
, "PCI connect %d", offset
));
1571 * PCI needs special sequencing of the control signals.
1574 if (hpc3130_read(handle
, HPC3130_GCR
, offset
,
1579 /* Assert RST to comply with PCI spec. */
1580 control
&= ~HPC3130_SLOTRST
;
1581 if (hpc3130_write(handle
, HPC3130_CONTROL
, offset
,
1582 control
) != DDI_SUCCESS
) {
1585 drv_usecwait(HPC3130_ADEQUATE_PAUSE
);
1587 /* Send the power on signal and verify the result */
1588 control
= control
| HPC3130_SLTPWRCTL
;
1589 if ((hpc3130_write(handle
, HPC3130_CONTROL
, offset
,
1590 control
) != DDI_SUCCESS
) ||
1591 (hpc3130_verify_slot_power(hpc3130_p
, handle
, offset
,
1592 phys_slot
, B_TRUE
) == HPC_ERR_FAILED
)) {
1596 /* The slot is now powered on. */
1598 drv_usecwait(HPC3130_ADEQUATE_PAUSE
);
1600 /* Extinguish the "OK-to-remove" indicator */
1601 (void) hpc3130_set_led(hpc3130_p
, offset
, HPC3130_LED_OK2REM
,
1605 * Perform bus/card speed check functions.
1607 if (hpc3130_read(handle
, HPC3130_STATUS
, offset
, &status
)) {
1610 if ((config
& HPC3130_SYSM66STAT
) &&
1611 !(status
& HPC3130_M66EN
)) {
1612 cmn_err(CE_WARN
, "66Mhz bus can't accept "
1613 "33Mhz card in %s", phys_slot
);
1614 needs_to_be_powered_off
= B_TRUE
;
1617 if (!(config
& HPC3130_SYSM66STAT
) &&
1618 (status
& HPC3130_M66EN
)) {
1619 cmn_err(CE_NOTE
, "66Mhz capable card throttled "
1620 "back to 33Mhz in %s", phys_slot
);
1624 * Send the connect sequence (see struct connect_sequence)
1626 for (i
= 0; i
< HPC3130_CONNECT_SEQ_COUNT
; i
++) {
1627 if (connect_sequence
[i
].set_bit
== B_TRUE
) {
1628 control
|= connect_sequence
[i
].value
;
1630 control
&= ~connect_sequence
[i
].value
;
1632 if (hpc3130_write(handle
, HPC3130_CONTROL
, offset
,
1633 control
) != DDI_SUCCESS
) {
1636 drv_usecwait(HPC3130_ADEQUATE_PAUSE
);
1640 (void) hpc_slot_event_notify(ste
->hpc3130_slot_handle
,
1641 HPC_EVENT_SLOT_POWER_ON
, 0);
1643 /* Flash the "fault" indicator */
1644 (void) hpc3130_set_led(hpc3130_p
, offset
, HPC3130_LED_FAULT
,
1647 result
= HPC_SUCCESS
;
1650 if (needs_to_be_powered_off
== B_TRUE
) {
1652 * We are in an error state where the slot is powered on, and
1653 * it must be powered off.
1656 /* Send the power off signal and verify the result */
1657 control
= control
& ~HPC3130_SLTPWRCTL
;
1658 if ((hpc3130_write(handle
, HPC3130_CONTROL
, offset
,
1659 control
) == DDI_SUCCESS
) &&
1660 (hpc3130_verify_slot_power(hpc3130_p
, handle
, offset
,
1661 phys_slot
, B_FALSE
) == HPC_SUCCESS
)) {
1662 /* Re-light "OK-to-remove" LED */
1663 (void) hpc3130_set_led(hpc3130_p
, offset
,
1664 HPC3130_LED_OK2REM
, HPC3130_ATTN_ON
);
1668 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
1675 hpc3130_slot_disconnect(caddr_t ops_arg
, hpc_slot_t slot_hdl
,
1676 void *data
, uint_t flags
)
1678 _NOTE(ARGUNUSED(slot_hdl
, data
, flags
))
1681 i2c_client_hdl_t handle
;
1682 hpc3130_unit_t
*hpc3130_p
;
1683 int result
= HPC_ERR_FAILED
;
1684 hpc3130_slot_type_t slot_type
;
1685 hpc3130_slot_table_entry_t
*ste
;
1686 char phys_slot
[MAXPATHLEN
];
1688 hpc3130_callback_arg_t
*info_p
= (hpc3130_callback_arg_t
*)ops_arg
;
1691 * Callback parameter has specific device handle and offset
1692 * information in it.
1694 hpc3130_p
= (hpc3130_unit_t
*)info_p
->statep
;
1697 mutex_enter(&hpc3130_p
->hpc3130_mutex
);
1699 handle
= (i2c_client_hdl_t
)info_p
->handle
;
1700 offset
= info_p
->offset
;
1702 ASSERT(handle
== hpc3130_p
->hpc3130_hdl
);
1704 ste
= &hpc3130_p
->hpc3130_slot_table
[offset
];
1706 if (hpc3130_p
->slots_are
== HPC3130_SLOT_TYPE_SBD
) {
1707 DAK_GET_SBD_APID(phys_slot
, MAXPATHLEN
, offset
);
1709 DAK_GET_PCI_APID(phys_slot
, MAXPATHLEN
,
1710 hpc3130_lookup_slot(ste
->nexus
,
1711 ste
->hpc3130_slot_info
.pci_dev_num
));
1714 ASSERT(ste
->hpc3130_slot_handle
!= NULL
);
1716 slot_type
= hpc3130_p
->slots_are
;
1719 * Read the slot control register to get current value
1721 if (hpc3130_read(handle
, HPC3130_CONTROL
, offset
,
1726 if (slot_type
== HPC3130_SLOT_TYPE_SBD
) {
1728 D1CMN_ERR((CE_NOTE
, "CPU disconnect %d", offset
));
1730 control
= control
& ~HPC3130_SLTPWRCTL
;
1732 * Write out the modified control register
1734 if (hpc3130_write(handle
, HPC3130_CONTROL
, offset
,
1735 control
) != DDI_SUCCESS
) {
1740 D1CMN_ERR((CE_NOTE
, "PCI disconnect %d", offset
));
1742 control
&= ~HPC3130_SLOTRST
;
1743 if (hpc3130_write(handle
, HPC3130_CONTROL
, offset
,
1744 control
) != DDI_SUCCESS
) {
1748 control
|= HPC3130_BUS_CTL
;
1749 if (hpc3130_write(handle
, HPC3130_CONTROL
, offset
,
1750 control
) != DDI_SUCCESS
) {
1755 D1CMN_ERR((CE_WARN
, "disconnect present[%d]==%d",
1756 offset
, hpc3130_p
->present
[offset
]));
1758 if (hpc3130_verify_slot_power(hpc3130_p
, handle
, offset
,
1759 phys_slot
, B_FALSE
) == HPC_ERR_FAILED
) {
1763 (void) hpc_slot_event_notify(ste
->hpc3130_slot_handle
,
1764 HPC_EVENT_SLOT_POWER_OFF
, 0);
1766 if (hpc3130_p
->present
[offset
] == B_TRUE
) {
1768 * Illuminate the "OK-to-remove" indicator
1769 * if there is a card in the slot.
1772 (void) hpc3130_set_led(hpc3130_p
, offset
, HPC3130_LED_OK2REM
,
1776 * Turn off the "fault" indicator
1778 (void) hpc3130_set_led(hpc3130_p
, offset
, HPC3130_LED_FAULT
,
1782 * If the slot is being powered off with
1783 * no cards in there, its at "boot time",
1784 * put the LEDs in a sane state
1786 if (slot_type
== HPC3130_SLOT_TYPE_PCI
) {
1787 (void) hpc3130_set_led(hpc3130_p
, offset
,
1788 HPC3130_LED_FAULT
, HPC3130_ATTN_OFF
);
1789 (void) hpc3130_set_led(hpc3130_p
, offset
,
1790 HPC3130_LED_OK2REM
, HPC3130_ATTN_OFF
);
1794 result
= HPC_SUCCESS
;
1796 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
1802 hpc3130_verify_slot_power(hpc3130_unit_t
*hpc3130_p
, i2c_client_hdl_t handle
,
1803 uint8_t offset
, char *phys_slot
, boolean_t slot_target_state
)
1807 int result
= HPC_SUCCESS
;
1809 clock_t tm
= drv_usectohz(300000);
1810 boolean_t slot_actual_state
;
1811 boolean_t failure
= B_FALSE
;
1812 hpc3130_slot_table_entry_t
*ste
;
1814 /* This function is called while holding the hpc3130 mutex. */
1817 * For slot_target_state and slot_actual_state:
1818 * B_TRUE == the slot is powered on
1819 * B_FALSE == the slot is powered off
1822 ste
= &hpc3130_p
->hpc3130_slot_table
[offset
];
1823 slot_actual_state
= hpc3130_p
->power
[offset
];
1825 while ((slot_actual_state
!= slot_target_state
) &&
1826 (failure
!= B_TRUE
)) {
1827 timeleft
= cv_reltimedwait(&hpc3130_p
->hpc3130_cond
,
1828 &hpc3130_p
->hpc3130_mutex
, tm
, TR_CLOCK_TICK
);
1829 if (timeleft
== -1) {
1830 if (tries
++ < HPC3130_POWER_TRIES
) {
1832 * The interrupt was missed - explicitly
1835 if (hpc3130_read(handle
,
1836 HPC3130_STATUS
, offset
, &status
)) {
1840 if (status
& HPC3130_PWRGOOD
) {
1841 slot_actual_state
= B_FALSE
;
1843 slot_actual_state
= B_TRUE
;
1845 hpc3130_p
->power
[offset
] = slot_actual_state
;
1847 /* Too many tries. We failed. */
1853 if (failure
== B_TRUE
) {
1854 result
= HPC_ERR_FAILED
;
1855 if (slot_target_state
== B_TRUE
) {
1857 "Could not power on slot %s", phys_slot
);
1860 "Could not power off slot %s", phys_slot
);
1862 (void) hpc3130_set_led(hpc3130_p
, offset
, HPC3130_LED_FAULT
,
1864 (void) hpc_slot_event_notify(ste
->hpc3130_slot_handle
,
1865 HPC_EVENT_SLOT_NOT_HEALTHY
, 0);
1872 hpc3130_slot_insert(caddr_t ops_arg
, hpc_slot_t slot_hdl
,
1873 void *data
, uint_t flags
)
1875 _NOTE(ARGUNUSED(ops_arg
, slot_hdl
, data
, flags
))
1876 return (HPC_ERR_NOTSUPPORTED
);
1880 hpc3130_slot_remove(caddr_t ops_arg
, hpc_slot_t slot_hdl
,
1881 void *data
, uint_t flags
)
1883 _NOTE(ARGUNUSED(ops_arg
, slot_hdl
, data
, flags
))
1884 return (HPC_ERR_NOTSUPPORTED
);
1888 hpc3130_slot_control(caddr_t ops_arg
, hpc_slot_t slot_hdl
,
1889 int request
, caddr_t arg
)
1891 _NOTE(ARGUNUSED(slot_hdl
))
1892 i2c_client_hdl_t handle
;
1895 hpc_led_info_t
*led_info
;
1896 hpc3130_unit_t
*hpc3130_p
;
1897 hpc3130_slot_type_t slot_type
;
1899 hpc3130_callback_arg_t
*info_p
= (hpc3130_callback_arg_t
*)ops_arg
;
1902 * Callback parameter has specific device handle and offset
1903 * information in it.
1906 hpc3130_p
= (hpc3130_unit_t
*)info_p
->statep
;
1909 mutex_enter(&hpc3130_p
->hpc3130_mutex
);
1911 handle
= (i2c_client_hdl_t
)info_p
->handle
;
1912 offset
= info_p
->offset
;
1914 ASSERT(handle
== hpc3130_p
->hpc3130_hdl
);
1916 slot_type
= hpc3130_p
->slots_are
;
1919 case HPC_CTRL_GET_LED_STATE
: {
1922 led_info
= (hpc_led_info_t
*)arg
;
1923 if (led_info
->led
!= HPC_FAULT_LED
&&
1924 led_info
->led
!= HPC_ATTN_LED
) {
1926 "Only FAULT and ATTN leds allowed"));
1927 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
1928 return (HPC_ERR_INVALID
);
1931 if (led_info
->led
== HPC_FAULT_LED
)
1932 led
= HPC3130_LED_FAULT
;
1934 led
= HPC3130_LED_OK2REM
;
1936 if (hpc3130_get_led(handle
, offset
, led
, &state
) !=
1938 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
1939 return (HPC_ERR_FAILED
);
1942 /* Make sure that no one broke the conversion macros */
1943 ASSERT(state
< sizeof (hpc3130_to_hpc_led_map
));
1945 HPC3130_FROM_HPC_LED(HPC3130_TO_HPC_LED(state
)));
1947 led_info
->state
= HPC3130_TO_HPC_LED(state
);
1950 case HPC_CTRL_SET_LED_STATE
: {
1954 * The HPC3130 support modifications to the Fault and
1955 * Ok-to-remove LEDs.
1957 led_info
= (hpc_led_info_t
*)arg
;
1958 if (led_info
->led
!= HPC_FAULT_LED
&&
1959 led_info
->led
!= HPC_ATTN_LED
) {
1961 "Only FAULT and ATTN leds allowed"));
1962 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
1963 return (HPC_ERR_INVALID
);
1966 if (led_info
->led
== HPC_FAULT_LED
)
1967 led
= HPC3130_LED_FAULT
;
1969 led
= HPC3130_LED_OK2REM
;
1971 state
= led_info
->state
;
1972 if (state
>= sizeof (hpc3130_from_hpc_led_map
) ||
1973 (state
!= HPC3130_TO_HPC_LED(
1974 HPC3130_FROM_HPC_LED(state
)))) {
1976 "Improper LED value: %d %d", state
,
1978 HPC3130_FROM_HPC_LED(state
))));
1979 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
1980 return (HPC_ERR_INVALID
);
1983 (void) hpc3130_set_led(hpc3130_p
, offset
, led
,
1984 HPC3130_FROM_HPC_LED(state
));
1987 case HPC_CTRL_GET_SLOT_STATE
: {
1988 if (hpc3130_p
->power
[offset
] == B_FALSE
) {
1989 if (hpc3130_p
->present
[offset
] == B_FALSE
) {
1990 *(ap_rstate_t
*)arg
=
1993 *(ap_rstate_t
*)arg
=
1994 AP_RSTATE_DISCONNECTED
;
1997 *(ap_rstate_t
*)arg
=
1998 AP_RSTATE_CONNECTED
;
2002 case HPC_CTRL_GET_BOARD_TYPE
: {
2003 *(hpc_board_type_t
*)arg
=
2004 (slot_type
== HPC3130_SLOT_TYPE_SBD
?
2005 HPC_BOARD_UNKNOWN
: HPC_BOARD_PCI_HOTPLUG
);
2008 case HPC_CTRL_DEV_CONFIG_START
:
2009 case HPC_CTRL_DEV_UNCONFIG_START
:
2010 (void) hpc3130_set_led(hpc3130_p
, offset
,
2011 HPC3130_LED_FAULT
, HPC3130_ATTN_SLO
);
2013 case HPC_CTRL_DEV_CONFIG_FAILURE
:
2014 (void) hpc3130_set_led(hpc3130_p
, offset
,
2015 HPC3130_LED_FAULT
, HPC3130_ATTN_ON
);
2017 case HPC_CTRL_DEV_CONFIGURED
:
2018 (void) hpc3130_set_led(hpc3130_p
, offset
,
2019 HPC3130_LED_FAULT
, HPC3130_ATTN_OFF
);
2020 hpc3130_p
->present
[offset
] = B_TRUE
;
2022 case HPC_CTRL_DEV_UNCONFIGURED
:
2023 if (hpc3130_p
->power
[offset
] == B_TRUE
) {
2024 (void) hpc3130_set_led(hpc3130_p
, offset
,
2025 HPC3130_LED_FAULT
, HPC3130_ATTN_SLO
);
2027 (void) hpc3130_set_led(hpc3130_p
, offset
,
2028 HPC3130_LED_FAULT
, HPC3130_ATTN_OFF
);
2031 case HPC_CTRL_DISABLE_SLOT
: {
2032 hpc3130_p
->enabled
[offset
] = B_FALSE
;
2035 case HPC_CTRL_ENABLE_SLOT
: {
2036 hpc3130_p
->enabled
[offset
] = B_TRUE
;
2040 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
2041 return (HPC_ERR_FAILED
);
2043 mutex_exit(&hpc3130_p
->hpc3130_mutex
);
2044 return (HPC_SUCCESS
);
2048 hpc3130_lookup_slot(char *nexus
, int pcidev
)
2052 while ((slot_translate
[i
].pcidev
!= pcidev
||
2053 strcmp(nexus
, slot_translate
[i
].nexus
) != 0) &&
2054 i
< HPC3130_LOOKUP_SLOTS
)
2056 ASSERT(i
!= HPC3130_LOOKUP_SLOTS
);
2061 * A routine to convert a number (represented as a string) to
2062 * the integer value it represents.
2068 return (ch
>= '0' && ch
<= '9');
2071 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
2072 #define bad(val) (val == NULL || !isdigit(*val))
2075 hpc3130_atoi(const char *p
)
2080 if (!isdigit(c
= *p
)) {
2093 for (n
= '0' - c
; isdigit(c
= *++p
); ) {
2094 n
*= 10; /* two steps to avoid unnecessary overflow */
2095 n
+= '0' - c
; /* accum neg to avoid surprises at MAX */
2097 return (neg
? n
: -n
);