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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * DRT device/interrupt handler
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
40 #include <sys/autoconf.h>
44 #include <sys/sunddi.h>
45 #include <sys/ddidmareq.h>
46 #include <sys/kstat.h>
49 #include <sys/pctypes.h>
50 #include <sys/pcmcia.h>
51 #include <sys/sservice.h>
53 #include <sys/stp4020_reg.h>
54 #include <sys/stp4020_var.h>
58 struct stpramap
*stpra_freelist
= NULL
;
62 char _depends_on
[] = "misc/pcmcia";
64 #define OUTB(a, b) outb(a, b)
67 int drt_getinfo(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
68 static int drt_attach(dev_info_t
*, ddi_attach_cmd_t
);
69 static int drt_detach(dev_info_t
*, ddi_detach_cmd_t
);
71 static void drt_ll_reset(drt_dev_t
*, int);
72 static void drt_stop_intr(drt_dev_t
*, int);
73 static void drt_cpr(drt_dev_t
*, int);
74 static void drt_new_card(drt_dev_t
*, int);
75 static void drt_fixprops(dev_info_t
*);
76 static int drt_inquire_adapter(dev_info_t
*, inquire_adapter_t
*);
78 static struct stpramap
*stpra_alloc_map();
79 static void stpra_free_map(struct stpramap
*);
80 static void stpra_free(struct stpramap
**, uint32_t, uint32_t);
81 static int stpra_alloc(struct stpramap
**, stpra_request_t
*, stpra_return_t
*);
82 static uint32_t stpra_fix_pow2(uint32_t);
85 static kmutex_t stpra_lock
;
88 struct bus_ops pcmciabus_ops
= {
105 NULL
, /* (*bus_get_eventcookie)(); */
106 NULL
, /* (*bus_add_eventcall)(); */
107 NULL
, /* (*bus_remove_eventcall)(); */
108 NULL
, /* (*bus_post_event)(); */
109 NULL
, /* (*bus_intr_ctl)(); */
110 NULL
, /* (*bus_config)(); */
111 NULL
, /* (*bus_unconfig)(); */
112 NULL
, /* (*bus_fm_init)(); */
113 NULL
, /* (*bus_fm_fini)(); */
114 NULL
, /* (*bus_enter)() */
115 NULL
, /* (*bus_exit)() */
116 NULL
, /* (*bus_power)() */
117 pcmcia_intr_ops
/* (*bus_intr_op)(); */
120 static struct dev_ops drt_devops
= {
132 ddi_quiesce_not_supported
, /* devo_quiesce */
138 #if defined(DRT_DEBUG)
139 static void drt_dmp_regs(stp4020_socket_csr_t
*);
143 /* bit patterns to select voltage levels */
144 int drt_vpp_levels
[13] = {
150 struct power_entry drt_power
[DRT_NUM_POWER
] = {
165 drt_dev_t
*drt_get_driver_private(dev_info_t
*);
166 uint32_t drt_hi_intr(caddr_t
);
167 uint32_t drt_lo_intr(caddr_t
);
169 static int drt_callback(dev_info_t
*, int (*)(), int);
170 static int drt_inquire_adapter(dev_info_t
*, inquire_adapter_t
*);
171 static int drt_get_adapter(dev_info_t
*, get_adapter_t
*);
172 static int drt_get_page(dev_info_t
*, get_page_t
*);
173 static int drt_get_socket(dev_info_t
*, get_socket_t
*);
174 static int drt_get_status(dev_info_t
*, get_ss_status_t
*);
175 static int drt_get_window(dev_info_t
*, get_window_t
*);
176 static int drt_inquire_socket(dev_info_t
*, inquire_socket_t
*);
177 static int drt_inquire_window(dev_info_t
*, inquire_window_t
*);
178 static int drt_reset_socket(dev_info_t
*, int, int);
179 static int drt_set_page(dev_info_t
*, set_page_t
*);
180 static int drt_set_window(dev_info_t
*, set_window_t
*);
181 static int drt_set_socket(dev_info_t
*, set_socket_t
*);
182 static int drt_set_interrupt(dev_info_t
*, set_irq_handler_t
*);
183 static int drt_clear_interrupt(dev_info_t
*, clear_irq_handler_t
*);
184 void drt_socket_card_id(drt_dev_t
*, drt_socket_t
*, int);
187 * pcmcia interface operations structure
188 * this is the private interface that is exported to the nexus
190 pcmcia_if_t drt_if_ops
= {
212 * This is the loadable module wrapper.
214 #include <sys/modctl.h>
216 extern struct mod_ops mod_driverops
;
218 static struct modldrv modldrv
= {
219 &mod_driverops
, /* Type of module. This one is a driver */
220 "STP4020 (SUNW,pcmcia) adapter driver", /* Name of the module. */
221 &drt_devops
, /* driver ops */
224 static struct modlinkage modlinkage
= {
225 MODREV_1
, (void *)&modldrv
, NULL
233 mutex_init(&stpra_lock
, NULL
, MUTEX_DRIVER
,
234 (void *)(uintptr_t)__ipltospl(SPL7
- 1));
235 if ((ret
= mod_install(&modlinkage
)) != 0) {
236 mutex_destroy(&stpra_lock
);
245 struct stpramap
*next
;
247 if ((ret
= mod_remove(&modlinkage
)) == 0) {
249 mutex_enter(&stpra_lock
);
250 while (stpra_freelist
!= NULL
) {
251 next
= stpra_freelist
->ra_next
;
252 kmem_free((caddr_t
)stpra_freelist
,
253 sizeof (struct stpramap
));
254 stpra_freelist
= next
;
256 mutex_exit(&stpra_lock
);
258 mutex_destroy(&stpra_lock
);
264 _info(struct modinfo
*modinfop
)
266 return (mod_info(&modlinkage
, modinfop
));
271 * provide instance/device information about driver
274 drt_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
276 int error
= DDI_SUCCESS
;
278 case DDI_INFO_DEVT2DEVINFO
:
279 /* should make independent of SUNW,pcmcia */
280 dip
= ddi_find_devinfo("SUNW,pcmcia", getminor((dev_t
)arg
), 1);
283 case DDI_INFO_DEVT2INSTANCE
:
296 * attach the DRT (SPARC STP4020) driver
297 * to the system. This is a child of "sysbus" since that is where
298 * the hardware lives, but it provides services to the "pcmcia"
299 * nexus driver. It gives a pointer back via its private data
300 * structure which contains both the dip and socket services entry
304 drt_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
307 struct pcmcia_adapter_nexus_private
*drt_nexus
;
309 ddi_device_acc_attr_t dev_attr
;
313 #if defined(DRT_DEBUG)
315 cmn_err(CE_CONT
, "drt_attach(%d): entered\n", cmd
);
320 return (DDI_FAILURE
);
322 drt_nexus
= ddi_get_driver_private(dip
);
323 drt
= (drt_dev_t
*)drt_get_driver_private(dip
);
324 #if defined(DRT_DEBUG)
326 cmn_err(CE_CONT
, "drt_attach: DDI_RESUME\n");
329 if (drt
!= NULL
&& drt
->pc_flags
& PCF_SUSPENDED
) {
330 /* XXX - why would drt be NULL?? */
332 for (sn
= 0; sn
< DRSOCKETS
; sn
++) {
333 drt_socket_t
*sockp
= &drt
->pc_sockets
[sn
];
335 /* Restore adapter hardware state */
336 mutex_enter(&drt
->pc_lock
);
337 drt_cpr(drt
, DRT_RESTORE_HW_STATE
);
338 drt_new_card(drt
, sn
);
339 drt_socket_card_id(drt
, sockp
,
340 drt
->pc_csr
->socket
[sn
].stat0
);
341 mutex_exit(&drt
->pc_lock
);
344 mutex_enter(&drt
->pc_lock
);
345 drt
->pc_flags
&= ~PCF_SUSPENDED
;
346 mutex_exit(&drt
->pc_lock
);
347 /* do we want to do anything here??? */
349 /* this code should do PC Card Standard form */
350 (void) pcmcia_begin_resume(dip
);
352 * this will do the CARD_INSERTION
353 * due to needing time for threads to
354 * run, it must be delayed for a short amount
355 * of time. pcmcia_wait_insert checks for all
356 * children to be removed and then triggers insert.
358 (void) pcmcia_wait_insert(dip
);
360 * for complete implementation need END_RESUME (later)
362 return (DDI_SUCCESS
);
364 return (DDI_FAILURE
);
369 drt
= (drt_dev_t
*)kmem_zalloc(sizeof (drt_dev_t
), KM_NOSLEEP
);
371 return (DDI_FAILURE
);
374 #if defined(DRT_DEBUG)
376 cmn_err(CE_CONT
, "drt_attach: drt=%p\n", (void *)drt
);
378 drt_nexus
= (struct pcmcia_adapter_nexus_private
*)
379 kmem_zalloc(sizeof (struct pcmcia_adapter_nexus_private
),
381 if (drt_nexus
== NULL
) {
382 kmem_free(drt
, sizeof (drt_dev_t
));
383 return (DDI_FAILURE
);
385 /* map everything in we will ultimately need */
386 drt
->pc_devinfo
= dip
;
388 dev_attr
.devacc_attr_version
= DDI_DEVICE_ATTR_V0
;
389 dev_attr
.devacc_attr_endian_flags
= DDI_NEVERSWAP_ACC
;
390 dev_attr
.devacc_attr_dataorder
= DDI_STRICTORDER_ACC
;
391 if (ddi_regs_map_setup(dip
, DRMAP_ASIC_CSRS
, (caddr_t
*)&drt
->pc_csr
,
392 (off_t
)0, sizeof (stp4020_socket_csr_t
),
393 &dev_attr
, &drt
->pc_handle
) != 0) {
394 kmem_free(drt
, sizeof (drt_dev_t
));
396 sizeof (struct pcmcia_adapter_nexus_private
*));
397 return (DDI_FAILURE
);
399 #if defined(DRT_DEBUG)
401 cmn_err(CE_CONT
, "drt_attach: %x->%p\n", DRMAP_ASIC_CSRS
,
402 (void *)drt
->pc_csr
);
407 if ((err
= ddi_getlongprop_buf(DDI_DEV_T_ANY
, dip
,
408 DDI_PROP_CANSLEEP
, "reg",
409 (caddr_t
)regs
, &i
)) != DDI_SUCCESS
) {
411 kmem_free(drt
, sizeof (drt_dev_t
));
413 sizeof (struct pcmcia_adapter_nexus_private
));
414 return (DDI_FAILURE
);
418 drt_nexus
->an_dip
= dip
;
419 drt_nexus
->an_if
= &drt_if_ops
;
420 drt_nexus
->an_private
= drt
;
422 drt
->pc_numpower
= DRT_NUM_POWER
;
423 drt
->pc_power
= drt_power
;
425 drt
->pc_numsockets
= DRSOCKETS
;
426 drt
->pc_flags
|= PCF_ATTACHING
;
428 ddi_set_driver_private(dip
, drt_nexus
);
430 /* allow property to override audio */
431 if (ddi_getprop(DDI_DEV_T_NONE
, dip
,
432 DDI_PROP_DONTPASS
, "disable-audio", -1) == -1)
433 drt
->pc_flags
|= PCF_AUDIO
;
435 /* now enable both interrupt handlers */
436 if (ddi_add_intr(dip
, 1, &drt
->pc_icookie_hi
, &drt
->pc_dcookie_hi
,
437 drt_hi_intr
, (caddr_t
)dip
) != DDI_SUCCESS
) {
438 /* if it fails, unwind everything */
439 ddi_regs_map_free(&drt
->pc_handle
);
440 kmem_free((caddr_t
)drt
, sizeof (drt_dev_t
));
441 kmem_free((caddr_t
)drt_nexus
, sizeof (*drt_nexus
));
442 return (DDI_FAILURE
);
446 if (ddi_add_intr(dip
, 0, &drt
->pc_icookie_lo
, &drt
->pc_dcookie_lo
,
447 drt_lo_intr
, (caddr_t
)dip
) != DDI_SUCCESS
) {
448 /* if it fails, unwind everything */
449 ddi_remove_intr(dip
, 0, &drt
->pc_icookie_hi
);
450 ddi_regs_map_free(&drt
->pc_handle
);
451 kmem_free((caddr_t
)drt
, sizeof (drt_dev_t
));
452 kmem_free((caddr_t
)drt_nexus
, sizeof (*drt_nexus
));
453 return (DDI_FAILURE
);
456 mutex_init(&drt
->pc_lock
, NULL
, MUTEX_DRIVER
, drt
->pc_icookie_hi
);
457 mutex_init(&drt
->pc_intr
, NULL
, MUTEX_DRIVER
, drt
->pc_icookie_hi
);
459 drt_nexus
->an_iblock
= &drt
->pc_icookie_hi
;
460 drt_nexus
->an_idev
= &drt
->pc_dcookie_hi
;
462 mutex_enter(&drt
->pc_lock
);
464 for (i
= 0; i
< DRSOCKETS
; i
++) {
465 struct stpramap
*map
;
467 drt
->pc_csr
->socket
[i
].ctl1
= 0; /* turn things off */
468 drt
->pc_csr
->socket
[i
].ctl0
= 0; /* before we touch anything */
470 /* work around for false status bugs */
471 drt
->pc_csr
->socket
[i
].stat1
= 0x3FFF;
472 drt
->pc_csr
->socket
[i
].stat0
= 0x3FFF;
475 * enable the socket as well
476 * want status change interrupts for all possible events
477 * We do this even though CS hasn't asked. The system
478 * wants to manage these and will only tell CS of those
481 /* identify current state of card */
482 drt_socket_card_id(drt
, &drt
->pc_sockets
[i
],
483 drt
->pc_csr
->socket
[i
].stat0
);
485 /* finally, turn it on */
486 drt
->pc_csr
->socket
[i
].ctl0
= DRT_CHANGE_DEFAULT
;
488 /* now we need per-socket I/O space allocation */
489 map
= drt
->pc_sockets
[i
].drt_iomap
= stpra_alloc_map();
491 map
->ra_len
= 0xffffff; /* 1MB */
497 * now that the adapter is fully operational
498 * it is time to pull in the PCMCIA framework
499 * and let it know we exist and are "ready"
501 mutex_exit(&drt
->pc_lock
);
502 err
= pcmcia_attach(dip
, drt_nexus
);
509 * request to detach from the system
512 drt_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
515 drt_dev_t
*drt
= (drt_dev_t
*)drt_get_driver_private(dip
);
520 /* turn everything off for all sockets and chips */
521 for (i
= 0; i
< drt
->pc_numsockets
; i
++) {
522 drt
->pc_csr
->socket
[i
].ctl0
= 0;
523 drt
->pc_csr
->socket
[i
].ctl1
= 0;
525 stpra_free_map(drt
->pc_sockets
[i
].drt_iomap
);
526 ddi_regs_map_free(&drt
->pc_handle
);
527 ddi_remove_intr(dip
, 0, drt
->pc_icookie_lo
);
528 ddi_remove_intr(dip
, 1, drt
->pc_icookie_hi
);
530 mutex_destroy(&drt
->pc_lock
);
531 return (DDI_SUCCESS
);
536 #if defined(DRT_DEBUG)
538 cmn_err(CE_WARN
, "stp4020: DDI_PM_SUSPEND\n");
543 #if defined(DRT_DEBUG)
545 cmn_err(CE_CONT
, "drt_detach: DDI_SUSPEND\n");
549 /* XXX - why is this test necessary here? */
551 mutex_enter(&drt
->pc_lock
);
552 drt
->pc_flags
|= PCF_SUSPENDED
;
553 mutex_exit(&drt
->pc_lock
);
554 for (sn
= 0; sn
< DRSOCKETS
; sn
++) {
555 /* drt_stop_intr(drt, sn); XXX ?? */
556 mutex_enter(&drt
->pc_lock
);
557 /* clears sockp->drt_flags */
558 drt_new_card(drt
, sn
);
559 mutex_exit(&drt
->pc_lock
);
562 * Save the adapter's hardware state here
564 mutex_enter(&drt
->pc_lock
);
565 drt_cpr(drt
, DRT_SAVE_HW_STATE
);
566 mutex_exit(&drt
->pc_lock
);
567 return (DDI_SUCCESS
);
570 return (DDI_FAILURE
);
574 drt_get_driver_private(dev_info_t
*dip
)
576 struct pcmcia_adapter_nexus_private
*nexus
;
577 nexus
= ddi_get_driver_private(dip
);
578 return ((drt_dev_t
*)nexus
->an_private
);
582 * drt_inquire_adapter()
583 * SocketServices InquireAdapter function
584 * get characteristics of the physical adapter
587 drt_inquire_adapter(dev_info_t
*dip
, inquire_adapter_t
*config
)
589 drt_dev_t
*drt
= drt_get_driver_private(dip
);
590 #if defined(DRT_DEBUG)
592 cmn_err(CE_CONT
, "drt_inquire_adapter\n");
594 config
->NumSockets
= drt
->pc_numsockets
;
595 config
->NumWindows
= DRT_NUMWINDOWS
;
598 config
->ActiveHigh
= 3;
599 config
->ActiveLow
= 0;
600 config
->NumPower
= drt
->pc_numpower
;
601 config
->power_entry
= drt
->pc_power
; /* until we resolve this */
602 config
->ResourceFlags
= RES_OWN_IRQ
| RES_OWN_IO
| RES_OWN_MEM
|
603 RES_IRQ_NEXUS
| RES_IRQ_SHAREABLE
;
609 * The PCMCIA nexus calls us via this function
610 * in order to set the callback function we are
611 * to call the nexus with
614 drt_callback(dev_info_t
*dip
, int (*handler
)(), int arg
)
616 drt_dev_t
*drt
= (drt_dev_t
*)drt_get_driver_private(dip
);
617 #if defined(DRT_DEBUG)
620 cmn_err(CE_CONT
, "drt_callback: drt=%x, lock=%x\n",
621 (int)drt
, (int)drt
->pc_lock
);
623 cmn_err(CE_CONT
, "\thandler=%p, arg=%x\n", (void *)handler
,
627 if (handler
!= NULL
) {
628 drt
->pc_callback
= handler
;
629 drt
->pc_cb_arg
= arg
;
630 drt
->pc_flags
|= PCF_CALLBACK
;
632 drt
->pc_callback
= NULL
;
634 drt
->pc_flags
&= ~PCF_CALLBACK
;
637 * we're now registered with the nexus
638 * it is acceptable to do callbacks at this point.
639 * don't call back from here though since it could block
647 * determine the bit pattern for speeds to be put in the control register
651 drt_calc_speed(int speed
)
656 * the documented speed determination (25MHZ) is
657 * 250 + (CMDLNG - 4) * 40 < speed <= 250 + (CMDLNG - 3) * 40
658 * The value of CMDLNG is roughly determined by
659 * CMDLNG == ((speed - 250) / 40) + [3|4]
660 * the calculation is very approximate.
661 * for speeds <= 250ns, use simple formula
663 * this should really be based on processor speed.
669 length
= (speed
- 100) / 50;
675 length
= ((speed
- 250) / 40);
676 if ((250 + (length
- 3) * 40) == speed
)
683 #if defined(DRT_DEBUG)
685 cmn_err(CE_CONT
, "drt_calc_speed: speed=%d, length=%x, "
686 "delay=%x, ret=%x\n",
687 speed
, length
, delay
,
688 (SET_DRWIN_CMDDLY(delay
) | SET_DRWIN_CMDLNG(length
)));
690 return (SET_DRWIN_CMDDLY(delay
) | SET_DRWIN_CMDLNG(length
));
695 * essentially the same as the Socket Services specification
696 * We use socket and not adapter since they are identifiable
697 * but the rest is the same
699 * dip drt driver's device information
700 * window parameters for the request
703 drt_set_window(dev_info_t
*dip
, set_window_t
*window
)
707 drt_dev_t
*drt
= drt_get_driver_private(dip
);
709 struct drt_window
*winp
;
710 stp4020_socket_csr_t
*csrp
;
713 #if defined(DRT_DEBUG)
715 cmn_err(CE_CONT
, "drt_set_window: entered\n");
717 "\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n",
718 window
->window
, window
->socket
, window
->WindowSize
,
721 "\tbase=%x, state=%x\n", (int)window
->base
,
728 * do some basic sanity checking on what we support
729 * we don't do paged mode
731 if (window
->state
& WS_PAGED
)
732 return (BAD_ATTRIBUTE
);
735 * make sure we use the correct internal socket/window
738 win
= window
->window
% DRWINDOWS
;
739 if (window
->socket
!= (window
->window
/ DRWINDOWS
)) {
743 if (!(window
->state
& WS_IO
) && (window
->WindowSize
!= DRWINSIZE
&&
744 !(window
->state
& WS_EXACT_MAPIN
)) ||
745 window
->WindowSize
> DRWINSIZE
) {
746 #if defined(DRT_DEBUG)
748 cmn_err(CE_CONT
, "\tBAD SIZE\n");
753 sockp
= &drt
->pc_sockets
[window
->socket
];
755 #if defined(DRT_DEBUG)
758 "\tusing window/socket %d/%d\n", win
, window
->socket
);
762 * we don't care about previous mappings.
763 * Card Services will deal with that so don't
767 winp
= &sockp
->drt_windows
[win
];
768 csrp
= &drt
->pc_csr
->socket
[window
->socket
];
770 mutex_enter(&drt
->pc_lock
); /* protect the registers */
771 prevstate
= winp
->drtw_flags
;
772 which
= 0; /* no error */
774 /* disable current settings */
775 csrp
->window
[win
].ctl0
= 0;
778 * disable current mapping
779 * this will handle the case of WS_ENABLED not being set
782 if ((window
->state
& (WS_IO
|WS_EXACT_MAPIN
)) ==
783 (WS_IO
|WS_EXACT_MAPIN
)) {
784 if (window
->base
.base
!= 0) {
785 /* compensate for having to start at 0 */
786 window
->WindowSize
+= (uint32_t)window
->base
.base
;
791 if (window
->socket
== 0)
792 windex
= DRMAP_CARD0_WIN0
+ win
;
794 windex
= DRMAP_CARD1_WIN0
+ win
;
796 if ((prevstate
& DRW_MAPPED
) &&
797 (window
->WindowSize
!= winp
->drtw_len
)) {
798 mutex_exit(&drt
->pc_lock
);
799 ddi_regs_map_free(&winp
->drtw_handle
);
800 mutex_enter(&drt
->pc_lock
);
801 #if defined(DRT_DEBUG)
804 "\tunmapped: base being set to NULL\n");
806 winp
->drtw_flags
&= ~(DRW_MAPPED
|DRW_ENABLED
);
807 if (prevstate
& DRW_IO
) {
808 stpra_free(&sockp
->drt_iomap
,
809 (uint32_t)(uintptr_t)winp
->drtw_reqaddr
,
810 (uint32_t)winp
->drtw_len
);
812 winp
->drtw_base
= NULL
;
815 if (window
->state
& WS_ENABLED
) {
816 if (winp
->drtw_base
== NULL
) {
817 if (window
->state
& WS_IO
) {
820 bzero((caddr_t
)&req
, sizeof (req
));
821 bzero((caddr_t
)&ret
, sizeof (ret
));
822 req
.ra_flags
= STP_RA_ALLOC_POW2
|
824 req
.ra_len
= window
->WindowSize
;
825 req
.ra_addr_lo
= window
->base
;
827 if (window
->base
!= 0)
828 req
.ra_flags
|= STP_RA_ALLOC_SPECIFIED
;
830 if (stpra_alloc(&sockp
->drt_iomap
,
831 &req
, &ret
) != DDI_SUCCESS
) {
832 mutex_exit(&drt
->pc_lock
);
835 /* now use the resultant address */
836 window
->base
= ret
.ra_addr_lo
;
838 mutex_exit(&drt
->pc_lock
);
839 which
= ddi_regs_map_setup(drt
->pc_devinfo
,
842 (offset_t
)window
->base
,
846 mutex_enter(&drt
->pc_lock
);
847 if (which
!= DDI_SUCCESS
) {
848 mutex_exit(&drt
->pc_lock
);
851 #if defined(DRT_DEBUG)
854 "\tmapped: handle = 0x%p base = %p, "
856 (void *)winp
->drtw_handle
,
857 (void *)winp
->drtw_base
,
858 (int)window
->WindowSize
);
861 winp
->drtw_reqaddr
= (caddr_t
)(uintptr_t)window
->base
;
862 winp
->drtw_flags
|= DRW_MAPPED
| DRW_ENABLED
;
864 if (!(window
->state
& WS_IO
)) {
865 winp
->drtw_speed
= window
->speed
;
866 winp
->drtw_ctl0
= drt_calc_speed(window
->speed
);
867 winp
->drtw_ctl0
|= DRWIN_ASPSEL_CM
;
868 winp
->drtw_flags
&= ~DRW_IO
;
870 winp
->drtw_flags
|= DRW_IO
;
871 winp
->drtw_ctl0
= DRWIN_ASPSEL_IO
|
872 drt_calc_speed(window
->speed
);
873 winp
->drtw_modhandle
.ah_addr
+= (int)window
->base
;
875 window
->handle
= winp
->drtw_handle
;
876 csrp
->window
[win
].ctl0
= winp
->drtw_ctl0
;
877 csrp
->window
[win
].ctl1
= SET_DRWIN_WAITREQ(1) |
878 SET_DRWIN_WAITDLY(0);
879 winp
->drtw_len
= window
->WindowSize
;
881 if (winp
->drtw_flags
& DRW_ENABLED
) {
882 winp
->drtw_flags
&= ~DRW_ENABLED
;
883 csrp
->window
[win
].ctl0
= 0; /* force off */
885 if (prevstate
& DRW_IO
) {
886 stpra_free(&sockp
->drt_iomap
,
887 (uint32_t)winp
->drtw_reqaddr
,
888 (uint32_t)winp
->drtw_len
);
892 winp
->drtw_base
= NULL
;
895 #if defined(DRT_DEBUG)
898 "\tbase now set to %p (->%p), csrp=%p, winreg=%p"
900 (void *)window
->handle
,
901 (void *)winp
->drtw_base
, (void *)csrp
,
902 (void *)&csrp
->window
[win
].ctl0
,
903 (int)window
->WindowSize
);
905 "\twindow type is now %s\n", window
->state
& WS_IO
?
912 mutex_exit(&drt
->pc_lock
);
919 * compute the instantaneous Card State information
922 drt_card_state(drt_dev_t
*drt
, int socket
)
926 mutex_enter(&drt
->pc_lock
); /* protect the registers */
928 value
= drt
->pc_csr
->socket
[socket
].stat0
;
929 #if defined(DRT_DEBUG)
931 cmn_err(CE_CONT
, "drt_card_state: socket=%d, *lock=%p\n",
932 socket
, (void *)&drt
->pc_lock
);
933 cmn_err(CE_CONT
, "\tcsr@%p\n", (void *)drt
->pc_csr
);
935 cmn_err(CE_CONT
, "\tstat0=%b\n", value
,
936 "\020\1PWRON\2WAIT\3WP\4RDYBSY\5BVD1\6BVD2\7CD1"
937 "\10CD2\011ACCTO\012WPC\013RBC\014BVD1C\015BVD2C"
941 (int)drt
->pc_csr
->socket
[socket
].stat1
);
942 cmn_err(CE_CONT
, "\t&stat0=%p, &stat1=%p\n",
943 (void *)&drt
->pc_csr
->socket
[socket
].stat0
,
944 (void *)&drt
->pc_csr
->socket
[socket
].stat1
);
948 if (value
& DRSTAT_WPST
)
953 switch (value
& DRSTAT_BVDST
) {
954 case DRSTAT_BATT_LOW
:
965 if (value
& DRSTAT_RDYST
)
966 result
|= SBM_RDYBSY
;
967 if ((value
& (DRSTAT_CD1ST
|DRSTAT_CD2ST
)) ==
968 (DRSTAT_CD1ST
|DRSTAT_CD2ST
))
971 mutex_exit(&drt
->pc_lock
);
978 * SocketServices SetPage function
979 * set the page of PC Card memory that should be in the mapped
984 drt_set_page(dev_info_t
*dip
, set_page_t
*page
)
986 int which
, socket
, win
;
987 drt_dev_t
*drt
= drt_get_driver_private(dip
);
989 struct drt_window
*winp
;
990 stp4020_socket_csr_t
*csrp
;
992 if (page
->window
>= DRT_NUMWINDOWS
) {
993 #if defined(DRT_DEBUG)
995 cmn_err(CE_CONT
, "drt_set_page: window=%d (%d)\n",
996 page
->window
, DRWINDOWS
);
1001 win
= page
->window
% DRWINDOWS
;
1002 socket
= page
->window
/ DRWINDOWS
;
1004 sockp
= &drt
->pc_sockets
[socket
];
1006 #if defined(DRT_DEBUG)
1009 "drt_set_page: window=%d, socket=%d, page=%d\n",
1010 win
, socket
, page
->page
);
1014 /* only one page supported (fixed at 1MB) */
1015 #if defined(DRT_DEBUG)
1017 cmn_err(CE_CONT
, "\tpage=%d\n", page
->page
);
1019 winp
= &sockp
->drt_windows
[win
];
1020 csrp
= &drt
->pc_csr
->socket
[socket
];
1022 if (winp
->drtw_flags
& DRW_IO
) {
1023 return (BAD_WINDOW
);
1026 if (page
->page
!= 0) {
1030 mutex_enter(&drt
->pc_lock
); /* protect the registers */
1033 * now map the card's memory pages - we start with page 0
1036 if (page
->state
& PS_ATTRIBUTE
) {
1037 which
= SET_DRWIN_CMDDLY(2) | SET_DRWIN_CMDLNG(4);
1038 winp
->drtw_flags
|= DRW_ATTRIBUTE
;
1040 which
= winp
->drtw_ctl0
& (DRWIN_CMDLNG_M
|DRWIN_CMDDLY_M
);
1041 winp
->drtw_flags
&= ~DRW_ATTRIBUTE
;
1044 which
|= (page
->state
& PS_ATTRIBUTE
) ?
1045 DRWIN_ASPSEL_AM
: DRWIN_ASPSEL_CM
;
1047 /* if card says Write Protect, enforce it */
1048 /* but we don't have hardware support to do it */
1050 /* The actual PC Card address mapping */
1051 #if defined(DRT_DEBUG)
1053 cmn_err(CE_CONT
, "\ta2p=%x, base=%x, csrp=%p\n",
1054 (int)ADDR2PAGE(page
->offset
),
1055 SET_DRWIN_BASE(ADDR2PAGE(page
->offset
)),
1058 which
|= SET_DRWIN_BASE(ADDR2PAGE(page
->offset
));
1059 winp
->drtw_addr
= (caddr_t
)page
->offset
;
1061 /* now set the register */
1062 #if defined(DRT_DEBUG)
1064 cmn_err(CE_CONT
, "\tset ctl0=%x\n", which
);
1067 csrp
->window
[win
].ctl0
= (ushort_t
)which
;
1068 csrp
->window
[win
].ctl1
= SET_DRWIN_WAITREQ(1) | SET_DRWIN_WAITDLY(0);
1072 #if defined(DRT_DEBUG)
1074 cmn_err(CE_CONT
, "\tmemory type = %s\n",
1075 (which
& DRWIN_ASPSEL_CM
) ? "common" : "attribute");
1080 #if defined(DRT_DEBUG)
1083 "\tpage offset=%x, base=%p (PC addr=%p, sockets=%d)\n",
1084 (int)page
->offset
, (void *)winp
->drtw_base
,
1085 (void *)winp
->drtw_addr
, drt
->pc_numsockets
);
1086 cmn_err(CE_CONT
, "\t*base=%x, win reg=%p\n",
1087 *(ushort_t
*)winp
->drtw_base
,
1088 (void *)&csrp
->window
[win
].ctl0
);
1093 mutex_exit(&drt
->pc_lock
);
1100 * Socket Services SetSocket call
1101 * sets basic socket configuration
1104 drt_set_socket(dev_info_t
*dip
, set_socket_t
*socket
)
1107 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1108 drt_socket_t
*sockp
= &drt
->pc_sockets
[socket
->socket
];
1113 sock
= socket
->socket
;
1115 #if defined(DRT_DEBUG)
1117 cmn_err(CE_CONT
, "drt_set_socket: entered (socket=%d)\n", sock
);
1121 * check VccLevel, etc. before setting mutex
1122 * if this is zero, power is being turned off
1123 * if it is non-zero, power is being turned on.
1124 * the default case is to assume Vcc only.
1127 /* this appears to be very implementation specific */
1129 if (socket
->VccLevel
== 0) {
1131 } else if (socket
->VccLevel
< drt
->pc_numpower
&&
1132 drt_power
[socket
->VccLevel
].ValidSignals
& VCC
) {
1134 powerlevel
= DRCTL_MSTPWR
|DRCTL_PCIFOE
;
1135 sockp
->drt_vcc
= socket
->VccLevel
;
1139 #if defined(DRT_DEBUG)
1141 cmn_err(CE_CONT
, "\tVccLevel=%d, Vpp1Level=%d, Vpp2Level=%d\n",
1143 socket
->Vpp1Level
, socket
->Vpp2Level
);
1146 ind
= 0; /* default index to 0 power */
1147 if (socket
->Vpp1Level
>= 0 && socket
->Vpp1Level
< drt
->pc_numpower
) {
1148 if (!(drt_power
[socket
->Vpp1Level
].ValidSignals
& VPP1
)) {
1151 ind
= drt_power
[socket
->Vpp1Level
].PowerLevel
/10;
1152 powerlevel
|= drt_vpp_levels
[ind
] << 2;
1153 sockp
->drt_vpp1
= socket
->Vpp1Level
;
1155 if (socket
->Vpp2Level
>= 0 && socket
->Vpp2Level
< drt
->pc_numpower
) {
1156 if (!(drt_power
[socket
->Vpp2Level
].ValidSignals
& VPP2
)) {
1159 ind
= drt_power
[socket
->Vpp2Level
].PowerLevel
/10;
1160 powerlevel
|= (drt_vpp_levels
[ind
] << 4);
1161 sockp
->drt_vpp2
= socket
->Vpp2Level
;
1164 #if defined(DRT_DEBUG)
1166 cmn_err(CE_CONT
, "\tpowerlevel=%x, ind=%x\n", powerlevel
, ind
);
1169 mutex_enter(&drt
->pc_lock
); /* protect the registers */
1171 /* make sure not still in RESET */
1172 value
= drt
->pc_csr
->socket
[sock
].ctl0
;
1173 drt
->pc_csr
->socket
[sock
].ctl0
= value
& ~DRCTL_RESET
;
1175 * ctlind processing -- we can ignore this
1176 * there aren't any outputs on the chip for this
1177 * the GUI will display what it thinks is correct
1181 /* handle event mask */
1182 sockp
->drt_intmask
= socket
->SCIntMask
;
1183 value
= (drt
->pc_csr
->socket
[sock
].ctl0
& ~DRT_CHANGE_MASK
) |
1184 DRT_CHANGE_DEFAULT
; /* always want CD */
1186 if (socket
->SCIntMask
& SBM_CD
)
1187 value
|= DRCTL_CDIE
;
1188 if (socket
->SCIntMask
& SBM_BVD1
)
1189 value
|= DRCTL_BVD1IE
;
1190 if (socket
->SCIntMask
& SBM_BVD2
)
1191 value
|= DRCTL_BVD2IE
;
1192 if (socket
->SCIntMask
& SBM_WP
)
1193 value
|= DRCTL_WPIE
;
1194 if (socket
->SCIntMask
& SBM_RDYBSY
)
1195 value
|= DRCTL_RDYIE
;
1196 /* irq processing */
1197 if (socket
->IFType
== IF_IO
) {
1198 /* IRQ only for I/O */
1199 irq
= socket
->IREQRouting
& 0xF;
1200 if (socket
->IREQRouting
& IRQ_ENABLE
) {
1203 if (socket
->IREQRouting
& IRQ_PRIORITY
) {
1204 irq
|= DRCTL_IOILVL_SB1
;
1205 sockp
->drt_flags
|= DRT_INTR_HIPRI
;
1207 irq
|= DRCTL_IOILVL_SB0
;
1210 irq
|= DRCTL_IOILVL_SB1
;
1211 sockp
->drt_flags
|= DRT_INTR_HIPRI
;
1213 sockp
->drt_flags
|= DRT_INTR_ENABLED
;
1215 irq
= 0; /* no interrupts */
1216 sockp
->drt_flags
&= ~(DRT_INTR_ENABLED
|DRT_INTR_HIPRI
);
1218 sockp
->drt_irq
= socket
->IREQRouting
;
1220 #if defined(DRT_DEBUG)
1223 "\tsocket type is I/O and irq %x is %s\n", irq
,
1224 (socket
->IREQRouting
& IRQ_ENABLE
) ?
1225 "enabled" : "not enabled");
1228 sockp
->drt_flags
|= DRT_SOCKET_IO
;
1229 if (drt
->pc_flags
& PCF_AUDIO
)
1230 value
|= DRCTL_IFTYPE_IO
| irq
| DRCTL_SPKREN
;
1232 value
|= DRCTL_IFTYPE_IO
| irq
;
1234 /* enforce memory mode */
1235 value
&= ~(DRCTL_IFTYPE_IO
| DRCTL_SPKREN
|
1236 DRCTL_IOILVL_SB1
| DRCTL_IOILVL_SB0
|
1238 sockp
->drt_flags
&= ~(DRT_INTR_ENABLED
|DRT_SOCKET_IO
);
1240 drt
->pc_csr
->socket
[sock
].ctl0
= (ushort_t
)value
;
1243 * set power to socket
1244 * note that the powerlevel was calculated earlier
1247 drt
->pc_csr
->socket
[sock
].ctl1
= (ushort_t
)powerlevel
;
1248 #if defined(DRT_DEBUG)
1251 "\tpowerlevel (socket->ctl1) = %x\n", powerlevel
);
1253 drt_dmp_regs(&drt
->pc_csr
->socket
[sock
]);
1256 sockp
->drt_state
&= ~socket
->State
;
1257 mutex_exit(&drt
->pc_lock
);
1262 * drt_inquire_socket()
1263 * SocketServices InquireSocket function
1264 * returns basic characteristics of the socket
1267 drt_inquire_socket(dev_info_t
*dip
, inquire_socket_t
*socket
)
1270 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1272 socket
->SCIntCaps
= DRT_DEFAULT_INT_CAPS
;
1273 socket
->SCRptCaps
= DRT_DEFAULT_RPT_CAPS
;
1274 socket
->CtlIndCaps
= DRT_DEFAULT_CTL_CAPS
;
1275 value
= drt
->pc_sockets
[socket
->socket
].drt_flags
;
1276 socket
->SocketCaps
= IF_IO
| IF_MEMORY
;
1277 socket
->ActiveHigh
= 3; /* 0 and 1 */
1278 socket
->ActiveLow
= 0;
1282 panic("lint panic");
1289 * drt_inquire_window()
1290 * SocketServices InquireWindow function
1291 * returns detailed characteristics of the window
1292 * this is where windows get tied to sockets
1295 drt_inquire_window(dev_info_t
*dip
, inquire_window_t
*window
)
1298 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1299 struct drt_window
*winp
;
1301 mem_win_char_t
*mem
;
1303 #if defined(DRT_DEBUG)
1306 "drt_inquire_window: win=%d\n", window
->window
);
1308 window
->WndCaps
= WC_COMMON
|WC_ATTRIBUTE
|WC_WAIT
|WC_IO
;
1310 /* get correct socket */
1311 socket
= window
->window
/ DRWINDOWS
;
1312 win
= window
->window
% DRWINDOWS
;
1313 winp
= &drt
->pc_sockets
[socket
].drt_windows
[win
];
1314 /* initialize the socket map - one socket per window */
1315 PR_ZERO(window
->Sockets
);
1316 PR_SET(window
->Sockets
, socket
);
1318 io
= &window
->iowin_char
;
1319 io
->IOWndCaps
= WC_CALIGN
|WC_IO_RANGE_PER_WINDOW
|WC_WENABLE
|
1320 WC_8BIT
|WC_16BIT
|WC_SIZE
;
1321 io
->FirstByte
= (baseaddr_t
)winp
->drtw_base
;
1322 io
->LastByte
= (baseaddr_t
)winp
->drtw_base
+ DRWINSIZE
;
1324 io
->MaxSize
= DRWINSIZE
;
1325 io
->ReqGran
= ddi_ptob(dip
, 1);
1326 io
->AddrLines
= DRADDRLINES
;
1329 mem
= &window
->mem_win_char
;
1330 mem
->MemWndCaps
= WC_CALIGN
|WC_WENABLE
|WC_8BIT
|WC_16BIT
;
1331 mem
->FirstByte
= (baseaddr_t
)winp
->drtw_base
;
1332 mem
->LastByte
= (baseaddr_t
)winp
->drtw_base
+ DRWINSIZE
;
1333 #if defined(DRT_DEBUG)
1335 cmn_err(CE_CONT
, "\tFirstByte=%p, LastByte=%p\n",
1336 (void *)mem
->FirstByte
, (void *)mem
->LastByte
);
1339 mem
->MinSize
= DRWINSIZE
;
1340 mem
->MaxSize
= DRWINSIZE
;
1341 mem
->ReqGran
= ddi_ptob(dip
, 1L);
1343 mem
->ReqOffset
= DRWINSIZE
;
1344 mem
->Slowest
= MEM_SPEED_MAX
;
1345 mem
->Fastest
= MEM_SPEED_MIN
;
1352 * SocketServices GetAdapter function
1353 * this is nearly a no-op.
1356 drt_get_adapter(dev_info_t
*dip
, get_adapter_t
*adapt
)
1358 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1360 if (drt
->pc_flags
& PCF_INTRENAB
)
1361 adapt
->SCRouting
= IRQ_ENABLE
;
1368 * SocketServices GetPage function
1369 * returns info about the window
1372 drt_get_page(dev_info_t
*dip
, get_page_t
*page
)
1375 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1376 struct drt_window
*winp
;
1378 window
= page
->window
% DRWINDOWS
;
1379 socket
= page
->window
/ DRWINDOWS
;
1381 winp
= &drt
->pc_sockets
[socket
].drt_windows
[window
];
1388 if (winp
->drtw_flags
& DRW_IO
)
1389 page
->state
|= PS_IO
;
1391 if (winp
->drtw_flags
& DRW_ENABLED
)
1392 page
->state
|= PS_ENABLED
;
1394 if (winp
->drtw_flags
& DRW_ATTRIBUTE
)
1395 page
->state
|= PS_ATTRIBUTE
;
1397 page
->offset
= (off_t
)winp
->drtw_addr
;
1404 * SocketServices GetSocket
1405 * returns information about the current socket settings
1408 drt_get_socket(dev_info_t
*dip
, get_socket_t
*socket
)
1410 int socknum
, irq_enabled
;
1411 drt_socket_t
*sockp
;
1412 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1414 socknum
= socket
->socket
;
1415 sockp
= &drt
->pc_sockets
[socknum
];
1417 socket
->SCIntMask
= sockp
->drt_intmask
;
1418 socket
->state
= sockp
->drt_state
;
1419 socket
->VccLevel
= sockp
->drt_vcc
;
1420 socket
->Vpp1Level
= sockp
->drt_vpp1
;
1421 socket
->Vpp2Level
= sockp
->drt_vpp2
;
1422 socket
->CtlInd
= 0; /* no indicators */
1423 irq_enabled
= (sockp
->drt_flags
& DRT_INTR_ENABLED
) ? IRQ_ENABLE
: 0;
1425 irq_enabled
|= (sockp
->drt_flags
& DRT_INTR_HIPRI
) ? IRQ_HIGH
: 0;
1427 socket
->IRQRouting
= sockp
->drt_irq
| irq_enabled
;
1428 socket
->IFType
= (sockp
->drt_flags
& DRT_SOCKET_IO
) ? IF_IO
: IF_MEMORY
;
1434 * SocketServices GetStatus
1435 * returns status information about the PC Card in
1436 * the selected socket
1439 drt_get_status(dev_info_t
*dip
, get_ss_status_t
*status
)
1441 int socknum
, irq_enabled
;
1442 drt_socket_t
*sockp
;
1443 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1444 #if defined(DRT_DEBUG)
1446 cmn_err(CE_CONT
, "drt_get_status: drt=%p\n", (void *)drt
);
1451 return (BAD_ADAPTER
);
1454 socknum
= status
->socket
;
1455 sockp
= &drt
->pc_sockets
[socknum
];
1457 status
->CardState
= drt_card_state(drt
, socknum
);
1458 status
->SocketState
= sockp
->drt_state
;
1459 status
->CtlInd
= 0; /* no indicators */
1460 irq_enabled
= (sockp
->drt_flags
& DRT_INTR_ENABLED
) ? IRQ_ENABLE
: 0;
1461 status
->IRQRouting
= sockp
->drt_irq
| irq_enabled
;
1462 status
->IFType
= (sockp
->drt_flags
& DRT_SOCKET_IO
) ?
1469 * SocketServices GetWindow function
1470 * returns state information about the specified window
1473 drt_get_window(dev_info_t
*dip
, get_window_t
*window
)
1476 drt_socket_t
*sockp
;
1477 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1478 struct drt_window
*winp
;
1480 if (window
->window
>= DRT_NUMWINDOWS
) {
1481 #if defined(DRT_DEBUG)
1483 cmn_err(CE_CONT
, "drt_get_window: failed\n");
1485 return (BAD_WINDOW
);
1487 socket
= window
->window
/ DRWINDOWS
;
1488 win
= window
->window
% DRWINDOWS
;
1489 window
->socket
= socket
;
1490 sockp
= &drt
->pc_sockets
[socket
];
1491 winp
= &sockp
->drt_windows
[win
];
1493 window
->size
= winp
->drtw_len
;
1494 window
->speed
= winp
->drtw_speed
;
1495 window
->base
= (uint32_t)(uintptr_t)winp
->drtw_reqaddr
;
1496 window
->handle
= winp
->drtw_handle
;
1499 if (winp
->drtw_flags
& DRW_IO
)
1500 window
->state
|= WS_IO
;
1502 if (winp
->drtw_flags
& DRW_ENABLED
)
1503 window
->state
|= WS_ENABLED
;
1504 #if defined(DRT_DEBUG)
1507 "drt_get_window: socket=%d, window=%d\n", socket
, win
);
1509 "\tsize=%d, speed=%d, base=%x, state=%x\n",
1510 window
->size
, (int)window
->speed
,
1520 * drt_ll_reset - This function handles the socket RESET signal timing and
1523 * There are two variables that control the RESET timing:
1524 * drt_prereset_time - time in mS before asserting RESET
1525 * drt_reset_time - time in mS to assert RESET
1527 * XXX - need to rethink RESET timing delays to avoid using drv_usecwait
1529 int drt_prereset_time
= 1;
1530 int drt_reset_time
= 5;
1533 drt_ll_reset(drt_dev_t
*drt
, int socket
)
1537 value
= drt
->pc_csr
->socket
[socket
].ctl0
;
1539 if (drt_prereset_time
> 0)
1540 drv_usecwait(drt_prereset_time
* 1000);
1542 /* turn reset on then off again */
1543 drt
->pc_csr
->socket
[socket
].ctl0
= value
| DRCTL_RESET
;
1545 if (drt_reset_time
> 0)
1546 drv_usecwait(drt_reset_time
* 1000);
1548 drt
->pc_csr
->socket
[socket
].ctl0
= value
& ~DRCTL_RESET
;
1550 #if defined(DRT_DEBUG)
1552 cmn_err(CE_CONT
, "drt_ll_reset: socket=%d, ctl0=%x, ctl1=%x\n",
1554 drt
->pc_csr
->socket
[socket
].ctl0
,
1555 drt
->pc_csr
->socket
[socket
].ctl1
);
1561 * put socket into known state on card insertion
1564 drt_new_card(drt_dev_t
*drt
, int socket
)
1566 drt
->pc_csr
->socket
[socket
].ctl0
= 0; /* off */
1567 drt
->pc_csr
->socket
[socket
].ctl0
= DRT_CHANGE_DEFAULT
; /* on */
1568 drt
->pc_csr
->socket
[socket
].ctl1
= 0;
1569 drt
->pc_sockets
[socket
].drt_state
= 0;
1570 drt
->pc_sockets
[socket
].drt_flags
= 0;
1574 * drt_reset_socket()
1575 * SocketServices ResetSocket function
1576 * puts the PC Card in the socket into the RESET state
1577 * and then takes it out after the the cycle time
1578 * The socket is back to initial state when done
1581 drt_reset_socket(dev_info_t
*dip
, int socket
, int mode
)
1583 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1585 drt_socket_t
*sockp
;
1587 mutex_enter(&drt
->pc_lock
); /* protect the registers */
1589 drt_ll_reset(drt
, socket
);
1591 if (mode
== RESET_MODE_FULL
) {
1592 /* need to unmap windows, etc. */
1594 drt
->pc_sockets
[socket
].drt_state
= 0;
1596 for (window
= 0, sockp
= &drt
->pc_sockets
[socket
];
1597 window
< DRT_NUMWINDOWS
; window
++) {
1598 sockp
->drt_windows
[window
].drtw_flags
&= ~DRW_ENABLED
;
1602 mutex_exit(&drt
->pc_lock
);
1607 * drt_set_interrupt()
1608 * SocketServices SetInterrupt function
1611 drt_set_interrupt(dev_info_t
*dip
, set_irq_handler_t
*handler
)
1614 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1616 #if defined(DRT_DEBUG)
1618 cmn_err(CE_CONT
, "drt_set_interrupt(%p, %p) pc_handlers=%p\n",
1619 (void *)dip
, (void *)handler
, (void *)drt
->pc_handlers
);
1622 intr
= (inthandler_t
*)kmem_zalloc(sizeof (inthandler_t
),
1628 intr
->intr
= (uint32_t (*)())handler
->handler
;
1629 intr
->handler_id
= handler
->handler_id
;
1630 intr
->arg1
= handler
->arg1
;
1631 intr
->arg2
= handler
->arg2
;
1632 intr
->socket
= handler
->socket
;
1633 intr
->irq
= handler
->irq
;
1634 mutex_enter(&drt
->pc_intr
);
1635 mutex_enter(&drt
->pc_lock
); /* protect the registers and structures */
1637 if (drt
->pc_handlers
== NULL
) {
1638 drt
->pc_handlers
= intr
;
1642 insque(intr
, drt
->pc_handlers
);
1645 /* interrupt handlers for both interrupts already done in attach */
1648 * need to fill in cookies in event of multiple high priority
1649 * interrupt handlers on same IRQ
1651 intr
->iblk_cookie
= drt
->pc_icookie_hi
;
1652 intr
->idev_cookie
= drt
->pc_dcookie_hi
;
1653 mutex_exit(&drt
->pc_lock
);
1654 mutex_exit(&drt
->pc_intr
);
1656 handler
->iblk_cookie
= &intr
->iblk_cookie
;
1657 handler
->idev_cookie
= &intr
->idev_cookie
;
1663 * drt_clear_interrupt()
1664 * SocketServices ClearInterrupt function
1665 * "What controls the socket interrupt?"
1668 drt_clear_interrupt(dev_info_t
*dip
, clear_irq_handler_t
*handler
)
1671 drt_dev_t
*drt
= drt_get_driver_private(dip
);
1672 inthandler_t
*intr
, *done
;
1674 #if defined(DRT_DEBUG)
1676 cmn_err(CE_CONT
, "drt_clear_interrupt(%p, %p) "
1677 "pc_handlers = %p\n",
1678 (void *)dip
, (void *)handler
, (void *)drt
->pc_handlers
);
1681 mutex_enter(&drt
->pc_lock
); /* protect the registers */
1683 for (intr
= drt
->pc_handlers
, done
= drt
->pc_handlers
;
1684 done
!= NULL
; /* empty */) {
1686 if (intr
->handler_id
== handler
->handler_id
) {
1687 /* Check if there is only one handler left */
1688 if ((intr
->next
== intr
) && (intr
->prev
== intr
)) {
1689 drt
->pc_handlers
= NULL
;
1691 if (drt
->pc_handlers
== intr
) {
1692 drt
->pc_handlers
= intr
->next
;
1696 kmem_free((caddr_t
)intr
, sizeof (inthandler_t
));
1704 mutex_exit(&drt
->pc_lock
);
1708 panic("lint panic");
1715 drt_stop_intr(drt_dev_t
*drt
, int socket
)
1720 mutex_enter(&drt
->pc_intr
);
1721 for (intr
= drt
->pc_handlers
, done
= 0; !done
&& intr
!= NULL
;
1722 intr
= intr
->next
) {
1723 if (socket
== intr
->socket
) {
1724 intr
->socket
|= 0x8000; /* make an illegal socket */
1726 if (intr
->next
== drt
->pc_handlers
)
1729 mutex_exit(&drt
->pc_intr
);
1734 drt_do_intr(drt_dev_t
*drt
, int socket
, int priority
)
1736 inthandler_t
*intr
, *done
;
1739 mutex_enter(&drt
->pc_intr
);
1741 #if defined(DRT_DEBUG)
1743 cmn_err(CE_CONT
, "drt_do_intr(%p, %d, %d)\n",
1744 (void *)drt
, socket
, priority
);
1748 * If we're suspended, then we don't need to process
1749 * any more interrupts. We have already (or will
1750 * shortly) be disabling all interrupts on the
1751 * adapter, but we still need to ACK any that
1752 * we receive and that the adapter has generated.
1753 * XXX - do we really want to do this here, or does it
1754 * make more sense to let the clients receive any
1755 * interrupts even as we're in the process of
1758 if (drt
->pc_flags
& PCF_SUSPENDED
) {
1759 mutex_exit(&drt
->pc_intr
);
1760 return (DDI_INTR_CLAIMED
);
1763 #if defined(DRT_DEBUG)
1764 if (drt_debug
&& drt
->pc_handlers
== NULL
)
1765 cmn_err(CE_CONT
, "drt_do_intr: pc_handlers == NULL\n");
1767 for (intr
= drt
->pc_handlers
, done
= drt
->pc_handlers
;
1768 done
!= NULL
&& intr
!= NULL
; intr
= intr
->next
) {
1769 #if defined(DRT_DEBUG)
1772 "\tintr-> socket=%d, priority=%d, intr=%p,"
1773 "arg1=%p arg2=%p (drt_flags=%x:%s)\n",
1774 intr
->socket
, intr
->priority
,
1775 (void *)intr
->intr
, intr
->arg1
, intr
->arg2
,
1776 drt
->pc_sockets
[socket
].drt_flags
,
1777 (drt
->pc_sockets
[socket
].drt_flags
&
1782 /* may need to rethink the priority stuff */
1783 if (socket
== intr
->socket
&&
1784 (priority
^ (intr
->priority
< 10)) &&
1785 drt
->pc_sockets
[socket
].drt_flags
& DRT_INTR_ENABLED
) {
1786 result
|= (*intr
->intr
)(intr
->arg
);
1789 result
|= (*intr
->intr
)(intr
->arg1
, intr
->arg2
);
1791 if (done
== intr
->next
)
1794 /* do a round robin adjust */
1795 if (drt
->pc_handlers
!= NULL
)
1796 drt
->pc_handlers
= drt
->pc_handlers
->next
;
1797 mutex_exit(&drt
->pc_intr
);
1802 drt_hi_intr(caddr_t arg
)
1804 drt_dev_t
*drt
= drt_get_driver_private((dev_info_t
*)arg
);
1805 int i
, intr_sockets
= 0;
1806 int result
, changes
;
1808 mutex_enter(&drt
->pc_lock
);
1810 #if defined(DRT_DEBUG)
1812 cmn_err(CE_CONT
, "drt_hi_intr: entered\n");
1816 * need to change to only ACK and touch the slot that
1817 * actually caused the interrupt. Currently everything
1820 * we need to look at all known sockets to determine
1821 * what might have happened, so step through the list
1826 for (i
= 0; i
< DRSOCKETS
; i
++) {
1828 int x
= drt
->pc_cb_arg
;
1829 drt_socket_t
*sockp
;
1831 sockp
= &drt
->pc_sockets
[i
];
1833 if (drt
->pc_csr
->socket
[i
].ctl0
& DRCTL_IFTYPE
)
1836 card_type
= IF_MEMORY
;
1838 changes
= drt
->pc_csr
->socket
[i
].stat0
;
1839 #if defined(DRT_DEBUG)
1841 cmn_err(CE_CONT
, "\tstat0=%x, type=%s\n",
1842 changes
, card_type
== IF_IO
? "IO":"MEM");
1844 /* ack the interrupts we see */
1845 drt
->pc_csr
->socket
[i
].stat0
= (ushort_t
)changes
;
1847 if (changes
& DRSTAT_SCINT
) {
1848 #if defined(DRT_DEBUG)
1851 "\tcard status change interrupt"
1852 " on socket %d\n", i
);
1855 * We set the result here mainly for IF_MEMORY cases.
1856 * The drt_do_intr() call at the end of this for loop
1857 * will not be called for IF_MEMORY cases since
1858 * intr_sockets are set ONLY for IF_IO cases.
1860 result
|= DDI_INTR_CLAIMED
;
1862 /* there was a valid interrupt on status change */
1863 if (drt
->pc_callback
== NULL
) {
1867 if (changes
& DRSTAT_CDCHG
) {
1868 if ((sockp
->drt_flags
&
1869 DRT_CARD_PRESENT
) &&
1870 (changes
& DRSTAT_CD_MASK
) !=
1871 DRSTAT_PRESENT_OK
) {
1875 * stop interrupt handler
1876 * then do the callback
1878 drt_stop_intr(drt
, i
);
1880 * XXX - note that drt_new_card will
1881 * clear sockp->drt_flags
1883 drt_new_card(drt
, i
); /* paranoia */
1884 PC_CALLBACK(drt
, arg
, x
,
1885 PCE_CARD_REMOVAL
, i
);
1888 if ((changes
& DRSTAT_CD_MASK
) ==
1889 DRSTAT_PRESENT_OK
&&
1890 !(sockp
->drt_flags
&
1891 DRT_CARD_PRESENT
)) {
1892 drt_new_card(drt
, i
);
1893 drt_ll_reset(drt
, i
);
1894 sockp
->drt_state
|= SBM_CD
;
1895 drt_socket_card_id(drt
,
1898 PC_CALLBACK(drt
, arg
, x
,
1905 * since other events may be the result of
1906 * "bounce", don't check them on this pass.
1907 * The insert code will check them anyway.
1912 /* Ready/Change Detect */
1913 #if defined(DRT_DEBUG)
1914 if (drt_debug
&& changes
& DRSTAT_RDYCHG
)
1915 cmn_err(CE_CONT
, "\trdychg: stat=%x, type=%s\n",
1917 card_type
== IF_MEMORY
?
1920 if (card_type
== IF_MEMORY
&&
1921 changes
& DRSTAT_RDYCHG
&&
1922 changes
& DRSTAT_RDYST
) {
1923 sockp
->drt_state
|= SBM_RDYBSY
;
1924 PC_CALLBACK(drt
, arg
, x
, PCE_CARD_READY
, i
);
1927 /* write protect switch moved */
1928 if (card_type
== IF_MEMORY
&& changes
& DRSTAT_WPCHG
) {
1929 if (changes
& DRSTAT_WPST
)
1930 sockp
->drt_state
|= SBM_WP
;
1932 sockp
->drt_state
&= ~SBM_WP
;
1933 PC_CALLBACK(drt
, arg
, x
,
1934 PCE_CARD_WRITE_PROTECT
, i
);
1937 if (card_type
== IF_MEMORY
&&
1938 changes
& DRSTAT_BVDCHG
) {
1940 * there was a change in battery state.
1941 * this could be a false alarm at
1942 * card insertion but could be real.
1943 * The individual change bits aren't
1944 * meaningful so look at the live
1945 * status and latch that
1947 switch (changes
& DRSTAT_BVDST
) {
1948 case DRSTAT_BATT_LOW
:
1949 if (!(sockp
->drt_flags
&
1953 sockp
->drt_state
|= SBM_BVD2
;
1954 sockp
->drt_state
&= ~SBM_BVD1
;
1955 PC_CALLBACK(drt
, arg
, x
,
1956 PCE_CARD_BATTERY_WARN
,
1960 case DRSTAT_BATT_OK
:
1965 ~(SBM_BVD1
|SBM_BVD2
);
1967 default: /* battery failed */
1968 if (!(sockp
->drt_flags
&
1969 DRT_BATTERY_DEAD
)) {
1970 /* so we only see one of them */
1975 sockp
->drt_state
|= SBM_BVD1
;
1976 PC_CALLBACK(drt
, arg
, x
,
1977 PCE_CARD_BATTERY_DEAD
,
1982 if (card_type
== IF_IO
&&
1983 !(changes
& DRSTAT_BVD1ST
)) {
1985 * Disable status change interrupts. We
1986 * will enable them again later after
1987 * Card Services has processed this
1990 drt
->pc_csr
->socket
[i
].ctl0
&=
1993 /* we have an I/O status change */
1994 PC_CALLBACK(drt
, arg
, x
,
1995 PCE_CARD_STATUS_CHANGE
,
2000 * need to reexamine this section to see what really
2003 /* Battery Warn Detect */
2004 if (changes
& DRSTAT_BVD2CHG
) {
2005 if (card_type
== IF_MEMORY
&&
2006 !(sockp
->drt_flags
& DRT_BATTERY_LOW
)) {
2007 sockp
->drt_flags
|= DRT_BATTERY_LOW
;
2008 sockp
->drt_state
|= SBM_BVD2
;
2009 PC_CALLBACK(drt
, arg
, x
,
2010 PCE_CARD_BATTERY_WARN
,
2012 } else if (card_type
== IF_IO
) {
2013 PC_CALLBACK(drt
, arg
, x
,
2014 PCE_CARD_STATUS_CHANGE
,
2019 /* Battery Fail Detect */
2020 if (card_type
== IF_MEMORY
&&
2021 changes
& DRSTAT_BVD1CHG
&&
2022 !(sockp
->drt_flags
& DRT_BATTERY_DEAD
)) {
2023 /* so we only see one of them */
2024 sockp
->drt_flags
|= DRT_BATTERY_DEAD
;
2025 sockp
->drt_state
|= SBM_BVD1
;
2026 PC_CALLBACK(drt
, arg
, x
,
2027 PCE_CARD_BATTERY_DEAD
, i
);
2031 /* now flag any PC Card interrupts */
2032 if (card_type
== IF_IO
&& changes
& DRSTAT_IOINT
) {
2033 intr_sockets
|= 1 << i
;
2035 #if defined(DRT_DEBUG)
2037 cmn_err(CE_CONT
, "\tsocket %d: ctl0=%x, ctl1=%x\n",
2039 drt
->pc_csr
->socket
[i
].ctl0
,
2040 drt
->pc_csr
->socket
[i
].ctl1
);
2044 mutex_exit(&drt
->pc_lock
);
2046 for (i
= 0; i
< DRSOCKETS
; i
++) {
2047 if (intr_sockets
& (1 << i
))
2048 result
|= drt_do_intr(drt
, i
, 1);
2051 if (changes
& DRSTAT_SCINT
|| result
|| intr_sockets
)
2052 return (DDI_INTR_CLAIMED
);
2053 if (drt
->pc_flags
& PCF_ATTACHING
) {
2054 drt
->pc_flags
&= ~PCF_ATTACHING
;
2055 return (DDI_INTR_CLAIMED
);
2058 return (DDI_INTR_UNCLAIMED
);
2062 drt_lo_intr(caddr_t arg
)
2064 drt_dev_t
*drt
= drt_get_driver_private((dev_info_t
*)arg
);
2067 #if defined(DRT_DEBUG)
2069 cmn_err(CE_CONT
, "drt_lo_intr(%p)\n", (void *)arg
);
2072 * we need to look at all known sockets to determine
2073 * what might have happened, so step through the list
2077 /* XXX is this the lost interrupt problem?? XXX */
2078 for (i
= 0, result
= 0; i
< drt
->pc_numsockets
; i
++) {
2079 if (drt
->pc_csr
->socket
[i
].stat0
& DRSTAT_IOINT
) {
2080 #if defined(DRT_DEBUG)
2082 cmn_err(CE_CONT
, "\tsocket=%x, stat0=%x\n",
2083 i
, drt
->pc_csr
->socket
[i
].stat0
);
2085 result
|= drt_do_intr(drt
, i
, 0);
2086 drt
->pc_csr
->socket
[i
].stat0
|= DRSTAT_IOINT
;
2090 return (DDI_INTR_CLAIMED
);
2091 return (DDI_INTR_UNCLAIMED
);
2095 * drt_socket_card_id()
2096 * figure out current status of card in socket
2097 * this is used to prevent callbacks at card insertion
2101 drt_socket_card_id(drt_dev_t
*drt
, drt_socket_t
*socket
, int status
)
2104 /* need to record if a card is present to init state */
2105 if ((status
& DRSTAT_CD_MASK
) == DRSTAT_PRESENT_OK
)
2106 socket
->drt_flags
|= DRT_CARD_PRESENT
;
2108 /* check battery state to avoid callbacks */
2109 switch (status
& DRSTAT_BVDST
) {
2110 case DRSTAT_BATT_LOW
:
2111 socket
->drt_flags
|= DRT_BATTERY_LOW
;
2112 socket
->drt_flags
&= ~DRT_BATTERY_DEAD
;
2113 socket
->drt_state
|= SBM_BVD2
;
2114 socket
->drt_state
&= ~SBM_BVD1
;
2116 case DRSTAT_BATT_OK
:
2117 socket
->drt_flags
&= ~(DRT_BATTERY_LOW
|DRT_BATTERY_DEAD
);
2118 socket
->drt_state
&= ~(SBM_BVD1
|SBM_BVD2
);
2122 socket
->drt_flags
|= DRT_BATTERY_DEAD
;
2123 socket
->drt_state
|= SBM_BVD1
;
2127 /* check write protect status */
2128 if (status
& DRSTAT_WPST
)
2129 socket
->drt_state
|= SBM_WP
;
2131 socket
->drt_state
&= ~SBM_WP
;
2133 /* and ready/busy */
2134 if (status
& DRSTAT_RDYST
)
2135 socket
->drt_state
|= SBM_RDYBSY
;
2137 socket
->drt_state
&= ~SBM_RDYBSY
;
2140 #if defined(DRT_DEBUG)
2142 drt_dmp_regs(stp4020_socket_csr_t
*csrp
)
2146 cmn_err(CE_CONT
, "drt_dmp_regs (%p):\n", (void *)csrp
);
2147 cmn_err(CE_CONT
, "\tctl0: %b\n", csrp
->ctl0
,
2148 "\020\1IFTYPE\2SFTRST\3SPKREN\4IOILVL\5IOIE\6RSVD"
2149 "\7CTOIE\010WPIE\011RDYIE\012BVD1IE\013BVD2IE\014CDIE"
2150 "\015SCILVL\016PROMEN\017RSVDX");
2152 "\tctl1: %b\n", csrp
->ctl1
,
2153 "\020\1PCIFOE\1MSTPWR\7APWREN"
2154 "\10RSVD\11DIAGEN\12WAITDB\13WPDB\14RDYDB\15BVD1DB\16BVD2DB"
2155 "\17CD1DB\20LPBKEN");
2157 "\tstat0: %b\n", csrp
->stat0
,
2158 "\020\1PWRON\2WAITST\3WPST"
2159 "\4RDYST\5BVD1ST\6BVD2ST\7CD1ST\10CD2ST\11PCTO\12WPCHG"
2160 "\13RDCHG\14BVD1CHG\15BVD2CHG\16CDCHG\17SCINT\20IOINT");
2162 "\tstat1: types=%x, rev=%x\n",
2163 (int)(csrp
->stat1
& DRSTAT_PCTYS_M
),
2164 csrp
->stat1
& DRSTAT_REV_M
);
2165 for (i
= 0; i
< 3; i
++) {
2166 cmn_err(CE_CONT
, "\twin%d:\tctl0: cmdlng=%x, cmddly=%x, "
2167 "aspsel=%x, base=%x\n", i
,
2168 GET_DRWIN_CMDLNG(csrp
->window
[i
].ctl0
),
2169 GET_DRWIN_CMDDLY(csrp
->window
[i
].ctl0
),
2170 csrp
->window
[i
].ctl0
& DRWIN_ASPSEL_M
,
2171 GET_DRWIN_BASE(csrp
->window
[i
].ctl0
));
2172 cmn_err(CE_CONT
, "\t\tctl1: %x\n", csrp
->window
[i
].ctl1
);
2179 * drt_cpr - save/restore the adapter's hardware state
2182 drt_cpr(drt_dev_t
*drt
, int cmd
)
2187 case DRT_SAVE_HW_STATE
:
2188 for (sn
= 0; sn
< DRSOCKETS
; sn
++) {
2189 stp4020_socket_csr_t
*drs
= &drt
->pc_csr
->socket
[sn
];
2190 for (wn
= 0; wn
< DRWINDOWS
; wn
++) {
2191 drt
->saved_socket
[sn
].window
[wn
].ctl0
=
2192 drs
->window
[wn
].ctl0
;
2193 drt
->saved_socket
[sn
].window
[wn
].ctl1
=
2194 drs
->window
[wn
].ctl1
;
2196 drt
->saved_socket
[sn
].ctl0
= drs
->ctl0
;
2197 drt
->saved_socket
[sn
].ctl1
= drs
->ctl1
;
2200 case DRT_RESTORE_HW_STATE
:
2201 for (sn
= 0; sn
< DRSOCKETS
; sn
++) {
2202 stp4020_socket_csr_t
*drs
= &drt
->pc_csr
->socket
[sn
];
2203 for (wn
= 0; wn
< DRWINDOWS
; wn
++) {
2204 drs
->window
[wn
].ctl0
=
2205 drt
->saved_socket
[sn
].window
[wn
].ctl0
;
2206 drs
->window
[wn
].ctl1
=
2207 drt
->saved_socket
[sn
].window
[wn
].ctl1
;
2210 /* work around for false status bugs */
2211 /* XXX - why 0x3FFF and not 0xFFFF?? */
2212 drs
->stat0
= 0x3FFF;
2213 drs
->stat1
= 0x3FFF;
2215 drs
->ctl0
= drt
->saved_socket
[sn
].ctl0
;
2216 drs
->ctl1
= drt
->saved_socket
[sn
].ctl1
;
2225 * if the adapter predates 1275 properties, add them.
2226 * We do this by checking presence of the property
2227 * and adding what we know if properties not present
2231 drt_fixprops(dev_info_t
*dip
)
2235 * note that there are a number of properties that
2236 * should be added here if not present
2246 * allocate an stpramap structure.
2252 struct stpramap
*new;
2253 mutex_enter(&stpra_lock
);
2255 if (stpra_freelist
!= NULL
) {
2256 new = stpra_freelist
;
2257 stpra_freelist
= new->ra_next
;
2259 mutex_exit(&stpra_lock
);
2261 new = (struct stpramap
*)kmem_zalloc(sizeof (struct stpramap
),
2264 bzero((caddr_t
)new, sizeof (struct stpramap
));
2270 * stpra_free_map(map)
2271 * return a used map to the freelist.
2272 * Should probably check to see if above
2273 * some threshold and kmem_free() any excess
2276 stpra_free_map(struct stpramap
*map
)
2279 mutex_enter(&stpra_lock
);
2280 map
->ra_next
= stpra_freelist
;
2281 stpra_freelist
= map
;
2282 mutex_exit(&stpra_lock
);
2288 * stpra_free(map, base, len)
2289 * return the specified range (base to base+len)
2290 * to the specified map
2294 stpra_free(struct stpramap
**map
, uint32_t base
, uint32_t len
)
2296 struct stpramap
*newmap
, *oldmap
= NULL
;
2297 struct stpramap
*mapp
, *backp
;
2298 uint32_t newbase
, mapend
;
2301 * always allocate a map entry so we can manipulate
2302 * things without blocking inside our lock
2304 newmap
= stpra_alloc_map();
2307 mutex_enter(&stpra_lock
);
2310 backp
= (struct stpramap
*)map
;
2312 /* now find where range lies and fix things up */
2313 newbase
= base
+ len
;
2314 for (; mapp
!= NULL
; backp
= mapp
, mapp
= mapp
->ra_next
) {
2315 mapend
= mapp
->ra_base
+ mapp
->ra_len
;
2318 * special case: sum is larger than 32bit
2320 mapend
= mapp
->ra_len
;
2322 if (newbase
== mapp
->ra_base
) {
2323 /* simple - on front */
2324 mapp
->ra_base
= base
;
2325 mapp
->ra_len
+= len
;
2327 * don't need to check if it merges with
2328 * previous since that would match on on end
2331 } else if (newbase
== mapend
) {
2332 /* simple - on end */
2333 mapp
->ra_len
+= len
;
2334 if (mapp
->ra_next
&& newbase
==
2335 mapp
->ra_next
->ra_base
) {
2336 /* merge with next node */
2337 oldmap
= mapp
->ra_next
;
2338 mapp
->ra_len
+= oldmap
->ra_len
;
2339 mapp
->ra_next
= oldmap
->ra_next
;
2342 } else if (base
< mapp
->ra_base
) {
2343 /* somewhere in between so just an insert */
2344 newmap
->ra_base
= base
;
2345 newmap
->ra_len
= len
;
2346 newmap
->ra_next
= mapp
;
2347 backp
->ra_next
= newmap
;
2351 /* else haven't found the spot yet */
2354 /* special case of running off the end - stick on end */
2355 newmap
->ra_base
= base
;
2356 newmap
->ra_len
= len
;
2357 backp
->ra_next
= newmap
;
2360 mutex_exit(&stpra_lock
);
2362 stpra_free_map(newmap
);
2364 stpra_free_map(oldmap
);
2368 * stpra_alloc(map, reqest, return)
2369 * Allocate a memory-like resource (physical memory, I/O space)
2370 * subject to the constraints defined in the request structure.
2374 stpra_alloc(struct stpramap
**map
, stpra_request_t
*req
, stpra_return_t
*ret
)
2376 struct stpramap
*mapp
, *backp
;
2377 struct stpramap
*newmap
, *old
= NULL
;
2380 int newlen
, rval
= DDI_FAILURE
;
2381 uint32_t base
, lower
, upper
;
2383 if (req
->ra_flags
& STP_RA_ALLOC_SPECIFIED
)
2384 type
= STP_RA_ALLOC_SPECIFIED
;
2388 if (req
->ra_flags
& (STP_RA_ALLOC_POW2
|STP_RA_ALIGN_SIZE
)) {
2389 if (req
->ra_len
!= stpra_fix_pow2(req
->ra_len
)) {
2390 #if defined(DRT_DEBUG)
2392 cmn_err(CE_WARN
, "ra: bad length (pow2) %d\n",
2395 ret
->ra_addr_hi
= 0;
2396 ret
->ra_addr_lo
= 0;
2398 return (DDI_FAILURE
);
2401 mask
= req
->ra_align
;
2402 if (req
->ra_flags
& STP_RA_ALIGN_SIZE
) {
2403 len
= stpra_fix_pow2(req
->ra_len
);
2405 #if defined(DRT_DEBUG)
2407 cmn_err(CE_CONT
, "len=%d, mask=%x\n", len
, mask
);
2411 newmap
= stpra_alloc_map(); /* just in case */
2413 mutex_enter(&stpra_lock
);
2416 #if defined(DRT_DEBUG)
2418 cmn_err(CE_CONT
, "stpra_alloc: mapp = %p\n",
2422 backp
= (struct stpramap
*)map
;
2427 upper
= ~(uint32_t)0;
2431 if (type
!= STP_RA_ALLOC_SPECIFIED
) {
2432 /* first fit - not user specified */
2433 #if defined(DRT_DEBUG)
2435 cmn_err(CE_CONT
, "stpra_alloc(unspecified request)"
2436 "lower=%x, upper=%x\n", lower
, upper
);
2438 for (; mapp
!= NULL
; backp
= mapp
, mapp
= mapp
->ra_next
) {
2439 #if defined(DRT_DEBUG)
2441 cmn_err(CE_CONT
, "stpra_alloc: ra_len = %x, len = %x",
2445 if (mapp
->ra_len
>= len
) {
2446 /* a candidate -- apply constraints */
2447 base
= mapp
->ra_base
;
2449 (base
+ mapp
->ra_len
) < (lower
+ len
)) {
2450 if (((base
+ mapp
->ra_len
) != 0) ||
2451 ((base
+ mapp
->ra_len
) >
2453 /* same as the above case */
2458 #if defined(DRT_DEBUG)
2461 "\tbase=%x, ra_base=%x,"
2463 base
, mapp
->ra_base
, mask
);
2465 if ((mapp
->ra_base
& mask
) != 0) {
2467 * failed a critical constraint
2468 * adjust and see if it still fits
2470 base
= mapp
->ra_base
& ~mask
;
2472 #if defined(DRT_DEBUG)
2478 if (len
> (mapp
->ra_len
-
2479 (base
- mapp
->ra_base
)))
2483 #if defined(DRT_DEBUG)
2485 cmn_err(CE_CONT
, "\thave a fit\n");
2488 upper
= upper
; /* need to check upper bound */
2490 if (base
!= mapp
->ra_base
) {
2491 /* in the middle or end */
2492 newlen
= base
- mapp
->ra_base
;
2493 if ((mapp
->ra_len
- newlen
) == len
) {
2495 mapp
->ra_len
= newlen
;
2497 newmap
->ra_next
= mapp
->ra_next
;
2498 newmap
->ra_base
= base
+ len
;
2499 newmap
->ra_len
= mapp
->ra_len
-
2501 mapp
->ra_len
= newlen
;
2502 mapp
->ra_next
= newmap
;
2507 /* at the beginning */
2508 mapp
->ra_base
+= len
;
2509 mapp
->ra_len
-= len
;
2510 if (mapp
->ra_len
== 0) {
2511 /* remove the whole node */
2512 backp
->ra_next
= mapp
->ra_next
;
2521 /* want an exact value/fit */
2522 base
= req
->ra_addr_lo
;
2524 for (; mapp
!= NULL
; backp
= mapp
, mapp
= mapp
->ra_next
) {
2525 if (base
>= mapp
->ra_base
&&
2526 base
< (mapp
->ra_base
+ mapp
->ra_len
)) {
2527 /* this is the node */
2529 (mapp
->ra_base
+ mapp
->ra_len
)) {
2533 /* this is the one */
2534 if (base
== mapp
->ra_base
) {
2536 mapp
->ra_base
+= len
;
2537 mapp
->ra_len
-= len
;
2538 if (mapp
->ra_len
== 0) {
2545 /* on the end or in middle */
2550 mapp
->ra_len
-= len
;
2555 newbase
= base
+ len
;
2562 newmap
->ra_len
= newlen
;
2565 mapp
->ra_next
= newmap
;
2578 mutex_exit(&stpra_lock
);
2581 stpra_free_map(old
);
2583 stpra_free_map(newmap
);
2586 if (rval
== DDI_SUCCESS
) {
2587 ret
->ra_addr_hi
= 0;
2588 ret
->ra_addr_lo
= base
;
2589 ret
->ra_len
= req
->ra_len
;
2598 * stpra_fix_pow2(value)
2599 * a utility function which rounds up to the
2600 * nearest power of two value.
2604 stpra_fix_pow2(uint32_t value
)
2608 if (ddi_ffs(value
) == ddi_fls(value
))
2610 /* not a power of two so round up */
2612 /* this works since ffs/fls is plus 1 */
2613 #if defined(DRT_DEBUG)
2615 cmn_err(CE_CONT
, "stpra_fix_pow2(%x)->%x:%x\n", value
, i
,
2618 "\tffs=%d, fls=%d\n", ddi_ffs(value
), ddi_fls(value
));