12305Sstevel /*
22305Sstevel * CDDL HEADER START
32305Sstevel *
42305Sstevel * The contents of this file are subject to the terms of the
52305Sstevel * Common Development and Distribution License (the "License").
62305Sstevel * You may not use this file except in compliance with the License.
72305Sstevel *
82305Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92305Sstevel * or http://www.opensolaris.org/os/licensing.
102305Sstevel * See the License for the specific language governing permissions
112305Sstevel * and limitations under the License.
122305Sstevel *
132305Sstevel * When distributing Covered Code, include this CDDL HEADER in each
142305Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152305Sstevel * If applicable, add the following below this CDDL HEADER, with the
162305Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
172305Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
182305Sstevel *
192305Sstevel * CDDL HEADER END
202305Sstevel */
212305Sstevel
222305Sstevel /*
237151Srw148561 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
242305Sstevel * Use is subject to license terms.
252305Sstevel */
262305Sstevel
272305Sstevel /*
282305Sstevel * PCIC device/interrupt handler
292305Sstevel * The "pcic" driver handles the Intel 82365SL, Cirrus Logic
302305Sstevel * and Toshiba (and possibly other clones) PCMCIA adapter chip
312305Sstevel * sets. It implements a subset of Socket Services as defined
322305Sstevel * in the Solaris PCMCIA design documents
332305Sstevel */
342305Sstevel
352305Sstevel /*
362305Sstevel * currently defined "properties"
372305Sstevel *
382305Sstevel * clock-frequency bus clock frequency
392305Sstevel * smi system management interrupt override
402305Sstevel * need-mult-irq need status IRQ for each pair of sockets
412305Sstevel * disable-audio don't route audio signal to speaker
422305Sstevel */
432305Sstevel
442305Sstevel
452305Sstevel #include <sys/types.h>
462305Sstevel #include <sys/inttypes.h>
472305Sstevel #include <sys/param.h>
482305Sstevel #include <sys/systm.h>
492305Sstevel #include <sys/user.h>
502305Sstevel #include <sys/buf.h>
512305Sstevel #include <sys/file.h>
522305Sstevel #include <sys/uio.h>
532305Sstevel #include <sys/conf.h>
542305Sstevel #include <sys/stat.h>
552305Sstevel #include <sys/autoconf.h>
562305Sstevel #include <sys/vtoc.h>
572305Sstevel #include <sys/dkio.h>
582305Sstevel #include <sys/ddi.h>
592305Sstevel #include <sys/sunddi.h>
602305Sstevel #include <sys/sunndi.h>
612305Sstevel #include <sys/var.h>
622305Sstevel #include <sys/callb.h>
632305Sstevel #include <sys/open.h>
642305Sstevel #include <sys/ddidmareq.h>
652305Sstevel #include <sys/dma_engine.h>
662305Sstevel #include <sys/kstat.h>
672305Sstevel #include <sys/kmem.h>
682305Sstevel #include <sys/modctl.h>
692305Sstevel #include <sys/pci.h>
702305Sstevel #include <sys/pci_impl.h>
712305Sstevel
722305Sstevel #include <sys/pctypes.h>
732305Sstevel #include <sys/pcmcia.h>
742305Sstevel #include <sys/sservice.h>
752305Sstevel
762305Sstevel #include <sys/note.h>
772305Sstevel
782305Sstevel #include <sys/pcic_reg.h>
792305Sstevel #include <sys/pcic_var.h>
802305Sstevel
817493SVincent.Wang@Sun.COM #if defined(__i386) || defined(__amd64)
827493SVincent.Wang@Sun.COM #include <sys/pci_cfgspace.h>
837493SVincent.Wang@Sun.COM #endif
847493SVincent.Wang@Sun.COM
852305Sstevel #if defined(__sparc)
862305Sstevel #include <sys/pci/pci_nexus.h>
872305Sstevel #endif
882305Sstevel
892451Srw148561 #include <sys/hotplug/hpcsvc.h>
902305Sstevel #include "cardbus/cardbus.h"
912305Sstevel
922305Sstevel #define SOFTC_SIZE (sizeof (anp_t))
932305Sstevel
942305Sstevel static int pcic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
952305Sstevel static int pcic_attach(dev_info_t *, ddi_attach_cmd_t);
962305Sstevel static int pcic_detach(dev_info_t *, ddi_detach_cmd_t);
97*8099SQuaker.Fang@Sun.COM static int32_t pcic_quiesce(dev_info_t *);
982305Sstevel static uint_t pcic_intr(caddr_t, caddr_t);
992305Sstevel static int pcic_do_io_intr(pcicdev_t *, uint32_t);
1002305Sstevel static int pcic_probe(dev_info_t *);
1012305Sstevel
1022305Sstevel static int pcic_open(dev_t *, int, int, cred_t *);
1032305Sstevel static int pcic_close(dev_t, int, int, cred_t *);
1042305Sstevel static int pcic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1052305Sstevel
1062305Sstevel typedef struct pcm_regs pcm_regs_t;
1072305Sstevel
1082305Sstevel static void pcic_init_assigned(dev_info_t *);
1092305Sstevel static int pcic_apply_avail_ranges(dev_info_t *, pcm_regs_t *,
1102305Sstevel pci_regspec_t *, int);
1112305Sstevel int pci_resource_setup_avail(dev_info_t *, pci_regspec_t *, int);
1122305Sstevel
1132305Sstevel /*
1142305Sstevel * On x86 platforms the ddi_iobp_alloc(9F) and ddi_mem_alloc(9F) calls
1152305Sstevel * are xlated into DMA ctlops. To make this nexus work on x86, we
1162305Sstevel * need to have the default ddi_dma_mctl ctlops in the bus_ops
1172305Sstevel * structure, just to pass the request to the parent. The correct
1182305Sstevel * ctlops should be ddi_no_dma_mctl because so far we don't do DMA.
1192305Sstevel */
1202305Sstevel static
1212305Sstevel struct bus_ops pcmciabus_ops = {
1222305Sstevel BUSO_REV,
1232305Sstevel pcmcia_bus_map,
1242305Sstevel NULL,
1252305Sstevel NULL,
1262305Sstevel NULL,
1272305Sstevel i_ddi_map_fault,
1282305Sstevel ddi_no_dma_map,
1292305Sstevel ddi_no_dma_allochdl,
1302305Sstevel ddi_no_dma_freehdl,
1312305Sstevel ddi_no_dma_bindhdl,
1322305Sstevel ddi_no_dma_unbindhdl,
1332305Sstevel ddi_no_dma_flush,
1342305Sstevel ddi_no_dma_win,
1352305Sstevel ddi_dma_mctl,
1362305Sstevel pcmcia_ctlops,
1372305Sstevel pcmcia_prop_op,
1382305Sstevel NULL, /* (*bus_get_eventcookie)(); */
1392305Sstevel NULL, /* (*bus_add_eventcall)(); */
1402305Sstevel NULL, /* (*bus_remove_eventcall)(); */
1412305Sstevel NULL, /* (*bus_post_event)(); */
1422305Sstevel NULL, /* (*bus_intr_ctl)(); */
1432305Sstevel NULL, /* (*bus_config)(); */
1442305Sstevel NULL, /* (*bus_unconfig)(); */
1452305Sstevel NULL, /* (*bus_fm_init)(); */
1462305Sstevel NULL, /* (*bus_fm_fini)(); */
1472305Sstevel NULL, /* (*bus_enter)() */
1482305Sstevel NULL, /* (*bus_exit)() */
1492305Sstevel NULL, /* (*bus_power)() */
1502305Sstevel pcmcia_intr_ops /* (*bus_intr_op)(); */
1512305Sstevel };
1522305Sstevel
1532305Sstevel static struct cb_ops pcic_cbops = {
1542305Sstevel pcic_open,
1552305Sstevel pcic_close,
1562305Sstevel nodev,
1572305Sstevel nodev,
1582305Sstevel nodev,
1592305Sstevel nodev,
1602305Sstevel nodev,
1612305Sstevel pcic_ioctl,
1622305Sstevel nodev,
1632305Sstevel nodev,
1642305Sstevel nodev,
1652305Sstevel nochpoll,
1662305Sstevel ddi_prop_op,
1672305Sstevel NULL,
1682305Sstevel #ifdef CARDBUS
1692305Sstevel D_NEW | D_MP | D_HOTPLUG
1702305Sstevel #else
1712305Sstevel D_NEW | D_MP
1722305Sstevel #endif
1732305Sstevel };
1742305Sstevel
1752305Sstevel static struct dev_ops pcic_devops = {
1762305Sstevel DEVO_REV,
1772305Sstevel 0,
1782305Sstevel pcic_getinfo,
1792305Sstevel nulldev,
1802305Sstevel pcic_probe,
1812305Sstevel pcic_attach,
1822305Sstevel pcic_detach,
1832305Sstevel nulldev,
1842305Sstevel &pcic_cbops,
1852305Sstevel &pcmciabus_ops,
1867656SSherry.Moore@Sun.COM NULL,
187*8099SQuaker.Fang@Sun.COM pcic_quiesce, /* devo_quiesce */
1882305Sstevel };
1892305Sstevel
1902305Sstevel void *pcic_soft_state_p = NULL;
1912305Sstevel static int pcic_maxinst = -1;
1922305Sstevel
1932305Sstevel int pcic_do_insertion = 1;
1942305Sstevel int pcic_do_removal = 1;
1952305Sstevel
1962305Sstevel struct irqmap {
1972305Sstevel int irq;
1982305Sstevel int count;
1992305Sstevel } pcic_irq_map[16];
2002305Sstevel
2012305Sstevel
2022305Sstevel int pcic_debug = 0x0;
2032305Sstevel static void pcic_err(dev_info_t *dip, int level, const char *fmt, ...);
2042305Sstevel extern void cardbus_dump_pci_config(dev_info_t *dip);
2052305Sstevel extern void cardbus_dump_socket(dev_info_t *dip);
2062305Sstevel extern int cardbus_validate_iline(dev_info_t *dip, ddi_acc_handle_t handle);
2072305Sstevel static void pcic_dump_debqueue(char *msg);
2082305Sstevel
2092305Sstevel #if defined(PCIC_DEBUG)
2102305Sstevel static void xxdmp_all_regs(pcicdev_t *, int, uint32_t);
2112305Sstevel
2122305Sstevel #define pcic_mutex_enter(a) \
2132305Sstevel { \
2142305Sstevel pcic_err(NULL, 10, "Set lock at %d\n", __LINE__); \
2152305Sstevel mutex_enter(a); \
2162305Sstevel };
2172305Sstevel
2182305Sstevel #define pcic_mutex_exit(a) \
2192305Sstevel { \
2202305Sstevel pcic_err(NULL, 10, "Clear lock at %d\n", __LINE__); \
2212305Sstevel mutex_exit(a); \
2222305Sstevel };
2232305Sstevel
2242305Sstevel #else
2252305Sstevel #define pcic_mutex_enter(a) mutex_enter(a)
2262305Sstevel #define pcic_mutex_exit(a) mutex_exit(a)
2272305Sstevel #endif
2282305Sstevel
2292305Sstevel #define PCIC_VCC_3VLEVEL 1
2302305Sstevel #define PCIC_VCC_5VLEVEL 2
2312305Sstevel #define PCIC_VCC_12LEVEL 3
2322305Sstevel
2332305Sstevel /* bit patterns to select voltage levels */
2342305Sstevel int pcic_vpp_levels[13] = {
2352305Sstevel 0, 0, 0,
2362305Sstevel 1, /* 3.3V */
2372305Sstevel 0,
2382305Sstevel 1, /* 5V */
2392305Sstevel 0, 0, 0, 0, 0, 0,
2402305Sstevel 2 /* 12V */
2412305Sstevel };
2422305Sstevel
2432305Sstevel uint8_t pcic_cbv_levels[13] = {
2442305Sstevel 0, 0, 0,
2452305Sstevel 3, /* 3.3V */
2462305Sstevel 0,
2472305Sstevel 2, /* 5V */
2482305Sstevel 0, 0, 0, 0, 0, 0,
2492305Sstevel 1 /* 12V */
2502305Sstevel };
2512305Sstevel
2522305Sstevel struct power_entry pcic_power[4] = {
2532305Sstevel {
2542305Sstevel 0, VCC|VPP1|VPP2
2552305Sstevel },
2562305Sstevel {
2572305Sstevel 33, /* 3.3Volt */
2582305Sstevel VCC|VPP1|VPP2
2592305Sstevel },
2602305Sstevel {
2612305Sstevel 5*10, /* 5Volt */
2622305Sstevel VCC|VPP1|VPP2 /* currently only know about this */
2632305Sstevel },
2642305Sstevel {
2652305Sstevel 12*10, /* 12Volt */
2662305Sstevel VPP1|VPP2
2672305Sstevel }
2682305Sstevel };
2692305Sstevel
2702305Sstevel /*
2712305Sstevel * Base used to allocate ranges of PCI memory on x86 systems
2722305Sstevel * Each instance gets a chunk above the base that is used to map
2732305Sstevel * in the memory and I/O windows for that device.
2742305Sstevel * Pages below the base are also allocated for the EXCA registers,
2752305Sstevel * one per instance.
2762305Sstevel */
2772305Sstevel #define PCIC_PCI_MEMCHUNK 0x1000000
2782305Sstevel
2792305Sstevel static int pcic_wait_insert_time = 5000000; /* In micro-seconds */
2802305Sstevel static int pcic_debounce_time = 200000; /* In micro-seconds */
2812305Sstevel
2822305Sstevel struct debounce {
2832305Sstevel pcic_socket_t *pcs;
2842305Sstevel clock_t expire;
2852305Sstevel struct debounce *next;
2862305Sstevel };
2872305Sstevel
2882305Sstevel static struct debounce *pcic_deb_queue = NULL;
2892305Sstevel static kmutex_t pcic_deb_mtx;
2902305Sstevel static kcondvar_t pcic_deb_cv;
2912305Sstevel static kthread_t *pcic_deb_threadid;
2922305Sstevel
2932305Sstevel static inthandler_t *pcic_handlers;
2942305Sstevel
2952305Sstevel static void pcic_setup_adapter(pcicdev_t *);
2962305Sstevel static int pcic_change(pcicdev_t *, int);
2972305Sstevel static int pcic_ll_reset(pcicdev_t *, int);
2982305Sstevel static void pcic_mswait(pcicdev_t *, int, int);
2992305Sstevel static boolean_t pcic_check_ready(pcicdev_t *, int);
3002305Sstevel static void pcic_set_cdtimers(pcicdev_t *, int, uint32_t, int);
3012305Sstevel static void pcic_ready_wait(pcicdev_t *, int);
3022305Sstevel extern int pcmcia_get_intr(dev_info_t *, int);
3032305Sstevel extern int pcmcia_return_intr(dev_info_t *, int);
3047151Srw148561 extern void pcmcia_cb_suspended(int);
3057151Srw148561 extern void pcmcia_cb_resumed(int);
3062305Sstevel
3072305Sstevel static int pcic_callback(dev_info_t *, int (*)(), int);
3082305Sstevel static int pcic_inquire_adapter(dev_info_t *, inquire_adapter_t *);
3092305Sstevel static int pcic_get_adapter(dev_info_t *, get_adapter_t *);
3102305Sstevel static int pcic_get_page(dev_info_t *, get_page_t *);
3112305Sstevel static int pcic_get_socket(dev_info_t *, get_socket_t *);
3122305Sstevel static int pcic_get_status(dev_info_t *, get_ss_status_t *);
3132305Sstevel static int pcic_get_window(dev_info_t *, get_window_t *);
3142305Sstevel static int pcic_inquire_socket(dev_info_t *, inquire_socket_t *);
3152305Sstevel static int pcic_inquire_window(dev_info_t *, inquire_window_t *);
3162305Sstevel static int pcic_reset_socket(dev_info_t *, int, int);
3172305Sstevel static int pcic_set_page(dev_info_t *, set_page_t *);
3182305Sstevel static int pcic_set_window(dev_info_t *, set_window_t *);
3192305Sstevel static int pcic_set_socket(dev_info_t *, set_socket_t *);
3202305Sstevel static int pcic_set_interrupt(dev_info_t *, set_irq_handler_t *);
3212305Sstevel static int pcic_clear_interrupt(dev_info_t *, clear_irq_handler_t *);
3222305Sstevel static void pcic_pm_detection(void *);
3232305Sstevel static void pcic_iomem_pci_ctl(ddi_acc_handle_t, uchar_t *, unsigned);
3242305Sstevel static int clext_reg_read(pcicdev_t *, int, uchar_t);
3252305Sstevel static void clext_reg_write(pcicdev_t *, int, uchar_t, uchar_t);
3262305Sstevel static int pcic_calc_speed(pcicdev_t *, uint32_t);
3272305Sstevel static int pcic_card_state(pcicdev_t *, pcic_socket_t *);
3282305Sstevel static int pcic_find_pci_type(pcicdev_t *);
3292305Sstevel static void pcic_82092_smiirq_ctl(pcicdev_t *, int, int, int);
3302305Sstevel static void pcic_handle_cd_change(pcicdev_t *, pcic_socket_t *, uint8_t);
3312305Sstevel static uint_t pcic_cd_softint(caddr_t, caddr_t);
3322305Sstevel static uint8_t pcic_getb(pcicdev_t *, int, int);
3332305Sstevel static void pcic_putb(pcicdev_t *, int, int, int8_t);
3342305Sstevel static int pcic_set_vcc_level(pcicdev_t *, set_socket_t *);
3352305Sstevel static uint_t pcic_softintr(caddr_t, caddr_t);
3362305Sstevel
3372305Sstevel static void pcic_debounce(pcic_socket_t *);
3387151Srw148561 static void pcic_do_resume(pcicdev_t *);
3392305Sstevel static void *pcic_add_debqueue(pcic_socket_t *, int);
3402305Sstevel static void pcic_rm_debqueue(void *);
3412305Sstevel static void pcic_deb_thread();
3422305Sstevel
3432305Sstevel static boolean_t pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp);
3442305Sstevel static void pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp);
3452305Sstevel static uint32_t pcic_getcb(pcicdev_t *pcic, int reg);
3462305Sstevel static void pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value);
3472305Sstevel static void pcic_cb_enable_intr(dev_info_t *);
3482305Sstevel static void pcic_cb_disable_intr(dev_info_t *);
3492305Sstevel static void pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq);
3502305Sstevel static void pcic_disable_io_intr(pcicdev_t *pcic, int socket);
3512305Sstevel
3522305Sstevel static cb_nexus_cb_t pcic_cbnexus_ops = {
3532305Sstevel pcic_cb_enable_intr,
3542305Sstevel pcic_cb_disable_intr
3552305Sstevel };
3562305Sstevel
3572305Sstevel static int pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel);
3582305Sstevel static int pcic_cbus_powerctl(pcicdev_t *pcic, int socket);
3592305Sstevel
3602305Sstevel #if defined(__sparc)
3612305Sstevel static int pcic_fault(enum pci_fault_ops op, void *arg);
3622305Sstevel #endif
3632305Sstevel
3642305Sstevel
3652305Sstevel /*
3662305Sstevel * pcmcia interface operations structure
3672305Sstevel * this is the private interface that is exported to the nexus
3682305Sstevel */
3692305Sstevel pcmcia_if_t pcic_if_ops = {
3702305Sstevel PCIF_MAGIC,
3712305Sstevel PCIF_VERSION,
3722305Sstevel pcic_callback,
3732305Sstevel pcic_get_adapter,
3742305Sstevel pcic_get_page,
3752305Sstevel pcic_get_socket,
3762305Sstevel pcic_get_status,
3772305Sstevel pcic_get_window,
3782305Sstevel pcic_inquire_adapter,
3792305Sstevel pcic_inquire_socket,
3802305Sstevel pcic_inquire_window,
3812305Sstevel pcic_reset_socket,
3822305Sstevel pcic_set_page,
3832305Sstevel pcic_set_window,
3842305Sstevel pcic_set_socket,
3852305Sstevel pcic_set_interrupt,
3862305Sstevel pcic_clear_interrupt,
3872305Sstevel NULL,
3882305Sstevel };
3892305Sstevel
3902305Sstevel /*
3912305Sstevel * chip type identification routines
3922305Sstevel * this list of functions is searched until one of them succeeds
3932305Sstevel * or all fail. i82365SL is assumed if failed.
3942305Sstevel */
3952305Sstevel static int pcic_ci_cirrus(pcicdev_t *);
3962305Sstevel static int pcic_ci_vadem(pcicdev_t *);
3972305Sstevel static int pcic_ci_ricoh(pcicdev_t *);
3982305Sstevel
3992305Sstevel int (*pcic_ci_funcs[])(pcicdev_t *) = {
4002305Sstevel pcic_ci_cirrus,
4012305Sstevel pcic_ci_vadem,
4022305Sstevel pcic_ci_ricoh,
4032305Sstevel NULL
4042305Sstevel };
4052305Sstevel
4062305Sstevel static struct modldrv modldrv = {
4072305Sstevel &mod_driverops, /* Type of module. This one is a driver */
4087240Srh87107 "PCIC PCMCIA adapter driver", /* Name of the module. */
4092305Sstevel &pcic_devops, /* driver ops */
4102305Sstevel };
4112305Sstevel
4122305Sstevel static struct modlinkage modlinkage = {
4132305Sstevel MODREV_1, (void *)&modldrv, NULL
4142305Sstevel };
4152305Sstevel
4162305Sstevel int
_init()4172305Sstevel _init()
4182305Sstevel {
4192305Sstevel int stat;
4202305Sstevel
4212305Sstevel /* Allocate soft state */
4222305Sstevel if ((stat = ddi_soft_state_init(&pcic_soft_state_p,
4232305Sstevel SOFTC_SIZE, 2)) != DDI_SUCCESS)
4242305Sstevel return (stat);
4252305Sstevel
4262305Sstevel if ((stat = mod_install(&modlinkage)) != 0)
4272305Sstevel ddi_soft_state_fini(&pcic_soft_state_p);
4282305Sstevel
4292305Sstevel return (stat);
4302305Sstevel }
4312305Sstevel
4322305Sstevel int
_fini()4332305Sstevel _fini()
4342305Sstevel {
4352305Sstevel int stat = 0;
4362305Sstevel
4372305Sstevel if ((stat = mod_remove(&modlinkage)) != 0)
4382305Sstevel return (stat);
4392305Sstevel
4402305Sstevel if (pcic_deb_threadid) {
4412305Sstevel mutex_enter(&pcic_deb_mtx);
4422305Sstevel pcic_deb_threadid = 0;
4432305Sstevel while (!pcic_deb_threadid)
4442305Sstevel cv_wait(&pcic_deb_cv, &pcic_deb_mtx);
4452305Sstevel pcic_deb_threadid = 0;
4462305Sstevel mutex_exit(&pcic_deb_mtx);
4472305Sstevel
4482305Sstevel mutex_destroy(&pcic_deb_mtx);
4492305Sstevel cv_destroy(&pcic_deb_cv);
4502305Sstevel }
4512305Sstevel
4522305Sstevel ddi_soft_state_fini(&pcic_soft_state_p);
4532305Sstevel
4542305Sstevel return (stat);
4552305Sstevel }
4562305Sstevel
4572305Sstevel int
_info(struct modinfo * modinfop)4582305Sstevel _info(struct modinfo *modinfop)
4592305Sstevel {
4602305Sstevel return (mod_info(&modlinkage, modinfop));
4612305Sstevel }
4622305Sstevel
4632305Sstevel /*
4642305Sstevel * pcic_getinfo()
4652305Sstevel * provide instance/device information about driver
4662305Sstevel */
4672305Sstevel /*ARGSUSED*/
4682305Sstevel static int
pcic_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)4692305Sstevel pcic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
4702305Sstevel {
4712305Sstevel anp_t *anp;
4722305Sstevel int error = DDI_SUCCESS;
4732305Sstevel minor_t minor;
4742305Sstevel
4752305Sstevel switch (cmd) {
4767656SSherry.Moore@Sun.COM case DDI_INFO_DEVT2DEVINFO:
4772305Sstevel minor = getminor((dev_t)arg);
4783981Sgd78059 minor &= 0x7f;
4792305Sstevel if (!(anp = ddi_get_soft_state(pcic_soft_state_p, minor)))
4802305Sstevel *result = NULL;
4812305Sstevel else
4822305Sstevel *result = anp->an_dip;
4832305Sstevel break;
4847656SSherry.Moore@Sun.COM case DDI_INFO_DEVT2INSTANCE:
4852305Sstevel minor = getminor((dev_t)arg);
4863981Sgd78059 minor &= 0x7f;
4872305Sstevel *result = (void *)((long)minor);
4882305Sstevel break;
4897656SSherry.Moore@Sun.COM default:
4902305Sstevel error = DDI_FAILURE;
4912305Sstevel break;
4922305Sstevel }
4932305Sstevel return (error);
4942305Sstevel }
4952305Sstevel
4962305Sstevel static int
pcic_probe(dev_info_t * dip)4972305Sstevel pcic_probe(dev_info_t *dip)
4982305Sstevel {
4992305Sstevel int value;
5002305Sstevel ddi_device_acc_attr_t attr;
5012305Sstevel ddi_acc_handle_t handle;
5022305Sstevel uchar_t *index, *data;
5032305Sstevel
5042305Sstevel if (ddi_dev_is_sid(dip) == DDI_SUCCESS)
5057656SSherry.Moore@Sun.COM return (DDI_PROBE_DONTCARE);
5062305Sstevel
5072305Sstevel /*
5082305Sstevel * find a PCIC device (any vendor)
5092305Sstevel * while there can be up to 4 such devices in
5102305Sstevel * a system, we currently only look for 1
5112305Sstevel * per probe. There will be up to 2 chips per
5122305Sstevel * instance since they share I/O space
5132305Sstevel */
5142305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5152305Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
5162305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5172305Sstevel
5182305Sstevel if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM,
5197656SSherry.Moore@Sun.COM (caddr_t *)&index,
5207656SSherry.Moore@Sun.COM PCIC_ISA_CONTROL_REG_OFFSET,
5217656SSherry.Moore@Sun.COM PCIC_ISA_CONTROL_REG_LENGTH,
5227656SSherry.Moore@Sun.COM &attr, &handle) != DDI_SUCCESS)
5237656SSherry.Moore@Sun.COM return (DDI_PROBE_FAILURE);
5242305Sstevel
5252305Sstevel data = index + 1;
5262305Sstevel
5272305Sstevel #if defined(PCIC_DEBUG)
5282305Sstevel if (pcic_debug)
5292305Sstevel cmn_err(CE_CONT, "pcic_probe: entered\n");
5302305Sstevel if (pcic_debug)
5312305Sstevel cmn_err(CE_CONT, "\tindex=%p\n", (void *)index);
5322305Sstevel #endif
5332305Sstevel ddi_put8(handle, index, PCIC_CHIP_REVISION);
5342305Sstevel ddi_put8(handle, data, 0);
5352305Sstevel value = ddi_get8(handle, data);
5362305Sstevel #if defined(PCIC_DEBUG)
5372305Sstevel if (pcic_debug)
5382305Sstevel cmn_err(CE_CONT, "\tchip revision register = %x\n", value);
5392305Sstevel #endif
5402305Sstevel if ((value & PCIC_REV_MASK) >= PCIC_REV_LEVEL_LOW &&
5412305Sstevel (value & 0x30) == 0) {
5422305Sstevel /*
5432305Sstevel * we probably have a PCIC chip in the system
5442305Sstevel * do a little more checking. If we find one,
5452305Sstevel * reset everything in case of softboot
5462305Sstevel */
5472305Sstevel ddi_put8(handle, index, PCIC_MAPPING_ENABLE);
5482305Sstevel ddi_put8(handle, data, 0);
5492305Sstevel value = ddi_get8(handle, data);
5502305Sstevel #if defined(PCIC_DEBUG)
5512305Sstevel if (pcic_debug)
5522305Sstevel cmn_err(CE_CONT, "\tzero test = %x\n", value);
5532305Sstevel #endif
5542305Sstevel /* should read back as zero */
5552305Sstevel if (value == 0) {
5562305Sstevel /*
5572305Sstevel * we do have one and it is off the bus
5582305Sstevel */
5592305Sstevel #if defined(PCIC_DEBUG)
5602305Sstevel if (pcic_debug)
5612305Sstevel cmn_err(CE_CONT, "pcic_probe: success\n");
5622305Sstevel #endif
5632305Sstevel ddi_regs_map_free(&handle);
5642305Sstevel return (DDI_PROBE_SUCCESS);
5652305Sstevel }
5662305Sstevel }
5672305Sstevel #if defined(PCIC_DEBUG)
5682305Sstevel if (pcic_debug)
5692305Sstevel cmn_err(CE_CONT, "pcic_probe: failed\n");
5702305Sstevel #endif
5712305Sstevel ddi_regs_map_free(&handle);
5722305Sstevel return (DDI_PROBE_FAILURE);
5732305Sstevel }
5742305Sstevel
5752305Sstevel /*
5762305Sstevel * These are just defaults they can also be changed via a property in the
5772305Sstevel * conf file.
5782305Sstevel */
5792305Sstevel static int pci_config_reg_num = PCIC_PCI_CONFIG_REG_NUM;
5802305Sstevel static int pci_control_reg_num = PCIC_PCI_CONTROL_REG_NUM;
5817151Srw148561 static int pcic_do_pcmcia_sr = 1;
5822305Sstevel static int pcic_use_cbpwrctl = PCF_CBPWRCTL;
5832305Sstevel
5842305Sstevel /*
5852305Sstevel * enable insertion/removal interrupt for 32bit cards
5862305Sstevel */
5872305Sstevel static int
cardbus_enable_cd_intr(dev_info_t * dip)5882305Sstevel cardbus_enable_cd_intr(dev_info_t *dip)
5892305Sstevel {
5902305Sstevel ddi_acc_handle_t iohandle;
5912305Sstevel caddr_t ioaddr;
5922305Sstevel ddi_device_acc_attr_t attr;
5932305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5942305Sstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
5952305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5962305Sstevel (void) ddi_regs_map_setup(dip, 1,
5977656SSherry.Moore@Sun.COM (caddr_t *)&ioaddr,
5987656SSherry.Moore@Sun.COM 0,
5997656SSherry.Moore@Sun.COM 4096,
6007656SSherry.Moore@Sun.COM &attr, &iohandle);
6012305Sstevel
6022305Sstevel /* CSC Interrupt: Card detect interrupt on */
6032305Sstevel ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK),
6047656SSherry.Moore@Sun.COM ddi_get32(iohandle,
6057656SSherry.Moore@Sun.COM (uint32_t *)(ioaddr+CB_STATUS_MASK)) | CB_SE_CCDMASK);
6062305Sstevel
6072305Sstevel ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT),
6087656SSherry.Moore@Sun.COM ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT)));
6092305Sstevel
6102305Sstevel ddi_regs_map_free(&iohandle);
6112305Sstevel return (1);
6122305Sstevel }
6132305Sstevel
6142305Sstevel /*
615*8099SQuaker.Fang@Sun.COM * quiesce(9E) entry point.
616*8099SQuaker.Fang@Sun.COM *
617*8099SQuaker.Fang@Sun.COM * This function is called when the system is single-threaded at high
618*8099SQuaker.Fang@Sun.COM * PIL with preemption disabled. Therefore, this function must not be
619*8099SQuaker.Fang@Sun.COM * blocked.
620*8099SQuaker.Fang@Sun.COM *
621*8099SQuaker.Fang@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
622*8099SQuaker.Fang@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen.
623*8099SQuaker.Fang@Sun.COM */
624*8099SQuaker.Fang@Sun.COM static int32_t
pcic_quiesce(dev_info_t * dip)625*8099SQuaker.Fang@Sun.COM pcic_quiesce(dev_info_t *dip)
626*8099SQuaker.Fang@Sun.COM {
627*8099SQuaker.Fang@Sun.COM anp_t *anp = ddi_get_driver_private(dip);
628*8099SQuaker.Fang@Sun.COM pcicdev_t *pcic = anp->an_private;
629*8099SQuaker.Fang@Sun.COM int i;
630*8099SQuaker.Fang@Sun.COM
631*8099SQuaker.Fang@Sun.COM for (i = 0; i < pcic->pc_numsockets; i++) {
632*8099SQuaker.Fang@Sun.COM pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
633*8099SQuaker.Fang@Sun.COM pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
634*8099SQuaker.Fang@Sun.COM pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
635*8099SQuaker.Fang@Sun.COM /* disable interrupts and put card into RESET */
636*8099SQuaker.Fang@Sun.COM pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
637*8099SQuaker.Fang@Sun.COM /* poweroff socket */
638*8099SQuaker.Fang@Sun.COM pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
639*8099SQuaker.Fang@Sun.COM pcic_putcb(pcic, CB_CONTROL, 0);
640*8099SQuaker.Fang@Sun.COM }
641*8099SQuaker.Fang@Sun.COM
642*8099SQuaker.Fang@Sun.COM return (DDI_SUCCESS);
643*8099SQuaker.Fang@Sun.COM }
644*8099SQuaker.Fang@Sun.COM
645*8099SQuaker.Fang@Sun.COM /*
6462305Sstevel * pcic_attach()
6472305Sstevel * attach the PCIC (Intel 82365SL/CirrusLogic/Toshiba) driver
6482305Sstevel * to the system. This is a child of "sysbus" since that is where
6492305Sstevel * the hardware lives, but it provides services to the "pcmcia"
6502305Sstevel * nexus driver. It gives a pointer back via its private data
6512305Sstevel * structure which contains both the dip and socket services entry
6522305Sstevel * points
6532305Sstevel */
6542305Sstevel static int
pcic_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)6552305Sstevel pcic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6562305Sstevel {
6572305Sstevel anp_t *pcic_nexus;
6582305Sstevel pcicdev_t *pcic;
6592305Sstevel int irqlevel, value;
6602305Sstevel int pci_cfrn, pci_ctrn;
6612305Sstevel int i, j, smi, actual;
6622305Sstevel char *typename;
6632305Sstevel char bus_type[16] = "(unknown)";
6642305Sstevel int len = sizeof (bus_type);
6652305Sstevel ddi_device_acc_attr_t attr;
6662305Sstevel anp_t *anp = ddi_get_driver_private(dip);
6672305Sstevel uint_t pri;
6682305Sstevel
6692305Sstevel #if defined(PCIC_DEBUG)
6702305Sstevel if (pcic_debug) {
6712305Sstevel cmn_err(CE_CONT, "pcic_attach: entered\n");
6722305Sstevel }
6732305Sstevel #endif
6742305Sstevel switch (cmd) {
6752305Sstevel case DDI_ATTACH:
6762305Sstevel break;
6772305Sstevel case DDI_RESUME:
6782305Sstevel pcic = anp->an_private;
6792305Sstevel /*
6802305Sstevel * for now, this is a simulated resume.
6812305Sstevel * a real one may need different things.
6822305Sstevel */
6832305Sstevel if (pcic != NULL && pcic->pc_flags & PCF_SUSPENDED) {
6842305Sstevel mutex_enter(&pcic->pc_lock);
6852305Sstevel /* should probe for new sockets showing up */
6862305Sstevel pcic_setup_adapter(pcic);
6872305Sstevel pcic->pc_flags &= ~PCF_SUSPENDED;
6882305Sstevel mutex_exit(&pcic->pc_lock);
6892305Sstevel (void) pcmcia_begin_resume(dip);
6907151Srw148561
6917151Srw148561 pcic_do_resume(pcic);
6927151Srw148561 #ifdef CARDBUS
6937151Srw148561 cardbus_restore_children(ddi_get_child(dip));
6947151Srw148561 #endif
6952305Sstevel
6962305Sstevel /*
6972305Sstevel * for complete implementation need END_RESUME (later)
6982305Sstevel */
6992305Sstevel return (DDI_SUCCESS);
7002305Sstevel
7012305Sstevel }
7022305Sstevel return (DDI_SUCCESS);
7032305Sstevel default:
7042305Sstevel return (DDI_FAILURE);
7052305Sstevel }
7062305Sstevel
7072305Sstevel /*
7082305Sstevel * Allocate soft state associated with this instance.
7092305Sstevel */
7102305Sstevel if (ddi_soft_state_zalloc(pcic_soft_state_p,
7117656SSherry.Moore@Sun.COM ddi_get_instance(dip)) != DDI_SUCCESS) {
7122305Sstevel cmn_err(CE_CONT, "pcic%d: Unable to alloc state\n",
7137656SSherry.Moore@Sun.COM ddi_get_instance(dip));
7142305Sstevel return (DDI_FAILURE);
7152305Sstevel }
7162305Sstevel
7172305Sstevel pcic_nexus = ddi_get_soft_state(pcic_soft_state_p,
7182305Sstevel ddi_get_instance(dip));
7192305Sstevel
7202305Sstevel pcic = kmem_zalloc(sizeof (pcicdev_t), KM_SLEEP);
7212305Sstevel
7222305Sstevel pcic->dip = dip;
7232305Sstevel pcic_nexus->an_dip = dip;
7242305Sstevel pcic_nexus->an_if = &pcic_if_ops;
7252305Sstevel pcic_nexus->an_private = pcic;
7262305Sstevel pcic->pc_numpower = sizeof (pcic_power)/sizeof (pcic_power[0]);
7272305Sstevel pcic->pc_power = pcic_power;
7282305Sstevel
7292305Sstevel pci_ctrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
7302305Sstevel "pci-control-reg-number", pci_control_reg_num);
7312305Sstevel pci_cfrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
7322305Sstevel "pci-config-reg-number", pci_config_reg_num);
7332305Sstevel
7342305Sstevel ddi_set_driver_private(dip, pcic_nexus);
7352305Sstevel
7362305Sstevel /*
7372305Sstevel * pcic->pc_irq is really the IPL level we want to run at
7382305Sstevel * set the default values here and override from intr spec
7392305Sstevel */
7402305Sstevel pcic->pc_irq = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
7417656SSherry.Moore@Sun.COM "interrupt-priorities", -1);
7422305Sstevel
7432305Sstevel if (pcic->pc_irq == -1) {
7442305Sstevel int actual;
7452305Sstevel uint_t pri;
7462305Sstevel ddi_intr_handle_t hdl;
7472305Sstevel
7482305Sstevel /* see if intrspec tells us different */
7492305Sstevel if (ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED,
7502305Sstevel 0, 1, &actual, DDI_INTR_ALLOC_NORMAL) == DDI_SUCCESS) {
7512305Sstevel if (ddi_intr_get_pri(hdl, &pri) == DDI_SUCCESS)
7522305Sstevel pcic->pc_irq = pri;
7532305Sstevel else
7542305Sstevel pcic->pc_irq = LOCK_LEVEL + 1;
7552305Sstevel (void) ddi_intr_free(hdl);
7562305Sstevel }
7572305Sstevel }
7582305Sstevel pcic_nexus->an_ipl = pcic->pc_irq;
7592305Sstevel
7602305Sstevel /*
7612305Sstevel * Check our parent bus type. We do different things based on which
7622305Sstevel * bus we're on.
7632305Sstevel */
7642305Sstevel if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
7657656SSherry.Moore@Sun.COM PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP,
7667656SSherry.Moore@Sun.COM "device_type", (caddr_t)&bus_type[0], &len) !=
7677656SSherry.Moore@Sun.COM DDI_PROP_SUCCESS) {
7682305Sstevel if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip),
7697656SSherry.Moore@Sun.COM PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP,
7707656SSherry.Moore@Sun.COM "bus-type", (caddr_t)&bus_type[0], &len) !=
7717656SSherry.Moore@Sun.COM DDI_PROP_SUCCESS) {
7722305Sstevel
7732305Sstevel cmn_err(CE_CONT,
7747656SSherry.Moore@Sun.COM "pcic%d: can't find parent bus type\n",
7757656SSherry.Moore@Sun.COM ddi_get_instance(dip));
7762305Sstevel
7772305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
7783867Srw148561 ddi_soft_state_free(pcic_soft_state_p,
7797656SSherry.Moore@Sun.COM ddi_get_instance(dip));
7802305Sstevel return (DDI_FAILURE);
7812305Sstevel }
7822305Sstevel } /* ddi_prop_op("device_type") */
7832305Sstevel
7843664Srw148561 if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 ||
7857656SSherry.Moore@Sun.COM strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0) {
7862305Sstevel pcic->pc_flags = PCF_PCIBUS;
7872305Sstevel } else {
7883867Srw148561 cmn_err(CE_WARN, "!pcic%d: non-pci mode (%s) not supported, "
7897656SSherry.Moore@Sun.COM "set BIOS to yenta mode if applicable\n",
7907656SSherry.Moore@Sun.COM ddi_get_instance(dip), bus_type);
7912305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
7923867Srw148561 ddi_soft_state_free(pcic_soft_state_p,
7937656SSherry.Moore@Sun.COM ddi_get_instance(dip));
7942305Sstevel return (DDI_FAILURE);
7952305Sstevel }
7962305Sstevel
7972305Sstevel if ((pcic->bus_speed = ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip),
7987656SSherry.Moore@Sun.COM DDI_PROP_CANSLEEP,
7997656SSherry.Moore@Sun.COM "clock-frequency", 0)) == 0) {
8002305Sstevel if (pcic->pc_flags & PCF_PCIBUS)
8012305Sstevel pcic->bus_speed = PCIC_PCI_DEF_SYSCLK;
8022305Sstevel else
8032305Sstevel pcic->bus_speed = PCIC_ISA_DEF_SYSCLK;
8042305Sstevel } else {
8052305Sstevel /*
8062305Sstevel * OBP can declare the speed in Hz...
8072305Sstevel */
8082305Sstevel if (pcic->bus_speed > 1000000)
8092305Sstevel pcic->bus_speed /= 1000000;
8102305Sstevel } /* ddi_prop_op("clock-frequency") */
8112305Sstevel
8122305Sstevel pcic->pc_io_type = PCIC_IO_TYPE_82365SL; /* default mode */
8132305Sstevel
8142305Sstevel #ifdef PCIC_DEBUG
8152305Sstevel if (pcic_debug) {
8162305Sstevel cmn_err(CE_CONT,
8177656SSherry.Moore@Sun.COM "pcic%d: parent bus type = [%s], speed = %d MHz\n",
8187656SSherry.Moore@Sun.COM ddi_get_instance(dip),
8197656SSherry.Moore@Sun.COM bus_type, pcic->bus_speed);
8202305Sstevel }
8212305Sstevel #endif
8222305Sstevel
8232305Sstevel /*
8242305Sstevel * The reg properties on a PCI node are different than those
8252305Sstevel * on a non-PCI node. Handle that difference here.
8262305Sstevel * If it turns out to be a CardBus chip, we have even more
8272305Sstevel * differences.
8282305Sstevel */
8292305Sstevel if (pcic->pc_flags & PCF_PCIBUS) {
8302305Sstevel int class_code;
8312305Sstevel #if defined(__i386) || defined(__amd64)
8322305Sstevel pcic->pc_base = 0x1000000;
8332305Sstevel pcic->pc_bound = (uint32_t)~0;
8342305Sstevel pcic->pc_iobase = 0x1000;
8352305Sstevel pcic->pc_iobound = 0xefff;
8362305Sstevel #elif defined(__sparc)
8372305Sstevel pcic->pc_base = 0x0;
8382305Sstevel pcic->pc_bound = (uint32_t)~0;
8392305Sstevel pcic->pc_iobase = 0x00000;
8402305Sstevel pcic->pc_iobound = 0xffff;
8412305Sstevel #endif
8422305Sstevel
8432305Sstevel /* usually need to get at config space so map first */
8442305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8452305Sstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
8462305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8472305Sstevel
8482305Sstevel if (ddi_regs_map_setup(dip, pci_cfrn,
8497656SSherry.Moore@Sun.COM (caddr_t *)&pcic->cfgaddr,
8507656SSherry.Moore@Sun.COM PCIC_PCI_CONFIG_REG_OFFSET,
8517656SSherry.Moore@Sun.COM PCIC_PCI_CONFIG_REG_LENGTH,
8527656SSherry.Moore@Sun.COM &attr,
8537656SSherry.Moore@Sun.COM &pcic->cfg_handle) !=
8542305Sstevel DDI_SUCCESS) {
8552305Sstevel cmn_err(CE_CONT,
8567656SSherry.Moore@Sun.COM "pcic%d: unable to map config space"
8577656SSherry.Moore@Sun.COM "regs\n",
8587656SSherry.Moore@Sun.COM ddi_get_instance(dip));
8592305Sstevel
8602305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
8612305Sstevel return (DDI_FAILURE);
8622305Sstevel } /* ddi_regs_map_setup */
8632305Sstevel
8642305Sstevel class_code = ddi_getprop(DDI_DEV_T_ANY, dip,
8657656SSherry.Moore@Sun.COM DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
8667656SSherry.Moore@Sun.COM "class-code", -1);
8672305Sstevel #ifdef PCIC_DEBUG
8682305Sstevel if (pcic_debug) {
8692305Sstevel cmn_err(CE_CONT, "pcic_attach class_code=%x\n",
8702305Sstevel class_code);
8712305Sstevel }
8722305Sstevel #endif
8732305Sstevel
8742305Sstevel switch (class_code) {
8752305Sstevel case PCIC_PCI_CARDBUS:
8762305Sstevel pcic->pc_flags |= PCF_CARDBUS;
8772305Sstevel pcic->pc_io_type = PCIC_IO_TYPE_YENTA;
8782305Sstevel /*
8792305Sstevel * Get access to the adapter registers on the
8802305Sstevel * PCI bus. A 4K memory page
8812305Sstevel */
8822305Sstevel #if defined(PCIC_DEBUG)
8832305Sstevel pcic_err(dip, 8, "Is Cardbus device\n");
8842305Sstevel if (pcic_debug) {
8852305Sstevel int nr;
8862305Sstevel long rs;
8872305Sstevel (void) ddi_dev_nregs(dip, &nr);
8882305Sstevel pcic_err(dip, 9, "\tdev, cfgaddr 0x%p,"
8892305Sstevel "cfghndl 0x%p nregs %d",
8902305Sstevel (void *)pcic->cfgaddr,
8912305Sstevel (void *)pcic->cfg_handle, nr);
8922305Sstevel
8932305Sstevel (void) ddi_dev_regsize(dip,
8942305Sstevel PCIC_PCI_CONTROL_REG_NUM, &rs);
8952305Sstevel
8962305Sstevel pcic_err(dip, 9, "\tsize of reg %d is 0x%x\n",
8972305Sstevel PCIC_PCI_CONTROL_REG_NUM, (int)rs);
8982305Sstevel }
8992305Sstevel #endif
9002305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
9012305Sstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
9022305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
9032305Sstevel
9042305Sstevel if (ddi_regs_map_setup(dip, pci_ctrn,
9057656SSherry.Moore@Sun.COM (caddr_t *)&pcic->ioaddr,
9067656SSherry.Moore@Sun.COM PCIC_PCI_CONTROL_REG_OFFSET,
9077656SSherry.Moore@Sun.COM PCIC_CB_CONTROL_REG_LENGTH,
9087656SSherry.Moore@Sun.COM &attr, &pcic->handle) !=
9092305Sstevel DDI_SUCCESS) {
9102305Sstevel cmn_err(CE_CONT,
9117656SSherry.Moore@Sun.COM "pcic%d: unable to map PCI regs\n",
9127656SSherry.Moore@Sun.COM ddi_get_instance(dip));
9132305Sstevel ddi_regs_map_free(&pcic->cfg_handle);
9142305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
9152305Sstevel return (DDI_FAILURE);
9162305Sstevel } /* ddi_regs_map_setup */
9172305Sstevel
9182305Sstevel /*
9192305Sstevel * Find out the chip type - If we're on a PCI bus,
9202305Sstevel * the adapter has that information in the PCI
9212305Sstevel * config space.
9222305Sstevel * Note that we call pcic_find_pci_type here since
9232305Sstevel * it needs a valid mapped pcic->handle to
9242305Sstevel * access some of the adapter registers in
9252305Sstevel * some cases.
9262305Sstevel */
9272305Sstevel if (pcic_find_pci_type(pcic) != DDI_SUCCESS) {
9282305Sstevel ddi_regs_map_free(&pcic->handle);
9292305Sstevel ddi_regs_map_free(&pcic->cfg_handle);
9302305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
9312305Sstevel cmn_err(CE_WARN, "pcic: %s: unsupported "
9327656SSherry.Moore@Sun.COM "bridge\n", ddi_get_name_addr(dip));
9332305Sstevel return (DDI_FAILURE);
9342305Sstevel }
9352305Sstevel break;
9362305Sstevel
9372305Sstevel default:
9382305Sstevel case PCIC_PCI_PCMCIA:
9392305Sstevel /*
9402305Sstevel * Get access to the adapter IO registers on the
9412305Sstevel * PCI bus config space.
9422305Sstevel */
9432305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
9442305Sstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
9452305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
9462305Sstevel
9472305Sstevel /*
9482305Sstevel * We need a default mapping to the adapter's IO
9492305Sstevel * control register space. For most adapters
9502305Sstevel * that are of class PCIC_PCI_PCMCIA (or of
9512305Sstevel * a default class) the control registers
9522305Sstevel * will be using the 82365-type control/data
9532305Sstevel * format.
9542305Sstevel */
9552305Sstevel if (ddi_regs_map_setup(dip, pci_ctrn,
9567656SSherry.Moore@Sun.COM (caddr_t *)&pcic->ioaddr,
9577656SSherry.Moore@Sun.COM PCIC_PCI_CONTROL_REG_OFFSET,
9587656SSherry.Moore@Sun.COM PCIC_PCI_CONTROL_REG_LENGTH,
9597656SSherry.Moore@Sun.COM &attr,
9607656SSherry.Moore@Sun.COM &pcic->handle) != DDI_SUCCESS) {
9612305Sstevel cmn_err(CE_CONT,
9627656SSherry.Moore@Sun.COM "pcic%d: unable to map PCI regs\n",
9637656SSherry.Moore@Sun.COM ddi_get_instance(dip));
9642305Sstevel ddi_regs_map_free(&pcic->cfg_handle);
9652305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
9662305Sstevel return (DDI_FAILURE);
9672305Sstevel } /* ddi_regs_map_setup */
9682305Sstevel
9692305Sstevel /*
9702305Sstevel * Find out the chip type - If we're on a PCI bus,
9712305Sstevel * the adapter has that information in the PCI
9722305Sstevel * config space.
9732305Sstevel * Note that we call pcic_find_pci_type here since
9742305Sstevel * it needs a valid mapped pcic->handle to
9752305Sstevel * access some of the adapter registers in
9762305Sstevel * some cases.
9772305Sstevel */
9782305Sstevel if (pcic_find_pci_type(pcic) != DDI_SUCCESS) {
9792305Sstevel ddi_regs_map_free(&pcic->handle);
9802305Sstevel ddi_regs_map_free(&pcic->cfg_handle);
9812305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
9822305Sstevel cmn_err(CE_WARN, "pcic: %s: unsupported "
9837656SSherry.Moore@Sun.COM "bridge\n",
9847656SSherry.Moore@Sun.COM ddi_get_name_addr(dip));
9852305Sstevel return (DDI_FAILURE);
9862305Sstevel }
9872305Sstevel
9882305Sstevel /*
9892305Sstevel * Some PCI-PCMCIA(R2) adapters are Yenta-compliant
9902305Sstevel * for extended registers even though they are
9912305Sstevel * not CardBus adapters. For those adapters,
9922305Sstevel * re-map pcic->handle to be large enough to
9932305Sstevel * encompass the Yenta registers.
9942305Sstevel */
9952305Sstevel switch (pcic->pc_type) {
9967656SSherry.Moore@Sun.COM case PCIC_TI_PCI1031:
9972305Sstevel ddi_regs_map_free(&pcic->handle);
9982305Sstevel
9992305Sstevel if (ddi_regs_map_setup(dip,
10007656SSherry.Moore@Sun.COM PCIC_PCI_CONTROL_REG_NUM,
10017656SSherry.Moore@Sun.COM (caddr_t *)&pcic->ioaddr,
10027656SSherry.Moore@Sun.COM PCIC_PCI_CONTROL_REG_OFFSET,
10037656SSherry.Moore@Sun.COM PCIC_CB_CONTROL_REG_LENGTH,
10047656SSherry.Moore@Sun.COM &attr,
10057656SSherry.Moore@Sun.COM &pcic->handle) != DDI_SUCCESS) {
10062305Sstevel cmn_err(CE_CONT,
10077656SSherry.Moore@Sun.COM "pcic%d: unable to map "
10087656SSherry.Moore@Sun.COM "PCI regs\n",
10097656SSherry.Moore@Sun.COM ddi_get_instance(dip));
10102305Sstevel ddi_regs_map_free(&pcic->cfg_handle);
10112305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
10122305Sstevel return (DDI_FAILURE);
10132305Sstevel } /* ddi_regs_map_setup */
10142305Sstevel break;
10157656SSherry.Moore@Sun.COM default:
10162305Sstevel break;
10172305Sstevel } /* switch (pcic->pc_type) */
10182305Sstevel break;
10192305Sstevel } /* switch (class_code) */
10202305Sstevel } else {
10212305Sstevel /*
10222305Sstevel * We're not on a PCI bus, so assume an ISA bus type
10232305Sstevel * register property. Get access to the adapter IO
10242305Sstevel * registers on a non-PCI bus.
10252305Sstevel */
10262305Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
10272305Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
10282305Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
10292305Sstevel pcic->mem_reg_num = PCIC_ISA_MEM_REG_NUM;
10302305Sstevel pcic->io_reg_num = PCIC_ISA_IO_REG_NUM;
10312305Sstevel
10322305Sstevel if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM,
10337656SSherry.Moore@Sun.COM (caddr_t *)&pcic->ioaddr,
10347656SSherry.Moore@Sun.COM PCIC_ISA_CONTROL_REG_OFFSET,
10357656SSherry.Moore@Sun.COM PCIC_ISA_CONTROL_REG_LENGTH,
10367656SSherry.Moore@Sun.COM &attr,
10377656SSherry.Moore@Sun.COM &pcic->handle) != DDI_SUCCESS) {
10382305Sstevel cmn_err(CE_CONT,
10397656SSherry.Moore@Sun.COM "pcic%d: unable to map ISA registers\n",
10407656SSherry.Moore@Sun.COM ddi_get_instance(dip));
10412305Sstevel
10422305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
10432305Sstevel return (DDI_FAILURE);
10442305Sstevel } /* ddi_regs_map_setup */
10452305Sstevel
10462305Sstevel /* ISA bus is limited to 24-bits, but not first 640K */
10472305Sstevel pcic->pc_base = 0xd0000;
10482305Sstevel pcic->pc_bound = (uint32_t)~0;
10492305Sstevel pcic->pc_iobase = 0x1000;
10502305Sstevel pcic->pc_iobound = 0xefff;
10512305Sstevel } /* !PCF_PCIBUS */
10522305Sstevel
10532305Sstevel #ifdef PCIC_DEBUG
10542305Sstevel if (pcic_debug) {
10552305Sstevel cmn_err(CE_CONT, "pcic_attach pc_flags=%x pc_type=%x\n",
10562305Sstevel pcic->pc_flags, pcic->pc_type);
10572305Sstevel }
10582305Sstevel #endif
10592305Sstevel
10602305Sstevel /*
10612305Sstevel * Setup various adapter registers for the PCI case. For the
10622305Sstevel * non-PCI case, find out the chip type.
10632305Sstevel */
10642305Sstevel if (pcic->pc_flags & PCF_PCIBUS) {
10652305Sstevel int iline;
10662305Sstevel #if defined(__sparc)
10672305Sstevel iline = 0;
10682305Sstevel #else
10692305Sstevel iline = cardbus_validate_iline(dip, pcic->cfg_handle);
10702305Sstevel #endif
10712305Sstevel
10722305Sstevel /* set flags and socket counts based on chip type */
10732305Sstevel switch (pcic->pc_type) {
10742305Sstevel uint32_t cfg;
10752305Sstevel case PCIC_INTEL_i82092:
10762305Sstevel cfg = ddi_get8(pcic->cfg_handle,
10777656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_82092_PCICON);
10782305Sstevel /* we can only support 4 Socket version */
10792305Sstevel if (cfg & PCIC_82092_4_SOCKETS) {
10807656SSherry.Moore@Sun.COM pcic->pc_numsockets = 4;
10817656SSherry.Moore@Sun.COM pcic->pc_type = PCIC_INTEL_i82092;
10827656SSherry.Moore@Sun.COM if (iline != 0xFF)
10837656SSherry.Moore@Sun.COM pcic->pc_intr_mode =
10847656SSherry.Moore@Sun.COM PCIC_INTR_MODE_PCI_1;
10857656SSherry.Moore@Sun.COM else
10867656SSherry.Moore@Sun.COM pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
10872305Sstevel } else {
10887656SSherry.Moore@Sun.COM cmn_err(CE_CONT,
10892305Sstevel "pcic%d: Intel 82092 adapter "
10902305Sstevel "in unsupported configuration: 0x%x",
10912305Sstevel ddi_get_instance(pcic->dip), cfg);
10927656SSherry.Moore@Sun.COM pcic->pc_numsockets = 0;
10932305Sstevel } /* PCIC_82092_4_SOCKETS */
10942305Sstevel break;
10952305Sstevel case PCIC_CL_PD6730:
10962305Sstevel case PCIC_CL_PD6729:
10972305Sstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
10982305Sstevel cfg = ddi_getprop(DDI_DEV_T_ANY, dip,
10997656SSherry.Moore@Sun.COM DDI_PROP_CANSLEEP,
11007656SSherry.Moore@Sun.COM "interrupts", 0);
11012305Sstevel /* if not interrupt pin then must use ISA style IRQs */
11022305Sstevel if (cfg == 0 || iline == 0xFF)
11032305Sstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
11042305Sstevel else {
11052305Sstevel /*
11062305Sstevel * we have the option to use PCI interrupts.
11072305Sstevel * this might not be optimal but in some cases
11082305Sstevel * is the only thing possible (sparc case).
11092305Sstevel * we now deterine what is possible.
11102305Sstevel */
11112305Sstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
11122305Sstevel }
11132305Sstevel pcic->pc_numsockets = 2;
11142305Sstevel pcic->pc_flags |= PCF_IO_REMAP;
11152305Sstevel break;
11162305Sstevel case PCIC_TI_PCI1031:
11172305Sstevel /* this chip doesn't do CardBus but looks like one */
11182305Sstevel pcic->pc_flags &= ~PCF_CARDBUS;
11192305Sstevel /* FALLTHROUGH */
11202305Sstevel default:
11212305Sstevel pcic->pc_flags |= PCF_IO_REMAP;
11222305Sstevel /* FALLTHROUGH */
11232305Sstevel /* indicate feature even if not supported */
11242305Sstevel pcic->pc_flags |= PCF_DMA | PCF_ZV;
11252305Sstevel /* Not sure if these apply to all these chips */
11262305Sstevel pcic->pc_flags |= (PCF_VPPX|PCF_33VCAP);
11272305Sstevel pcic->pc_flags |= pcic_use_cbpwrctl;
11282305Sstevel
11292305Sstevel pcic->pc_numsockets = 1; /* one per function */
11302305Sstevel if (iline != 0xFF) {
11312305Sstevel uint8_t cfg;
11322305Sstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1;
11332305Sstevel
11342305Sstevel cfg = ddi_get8(pcic->cfg_handle,
11357656SSherry.Moore@Sun.COM (pcic->cfgaddr + PCIC_BRIDGE_CTL_REG));
11362305Sstevel cfg &= (~PCIC_FUN_INT_MOD_ISA);
11372305Sstevel ddi_put8(pcic->cfg_handle, (pcic->cfgaddr +
11387656SSherry.Moore@Sun.COM PCIC_BRIDGE_CTL_REG), cfg);
11392305Sstevel }
11402305Sstevel else
11412305Sstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA;
11422305Sstevel pcic->pc_io_type = PCIC_IOTYPE_YENTA;
11432305Sstevel break;
11442305Sstevel }
11452305Sstevel } else {
11462305Sstevel /*
11472305Sstevel * We're not on a PCI bus so do some more
11482305Sstevel * checking for adapter type here.
11492305Sstevel * For the non-PCI bus case:
11502305Sstevel * It could be any one of a number of different chips
11512305Sstevel * If we can't determine anything else, it is assumed
11522305Sstevel * to be an Intel 82365SL. The Cirrus Logic PD6710
11532305Sstevel * has an extension register that provides unique
11542305Sstevel * identification. Toshiba chip isn't detailed as yet.
11552305Sstevel */
11562305Sstevel
11572305Sstevel /* Init the CL id mode */
11582305Sstevel pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0);
11592305Sstevel value = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
11602305Sstevel
11612305Sstevel /* default to Intel i82365SL and then refine */
11622305Sstevel pcic->pc_type = PCIC_I82365SL;
11632305Sstevel pcic->pc_chipname = PCIC_TYPE_I82365SL;
11642305Sstevel for (value = 0; pcic_ci_funcs[value] != NULL; value++) {
11652305Sstevel /* go until one succeeds or none left */
11662305Sstevel if (pcic_ci_funcs[value](pcic))
11672305Sstevel break;
11682305Sstevel }
11692305Sstevel
11702305Sstevel /* any chip specific flags get set here */
11712305Sstevel switch (pcic->pc_type) {
11722305Sstevel case PCIC_CL_PD6722:
11732305Sstevel pcic->pc_flags |= PCF_DMA;
11742305Sstevel }
11752305Sstevel
11762305Sstevel for (i = 0; i < PCIC_MAX_SOCKETS; i++) {
11772305Sstevel /*
11782305Sstevel * look for total number of sockets.
11792305Sstevel * basically check each possible socket for
11802305Sstevel * presence like in probe
11812305Sstevel */
11822305Sstevel
11832305Sstevel /* turn all windows off */
11842305Sstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
11852305Sstevel value = pcic_getb(pcic, i, PCIC_MAPPING_ENABLE);
11862305Sstevel
11872305Sstevel /*
11882305Sstevel * if a zero is read back, then this socket
11892305Sstevel * might be present. It would be except for
11902305Sstevel * some systems that map the secondary PCIC
11912305Sstevel * chip space back to the first.
11922305Sstevel */
11932305Sstevel if (value != 0) {
11942305Sstevel /* definitely not so skip */
11952305Sstevel /* note: this is for Compaq support */
11962305Sstevel continue;
11972305Sstevel }
11982305Sstevel
11992305Sstevel /* further tests */
12002305Sstevel value = pcic_getb(pcic, i, PCIC_CHIP_REVISION) &
12017656SSherry.Moore@Sun.COM PCIC_REV_MASK;
12022305Sstevel if (!(value >= PCIC_REV_LEVEL_LOW &&
12037656SSherry.Moore@Sun.COM value <= PCIC_REV_LEVEL_HI))
12042305Sstevel break;
12052305Sstevel
12062305Sstevel pcic_putb(pcic, i, PCIC_SYSMEM_0_STARTLOW, 0xaa);
12072305Sstevel pcic_putb(pcic, i, PCIC_SYSMEM_1_STARTLOW, 0x55);
12082305Sstevel value = pcic_getb(pcic, i, PCIC_SYSMEM_0_STARTLOW);
12092305Sstevel
12102305Sstevel j = pcic_getb(pcic, i, PCIC_SYSMEM_1_STARTLOW);
12112305Sstevel if (value != 0xaa || j != 0x55)
12122305Sstevel break;
12132305Sstevel
12142305Sstevel /*
12152305Sstevel * at this point we know if we have hardware
12162305Sstevel * of some type and not just the bus holding
12172305Sstevel * a pattern for us. We still have to determine
12182305Sstevel * the case where more than 2 sockets are
12192305Sstevel * really the same due to peculiar mappings of
12202305Sstevel * hardware.
12212305Sstevel */
12222305Sstevel j = pcic->pc_numsockets++;
12232305Sstevel pcic->pc_sockets[j].pcs_flags = 0;
12242305Sstevel pcic->pc_sockets[j].pcs_io = pcic->ioaddr;
12252305Sstevel pcic->pc_sockets[j].pcs_socket = i;
12262305Sstevel
12272305Sstevel /* put PC Card into RESET, just in case */
12282305Sstevel value = pcic_getb(pcic, i, PCIC_INTERRUPT);
12292305Sstevel pcic_putb(pcic, i, PCIC_INTERRUPT,
12307656SSherry.Moore@Sun.COM value & ~PCIC_RESET);
12312305Sstevel }
12322305Sstevel
12332305Sstevel #if defined(PCIC_DEBUG)
12342305Sstevel if (pcic_debug)
12352305Sstevel cmn_err(CE_CONT, "num sockets = %d\n",
12367656SSherry.Moore@Sun.COM pcic->pc_numsockets);
12372305Sstevel #endif
12382305Sstevel if (pcic->pc_numsockets == 0) {
12392305Sstevel ddi_regs_map_free(&pcic->handle);
12402305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
12412305Sstevel return (DDI_FAILURE);
12422305Sstevel }
12432305Sstevel
12442305Sstevel /*
12452305Sstevel * need to think this through again in light of
12462305Sstevel * Compaq not following the model that all the
12472305Sstevel * chip vendors recommend. IBM 755 seems to be
12482305Sstevel * afflicted as well. Basically, if the vendor
12492305Sstevel * wired things wrong, socket 0 responds for socket 2
12502305Sstevel * accesses, etc.
12512305Sstevel */
12522305Sstevel if (pcic->pc_numsockets > 2) {
12532305Sstevel int count = pcic->pc_numsockets / 4;
12542305Sstevel for (i = 0; i < count; i++) {
12552305Sstevel /* put pattern into socket 0 */
12562305Sstevel pcic_putb(pcic, i,
12577656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTLOW, 0x11);
12582305Sstevel
12592305Sstevel /* put pattern into socket 2 */
12602305Sstevel pcic_putb(pcic, i + 2,
12617656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTLOW, 0x33);
12622305Sstevel
12632305Sstevel /* read back socket 0 */
12642305Sstevel value = pcic_getb(pcic, i,
12657656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTLOW);
12662305Sstevel
12672305Sstevel /* read back chip 1 socket 0 */
12682305Sstevel j = pcic_getb(pcic, i + 2,
12697656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTLOW);
12702305Sstevel if (j == value) {
12712305Sstevel pcic->pc_numsockets -= 2;
12722305Sstevel }
12732305Sstevel }
12742305Sstevel }
12752305Sstevel
12762305Sstevel smi = 0xff; /* no more override */
12772305Sstevel
12782305Sstevel if (ddi_getprop(DDI_DEV_T_NONE, dip,
12797656SSherry.Moore@Sun.COM DDI_PROP_DONTPASS, "need-mult-irq",
12807656SSherry.Moore@Sun.COM 0xffff) != 0xffff)
12812305Sstevel pcic->pc_flags |= PCF_MULT_IRQ;
12822305Sstevel
12832305Sstevel } /* !PCF_PCIBUS */
12842305Sstevel
12852305Sstevel /*
12862305Sstevel * some platforms/busses need to have resources setup
12872305Sstevel * this is temporary until a real resource allocator is
12882305Sstevel * implemented.
12892305Sstevel */
12902305Sstevel
12912305Sstevel pcic_init_assigned(dip);
12922305Sstevel
12932305Sstevel typename = pcic->pc_chipname;
12942305Sstevel
12952305Sstevel #ifdef PCIC_DEBUG
12962305Sstevel if (pcic_debug) {
12972305Sstevel int nregs, nintrs;
12982305Sstevel
12992305Sstevel if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS)
13002305Sstevel nregs = 0;
13012305Sstevel
13022305Sstevel if (ddi_dev_nintrs(dip, &nintrs) != DDI_SUCCESS)
13032305Sstevel nintrs = 0;
13042305Sstevel
13052305Sstevel cmn_err(CE_CONT,
13067656SSherry.Moore@Sun.COM "pcic%d: %d register sets, %d interrupts\n",
13077656SSherry.Moore@Sun.COM ddi_get_instance(dip), nregs, nintrs);
13082305Sstevel
13092305Sstevel nintrs = 0;
13102305Sstevel while (nregs--) {
13112305Sstevel off_t size;
13122305Sstevel
13132305Sstevel if (ddi_dev_regsize(dip, nintrs, &size) ==
13142305Sstevel DDI_SUCCESS) {
13152305Sstevel cmn_err(CE_CONT,
13167656SSherry.Moore@Sun.COM "\tregnum %d size %ld (0x%lx)"
13177656SSherry.Moore@Sun.COM "bytes",
13187656SSherry.Moore@Sun.COM nintrs, size, size);
13192305Sstevel if (nintrs ==
13202305Sstevel (pcic->pc_io_type == PCIC_IO_TYPE_82365SL ?
13212305Sstevel PCIC_ISA_CONTROL_REG_NUM :
13222305Sstevel PCIC_PCI_CONTROL_REG_NUM))
13232305Sstevel cmn_err(CE_CONT,
13247656SSherry.Moore@Sun.COM " mapped at: 0x%p\n",
13257656SSherry.Moore@Sun.COM (void *)pcic->ioaddr);
13262305Sstevel else
13272305Sstevel cmn_err(CE_CONT, "\n");
13282305Sstevel } else {
13292305Sstevel cmn_err(CE_CONT,
13307656SSherry.Moore@Sun.COM "\tddi_dev_regsize(rnumber"
13317656SSherry.Moore@Sun.COM "= %d) returns DDI_FAILURE\n",
13327656SSherry.Moore@Sun.COM nintrs);
13332305Sstevel }
13342305Sstevel nintrs++;
13352305Sstevel } /* while */
13362305Sstevel } /* if (pcic_debug) */
13372305Sstevel #endif
13382305Sstevel
13392305Sstevel cv_init(&pcic->pm_cv, NULL, CV_DRIVER, NULL);
13402305Sstevel
13412305Sstevel if (!ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
13427656SSherry.Moore@Sun.COM "disable-audio", 0))
13432305Sstevel pcic->pc_flags |= PCF_AUDIO;
13442305Sstevel
13452305Sstevel if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP,
13462305Sstevel "disable-cardbus", 0))
13472305Sstevel pcic->pc_flags &= ~PCF_CARDBUS;
13482305Sstevel
13492305Sstevel (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, PCICPROP_CTL,
13502305Sstevel typename);
13512305Sstevel
13522305Sstevel /*
13532305Sstevel * Init all socket SMI levels to 0 (no SMI)
13542305Sstevel */
13552305Sstevel for (i = 0; i < PCIC_MAX_SOCKETS; i++) {
13567656SSherry.Moore@Sun.COM pcic->pc_sockets[i].pcs_smi = 0;
13577656SSherry.Moore@Sun.COM pcic->pc_sockets[i].pcs_debounce_id = 0;
13587656SSherry.Moore@Sun.COM pcic->pc_sockets[i].pcs_pcic = pcic;
13592305Sstevel }
13602305Sstevel pcic->pc_lastreg = -1; /* just to make sure we are in sync */
13612305Sstevel
13622305Sstevel /*
13632305Sstevel * Setup the IRQ handler(s)
13642305Sstevel */
13652305Sstevel switch (pcic->pc_intr_mode) {
13662305Sstevel int xx;
13672305Sstevel case PCIC_INTR_MODE_ISA:
13682305Sstevel /*
13692305Sstevel * On a non-PCI bus, we just use whatever SMI IRQ level was
13702305Sstevel * specified above, and the IO IRQ levels are allocated
13712305Sstevel * dynamically.
13722305Sstevel */
13732305Sstevel for (xx = 15, smi = 0; xx >= 0; xx--) {
13742305Sstevel if (PCIC_IRQ(xx) &
13752305Sstevel PCIC_AVAIL_IRQS) {
13762305Sstevel smi = pcmcia_get_intr(dip, xx);
13772305Sstevel if (smi >= 0)
13782305Sstevel break;
13792305Sstevel }
13802305Sstevel }
13812305Sstevel #if defined(PCIC_DEBUG)
13822305Sstevel if (pcic_debug)
13832305Sstevel cmn_err(CE_NOTE, "\tselected IRQ %d as SMI\n", smi);
13842305Sstevel #endif
13852305Sstevel /* init to same so share is easy */
13862305Sstevel for (i = 0; i < pcic->pc_numsockets; i++)
13872305Sstevel pcic->pc_sockets[i].pcs_smi = smi;
13882305Sstevel /* any special handling of IRQ levels */
13892305Sstevel if (pcic->pc_flags & PCF_MULT_IRQ) {
13902305Sstevel for (i = 2; i < pcic->pc_numsockets; i++) {
13912305Sstevel if ((i & 1) == 0) {
13922305Sstevel int xx;
13932305Sstevel for (xx = 15, smi = 0; xx >= 0; xx--) {
13942305Sstevel if (PCIC_IRQ(xx) &
13952305Sstevel PCIC_AVAIL_IRQS) {
13962305Sstevel smi =
13972305Sstevel pcmcia_get_intr(dip,
13987656SSherry.Moore@Sun.COM xx);
13992305Sstevel if (smi >= 0)
14002305Sstevel break;
14012305Sstevel }
14022305Sstevel }
14032305Sstevel }
14042305Sstevel if (smi >= 0)
14052305Sstevel pcic->pc_sockets[i].pcs_smi = smi;
14062305Sstevel }
14072305Sstevel }
14082305Sstevel pcic->pc_intr_htblp = kmem_alloc(pcic->pc_numsockets *
14092305Sstevel sizeof (ddi_intr_handle_t), KM_SLEEP);
14102305Sstevel for (i = 0, irqlevel = -1; i < pcic->pc_numsockets; i++) {
14112305Sstevel struct intrspec *ispecp;
14122305Sstevel struct ddi_parent_private_data *pdp;
14132305Sstevel
14142305Sstevel if (irqlevel == pcic->pc_sockets[i].pcs_smi)
14152305Sstevel continue;
14162305Sstevel else {
14172305Sstevel irqlevel = pcic->pc_sockets[i].pcs_smi;
14182305Sstevel }
14192305Sstevel /*
14202305Sstevel * now convert the allocated IRQ into an intrspec
14212305Sstevel * and ask our parent to add it. Don't use
14222305Sstevel * the ddi_add_intr since we don't have a
14232305Sstevel * default intrspec in all cases.
14242305Sstevel *
14252305Sstevel * note: this sort of violates DDI but we don't
14262305Sstevel * get hardware intrspecs for many of the devices.
14272305Sstevel * at the same time, we know how to allocate them
14282305Sstevel * so we do the right thing.
14292305Sstevel */
14302305Sstevel if (ddi_intr_alloc(dip, &pcic->pc_intr_htblp[i],
14312305Sstevel DDI_INTR_TYPE_FIXED, 0, 1, &actual,
14322305Sstevel DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) {
14332305Sstevel cmn_err(CE_WARN, "%s: ddi_intr_alloc failed",
14342305Sstevel ddi_get_name(dip));
14352305Sstevel goto isa_exit1;
14362305Sstevel }
14372305Sstevel
14382305Sstevel /*
14392305Sstevel * See earlier note:
14402305Sstevel * Since some devices don't have 'intrspec'
14412305Sstevel * we make one up in rootnex.
14422305Sstevel *
14432305Sstevel * However, it is not properly initialized as
14442305Sstevel * the data it needs is present in this driver
14452305Sstevel * and there is no interface to pass that up.
14462305Sstevel * Specially 'irqlevel' is very important and
14472305Sstevel * it is part of pcic struct.
14482305Sstevel *
14492305Sstevel * Set 'intrspec' up here; otherwise adding the
14502305Sstevel * interrupt will fail.
14512305Sstevel */
14522305Sstevel pdp = ddi_get_parent_data(dip);
14532305Sstevel ispecp = (struct intrspec *)&pdp->par_intr[0];
14542305Sstevel ispecp->intrspec_vec = irqlevel;
14552305Sstevel ispecp->intrspec_pri = pcic->pc_irq;
14562305Sstevel
14572305Sstevel /* Stay compatible w/ PCMCIA */
14582305Sstevel pcic->pc_pri = (ddi_iblock_cookie_t)
14592305Sstevel (uintptr_t)pcic->pc_irq;
14602305Sstevel pcic->pc_dcookie.idev_priority =
14612305Sstevel (uintptr_t)pcic->pc_pri;
14622305Sstevel pcic->pc_dcookie.idev_vector = (ushort_t)irqlevel;
14632305Sstevel
14642305Sstevel (void) ddi_intr_set_pri(pcic->pc_intr_htblp[i],
14652305Sstevel pcic->pc_irq);
14662305Sstevel
14672305Sstevel if (i == 0) {
14682305Sstevel mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER,
14692305Sstevel DDI_INTR_PRI(pcic->pc_irq));
14702305Sstevel mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER,
14712305Sstevel NULL);
14722305Sstevel }
14732305Sstevel
14742305Sstevel if (ddi_intr_add_handler(pcic->pc_intr_htblp[i],
14752305Sstevel pcic_intr, (caddr_t)pcic, NULL)) {
14762305Sstevel cmn_err(CE_WARN,
14772305Sstevel "%s: ddi_intr_add_handler failed",
14782305Sstevel ddi_get_name(dip));
14792305Sstevel goto isa_exit2;
14802305Sstevel }
14812305Sstevel
14822305Sstevel if (ddi_intr_enable(pcic->pc_intr_htblp[i])) {
14832305Sstevel cmn_err(CE_WARN, "%s: ddi_intr_enable failed",
14842305Sstevel ddi_get_name(dip));
14852305Sstevel for (j = i; j < 0; j--)
14862305Sstevel (void) ddi_intr_remove_handler(
14872305Sstevel pcic->pc_intr_htblp[j]);
14882305Sstevel goto isa_exit2;
14892305Sstevel }
14902305Sstevel }
14912305Sstevel break;
14922305Sstevel case PCIC_INTR_MODE_PCI_1:
14932305Sstevel case PCIC_INTR_MODE_PCI:
14942305Sstevel /*
14952305Sstevel * If we're on a PCI bus, we route all interrupts, both SMI
14962305Sstevel * and IO interrupts, through a single interrupt line.
14972305Sstevel * Assign the SMI IRQ level to the IO IRQ level here.
14982305Sstevel */
14992305Sstevel pcic->pc_pci_intr_hdlp = kmem_alloc(sizeof (ddi_intr_handle_t),
15002305Sstevel KM_SLEEP);
15012305Sstevel if (ddi_intr_alloc(dip, pcic->pc_pci_intr_hdlp,
15022305Sstevel DDI_INTR_TYPE_FIXED, 0, 1, &actual,
15032305Sstevel DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS)
15042305Sstevel goto pci_exit1;
15052305Sstevel
15062305Sstevel if (ddi_intr_get_pri(pcic->pc_pci_intr_hdlp[0],
15072305Sstevel &pri) != DDI_SUCCESS) {
15082305Sstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
15092305Sstevel goto pci_exit1;
15102305Sstevel }
15112305Sstevel
15122305Sstevel pcic->pc_pri = (void *)(uintptr_t)pri;
15132305Sstevel mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, pcic->pc_pri);
15142305Sstevel mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, NULL);
15152305Sstevel
15162305Sstevel if (ddi_intr_add_handler(pcic->pc_pci_intr_hdlp[0],
15172305Sstevel pcic_intr, (caddr_t)pcic, NULL))
15182305Sstevel goto pci_exit2;
15192305Sstevel
15202305Sstevel if (ddi_intr_enable(pcic->pc_pci_intr_hdlp[0])) {
15212305Sstevel (void) ddi_intr_remove_handler(
15222305Sstevel pcic->pc_pci_intr_hdlp[0]);
15232305Sstevel goto pci_exit2;
15242305Sstevel }
15252305Sstevel
15262305Sstevel /* Stay compatible w/ PCMCIA */
15272305Sstevel pcic->pc_dcookie.idev_priority = (ushort_t)pri;
15282305Sstevel
15292305Sstevel /* init to same (PCI) so share is easy */
15302305Sstevel for (i = 0; i < pcic->pc_numsockets; i++)
15312305Sstevel pcic->pc_sockets[i].pcs_smi = 0xF; /* any valid */
15322305Sstevel break;
15332305Sstevel }
15342305Sstevel
15352305Sstevel /*
15362305Sstevel * Setup the adapter hardware to some reasonable defaults.
15372305Sstevel */
15382305Sstevel mutex_enter(&pcic->pc_lock);
15392305Sstevel /* mark the driver state as attached */
15402305Sstevel pcic->pc_flags |= PCF_ATTACHED;
15412305Sstevel pcic_setup_adapter(pcic);
15422305Sstevel
15432305Sstevel for (j = 0; j < pcic->pc_numsockets; j++)
15442305Sstevel if (ddi_intr_add_softint(dip,
15452305Sstevel &pcic->pc_sockets[j].pcs_cd_softint_hdl,
15462305Sstevel PCIC_SOFTINT_PRI_VAL, pcic_cd_softint,
15472305Sstevel (caddr_t)&pcic->pc_sockets[j]) != DDI_SUCCESS)
15482305Sstevel goto pci_exit2;
15492305Sstevel
15502305Sstevel #if defined(PCIC_DEBUG)
15512305Sstevel if (pcic_debug)
15522305Sstevel cmn_err(CE_CONT, "type = %s sockets = %d\n", typename,
15537656SSherry.Moore@Sun.COM pcic->pc_numsockets);
15542305Sstevel #endif
15552305Sstevel
15562305Sstevel pcic_nexus->an_iblock = &pcic->pc_pri;
15572305Sstevel pcic_nexus->an_idev = &pcic->pc_dcookie;
15582305Sstevel
15592305Sstevel mutex_exit(&pcic->pc_lock);
15602305Sstevel
15612305Sstevel #ifdef CARDBUS
15622305Sstevel (void) cardbus_enable_cd_intr(dip);
15632305Sstevel if (pcic_debug) {
15642305Sstevel
15652305Sstevel cardbus_dump_pci_config(dip);
15662305Sstevel cardbus_dump_socket(dip);
15672305Sstevel }
15682305Sstevel
15692305Sstevel /*
15702305Sstevel * Give the Cardbus misc module a chance to do it's per-adapter
15712305Sstevel * instance setup. Note that there is no corresponding detach()
15722305Sstevel * call.
15732305Sstevel */
15742305Sstevel if (pcic->pc_flags & PCF_CARDBUS)
15752305Sstevel if (cardbus_attach(dip, &pcic_cbnexus_ops) != DDI_SUCCESS) {
15762305Sstevel cmn_err(CE_CONT,
15772305Sstevel "pcic_attach: cardbus_attach failed\n");
15782305Sstevel goto pci_exit2;
15792305Sstevel }
15802305Sstevel #endif
15812305Sstevel
15822305Sstevel /*
15832305Sstevel * Give the PCMCIA misc module a chance to do it's per-adapter
15842305Sstevel * instance setup.
15852305Sstevel */
15862305Sstevel if ((i = pcmcia_attach(dip, pcic_nexus)) != DDI_SUCCESS)
15872305Sstevel goto pci_exit2;
15882305Sstevel
15892305Sstevel if (pcic_maxinst == -1) {
15902305Sstevel /* This assumes that all instances run at the same IPL. */
15912305Sstevel mutex_init(&pcic_deb_mtx, NULL, MUTEX_DRIVER, NULL);
15922305Sstevel cv_init(&pcic_deb_cv, NULL, CV_DRIVER, NULL);
15932305Sstevel pcic_deb_threadid = thread_create((caddr_t)NULL, 0,
15942305Sstevel pcic_deb_thread, (caddr_t)NULL, 0, &p0, TS_RUN,
15952305Sstevel v.v_maxsyspri - 2);
15962305Sstevel }
15972305Sstevel pcic_maxinst = max(pcic_maxinst, ddi_get_instance(dip));
15982305Sstevel /*
15992305Sstevel * Setup a debounce timeout to do an initial card detect
16002305Sstevel * and enable interrupts.
16012305Sstevel */
16022305Sstevel for (j = 0; j < pcic->pc_numsockets; j++) {
16032305Sstevel pcic->pc_sockets[j].pcs_debounce_id =
16042305Sstevel pcic_add_debqueue(&pcic->pc_sockets[j],
16057656SSherry.Moore@Sun.COM drv_usectohz(pcic_debounce_time));
16062305Sstevel }
16072305Sstevel
16082305Sstevel return (i);
16092305Sstevel
16102305Sstevel isa_exit2:
16112305Sstevel mutex_destroy(&pcic->intr_lock);
16122305Sstevel mutex_destroy(&pcic->pc_lock);
16132305Sstevel for (j = i; j < 0; j--)
16142305Sstevel (void) ddi_intr_free(pcic->pc_intr_htblp[j]);
16152305Sstevel isa_exit1:
16162305Sstevel (void) pcmcia_return_intr(dip, pcic->pc_sockets[i].pcs_smi);
16172305Sstevel ddi_regs_map_free(&pcic->handle);
16182305Sstevel if (pcic->pc_flags & PCF_PCIBUS)
16192305Sstevel ddi_regs_map_free(&pcic->cfg_handle);
16202305Sstevel kmem_free(pcic->pc_intr_htblp, pcic->pc_numsockets *
16212305Sstevel sizeof (ddi_intr_handle_t));
16222305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
16232305Sstevel return (DDI_FAILURE);
16242305Sstevel
16252305Sstevel pci_exit2:
16262305Sstevel mutex_destroy(&pcic->intr_lock);
16272305Sstevel mutex_destroy(&pcic->pc_lock);
16282305Sstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
16292305Sstevel pci_exit1:
16302305Sstevel ddi_regs_map_free(&pcic->handle);
16312305Sstevel if (pcic->pc_flags & PCF_PCIBUS)
16322305Sstevel ddi_regs_map_free(&pcic->cfg_handle);
16332305Sstevel kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t));
16342305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
16352305Sstevel return (DDI_FAILURE);
16362305Sstevel }
16372305Sstevel
16382305Sstevel /*
16392305Sstevel * pcic_detach()
16402305Sstevel * request to detach from the system
16412305Sstevel */
16422305Sstevel static int
pcic_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)16432305Sstevel pcic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
16442305Sstevel {
16452305Sstevel anp_t *anp = ddi_get_driver_private(dip);
16462305Sstevel pcicdev_t *pcic = anp->an_private;
16472305Sstevel int i;
16482305Sstevel
16492305Sstevel switch (cmd) {
16502305Sstevel case DDI_DETACH:
16512305Sstevel /* don't detach if the nexus still talks to us */
16522305Sstevel if (pcic->pc_callback != NULL)
16532305Sstevel return (DDI_FAILURE);
16542305Sstevel
16552305Sstevel /* kill off the pm simulation */
16562305Sstevel if (pcic->pc_pmtimer)
16572305Sstevel (void) untimeout(pcic->pc_pmtimer);
16582305Sstevel
16592305Sstevel /* turn everything off for all sockets and chips */
16602305Sstevel for (i = 0; i < pcic->pc_numsockets; i++) {
16612305Sstevel if (pcic->pc_sockets[i].pcs_debounce_id)
16622305Sstevel pcic_rm_debqueue(
16632305Sstevel pcic->pc_sockets[i].pcs_debounce_id);
16642305Sstevel pcic->pc_sockets[i].pcs_debounce_id = 0;
16652305Sstevel
16662305Sstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
16672305Sstevel pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
16682305Sstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
16692305Sstevel /* disable interrupts and put card into RESET */
16702305Sstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
16712305Sstevel }
16722305Sstevel (void) ddi_intr_disable(pcic->pc_pci_intr_hdlp[0]);
16732305Sstevel (void) ddi_intr_remove_handler(pcic->pc_pci_intr_hdlp[0]);
16742305Sstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]);
16752305Sstevel kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t));
16762305Sstevel pcic->pc_flags = 0;
16772305Sstevel mutex_destroy(&pcic->pc_lock);
16782305Sstevel mutex_destroy(&pcic->intr_lock);
16792305Sstevel cv_destroy(&pcic->pm_cv);
16802305Sstevel if (pcic->pc_flags & PCF_PCIBUS)
16817656SSherry.Moore@Sun.COM ddi_regs_map_free(&pcic->cfg_handle);
16822305Sstevel if (pcic->handle)
16837656SSherry.Moore@Sun.COM ddi_regs_map_free(&pcic->handle);
16842305Sstevel kmem_free(pcic, sizeof (pcicdev_t));
16852305Sstevel ddi_soft_state_free(pcic_soft_state_p, ddi_get_instance(dip));
16862305Sstevel return (DDI_SUCCESS);
16872305Sstevel
16882305Sstevel case DDI_SUSPEND:
16892305Sstevel case DDI_PM_SUSPEND:
16902305Sstevel /*
16912305Sstevel * we got a suspend event (either real or imagined)
16922305Sstevel * so notify the nexus proper that all existing cards
16932305Sstevel * should go away.
16942305Sstevel */
16952305Sstevel mutex_enter(&pcic->pc_lock);
16962305Sstevel #ifdef CARDBUS
16977151Srw148561 if (pcic->pc_flags & PCF_CARDBUS) {
16987151Srw148561 for (i = 0; i < pcic->pc_numsockets; i++) {
16992305Sstevel if ((pcic->pc_sockets[i].pcs_flags &
17002305Sstevel (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) ==
17017151Srw148561 (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) {
17027151Srw148561
17037151Srw148561 pcmcia_cb_suspended(
17047656SSherry.Moore@Sun.COM pcic->pc_sockets[i].pcs_socket);
17057151Srw148561 }
17067151Srw148561 }
17077151Srw148561
17087151Srw148561 cardbus_save_children(ddi_get_child(dip));
17097151Srw148561 }
17102305Sstevel #endif
17112305Sstevel /* turn everything off for all sockets and chips */
17122305Sstevel for (i = 0; i < pcic->pc_numsockets; i++) {
17132305Sstevel if (pcic->pc_sockets[i].pcs_debounce_id)
17142305Sstevel pcic_rm_debqueue(
17152305Sstevel pcic->pc_sockets[i].pcs_debounce_id);
17162305Sstevel pcic->pc_sockets[i].pcs_debounce_id = 0;
17172305Sstevel
17182305Sstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0);
17192305Sstevel pcic_putb(pcic, i, PCIC_CARD_DETECT, 0);
17202305Sstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
17212305Sstevel /* disable interrupts and put card into RESET */
17222305Sstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 0);
17232305Sstevel pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
17242305Sstevel if (pcic->pc_flags & PCF_CBPWRCTL)
17252305Sstevel pcic_putcb(pcic, CB_CONTROL, 0);
17262305Sstevel
17272305Sstevel if (pcic->pc_sockets[i].pcs_flags & PCS_CARD_PRESENT) {
17282305Sstevel pcic->pc_sockets[i].pcs_flags = PCS_STARTING;
17292305Sstevel /*
17302305Sstevel * Because we are half way through a save
17312305Sstevel * all this does is schedule a removal event
17322305Sstevel * to cs for when the system comes back.
17332305Sstevel * This doesn't actually matter.
17342305Sstevel */
17352305Sstevel if (!pcic_do_pcmcia_sr && pcic_do_removal &&
17362305Sstevel pcic->pc_callback) {
17372305Sstevel PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
17382305Sstevel PCE_CARD_REMOVAL,
17392305Sstevel pcic->pc_sockets[i].pcs_socket);
17402305Sstevel }
17412305Sstevel }
17422305Sstevel }
17432305Sstevel
17442305Sstevel pcic->pc_flags |= PCF_SUSPENDED;
17452305Sstevel mutex_exit(&pcic->pc_lock);
17462305Sstevel
17472305Sstevel /*
17482305Sstevel * when true power management exists, save the adapter
17492305Sstevel * state here to enable a recovery. For the emulation
17502305Sstevel * condition, the state is gone
17512305Sstevel */
17522305Sstevel return (DDI_SUCCESS);
17532305Sstevel
17542305Sstevel default:
17552305Sstevel return (EINVAL);
17562305Sstevel }
17572305Sstevel }
17582305Sstevel
17592305Sstevel static uint32_t pcic_tisysctl_onbits = ((1<<27) | (1<<15) | (1<<14));
17602305Sstevel static uint32_t pcic_tisysctl_offbits = 0;
17612305Sstevel static uint32_t pcic_default_latency = 0x40;
17622305Sstevel
17632305Sstevel static void
pcic_setup_adapter(pcicdev_t * pcic)17642305Sstevel pcic_setup_adapter(pcicdev_t *pcic)
17652305Sstevel {
17662305Sstevel int i;
17672305Sstevel int value, flags;
17682305Sstevel
17697493SVincent.Wang@Sun.COM #if defined(__i386) || defined(__amd64)
17707493SVincent.Wang@Sun.COM pci_regspec_t *reg;
17717493SVincent.Wang@Sun.COM uchar_t bus, dev, func;
17727493SVincent.Wang@Sun.COM uint_t classcode;
17737493SVincent.Wang@Sun.COM int length;
17747493SVincent.Wang@Sun.COM #endif
17757493SVincent.Wang@Sun.COM
17762305Sstevel if (pcic->pc_flags & PCF_PCIBUS) {
17772305Sstevel /*
17782305Sstevel * all PCI-to-PCMCIA bus bridges need memory and I/O enabled
17792305Sstevel */
17802305Sstevel flags = (PCIC_ENABLE_IO | PCIC_ENABLE_MEM);
17812305Sstevel pcic_iomem_pci_ctl(pcic->cfg_handle, pcic->cfgaddr, flags);
17822305Sstevel }
17832305Sstevel /* enable each socket */
17842305Sstevel for (i = 0; i < pcic->pc_numsockets; i++) {
17852305Sstevel pcic->pc_sockets[i].pcs_flags = 0;
17862305Sstevel /* find out the socket capabilities (I/O vs memory) */
17872305Sstevel value = pcic_getb(pcic, i,
17887656SSherry.Moore@Sun.COM PCIC_CHIP_REVISION) & PCIC_REV_ID_MASK;
17892305Sstevel if (value == PCIC_REV_ID_IO || value == PCIC_REV_ID_BOTH)
17902305Sstevel pcic->pc_sockets[i].pcs_flags |= PCS_SOCKET_IO;
17912305Sstevel
17922305Sstevel /* disable all windows just in case */
17932305Sstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0);
17942305Sstevel
17952305Sstevel switch (pcic->pc_type) {
17962305Sstevel uint32_t cfg32;
17972305Sstevel uint16_t cfg16;
17982305Sstevel uint8_t cfg;
17992305Sstevel
18002305Sstevel /* enable extended registers for Vadem */
18017656SSherry.Moore@Sun.COM case PCIC_VADEM_VG469:
18027656SSherry.Moore@Sun.COM case PCIC_VADEM:
18032305Sstevel
18042305Sstevel /* enable card status change interrupt for socket */
18052305Sstevel break;
18062305Sstevel
18077656SSherry.Moore@Sun.COM case PCIC_I82365SL:
18082305Sstevel break;
18092305Sstevel
18107656SSherry.Moore@Sun.COM case PCIC_CL_PD6710:
18112305Sstevel pcic_putb(pcic, 0, PCIC_MISC_CTL_2, PCIC_LED_ENABLE);
18122305Sstevel break;
18132305Sstevel
18142305Sstevel /*
18152305Sstevel * On the CL_6730, we need to set up the interrupt
18162305Sstevel * signalling mode (PCI mode) and set the SMI and
18172305Sstevel * IRQ interrupt lines to PCI/level-mode.
18182305Sstevel */
18197656SSherry.Moore@Sun.COM case PCIC_CL_PD6730:
18202305Sstevel switch (pcic->pc_intr_mode) {
18212305Sstevel case PCIC_INTR_MODE_PCI_1:
18222305Sstevel clext_reg_write(pcic, i, PCIC_CLEXT_MISC_CTL_3,
18237656SSherry.Moore@Sun.COM ((clext_reg_read(pcic, i,
18247656SSherry.Moore@Sun.COM PCIC_CLEXT_MISC_CTL_3) &
18257656SSherry.Moore@Sun.COM ~PCIC_CLEXT_INT_PCI) |
18267656SSherry.Moore@Sun.COM PCIC_CLEXT_INT_PCI));
18272305Sstevel clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1,
18287656SSherry.Moore@Sun.COM (PCIC_CLEXT_IRQ_LVL_MODE |
18297656SSherry.Moore@Sun.COM PCIC_CLEXT_SMI_LVL_MODE));
18302305Sstevel cfg = PCIC_CL_LP_DYN_MODE;
18312305Sstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg);
18322305Sstevel break;
18332305Sstevel case PCIC_INTR_MODE_ISA:
18342305Sstevel break;
18352305Sstevel }
18362305Sstevel break;
18372305Sstevel /*
18382305Sstevel * On the CL_6729, we set the SMI and IRQ interrupt
18392305Sstevel * lines to PCI/level-mode. as well as program the
18402305Sstevel * correct clock speed divider bit.
18412305Sstevel */
18427656SSherry.Moore@Sun.COM case PCIC_CL_PD6729:
18432305Sstevel switch (pcic->pc_intr_mode) {
18442305Sstevel case PCIC_INTR_MODE_PCI_1:
18452305Sstevel clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1,
18467656SSherry.Moore@Sun.COM (PCIC_CLEXT_IRQ_LVL_MODE |
18477656SSherry.Moore@Sun.COM PCIC_CLEXT_SMI_LVL_MODE));
18482305Sstevel
18492305Sstevel break;
18502305Sstevel case PCIC_INTR_MODE_ISA:
18512305Sstevel break;
18522305Sstevel }
18532305Sstevel if (pcic->bus_speed > PCIC_PCI_25MHZ && i == 0) {
18542305Sstevel cfg = 0;
18552305Sstevel cfg |= PCIC_CL_TIMER_CLK_DIV;
18562305Sstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg);
18572305Sstevel }
18582305Sstevel break;
18597656SSherry.Moore@Sun.COM case PCIC_INTEL_i82092:
18602305Sstevel cfg = PCIC_82092_EN_TIMING;
18612305Sstevel if (pcic->bus_speed < PCIC_SYSCLK_33MHZ)
18627656SSherry.Moore@Sun.COM cfg |= PCIC_82092_PCICLK_25MHZ;
18632305Sstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr +
18647656SSherry.Moore@Sun.COM PCIC_82092_PCICON, cfg);
18652305Sstevel break;
18667656SSherry.Moore@Sun.COM case PCIC_TI_PCI1130:
18677656SSherry.Moore@Sun.COM case PCIC_TI_PCI1131:
18687656SSherry.Moore@Sun.COM case PCIC_TI_PCI1250:
18697656SSherry.Moore@Sun.COM case PCIC_TI_PCI1031:
18702305Sstevel cfg = ddi_get8(pcic->cfg_handle,
18717656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG);
18722305Sstevel cfg &= ~PCIC_DEVCTL_INTR_MASK;
18732305Sstevel switch (pcic->pc_intr_mode) {
18742305Sstevel case PCIC_INTR_MODE_ISA:
18752305Sstevel cfg |= PCIC_DEVCTL_INTR_ISA;
18762305Sstevel break;
18772305Sstevel }
18782305Sstevel #ifdef PCIC_DEBUG
18792305Sstevel if (pcic_debug) {
18802305Sstevel cmn_err(CE_CONT, "pcic_setup_adapter: "
18812305Sstevel "write reg 0x%x=%x \n",
18822305Sstevel PCIC_DEVCTL_REG, cfg);
18832305Sstevel }
18842305Sstevel #endif
18852305Sstevel ddi_put8(pcic->cfg_handle,
18867656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG,
18877656SSherry.Moore@Sun.COM cfg);
18882305Sstevel
18892305Sstevel cfg = ddi_get8(pcic->cfg_handle,
18907656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_CRDCTL_REG);
18912305Sstevel cfg &= ~(PCIC_CRDCTL_PCIINTR|PCIC_CRDCTL_PCICSC|
18927656SSherry.Moore@Sun.COM PCIC_CRDCTL_PCIFUNC);
18932305Sstevel switch (pcic->pc_intr_mode) {
18942305Sstevel case PCIC_INTR_MODE_PCI_1:
18952305Sstevel cfg |= PCIC_CRDCTL_PCIINTR |
18967656SSherry.Moore@Sun.COM PCIC_CRDCTL_PCICSC |
18977656SSherry.Moore@Sun.COM PCIC_CRDCTL_PCIFUNC;
18982305Sstevel pcic->pc_flags |= PCF_USE_SMI;
18992305Sstevel break;
19002305Sstevel }
19012305Sstevel #ifdef PCIC_DEBUG
19022305Sstevel if (pcic_debug) {
19032305Sstevel cmn_err(CE_CONT, "pcic_setup_adapter: "
19042305Sstevel " write reg 0x%x=%x \n",
19052305Sstevel PCIC_CRDCTL_REG, cfg);
19062305Sstevel }
19072305Sstevel #endif
19082305Sstevel ddi_put8(pcic->cfg_handle,
19097656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_CRDCTL_REG,
19107656SSherry.Moore@Sun.COM cfg);
19112305Sstevel break;
19127656SSherry.Moore@Sun.COM case PCIC_TI_PCI1221:
19137656SSherry.Moore@Sun.COM case PCIC_TI_PCI1225:
19142305Sstevel cfg = ddi_get8(pcic->cfg_handle,
19152305Sstevel pcic->cfgaddr + PCIC_DEVCTL_REG);
19162305Sstevel cfg |= (PCIC_DEVCTL_INTR_DFLT | PCIC_DEVCTL_3VCAPABLE);
19172305Sstevel #ifdef PCIC_DEBUG
19182305Sstevel if (pcic_debug) {
19192305Sstevel cmn_err(CE_CONT, "pcic_setup_adapter: "
19202305Sstevel " write reg 0x%x=%x \n",
19212305Sstevel PCIC_DEVCTL_REG, cfg);
19222305Sstevel }
19232305Sstevel #endif
19242305Sstevel ddi_put8(pcic->cfg_handle,
19252305Sstevel pcic->cfgaddr + PCIC_DEVCTL_REG, cfg);
19262305Sstevel
19272305Sstevel cfg = ddi_get8(pcic->cfg_handle,
19282305Sstevel pcic->cfgaddr + PCIC_DIAG_REG);
19292305Sstevel if (pcic->pc_type == PCIC_TI_PCI1225) {
19302305Sstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
19312305Sstevel } else {
19322305Sstevel cfg |= PCIC_DIAG_ASYNC;
19332305Sstevel }
19342305Sstevel pcic->pc_flags |= PCF_USE_SMI;
19352305Sstevel #ifdef PCIC_DEBUG
19362305Sstevel if (pcic_debug) {
19372305Sstevel cmn_err(CE_CONT, "pcic_setup_adapter: "
19382305Sstevel " write reg 0x%x=%x \n",
19392305Sstevel PCIC_DIAG_REG, cfg);
19402305Sstevel }
19412305Sstevel #endif
19422305Sstevel ddi_put8(pcic->cfg_handle,
19432305Sstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg);
19442305Sstevel break;
19457656SSherry.Moore@Sun.COM case PCIC_TI_PCI1520:
19467656SSherry.Moore@Sun.COM case PCIC_TI_PCI1510:
19477656SSherry.Moore@Sun.COM case PCIC_TI_VENDOR:
19482305Sstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) {
19497493SVincent.Wang@Sun.COM /* functional intr routed by ExCA register */
19502305Sstevel cfg = ddi_get8(pcic->cfg_handle,
19517656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
19522305Sstevel cfg |= PCIC_FUN_INT_MOD_ISA;
19532305Sstevel ddi_put8(pcic->cfg_handle,
19547656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
19557656SSherry.Moore@Sun.COM cfg);
19567493SVincent.Wang@Sun.COM
19577493SVincent.Wang@Sun.COM /* IRQ serialized interrupts */
19587493SVincent.Wang@Sun.COM cfg = ddi_get8(pcic->cfg_handle,
19597656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG);
19607493SVincent.Wang@Sun.COM cfg &= ~PCIC_DEVCTL_INTR_MASK;
19617493SVincent.Wang@Sun.COM cfg |= PCIC_DEVCTL_INTR_ISA;
19627493SVincent.Wang@Sun.COM ddi_put8(pcic->cfg_handle,
19637656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG,
19647656SSherry.Moore@Sun.COM cfg);
19657493SVincent.Wang@Sun.COM break;
19662305Sstevel }
19677493SVincent.Wang@Sun.COM
19687493SVincent.Wang@Sun.COM /* CSC interrupt routed to PCI */
19697493SVincent.Wang@Sun.COM cfg = ddi_get8(pcic->cfg_handle,
19707493SVincent.Wang@Sun.COM pcic->cfgaddr + PCIC_DIAG_REG);
19717493SVincent.Wang@Sun.COM cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
19727493SVincent.Wang@Sun.COM ddi_put8(pcic->cfg_handle,
19737493SVincent.Wang@Sun.COM pcic->cfgaddr + PCIC_DIAG_REG, cfg);
19747493SVincent.Wang@Sun.COM
19757493SVincent.Wang@Sun.COM #if defined(__i386) || defined(__amd64)
19767493SVincent.Wang@Sun.COM /*
19777493SVincent.Wang@Sun.COM * Some TI chips have 2 cardbus slots(function0 and
19787493SVincent.Wang@Sun.COM * function1), and others may have just 1 cardbus slot.
19797493SVincent.Wang@Sun.COM * The interrupt routing register is shared between the
19807493SVincent.Wang@Sun.COM * 2 functions and can only be accessed through
19817493SVincent.Wang@Sun.COM * function0. Here we check the presence of the second
19827493SVincent.Wang@Sun.COM * cardbus slot and do the right thing.
19837493SVincent.Wang@Sun.COM */
19847493SVincent.Wang@Sun.COM
19857493SVincent.Wang@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, pcic->dip,
19867493SVincent.Wang@Sun.COM DDI_PROP_DONTPASS, "reg", (caddr_t)®,
19877493SVincent.Wang@Sun.COM &length) != DDI_PROP_SUCCESS) {
19887656SSherry.Moore@Sun.COM cmn_err(CE_WARN,
19897656SSherry.Moore@Sun.COM "pcic_setup_adapter(), failed to"
19907656SSherry.Moore@Sun.COM " read reg property\n");
19917493SVincent.Wang@Sun.COM break;
19927493SVincent.Wang@Sun.COM }
19937493SVincent.Wang@Sun.COM
19947493SVincent.Wang@Sun.COM bus = PCI_REG_BUS_G(reg->pci_phys_hi);
19957493SVincent.Wang@Sun.COM dev = PCI_REG_DEV_G(reg->pci_phys_hi);
19967493SVincent.Wang@Sun.COM func = PCI_REG_FUNC_G(reg->pci_phys_hi);
19977493SVincent.Wang@Sun.COM kmem_free((caddr_t)reg, length);
19987493SVincent.Wang@Sun.COM
19997493SVincent.Wang@Sun.COM if (func != 0) {
20007493SVincent.Wang@Sun.COM break;
20017493SVincent.Wang@Sun.COM }
20027493SVincent.Wang@Sun.COM
20037493SVincent.Wang@Sun.COM classcode = (*pci_getl_func)(bus, dev, 1,
20047656SSherry.Moore@Sun.COM PCI_CONF_REVID);
20057493SVincent.Wang@Sun.COM classcode >>= 8;
20067493SVincent.Wang@Sun.COM if (classcode != 0x060700 &&
20077493SVincent.Wang@Sun.COM classcode != 0x060500) {
20087493SVincent.Wang@Sun.COM break;
20097493SVincent.Wang@Sun.COM }
20107493SVincent.Wang@Sun.COM
20117493SVincent.Wang@Sun.COM /* Parallel PCI interrupts only */
20122305Sstevel cfg = ddi_get8(pcic->cfg_handle,
20137656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG);
20142305Sstevel cfg &= ~PCIC_DEVCTL_INTR_MASK;
20152305Sstevel ddi_put8(pcic->cfg_handle,
20167656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_DEVCTL_REG,
20177656SSherry.Moore@Sun.COM cfg);
20182305Sstevel
20192305Sstevel /* tie INTA and INTB together */
20202305Sstevel cfg = ddi_get8(pcic->cfg_handle,
20217656SSherry.Moore@Sun.COM (pcic->cfgaddr + PCIC_SYSCTL_REG + 3));
20222305Sstevel cfg |= PCIC_SYSCTL_INTRTIE;
20232305Sstevel ddi_put8(pcic->cfg_handle, (pcic->cfgaddr +
20247656SSherry.Moore@Sun.COM PCIC_SYSCTL_REG + 3), cfg);
20257493SVincent.Wang@Sun.COM #endif
20267493SVincent.Wang@Sun.COM
20272305Sstevel break;
20287656SSherry.Moore@Sun.COM case PCIC_TI_PCI1410:
20292305Sstevel cfg = ddi_get8(pcic->cfg_handle,
20302305Sstevel pcic->cfgaddr + PCIC_DIAG_REG);
20312305Sstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC);
20322305Sstevel ddi_put8(pcic->cfg_handle,
20332305Sstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg);
20342305Sstevel break;
20357656SSherry.Moore@Sun.COM case PCIC_TOSHIBA_TOPIC100:
20367656SSherry.Moore@Sun.COM case PCIC_TOSHIBA_TOPIC95:
20377656SSherry.Moore@Sun.COM case PCIC_TOSHIBA_VENDOR:
20382305Sstevel cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr +
20397656SSherry.Moore@Sun.COM PCIC_TOSHIBA_SLOT_CTL_REG);
20402305Sstevel cfg |= (PCIC_TOSHIBA_SCR_SLOTON |
20417656SSherry.Moore@Sun.COM PCIC_TOSHIBA_SCR_SLOTEN);
20422305Sstevel cfg &= (~PCIC_TOSHIBA_SCR_PRT_MASK);
20432305Sstevel cfg |= PCIC_TOSHIBA_SCR_PRT_3E2;
20442305Sstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr +
20457656SSherry.Moore@Sun.COM PCIC_TOSHIBA_SLOT_CTL_REG, cfg);
20462305Sstevel cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr +
20477656SSherry.Moore@Sun.COM PCIC_TOSHIBA_INTR_CTL_REG);
20482305Sstevel switch (pcic->pc_intr_mode) {
20492305Sstevel case PCIC_INTR_MODE_ISA:
20502305Sstevel cfg &= ~PCIC_TOSHIBA_ICR_SRC;
20512305Sstevel ddi_put8(pcic->cfg_handle,
20527656SSherry.Moore@Sun.COM pcic->cfgaddr +
20537656SSherry.Moore@Sun.COM PCIC_TOSHIBA_INTR_CTL_REG, cfg);
20542305Sstevel
20552305Sstevel cfg = ddi_get8(pcic->cfg_handle,
20567656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
20572305Sstevel cfg |= PCIC_FUN_INT_MOD_ISA;
20582305Sstevel ddi_put8(pcic->cfg_handle,
20597656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
20607656SSherry.Moore@Sun.COM cfg);
20612305Sstevel break;
20622305Sstevel case PCIC_INTR_MODE_PCI_1:
20632305Sstevel cfg |= PCIC_TOSHIBA_ICR_SRC;
20642305Sstevel cfg &= (~PCIC_TOSHIBA_ICR_PIN_MASK);
20652305Sstevel cfg |= PCIC_TOSHIBA_ICR_PIN_INTA;
20662305Sstevel ddi_put8(pcic->cfg_handle,
20677656SSherry.Moore@Sun.COM pcic->cfgaddr +
20687656SSherry.Moore@Sun.COM PCIC_TOSHIBA_INTR_CTL_REG, cfg);
20692305Sstevel break;
20702305Sstevel }
20712305Sstevel break;
20727656SSherry.Moore@Sun.COM case PCIC_O2MICRO_VENDOR:
20732305Sstevel cfg32 = ddi_get32(pcic->cfg_handle,
20747656SSherry.Moore@Sun.COM (uint32_t *)(pcic->cfgaddr +
20757656SSherry.Moore@Sun.COM PCIC_O2MICRO_MISC_CTL));
20762305Sstevel switch (pcic->pc_intr_mode) {
20772305Sstevel case PCIC_INTR_MODE_ISA:
20782305Sstevel cfg32 |= (PCIC_O2MICRO_ISA_LEGACY |
20797656SSherry.Moore@Sun.COM PCIC_O2MICRO_INT_MOD_PCI);
20802305Sstevel ddi_put32(pcic->cfg_handle,
20817656SSherry.Moore@Sun.COM (uint32_t *)(pcic->cfgaddr +
20827656SSherry.Moore@Sun.COM PCIC_O2MICRO_MISC_CTL),
20837656SSherry.Moore@Sun.COM cfg32);
20842305Sstevel cfg = ddi_get8(pcic->cfg_handle,
20857656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
20862305Sstevel cfg |= PCIC_FUN_INT_MOD_ISA;
20872305Sstevel ddi_put8(pcic->cfg_handle,
20887656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
20897656SSherry.Moore@Sun.COM cfg);
20902305Sstevel break;
20912305Sstevel case PCIC_INTR_MODE_PCI_1:
20922305Sstevel cfg32 &= ~PCIC_O2MICRO_ISA_LEGACY;
20932305Sstevel cfg32 |= PCIC_O2MICRO_INT_MOD_PCI;
20942305Sstevel ddi_put32(pcic->cfg_handle,
20957656SSherry.Moore@Sun.COM (uint32_t *)(pcic->cfgaddr +
20967656SSherry.Moore@Sun.COM PCIC_O2MICRO_MISC_CTL),
20977656SSherry.Moore@Sun.COM cfg32);
20982305Sstevel break;
20992305Sstevel }
21002305Sstevel break;
21017656SSherry.Moore@Sun.COM case PCIC_RICOH_VENDOR:
21022305Sstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) {
21032305Sstevel cfg16 = ddi_get16(pcic->cfg_handle,
21047656SSherry.Moore@Sun.COM (uint16_t *)(pcic->cfgaddr +
21057656SSherry.Moore@Sun.COM PCIC_RICOH_MISC_CTL_2));
21062305Sstevel cfg16 |= (PCIC_RICOH_CSC_INT_MOD |
21077656SSherry.Moore@Sun.COM PCIC_RICOH_FUN_INT_MOD);
21082305Sstevel ddi_put16(pcic->cfg_handle,
21097656SSherry.Moore@Sun.COM (uint16_t *)(pcic->cfgaddr +
21107656SSherry.Moore@Sun.COM PCIC_RICOH_MISC_CTL_2),
21117656SSherry.Moore@Sun.COM cfg16);
21122305Sstevel
21132305Sstevel cfg16 = ddi_get16(pcic->cfg_handle,
21147656SSherry.Moore@Sun.COM (uint16_t *)(pcic->cfgaddr +
21157656SSherry.Moore@Sun.COM PCIC_RICOH_MISC_CTL));
21162305Sstevel cfg16 |= PCIC_RICOH_SIRQ_EN;
21172305Sstevel ddi_put16(pcic->cfg_handle,
21187656SSherry.Moore@Sun.COM (uint16_t *)(pcic->cfgaddr +
21197656SSherry.Moore@Sun.COM PCIC_RICOH_MISC_CTL),
21207656SSherry.Moore@Sun.COM cfg16);
21212305Sstevel
21222305Sstevel cfg = ddi_get8(pcic->cfg_handle,
21237656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
21242305Sstevel cfg |= PCIC_FUN_INT_MOD_ISA;
21252305Sstevel ddi_put8(pcic->cfg_handle,
21267656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
21277656SSherry.Moore@Sun.COM cfg);
21282305Sstevel }
21292305Sstevel break;
21307656SSherry.Moore@Sun.COM default:
21312305Sstevel break;
21322305Sstevel } /* switch */
21332305Sstevel
21343097Srw148561 /*
21353097Srw148561 * The default value in the EEPROM (loaded on reset) for
21363097Srw148561 * MFUNC0/MFUNC1 may be incorrect. Here we make sure that
21373097Srw148561 * MFUNC0 is connected to INTA, and MFUNC1 is connected to
21383097Srw148561 * INTB. This applies to all TI CardBus controllers.
21393097Srw148561 */
21403097Srw148561 if ((pcic->pc_type >> 16) == PCIC_TI_VENDORID &&
21417656SSherry.Moore@Sun.COM pcic->pc_intr_mode == PCIC_INTR_MODE_PCI_1) {
21423097Srw148561 value = ddi_get32(pcic->cfg_handle,
21433097Srw148561 (uint32_t *)(pcic->cfgaddr + PCIC_MFROUTE_REG));
21443097Srw148561 value &= ~0xff;
21453097Srw148561 ddi_put32(pcic->cfg_handle, (uint32_t *)(pcic->cfgaddr +
21463664Srw148561 PCIC_MFROUTE_REG), value|PCIC_TI_MFUNC_SEL);
21473097Srw148561 }
21483097Srw148561
21492305Sstevel /* setup general card status change interrupt */
21502305Sstevel switch (pcic->pc_type) {
21512305Sstevel case PCIC_TI_PCI1225:
21522305Sstevel case PCIC_TI_PCI1221:
21532305Sstevel case PCIC_TI_PCI1031:
21542305Sstevel case PCIC_TI_PCI1520:
21552305Sstevel case PCIC_TI_PCI1410:
21562305Sstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
21572305Sstevel PCIC_CHANGE_DEFAULT);
21582305Sstevel break;
21592305Sstevel default:
21602305Sstevel if (pcic->pc_intr_mode ==
21617656SSherry.Moore@Sun.COM PCIC_INTR_MODE_PCI_1) {
21622305Sstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
21637656SSherry.Moore@Sun.COM PCIC_CHANGE_DEFAULT);
21642305Sstevel break;
21652305Sstevel } else {
21662305Sstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT,
21677656SSherry.Moore@Sun.COM PCIC_CHANGE_DEFAULT |
21687656SSherry.Moore@Sun.COM (pcic->pc_sockets[i].pcs_smi << 4));
21692305Sstevel break;
21702305Sstevel }
21712305Sstevel }
21722305Sstevel
21732305Sstevel pcic->pc_flags |= PCF_INTRENAB;
21742305Sstevel
21752305Sstevel /* take card out of RESET */
21762305Sstevel pcic_putb(pcic, i, PCIC_INTERRUPT, PCIC_RESET);
21772305Sstevel /* turn power off and let CS do this */
21782305Sstevel pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0);
21792305Sstevel
21802305Sstevel /* final chip specific initialization */
21812305Sstevel switch (pcic->pc_type) {
21827656SSherry.Moore@Sun.COM case PCIC_VADEM:
21832305Sstevel pcic_putb(pcic, i, PCIC_VG_CONTROL,
21847656SSherry.Moore@Sun.COM PCIC_VC_DELAYENABLE);
21852305Sstevel pcic->pc_flags |= PCF_DEBOUNCE;
21862305Sstevel /* FALLTHROUGH */
21877656SSherry.Moore@Sun.COM case PCIC_I82365SL:
21882305Sstevel pcic_putb(pcic, i, PCIC_GLOBAL_CONTROL,
21897656SSherry.Moore@Sun.COM PCIC_GC_CSC_WRITE);
21902305Sstevel /* clear any pending interrupts */
21912305Sstevel value = pcic_getb(pcic, i, PCIC_CARD_STATUS_CHANGE);
21922305Sstevel pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, value);
21932305Sstevel break;
21942305Sstevel /* The 82092 uses PCI config space to enable interrupts */
21957656SSherry.Moore@Sun.COM case PCIC_INTEL_i82092:
21962305Sstevel pcic_82092_smiirq_ctl(pcic, i, PCIC_82092_CTL_SMI,
21977656SSherry.Moore@Sun.COM PCIC_82092_INT_ENABLE);
21982305Sstevel break;
21997656SSherry.Moore@Sun.COM case PCIC_CL_PD6729:
22002305Sstevel if (pcic->bus_speed >= PCIC_PCI_DEF_SYSCLK && i == 0) {
22012305Sstevel value = pcic_getb(pcic, i, PCIC_MISC_CTL_2);
22022305Sstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2,
22037656SSherry.Moore@Sun.COM value | PCIC_CL_TIMER_CLK_DIV);
22042305Sstevel }
22052305Sstevel break;
22062305Sstevel } /* switch */
22072305Sstevel
22082305Sstevel #if defined(PCIC_DEBUG)
22092305Sstevel if (pcic_debug)
22102305Sstevel cmn_err(CE_CONT,
22117656SSherry.Moore@Sun.COM "socket %d value=%x, flags = %x (%s)\n",
22127656SSherry.Moore@Sun.COM i, value, pcic->pc_sockets[i].pcs_flags,
22137656SSherry.Moore@Sun.COM (pcic->pc_sockets[i].pcs_flags &
22147656SSherry.Moore@Sun.COM PCS_CARD_PRESENT) ?
22157656SSherry.Moore@Sun.COM "card present" : "no card");
22162305Sstevel #endif
22172305Sstevel }
22182305Sstevel }
22192305Sstevel
22202305Sstevel /*
22212305Sstevel * pcic_intr(caddr_t, caddr_t)
22222305Sstevel * interrupt handler for the PCIC style adapter
22232305Sstevel * handles all basic interrupts and also checks
22242305Sstevel * for status changes and notifies the nexus if
22252305Sstevel * necessary
22262305Sstevel *
22272305Sstevel * On PCI bus adapters, also handles all card
22282305Sstevel * IO interrupts.
22292305Sstevel */
22302305Sstevel /*ARGSUSED*/
22312305Sstevel uint32_t
pcic_intr(caddr_t arg1,caddr_t arg2)22322305Sstevel pcic_intr(caddr_t arg1, caddr_t arg2)
22332305Sstevel {
22342305Sstevel pcicdev_t *pcic = (pcicdev_t *)arg1;
22352305Sstevel int value = 0, i, ret = DDI_INTR_UNCLAIMED;
22362305Sstevel uint8_t status;
22372305Sstevel uint_t io_ints;
22382305Sstevel
22392305Sstevel #if defined(PCIC_DEBUG)
22402305Sstevel pcic_err(pcic->dip, 0xf,
22417656SSherry.Moore@Sun.COM "pcic_intr: enter pc_flags=0x%x PCF_ATTACHED=0x%x"
22427656SSherry.Moore@Sun.COM " pc_numsockets=%d \n",
22437656SSherry.Moore@Sun.COM pcic->pc_flags, PCF_ATTACHED, pcic->pc_numsockets);
22442305Sstevel #endif
22452305Sstevel
22462305Sstevel if (!(pcic->pc_flags & PCF_ATTACHED))
22477656SSherry.Moore@Sun.COM return (DDI_INTR_UNCLAIMED);
22482305Sstevel
22492305Sstevel mutex_enter(&pcic->intr_lock);
22502305Sstevel
22512305Sstevel if (pcic->pc_flags & PCF_SUSPENDED) {
22522305Sstevel mutex_exit(&pcic->intr_lock);
22532305Sstevel return (ret);
22542305Sstevel }
22552305Sstevel
22562305Sstevel /*
22572305Sstevel * need to change to only ACK and touch the slot that
22582305Sstevel * actually caused the interrupt. Currently everything
22592305Sstevel * is acked
22602305Sstevel *
22612305Sstevel * we need to look at all known sockets to determine
22622305Sstevel * what might have happened, so step through the list
22632305Sstevel * of them
22642305Sstevel */
22652305Sstevel
22662305Sstevel /*
22672305Sstevel * Set the bitmask for IO interrupts to initially include all sockets
22682305Sstevel */
22692305Sstevel io_ints = (1 << pcic->pc_numsockets) - 1;
22702305Sstevel
22712305Sstevel for (i = 0; i < pcic->pc_numsockets; i++) {
22722305Sstevel int card_type;
22732305Sstevel pcic_socket_t *sockp;
22742305Sstevel int value_cb = 0;
22752305Sstevel
22762305Sstevel sockp = &pcic->pc_sockets[i];
22772305Sstevel /* get the socket's I/O addresses */
22782305Sstevel
22792305Sstevel if (sockp->pcs_flags & PCS_WAITING) {
22802305Sstevel io_ints &= ~(1 << i);
22812305Sstevel continue;
22822305Sstevel }
22832305Sstevel
22842305Sstevel if (sockp->pcs_flags & PCS_CARD_IO)
22852305Sstevel card_type = IF_IO;
22862305Sstevel else
22872305Sstevel card_type = IF_MEMORY;
22882305Sstevel
22892305Sstevel if (pcic->pc_io_type == PCIC_IO_TYPE_YENTA)
22902305Sstevel value_cb = pcic_getcb(pcic, CB_STATUS_EVENT);
22912305Sstevel
22922305Sstevel value = pcic_change(pcic, i);
22932305Sstevel
22942305Sstevel if ((value != 0) || (value_cb != 0)) {
22952305Sstevel int x = pcic->pc_cb_arg;
22962305Sstevel
22972305Sstevel ret = DDI_INTR_CLAIMED;
22982305Sstevel
22992305Sstevel #if defined(PCIC_DEBUG)
23002305Sstevel pcic_err(pcic->dip, 0x9,
23012305Sstevel "card_type = %d, value_cb = 0x%x\n",
23022305Sstevel card_type,
23032305Sstevel value_cb ? value_cb :
23047656SSherry.Moore@Sun.COM pcic_getcb(pcic, CB_STATUS_EVENT));
23052305Sstevel if (pcic_debug)
23062305Sstevel cmn_err(CE_CONT,
23077656SSherry.Moore@Sun.COM "\tchange on socket %d (%x)\n", i,
23087656SSherry.Moore@Sun.COM value);
23092305Sstevel #endif
23102305Sstevel /* find out what happened */
23112305Sstevel status = pcic_getb(pcic, i, PCIC_INTERFACE_STATUS);
23122305Sstevel
23132305Sstevel /* acknowledge the interrupt */
23142305Sstevel if (value_cb)
23152305Sstevel pcic_putcb(pcic, CB_STATUS_EVENT, value_cb);
23162305Sstevel
23172305Sstevel if (value)
23182305Sstevel pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE,
23192305Sstevel value);
23202305Sstevel
23212305Sstevel if (pcic->pc_callback == NULL) {
23222305Sstevel /* if not callback handler, nothing to do */
23232305Sstevel continue;
23242305Sstevel }
23252305Sstevel
23262305Sstevel /* Card Detect */
23272305Sstevel if (value & PCIC_CD_DETECT ||
23282305Sstevel value_cb & CB_PS_CCDMASK) {
23292305Sstevel uint8_t irq;
23302305Sstevel #if defined(PCIC_DEBUG)
23312305Sstevel if (pcic_debug)
23322305Sstevel cmn_err(CE_CONT,
23337656SSherry.Moore@Sun.COM "\tcd_detect: status=%x,"
23347656SSherry.Moore@Sun.COM " flags=%x\n",
23357656SSherry.Moore@Sun.COM status, sockp->pcs_flags);
23362305Sstevel #else
23372305Sstevel #ifdef lint
23382305Sstevel if (status == 0)
23397656SSherry.Moore@Sun.COM status++;
23402305Sstevel #endif
23412305Sstevel #endif
23422305Sstevel /*
23432305Sstevel * Turn off all interrupts for this socket here.
23442305Sstevel */
23452305Sstevel irq = pcic_getb(pcic, sockp->pcs_socket,
23462305Sstevel PCIC_MANAGEMENT_INT);
23472305Sstevel irq &= ~PCIC_CHANGE_MASK;
23482305Sstevel pcic_putb(pcic, sockp->pcs_socket,
23492305Sstevel PCIC_MANAGEMENT_INT, irq);
23502305Sstevel
23512305Sstevel pcic_putcb(pcic, CB_STATUS_MASK, 0x0);
23522305Sstevel
23532451Srw148561 /*
23542451Srw148561 * Put the socket in debouncing state so that
23552451Srw148561 * the leaf driver won't receive interrupts.
23562451Srw148561 * Crucial for handling surprise-removal.
23572451Srw148561 */
23582451Srw148561 sockp->pcs_flags |= PCS_DEBOUNCING;
23592451Srw148561
23602305Sstevel if (!sockp->pcs_cd_softint_flg) {
23612305Sstevel sockp->pcs_cd_softint_flg = 1;
23622305Sstevel (void) ddi_intr_trigger_softint(
23632305Sstevel sockp->pcs_cd_softint_hdl, NULL);
23642305Sstevel }
23652305Sstevel
23662305Sstevel io_ints &= ~(1 << i);
23672305Sstevel } /* PCIC_CD_DETECT */
23682305Sstevel
23692305Sstevel /* Ready/Change Detect */
23702305Sstevel sockp->pcs_state ^= SBM_RDYBSY;
23712305Sstevel if (card_type == IF_MEMORY && value & PCIC_RD_DETECT) {
23722305Sstevel sockp->pcs_flags |= PCS_READY;
23732305Sstevel PC_CALLBACK(pcic->dip, x, PCE_CARD_READY, i);
23742305Sstevel }
23752305Sstevel
23762305Sstevel /* Battery Warn Detect */
23772305Sstevel if (card_type == IF_MEMORY &&
23782305Sstevel value & PCIC_BW_DETECT &&
23792305Sstevel !(sockp->pcs_state & SBM_BVD2)) {
23802305Sstevel sockp->pcs_state |= SBM_BVD2;
23812305Sstevel PC_CALLBACK(pcic->dip, x,
23827656SSherry.Moore@Sun.COM PCE_CARD_BATTERY_WARN, i);
23832305Sstevel }
23842305Sstevel
23852305Sstevel /* Battery Dead Detect */
23862305Sstevel if (value & PCIC_BD_DETECT) {
23872305Sstevel /*
23882305Sstevel * need to work out event if RI not enabled
23892305Sstevel * and card_type == IF_IO
23902305Sstevel */
23912305Sstevel if (card_type == IF_MEMORY &&
23927656SSherry.Moore@Sun.COM !(sockp->pcs_state & SBM_BVD1)) {
23932305Sstevel sockp->pcs_state |= SBM_BVD1;
23942305Sstevel PC_CALLBACK(pcic->dip, x,
23957656SSherry.Moore@Sun.COM PCE_CARD_BATTERY_DEAD,
23967656SSherry.Moore@Sun.COM i);
23972305Sstevel } else {
23982305Sstevel /*
23992305Sstevel * information in pin replacement
24002305Sstevel * register if one is available
24012305Sstevel */
24022305Sstevel PC_CALLBACK(pcic->dip, x,
24037656SSherry.Moore@Sun.COM PCE_CARD_STATUS_CHANGE,
24047656SSherry.Moore@Sun.COM i);
24052305Sstevel } /* IF_MEMORY */
24062305Sstevel } /* PCIC_BD_DETECT */
24072305Sstevel } /* if pcic_change */
24082305Sstevel /*
24092305Sstevel * for any controllers that we can detect whether a socket
24102305Sstevel * had an interrupt for the PC Card, we should sort that out
24112305Sstevel * here.
24122305Sstevel */
24132305Sstevel } /* for pc_numsockets */
24142305Sstevel
24152305Sstevel /*
24162305Sstevel * If we're on a PCI bus, we may need to cycle through each IO
24172305Sstevel * interrupt handler that is registered since they all
24182305Sstevel * share the same interrupt line.
24192305Sstevel */
24202305Sstevel
24212305Sstevel
24222305Sstevel #if defined(PCIC_DEBUG)
24232305Sstevel pcic_err(pcic->dip, 0xf,
24242305Sstevel "pcic_intr: pc_intr_mode=%d pc_type=%x io_ints=0x%x\n",
24252305Sstevel pcic->pc_intr_mode, pcic->pc_type, io_ints);
24262305Sstevel #endif
24272305Sstevel
24282451Srw148561 if (io_ints) {
24292451Srw148561 if (pcic_do_io_intr(pcic, io_ints) == DDI_INTR_CLAIMED)
24302305Sstevel ret = DDI_INTR_CLAIMED;
24312305Sstevel }
24322305Sstevel
24332305Sstevel mutex_exit(&pcic->intr_lock);
24342305Sstevel
24352305Sstevel #if defined(PCIC_DEBUG)
24362305Sstevel pcic_err(pcic->dip, 0xf,
24372305Sstevel "pcic_intr: ret=%d value=%d DDI_INTR_CLAIMED=%d\n",
24382305Sstevel ret, value, DDI_INTR_CLAIMED);
24392305Sstevel #endif
24402305Sstevel
24412305Sstevel return (ret);
24422305Sstevel }
24432305Sstevel
24442305Sstevel /*
24452305Sstevel * pcic_change()
24462305Sstevel * check to see if this socket had a change in state
24472305Sstevel * by checking the status change register
24482305Sstevel */
24492305Sstevel static int
pcic_change(pcicdev_t * pcic,int socket)24502305Sstevel pcic_change(pcicdev_t *pcic, int socket)
24512305Sstevel {
24522305Sstevel return (pcic_getb(pcic, socket, PCIC_CARD_STATUS_CHANGE));
24532305Sstevel }
24542305Sstevel
24552305Sstevel /*
24562305Sstevel * pcic_do_io_intr - calls client interrupt handlers
24572305Sstevel */
24582305Sstevel static int
pcic_do_io_intr(pcicdev_t * pcic,uint32_t sockets)24592305Sstevel pcic_do_io_intr(pcicdev_t *pcic, uint32_t sockets)
24602305Sstevel {
24612305Sstevel inthandler_t *tmp;
24622305Sstevel int ret = DDI_INTR_UNCLAIMED;
24632305Sstevel
24642305Sstevel #if defined(PCIC_DEBUG)
24652305Sstevel pcic_err(pcic->dip, 0xf,
24667656SSherry.Moore@Sun.COM "pcic_do_io_intr: pcic=%p sockets=%d irq_top=%p\n",
24677656SSherry.Moore@Sun.COM (void *)pcic, (int)sockets, (void *)pcic->irq_top);
24682305Sstevel #endif
24692305Sstevel
24702305Sstevel if (pcic->irq_top != NULL) {
24717656SSherry.Moore@Sun.COM tmp = pcic->irq_current;
24727656SSherry.Moore@Sun.COM
24737656SSherry.Moore@Sun.COM do {
24742305Sstevel int cur = pcic->irq_current->socket;
24752305Sstevel pcic_socket_t *sockp =
24767656SSherry.Moore@Sun.COM &pcic->pc_sockets[cur];
24772305Sstevel
24782305Sstevel #if defined(PCIC_DEBUG)
24792305Sstevel pcic_err(pcic->dip, 0xf,
24802305Sstevel "\t pcs_flags=0x%x PCS_CARD_PRESENT=0x%x\n",
24812305Sstevel sockp->pcs_flags, PCS_CARD_PRESENT);
24822305Sstevel pcic_err(pcic->dip, 0xf,
24832305Sstevel "\t sockets=%d cur=%d intr=%p arg1=%p "
24842305Sstevel "arg2=%p\n",
24852305Sstevel sockets, cur, (void *)pcic->irq_current->intr,
24862305Sstevel pcic->irq_current->arg1,
24872305Sstevel pcic->irq_current->arg2);
24882305Sstevel #endif
24892451Srw148561 if ((sockp->pcs_flags & PCS_CARD_PRESENT) &&
24902451Srw148561 !(sockp->pcs_flags & PCS_DEBOUNCING) &&
24912451Srw148561 (sockets & (1 << cur))) {
24922305Sstevel
24932305Sstevel if ((*pcic->irq_current->intr)(pcic->irq_current->arg1,
24942305Sstevel pcic->irq_current->arg2) == DDI_INTR_CLAIMED)
24952305Sstevel ret = DDI_INTR_CLAIMED;
24962305Sstevel
24972305Sstevel #if defined(PCIC_DEBUG)
24982305Sstevel pcic_err(pcic->dip, 0xf,
24992305Sstevel "\t ret=%d DDI_INTR_CLAIMED=%d\n",
25002305Sstevel ret, DDI_INTR_CLAIMED);
25012305Sstevel #endif
25022305Sstevel }
25032305Sstevel
25042305Sstevel
25052305Sstevel if ((pcic->irq_current = pcic->irq_current->next) == NULL)
25062305Sstevel pcic->irq_current = pcic->irq_top;
25072305Sstevel
25087656SSherry.Moore@Sun.COM } while (pcic->irq_current != tmp);
25097656SSherry.Moore@Sun.COM
25107656SSherry.Moore@Sun.COM if ((pcic->irq_current = pcic->irq_current->next) == NULL)
25112305Sstevel pcic->irq_current = pcic->irq_top;
25122305Sstevel
25132305Sstevel } else {
25142305Sstevel ret = DDI_INTR_UNCLAIMED;
25152305Sstevel }
25162305Sstevel
25172305Sstevel #if defined(PCIC_DEBUG)
25182305Sstevel pcic_err(pcic->dip, 0xf,
25197656SSherry.Moore@Sun.COM "pcic_do_io_intr: exit ret=%d DDI_INTR_CLAIMED=%d\n",
25207656SSherry.Moore@Sun.COM ret, DDI_INTR_CLAIMED);
25212305Sstevel #endif
25222305Sstevel
25232305Sstevel return (ret);
25242305Sstevel
25252305Sstevel }
25262305Sstevel
25272305Sstevel /*
25282305Sstevel * pcic_inquire_adapter()
25292305Sstevel * SocketServices InquireAdapter function
25302305Sstevel * get characteristics of the physical adapter
25312305Sstevel */
25322305Sstevel /*ARGSUSED*/
25332305Sstevel static int
pcic_inquire_adapter(dev_info_t * dip,inquire_adapter_t * config)25342305Sstevel pcic_inquire_adapter(dev_info_t *dip, inquire_adapter_t *config)
25352305Sstevel {
25362305Sstevel anp_t *anp = ddi_get_driver_private(dip);
25372305Sstevel pcicdev_t *pcic = anp->an_private;
25382305Sstevel
25392305Sstevel config->NumSockets = pcic->pc_numsockets;
25402305Sstevel config->NumWindows = pcic->pc_numsockets * PCIC_NUMWINSOCK;
25412305Sstevel config->NumEDCs = 0;
25422305Sstevel config->AdpCaps = 0;
25432305Sstevel config->ActiveHigh = 0;
25442305Sstevel config->ActiveLow = PCIC_AVAIL_IRQS;
25452305Sstevel config->NumPower = pcic->pc_numpower;
25462305Sstevel config->power_entry = pcic->pc_power; /* until we resolve this */
25472305Sstevel #if defined(PCIC_DEBUG)
25482305Sstevel if (pcic_debug) {
25492305Sstevel cmn_err(CE_CONT, "pcic_inquire_adapter:\n");
25502305Sstevel cmn_err(CE_CONT, "\tNumSockets=%d\n", config->NumSockets);
25512305Sstevel cmn_err(CE_CONT, "\tNumWindows=%d\n", config->NumWindows);
25522305Sstevel }
25532305Sstevel #endif
25542305Sstevel config->ResourceFlags = 0;
25552305Sstevel switch (pcic->pc_intr_mode) {
25562305Sstevel case PCIC_INTR_MODE_PCI_1:
25572305Sstevel config->ResourceFlags |= RES_OWN_IRQ | RES_IRQ_NEXUS |
25587656SSherry.Moore@Sun.COM RES_IRQ_SHAREABLE;
25592305Sstevel break;
25602305Sstevel }
25612305Sstevel return (SUCCESS);
25622305Sstevel }
25632305Sstevel
25642305Sstevel /*
25652305Sstevel * pcic_callback()
25662305Sstevel * The PCMCIA nexus calls us via this function
25672305Sstevel * in order to set the callback function we are
25682305Sstevel * to call the nexus with
25692305Sstevel */
25702305Sstevel /*ARGSUSED*/
25712305Sstevel static int
pcic_callback(dev_info_t * dip,int (* handler)(),int arg)25722305Sstevel pcic_callback(dev_info_t *dip, int (*handler)(), int arg)
25732305Sstevel {
25742305Sstevel anp_t *anp = ddi_get_driver_private(dip);
25752305Sstevel pcicdev_t *pcic = anp->an_private;
25762305Sstevel
25772305Sstevel if (handler != NULL) {
25782305Sstevel pcic->pc_callback = handler;
25792305Sstevel pcic->pc_cb_arg = arg;
25802305Sstevel pcic->pc_flags |= PCF_CALLBACK;
25812305Sstevel } else {
25822305Sstevel pcic->pc_callback = NULL;
25832305Sstevel pcic->pc_cb_arg = 0;
25842305Sstevel pcic->pc_flags &= ~PCF_CALLBACK;
25852305Sstevel }
25862305Sstevel /*
25872305Sstevel * we're now registered with the nexus
25882305Sstevel * it is acceptable to do callbacks at this point.
25892305Sstevel * don't call back from here though since it could block
25902305Sstevel */
25912305Sstevel return (PC_SUCCESS);
25922305Sstevel }
25932305Sstevel
25942305Sstevel /*
25952305Sstevel * pcic_calc_speed (pcicdev_t *pcic, uint32_t speed)
25962305Sstevel * calculate the speed bits from the specified memory speed
25972305Sstevel * there may be more to do here
25982305Sstevel */
25992305Sstevel
26002305Sstevel static int
pcic_calc_speed(pcicdev_t * pcic,uint32_t speed)26012305Sstevel pcic_calc_speed(pcicdev_t *pcic, uint32_t speed)
26022305Sstevel {
26032305Sstevel uint32_t wspeed = 1; /* assume 1 wait state when unknown */
26042305Sstevel uint32_t bspeed = PCIC_ISA_DEF_SYSCLK;
26052305Sstevel
26062305Sstevel switch (pcic->pc_type) {
26077656SSherry.Moore@Sun.COM case PCIC_I82365SL:
26087656SSherry.Moore@Sun.COM case PCIC_VADEM:
26097656SSherry.Moore@Sun.COM case PCIC_VADEM_VG469:
26107656SSherry.Moore@Sun.COM default:
26112305Sstevel /* Intel chip wants it in waitstates */
26122305Sstevel wspeed = mhztons(PCIC_ISA_DEF_SYSCLK) * 3;
26132305Sstevel if (speed <= wspeed)
26142305Sstevel wspeed = 0;
26152305Sstevel else if (speed <= (wspeed += mhztons(bspeed)))
26162305Sstevel wspeed = 1;
26172305Sstevel else if (speed <= (wspeed += mhztons(bspeed)))
26182305Sstevel wspeed = 2;
26192305Sstevel else
26202305Sstevel wspeed = 3;
26212305Sstevel wspeed <<= 6; /* put in right bit positions */
26222305Sstevel break;
26232305Sstevel
26247656SSherry.Moore@Sun.COM case PCIC_INTEL_i82092:
26252305Sstevel wspeed = SYSMEM_82092_80NS;
26262305Sstevel if (speed > 80)
26277656SSherry.Moore@Sun.COM wspeed = SYSMEM_82092_100NS;
26282305Sstevel if (speed > 100)
26297656SSherry.Moore@Sun.COM wspeed = SYSMEM_82092_150NS;
26302305Sstevel if (speed > 150)
26317656SSherry.Moore@Sun.COM wspeed = SYSMEM_82092_200NS;
26322305Sstevel if (speed > 200)
26337656SSherry.Moore@Sun.COM wspeed = SYSMEM_82092_250NS;
26342305Sstevel if (speed > 250)
26357656SSherry.Moore@Sun.COM wspeed = SYSMEM_82092_600NS;
26362305Sstevel wspeed <<= 5; /* put in right bit positions */
26372305Sstevel break;
26382305Sstevel
26392305Sstevel } /* switch */
26402305Sstevel
26412305Sstevel return (wspeed);
26422305Sstevel }
26432305Sstevel
26442305Sstevel /*
26452305Sstevel * These values are taken from the PC Card Standard Electrical Specification.
26462305Sstevel * Generally the larger value is taken if 2 are possible.
26472305Sstevel */
26482305Sstevel static struct pcic_card_times {
26492305Sstevel uint16_t cycle; /* Speed as found in the atribute space of he card. */
26502305Sstevel uint16_t setup; /* Corresponding address setup time. */
26512305Sstevel uint16_t width; /* Corresponding width, OE or WE. */
26522305Sstevel uint16_t hold; /* Corresponding data or address hold time. */
26532305Sstevel } pcic_card_times[] = {
26542305Sstevel
26552305Sstevel /*
26562305Sstevel * Note: The rounded up times for 250, 200 & 150 have been increased
26572305Sstevel * due to problems with the 3-Com ethernet cards (pcelx) on UBIIi.
26582305Sstevel * See BugID 00663.
26592305Sstevel */
26602305Sstevel
26612305Sstevel /*
26622305Sstevel * Rounded up times Original times from
26632305Sstevel * that add up to the the PCMCIA Spec.
26642305Sstevel * cycle time.
26652305Sstevel */
26662305Sstevel {600, 180, 370, 140}, /* 100, 300, 70 */
26672305Sstevel {400, 120, 300, 90}, /* Made this one up */
26682305Sstevel {250, 100, 190, 70}, /* 30, 150, 30 */
26692305Sstevel {200, 80, 170, 70}, /* 20, 120, 30 */
26702305Sstevel {150, 50, 110, 40}, /* 20, 80, 20 */
26712305Sstevel {100, 40, 80, 40}, /* 10, 60, 15 */
26722305Sstevel {0, 10, 60, 15} /* 10, 60, 15 */
26732305Sstevel };
26742305Sstevel
26752305Sstevel /*
26762305Sstevel * pcic_set_cdtimers
26772305Sstevel * This is specific to several Cirrus Logic chips
26782305Sstevel */
26792305Sstevel static void
pcic_set_cdtimers(pcicdev_t * pcic,int socket,uint32_t speed,int tset)26802305Sstevel pcic_set_cdtimers(pcicdev_t *pcic, int socket, uint32_t speed, int tset)
26812305Sstevel {
26822305Sstevel int cmd, set, rec, offset, clk_pulse;
26832305Sstevel struct pcic_card_times *ctp;
26842305Sstevel
26852305Sstevel if ((tset == IOMEM_CLTIMER_SET_1) || (tset == SYSMEM_CLTIMER_SET_1))
26862305Sstevel offset = 3;
26872305Sstevel else
26882305Sstevel offset = 0;
26892305Sstevel
26902305Sstevel clk_pulse = mhztons(pcic->bus_speed);
26917656SSherry.Moore@Sun.COM for (ctp = pcic_card_times; speed < ctp->cycle; ctp++)
26927656SSherry.Moore@Sun.COM ;
26932305Sstevel
26942305Sstevel /*
26952305Sstevel * Add (clk_pulse/2) and an extra 1 to account for rounding errors.
26962305Sstevel */
26972305Sstevel set = ((ctp->setup + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1;
26982305Sstevel if (set < 0)
26992305Sstevel set = 0;
27002305Sstevel
27012305Sstevel cmd = ((ctp->width + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1;
27022305Sstevel if (cmd < 0)
27032305Sstevel cmd = 0;
27042305Sstevel
27052305Sstevel rec = ((ctp->hold + 10 + 1 + (clk_pulse/2))/clk_pulse) - 2;
27062305Sstevel if (rec < 0)
27072305Sstevel rec = 0;
27082305Sstevel
27092305Sstevel #if defined(PCIC_DEBUG)
27102305Sstevel pcic_err(pcic->dip, 8, "pcic_set_cdtimers(%d, Timer Set %d)\n"
27112305Sstevel "ct=%d, cp=%d, cmd=0x%x, setup=0x%x, rec=0x%x\n",
27122305Sstevel (unsigned)speed, offset == 3 ? 1 : 0,
27132305Sstevel ctp->cycle, clk_pulse, cmd, set, rec);
27142305Sstevel #endif
27152305Sstevel
27162305Sstevel pcic_putb(pcic, socket, PCIC_TIME_COMMAND_0 + offset, cmd);
27172305Sstevel pcic_putb(pcic, socket, PCIC_TIME_SETUP_0 + offset, set);
27182305Sstevel pcic_putb(pcic, socket, PCIC_TIME_RECOVER_0 + offset, rec);
27192305Sstevel }
27202305Sstevel
27212305Sstevel /*
27222305Sstevel * pcic_set_window
27232305Sstevel * essentially the same as the Socket Services specification
27242305Sstevel * We use socket and not adapter since they are identifiable
27252305Sstevel * but the rest is the same
27262305Sstevel *
27272305Sstevel * dip pcic driver's device information
27282305Sstevel * window parameters for the request
27292305Sstevel */
27302305Sstevel static int
pcic_set_window(dev_info_t * dip,set_window_t * window)27312305Sstevel pcic_set_window(dev_info_t *dip, set_window_t *window)
27322305Sstevel {
27332305Sstevel anp_t *anp = ddi_get_driver_private(dip);
27342305Sstevel pcicdev_t *pcic = anp->an_private;
27352305Sstevel int select;
27362305Sstevel int socket, pages, which, ret;
27372305Sstevel pcic_socket_t *sockp = &pcic->pc_sockets[window->socket];
27382305Sstevel ra_return_t res;
27392305Sstevel ndi_ra_request_t req;
27402305Sstevel uint32_t base = window->base;
27412305Sstevel
27422305Sstevel #if defined(PCIC_DEBUG)
27432305Sstevel if (pcic_debug) {
27442305Sstevel cmn_err(CE_CONT, "pcic_set_window: entered\n");
27452305Sstevel cmn_err(CE_CONT,
27467656SSherry.Moore@Sun.COM "\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n",
27477656SSherry.Moore@Sun.COM window->window, window->socket, window->WindowSize,
27487656SSherry.Moore@Sun.COM window->speed);
27492305Sstevel cmn_err(CE_CONT,
27507656SSherry.Moore@Sun.COM "\tbase=%x, state=%x\n", (unsigned)window->base,
27517656SSherry.Moore@Sun.COM (unsigned)window->state);
27522305Sstevel }
27532305Sstevel #endif
27542305Sstevel
27552305Sstevel /*
27562305Sstevel * do some basic sanity checking on what we support
27572305Sstevel * we don't do paged mode
27582305Sstevel */
27592305Sstevel if (window->state & WS_PAGED) {
27602305Sstevel cmn_err(CE_WARN, "pcic_set_window: BAD_ATTRIBUTE\n");
27612305Sstevel return (BAD_ATTRIBUTE);
27622305Sstevel }
27632305Sstevel
27642305Sstevel /*
27652305Sstevel * we don't care about previous mappings.
27662305Sstevel * Card Services will deal with that so don't
27672305Sstevel * even check
27682305Sstevel */
27692305Sstevel
27702305Sstevel socket = window->socket;
27712305Sstevel
27722305Sstevel if (!(window->state & WS_IO)) {
27732305Sstevel int win, tmp;
27742305Sstevel pcs_memwin_t *memp;
27752305Sstevel #if defined(PCIC_DEBUG)
27762305Sstevel if (pcic_debug)
27772305Sstevel cmn_err(CE_CONT, "\twindow type is memory\n");
27782305Sstevel #endif
27792305Sstevel /* this is memory window mapping */
27802305Sstevel win = window->window % PCIC_NUMWINSOCK;
27812305Sstevel tmp = window->window / PCIC_NUMWINSOCK;
27822305Sstevel
27832305Sstevel /* only windows 2-6 can do memory mapping */
27842305Sstevel if (tmp != window->socket || win < PCIC_IOWINDOWS) {
27852305Sstevel cmn_err(CE_CONT,
27867656SSherry.Moore@Sun.COM "\tattempt to map to non-mem window\n");
27872305Sstevel return (BAD_WINDOW);
27882305Sstevel }
27892305Sstevel
27902305Sstevel if (window->WindowSize == 0)
27912305Sstevel window->WindowSize = MEM_MIN;
27922305Sstevel else if ((window->WindowSize & (PCIC_PAGE-1)) != 0) {
27932305Sstevel cmn_err(CE_WARN, "pcic_set_window: BAD_SIZE\n");
27942305Sstevel return (BAD_SIZE);
27952305Sstevel }
27962305Sstevel
27972305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
27982305Sstevel
27992305Sstevel memp = &sockp->pcs_windows[win].mem;
28002305Sstevel memp->pcw_speed = window->speed;
28012305Sstevel
28022305Sstevel win -= PCIC_IOWINDOWS; /* put in right range */
28032305Sstevel
28042305Sstevel if (window->WindowSize != memp->pcw_len)
28052305Sstevel which = memp->pcw_len;
28062305Sstevel else
28072305Sstevel which = 0;
28082305Sstevel
28092305Sstevel if (window->state & WS_ENABLED) {
28102305Sstevel uint32_t wspeed;
28112305Sstevel #if defined(PCIC_DEBUG)
28122305Sstevel if (pcic_debug) {
28132305Sstevel cmn_err(CE_CONT,
28147656SSherry.Moore@Sun.COM "\tbase=%x, win=%d\n", (unsigned)base,
28157656SSherry.Moore@Sun.COM win);
28162305Sstevel if (which)
28172305Sstevel cmn_err(CE_CONT,
28187656SSherry.Moore@Sun.COM "\tneed to remap window\n");
28192305Sstevel }
28202305Sstevel #endif
28212305Sstevel
28222305Sstevel if (which && (memp->pcw_status & PCW_MAPPED)) {
28232305Sstevel ddi_regs_map_free(&memp->pcw_handle);
28242305Sstevel res.ra_addr_lo = memp->pcw_base;
28252305Sstevel res.ra_len = memp->pcw_len;
28263664Srw148561 (void) pcmcia_free_mem(memp->res_dip, &res);
28272305Sstevel memp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
28282305Sstevel memp->pcw_hostmem = NULL;
28292305Sstevel memp->pcw_base = NULL;
28302305Sstevel memp->pcw_len = 0;
28312305Sstevel }
28322305Sstevel
28332305Sstevel which = window->WindowSize >> PAGE_SHIFT;
28342305Sstevel
28352305Sstevel if (!(memp->pcw_status & PCW_MAPPED)) {
28362305Sstevel ret = 0;
28372305Sstevel
28382305Sstevel memp->pcw_base = base;
28392305Sstevel bzero(&req, sizeof (req));
28402305Sstevel req.ra_len = which << PAGE_SHIFT;
28412305Sstevel req.ra_addr = (uint64_t)memp->pcw_base;
28422305Sstevel req.ra_boundbase = pcic->pc_base;
28432305Sstevel req.ra_boundlen = pcic->pc_bound;
28442305Sstevel req.ra_flags = (memp->pcw_base ?
28457656SSherry.Moore@Sun.COM NDI_RA_ALLOC_SPECIFIED : 0) |
28467656SSherry.Moore@Sun.COM NDI_RA_ALLOC_BOUNDED;
28472305Sstevel req.ra_align_mask =
28487656SSherry.Moore@Sun.COM (PAGESIZE - 1) | (PCIC_PAGE - 1);
28492305Sstevel #if defined(PCIC_DEBUG)
28507656SSherry.Moore@Sun.COM pcic_err(dip, 8,
28512305Sstevel "\tlen 0x%"PRIx64
28522305Sstevel "addr 0x%"PRIx64"bbase 0x%"PRIx64
28532305Sstevel " blen 0x%"PRIx64" flags 0x%x"
28542305Sstevel " algn 0x%"PRIx64"\n",
28552305Sstevel req.ra_len, req.ra_addr,
28562305Sstevel req.ra_boundbase,
28572305Sstevel req.ra_boundlen, req.ra_flags,
28582305Sstevel req.ra_align_mask);
28592305Sstevel #endif
28602305Sstevel
28613664Srw148561 ret = pcmcia_alloc_mem(dip, &req, &res,
28627656SSherry.Moore@Sun.COM &memp->res_dip);
28632305Sstevel if (ret == DDI_FAILURE) {
28642305Sstevel mutex_exit(&pcic->pc_lock);
28652305Sstevel cmn_err(CE_WARN,
28662305Sstevel "\tpcmcia_alloc_mem() failed\n");
28672305Sstevel return (BAD_SIZE);
28682305Sstevel }
28692305Sstevel memp->pcw_base = res.ra_addr_lo;
28702305Sstevel base = memp->pcw_base;
28712305Sstevel
28722305Sstevel #if defined(PCIC_DEBUG)
28732305Sstevel if (pcic_debug)
28742305Sstevel cmn_err(CE_CONT,
28757656SSherry.Moore@Sun.COM "\tsetwindow: new base=%x\n",
28767656SSherry.Moore@Sun.COM (unsigned)memp->pcw_base);
28772305Sstevel #endif
28782305Sstevel memp->pcw_len = window->WindowSize;
28792305Sstevel
28802305Sstevel which = pcmcia_map_reg(pcic->dip,
28817656SSherry.Moore@Sun.COM window->child,
28827656SSherry.Moore@Sun.COM &res,
28837656SSherry.Moore@Sun.COM (uint32_t)(window->state &
28847656SSherry.Moore@Sun.COM 0xffff) |
28857656SSherry.Moore@Sun.COM (window->socket << 16),
28867656SSherry.Moore@Sun.COM (caddr_t *)&memp->pcw_hostmem,
28877656SSherry.Moore@Sun.COM &memp->pcw_handle,
28887656SSherry.Moore@Sun.COM &window->attr, NULL);
28892305Sstevel
28902305Sstevel if (which != DDI_SUCCESS) {
28912305Sstevel
28922305Sstevel cmn_err(CE_WARN, "\tpcmcia_map_reg() "
28937656SSherry.Moore@Sun.COM "failed\n");
28947656SSherry.Moore@Sun.COM
28957656SSherry.Moore@Sun.COM res.ra_addr_lo = memp->pcw_base;
28967656SSherry.Moore@Sun.COM res.ra_len = memp->pcw_len;
28977656SSherry.Moore@Sun.COM (void) pcmcia_free_mem(memp->res_dip,
28987656SSherry.Moore@Sun.COM &res);
28997656SSherry.Moore@Sun.COM
29007656SSherry.Moore@Sun.COM mutex_exit(&pcic->pc_lock);
29017656SSherry.Moore@Sun.COM
29027656SSherry.Moore@Sun.COM return (BAD_WINDOW);
29032305Sstevel }
29042305Sstevel memp->pcw_status |= PCW_MAPPED;
29052305Sstevel #if defined(PCIC_DEBUG)
29062305Sstevel if (pcic_debug)
29072305Sstevel cmn_err(CE_CONT,
29087656SSherry.Moore@Sun.COM "\tmap=%x, hostmem=%p\n",
29097656SSherry.Moore@Sun.COM which,
29107656SSherry.Moore@Sun.COM (void *)memp->pcw_hostmem);
29112305Sstevel #endif
29122305Sstevel } else {
29132305Sstevel base = memp->pcw_base;
29142305Sstevel }
29152305Sstevel
29162305Sstevel /* report the handle back to caller */
29172305Sstevel window->handle = memp->pcw_handle;
29182305Sstevel
29192305Sstevel #if defined(PCIC_DEBUG)
29202305Sstevel if (pcic_debug) {
29212305Sstevel cmn_err(CE_CONT,
29227656SSherry.Moore@Sun.COM "\twindow mapped to %x@%x len=%d\n",
29237656SSherry.Moore@Sun.COM (unsigned)window->base,
29247656SSherry.Moore@Sun.COM (unsigned)memp->pcw_base,
29257656SSherry.Moore@Sun.COM memp->pcw_len);
29262305Sstevel }
29272305Sstevel #endif
29282305Sstevel
29292305Sstevel /* find the register set offset */
29302305Sstevel select = win * PCIC_MEM_1_OFFSET;
29312305Sstevel #if defined(PCIC_DEBUG)
29322305Sstevel if (pcic_debug)
29332305Sstevel cmn_err(CE_CONT, "\tselect=%x\n", select);
29342305Sstevel #endif
29352305Sstevel
29362305Sstevel /*
29372305Sstevel * at this point, the register window indicator has
29382305Sstevel * been converted to be an offset from the first
29392305Sstevel * set of registers that are used for programming
29402305Sstevel * the window mapping and the offset used to select
29412305Sstevel * the correct set of registers to access the
29422305Sstevel * specified socket. This allows basing everything
29432305Sstevel * off the _0 window
29442305Sstevel */
29452305Sstevel
29462305Sstevel /* map the physical page base address */
29472305Sstevel which = (window->state & WS_16BIT) ? SYSMEM_DATA_16 : 0;
29482305Sstevel which |= (window->speed <= MEM_SPEED_MIN) ?
29497656SSherry.Moore@Sun.COM SYSMEM_ZERO_WAIT : 0;
29502305Sstevel
29512305Sstevel /* need to select register set */
29522305Sstevel select = PCIC_MEM_1_OFFSET * win;
29532305Sstevel
29542305Sstevel pcic_putb(pcic, socket,
29557656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTLOW + select,
29567656SSherry.Moore@Sun.COM SYSMEM_LOW(base));
29572305Sstevel pcic_putb(pcic, socket,
29587656SSherry.Moore@Sun.COM PCIC_SYSMEM_0_STARTHI + select,
29597656SSherry.Moore@Sun.COM SYSMEM_HIGH(base) | which);
29602305Sstevel
29612305Sstevel /*
29622305Sstevel * Some adapters can decode window addresses greater
29632305Sstevel * than 16-bits worth, so handle them here.
29642305Sstevel */
29652305Sstevel switch (pcic->pc_type) {
29662305Sstevel case PCIC_INTEL_i82092:
29672305Sstevel pcic_putb(pcic, socket,
29687656SSherry.Moore@Sun.COM PCIC_82092_CPAGE,
29697656SSherry.Moore@Sun.COM SYSMEM_EXT(base));
29702305Sstevel break;
29712305Sstevel case PCIC_CL_PD6729:
29722305Sstevel case PCIC_CL_PD6730:
29732305Sstevel clext_reg_write(pcic, socket,
29747656SSherry.Moore@Sun.COM PCIC_CLEXT_MMAP0_UA + win,
29757656SSherry.Moore@Sun.COM SYSMEM_EXT(base));
29762305Sstevel break;
29772305Sstevel case PCIC_TI_PCI1130:
29782305Sstevel /*
29792305Sstevel * Note that the TI chip has one upper byte
29802305Sstevel * per socket so all windows get bound to a
29812305Sstevel * 16MB segment. This must be detected and
29822305Sstevel * handled appropriately. We can detect that
29832305Sstevel * it is done by seeing if the pc_base has
29842305Sstevel * changed and changing when the register
29852305Sstevel * is first set. This will force the bounds
29862305Sstevel * to be correct.
29872305Sstevel */
29882305Sstevel if (pcic->pc_bound == 0xffffffff) {
29892305Sstevel pcic_putb(pcic, socket,
29907656SSherry.Moore@Sun.COM PCIC_TI_WINDOW_PAGE_PCI,
29917656SSherry.Moore@Sun.COM SYSMEM_EXT(base));
29922305Sstevel pcic->pc_base = SYSMEM_EXT(base) << 24;
29932305Sstevel pcic->pc_bound = 0x1000000;
29942305Sstevel }
29952305Sstevel break;
29962305Sstevel case PCIC_TI_PCI1031:
29972305Sstevel case PCIC_TI_PCI1131:
29982305Sstevel case PCIC_TI_PCI1250:
29992305Sstevel case PCIC_TI_PCI1225:
30002305Sstevel case PCIC_TI_PCI1221:
30012305Sstevel case PCIC_SMC_34C90:
30022305Sstevel case PCIC_CL_PD6832:
30032305Sstevel case PCIC_RICOH_RL5C466:
30042305Sstevel case PCIC_TI_PCI1410:
30052305Sstevel case PCIC_ENE_1410:
30062305Sstevel case PCIC_TI_PCI1510:
30072305Sstevel case PCIC_TI_PCI1520:
30082305Sstevel case PCIC_O2_OZ6912:
30092305Sstevel case PCIC_TI_PCI1420:
30102305Sstevel case PCIC_ENE_1420:
30112305Sstevel case PCIC_TI_VENDOR:
30122305Sstevel case PCIC_TOSHIBA_TOPIC100:
30132305Sstevel case PCIC_TOSHIBA_TOPIC95:
30142305Sstevel case PCIC_TOSHIBA_VENDOR:
30152305Sstevel case PCIC_RICOH_VENDOR:
30162305Sstevel case PCIC_O2MICRO_VENDOR:
30172305Sstevel pcic_putb(pcic, socket,
30187656SSherry.Moore@Sun.COM PCIC_YENTA_MEM_PAGE + win,
30197656SSherry.Moore@Sun.COM SYSMEM_EXT(base));
30202305Sstevel break;
30212305Sstevel default:
30222305Sstevel cmn_err(CE_NOTE, "pcic_set_window: unknown "
30237656SSherry.Moore@Sun.COM "cardbus vendor:0x%X\n",
30247656SSherry.Moore@Sun.COM pcic->pc_type);
30252305Sstevel pcic_putb(pcic, socket,
30267656SSherry.Moore@Sun.COM PCIC_YENTA_MEM_PAGE + win,
30277656SSherry.Moore@Sun.COM SYSMEM_EXT(base));
30282305Sstevel
30292305Sstevel break;
30302305Sstevel } /* switch */
30312305Sstevel
30322305Sstevel /*
30332305Sstevel * specify the length of the mapped range
30342305Sstevel * we convert to pages (rounding up) so that
30352305Sstevel * the hardware gets the right thing
30362305Sstevel */
30372305Sstevel pages = (window->WindowSize+PCIC_PAGE-1)/PCIC_PAGE;
30382305Sstevel
30392305Sstevel /*
30402305Sstevel * Setup this window's timing.
30412305Sstevel */
30422305Sstevel switch (pcic->pc_type) {
30432305Sstevel case PCIC_CL_PD6729:
30442305Sstevel case PCIC_CL_PD6730:
30452305Sstevel case PCIC_CL_PD6710:
30462305Sstevel case PCIC_CL_PD6722:
30472305Sstevel wspeed = SYSMEM_CLTIMER_SET_0;
30482305Sstevel pcic_set_cdtimers(pcic, socket,
30497656SSherry.Moore@Sun.COM window->speed,
30507656SSherry.Moore@Sun.COM wspeed);
30512305Sstevel break;
30522305Sstevel
30532305Sstevel case PCIC_INTEL_i82092:
30542305Sstevel default:
30552305Sstevel wspeed = pcic_calc_speed(pcic, window->speed);
30562305Sstevel break;
30572305Sstevel } /* switch */
30582305Sstevel
30592305Sstevel #if defined(PCIC_DEBUG)
30602305Sstevel if (pcic_debug)
30612305Sstevel cmn_err(CE_CONT,
30627656SSherry.Moore@Sun.COM "\twindow %d speed bits = %x for "
30637656SSherry.Moore@Sun.COM "%dns\n",
30647656SSherry.Moore@Sun.COM win, (unsigned)wspeed, window->speed);
30652305Sstevel #endif
30662305Sstevel
30672305Sstevel pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPLOW + select,
30687656SSherry.Moore@Sun.COM SYSMEM_LOW(base +
30697656SSherry.Moore@Sun.COM (pages * PCIC_PAGE)-1));
30702305Sstevel
30712305Sstevel wspeed |= SYSMEM_HIGH(base + (pages * PCIC_PAGE)-1);
30722305Sstevel pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPHI + select,
30737656SSherry.Moore@Sun.COM wspeed);
30742305Sstevel
30752305Sstevel /*
30762305Sstevel * now map the card's memory pages - we start with page
30772305Sstevel * 0
30782305Sstevel * we also default to AM -- set page might change it
30792305Sstevel */
30802305Sstevel base = memp->pcw_base;
30812305Sstevel pcic_putb(pcic, socket,
30827656SSherry.Moore@Sun.COM PCIC_CARDMEM_0_LOW + select,
30837656SSherry.Moore@Sun.COM CARDMEM_LOW(0 - (uint32_t)base));
30842305Sstevel
30852305Sstevel pcic_putb(pcic, socket,
30867656SSherry.Moore@Sun.COM PCIC_CARDMEM_0_HI + select,
30877656SSherry.Moore@Sun.COM CARDMEM_HIGH(0 - (uint32_t)base) |
30887656SSherry.Moore@Sun.COM CARDMEM_REG_ACTIVE);
30892305Sstevel
30902305Sstevel /*
30912305Sstevel * enable the window even though redundant
30922305Sstevel * and SetPage may do it again.
30932305Sstevel */
30942305Sstevel select = pcic_getb(pcic, socket,
30957656SSherry.Moore@Sun.COM PCIC_MAPPING_ENABLE);
30962305Sstevel select |= SYSMEM_WINDOW(win);
30972305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select);
30982305Sstevel memp->pcw_offset = 0;
30992305Sstevel memp->pcw_status |= PCW_ENABLED;
31002305Sstevel } else {
31012305Sstevel /*
31022305Sstevel * not only do we unmap the memory, the
31032305Sstevel * window has been turned off.
31042305Sstevel */
31052305Sstevel if (which && memp->pcw_status & PCW_MAPPED) {
31062305Sstevel ddi_regs_map_free(&memp->pcw_handle);
31072305Sstevel res.ra_addr_lo = memp->pcw_base;
31082305Sstevel res.ra_len = memp->pcw_len;
31093664Srw148561 (void) pcmcia_free_mem(memp->res_dip, &res);
31102305Sstevel memp->pcw_hostmem = NULL;
31112305Sstevel memp->pcw_status &= ~PCW_MAPPED;
31122305Sstevel }
31132305Sstevel
31142305Sstevel /* disable current mapping */
31152305Sstevel select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
31162305Sstevel select &= ~SYSMEM_WINDOW(win);
31172305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select);
31182305Sstevel memp->pcw_status &= ~PCW_ENABLED;
31192305Sstevel }
31202305Sstevel memp->pcw_len = window->WindowSize;
31212305Sstevel window->handle = memp->pcw_handle;
31222305Sstevel #if defined(PCIC_DEBUG)
31232305Sstevel if (pcic_debug)
31242305Sstevel xxdmp_all_regs(pcic, window->socket, -1);
31252305Sstevel #endif
31262305Sstevel } else {
31272305Sstevel /*
31282305Sstevel * This is a request for an IO window
31292305Sstevel */
31302305Sstevel int win, tmp;
31312305Sstevel pcs_iowin_t *winp;
31322305Sstevel /* I/O windows */
31332305Sstevel #if defined(PCIC_DEBUG)
31342305Sstevel if (pcic_debug)
31352305Sstevel cmn_err(CE_CONT, "\twindow type is I/O\n");
31362305Sstevel #endif
31372305Sstevel
31382305Sstevel /* only windows 0 and 1 can do I/O */
31392305Sstevel win = window->window % PCIC_NUMWINSOCK;
31402305Sstevel tmp = window->window / PCIC_NUMWINSOCK;
31412305Sstevel
31422305Sstevel if (win >= PCIC_IOWINDOWS || tmp != window->socket) {
31432305Sstevel cmn_err(CE_WARN,
31447656SSherry.Moore@Sun.COM "\twindow is out of range (%d)\n",
31457656SSherry.Moore@Sun.COM window->window);
31462305Sstevel return (BAD_WINDOW);
31472305Sstevel }
31482305Sstevel
31492305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
31502305Sstevel
31512305Sstevel winp = &sockp->pcs_windows[win].io;
31522305Sstevel winp->pcw_speed = window->speed;
31532305Sstevel if (window->WindowSize != 1 && window->WindowSize & 1) {
31542305Sstevel /* we don't want an odd-size window */
31552305Sstevel window->WindowSize++;
31562305Sstevel }
31572305Sstevel winp->pcw_len = window->WindowSize;
31582305Sstevel
31592305Sstevel if (window->state & WS_ENABLED) {
31602305Sstevel if (winp->pcw_status & PCW_MAPPED) {
31612305Sstevel ddi_regs_map_free(&winp->pcw_handle);
31622305Sstevel res.ra_addr_lo = winp->pcw_base;
31632305Sstevel res.ra_len = winp->pcw_len;
31643664Srw148561 (void) pcmcia_free_io(winp->res_dip, &res);
31652305Sstevel winp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED);
31662305Sstevel }
31672305Sstevel
31682305Sstevel /*
31692305Sstevel * if the I/O address wasn't allocated, allocate
31702305Sstevel * it now. If it was allocated, it better
31712305Sstevel * be free to use.
31722305Sstevel * The winp->pcw_offset value is set and used
31732305Sstevel * later on if the particular adapter
31742305Sstevel * that we're running on has the ability
31752305Sstevel * to translate IO accesses to the card
31762305Sstevel * (such as some adapters in the Cirrus
31772305Sstevel * Logic family).
31782305Sstevel */
31792305Sstevel winp->pcw_offset = 0;
31802305Sstevel
31812305Sstevel /*
31822305Sstevel * Setup the request parameters for the
31832305Sstevel * requested base and length. If
31842305Sstevel * we're on an adapter that has
31852305Sstevel * IO window offset registers, then
31862305Sstevel * we don't need a specific base
31872305Sstevel * address, just a length, and then
31882305Sstevel * we'll cause the correct IO address
31892305Sstevel * to be generated on the socket by
31902305Sstevel * setting up the IO window offset
31912305Sstevel * registers.
31922305Sstevel * For adapters that support this capability, we
31932305Sstevel * always use the IO window offset registers,
31942305Sstevel * even if the passed base/length would be in
31952305Sstevel * range.
31962305Sstevel */
31972305Sstevel base = window->base;
31982305Sstevel bzero(&req, sizeof (req));
31992305Sstevel req.ra_len = window->WindowSize;
32002305Sstevel
32012305Sstevel req.ra_addr = (uint64_t)
32027656SSherry.Moore@Sun.COM ((pcic->pc_flags & PCF_IO_REMAP) ? 0 : base);
32032305Sstevel req.ra_flags = (req.ra_addr) ?
32047656SSherry.Moore@Sun.COM NDI_RA_ALLOC_SPECIFIED : 0;
32052305Sstevel
32062305Sstevel req.ra_flags |= NDI_RA_ALIGN_SIZE;
32072305Sstevel /* need to rethink this */
32082305Sstevel req.ra_boundbase = pcic->pc_iobase;
32092305Sstevel req.ra_boundlen = pcic->pc_iobound;
32102305Sstevel req.ra_flags |= NDI_RA_ALLOC_BOUNDED;
32112305Sstevel
32122305Sstevel #if defined(PCIC_DEBUG)
32137656SSherry.Moore@Sun.COM pcic_err(dip, 8,
32147656SSherry.Moore@Sun.COM "\tlen 0x%"PRIx64" addr 0x%"PRIx64
32157656SSherry.Moore@Sun.COM "bbase 0x%"PRIx64
32167656SSherry.Moore@Sun.COM "blen 0x%"PRIx64" flags 0x%x algn 0x%"
32177656SSherry.Moore@Sun.COM PRIx64"\n",
32187656SSherry.Moore@Sun.COM req.ra_len, (uint64_t)req.ra_addr,
32197656SSherry.Moore@Sun.COM req.ra_boundbase,
32207656SSherry.Moore@Sun.COM req.ra_boundlen, req.ra_flags,
32217656SSherry.Moore@Sun.COM req.ra_align_mask);
32222305Sstevel #endif
32232305Sstevel
32242305Sstevel /*
32252305Sstevel * Try to allocate the space. If we fail this,
32262305Sstevel * return the appropriate error depending
32272305Sstevel * on whether the caller specified a
32282305Sstevel * specific base address or not.
32292305Sstevel */
32303664Srw148561 if (pcmcia_alloc_io(dip, &req, &res,
32317656SSherry.Moore@Sun.COM &winp->res_dip) == DDI_FAILURE) {
32322305Sstevel winp->pcw_status &= ~PCW_ENABLED;
32332305Sstevel mutex_exit(&pcic->pc_lock);
32342305Sstevel cmn_err(CE_WARN, "Failed to alloc I/O:\n"
32357656SSherry.Moore@Sun.COM "\tlen 0x%" PRIx64 " addr 0x%" PRIx64
32367656SSherry.Moore@Sun.COM "bbase 0x%" PRIx64
32377656SSherry.Moore@Sun.COM "blen 0x%" PRIx64 "flags 0x%x"
32387656SSherry.Moore@Sun.COM "algn 0x%" PRIx64 "\n",
32397656SSherry.Moore@Sun.COM req.ra_len, req.ra_addr,
32407656SSherry.Moore@Sun.COM req.ra_boundbase,
32417656SSherry.Moore@Sun.COM req.ra_boundlen, req.ra_flags,
32427656SSherry.Moore@Sun.COM req.ra_align_mask);
32432305Sstevel
32442305Sstevel return (base?BAD_BASE:BAD_SIZE);
32452305Sstevel } /* pcmcia_alloc_io */
32462305Sstevel
32472305Sstevel /*
32482305Sstevel * Don't change the original base. Either we use
32492305Sstevel * the offset registers below (PCF_IO_REMAP is set)
32502305Sstevel * or it was allocated correctly anyway.
32512305Sstevel */
32522305Sstevel winp->pcw_base = res.ra_addr_lo;
32532305Sstevel
32542305Sstevel #if defined(PCIC_DEBUG)
32557656SSherry.Moore@Sun.COM pcic_err(dip, 8,
32562305Sstevel "\tsetwindow: new base=%x orig base 0x%x\n",
32572305Sstevel (unsigned)winp->pcw_base, base);
32582305Sstevel #endif
32592305Sstevel
32602305Sstevel if ((which = pcmcia_map_reg(pcic->dip,
32617656SSherry.Moore@Sun.COM window->child,
32627656SSherry.Moore@Sun.COM &res,
32637656SSherry.Moore@Sun.COM (uint32_t)(window->state &
32647656SSherry.Moore@Sun.COM 0xffff) |
32657656SSherry.Moore@Sun.COM (window->socket << 16),
32667656SSherry.Moore@Sun.COM (caddr_t *)&winp->pcw_hostmem,
32677656SSherry.Moore@Sun.COM &winp->pcw_handle,
32687656SSherry.Moore@Sun.COM &window->attr,
32697656SSherry.Moore@Sun.COM base)) != DDI_SUCCESS) {
32707656SSherry.Moore@Sun.COM
32717656SSherry.Moore@Sun.COM cmn_err(CE_WARN, "pcmcia_map_reg()"
32727656SSherry.Moore@Sun.COM "failed\n");
32737656SSherry.Moore@Sun.COM
32747656SSherry.Moore@Sun.COM res.ra_addr_lo = winp->pcw_base;
32757656SSherry.Moore@Sun.COM res.ra_len = winp->pcw_len;
32767656SSherry.Moore@Sun.COM (void) pcmcia_free_io(winp->res_dip,
32777656SSherry.Moore@Sun.COM &res);
32787656SSherry.Moore@Sun.COM
32797656SSherry.Moore@Sun.COM mutex_exit(&pcic->pc_lock);
32807656SSherry.Moore@Sun.COM return (BAD_WINDOW);
32812305Sstevel }
32822305Sstevel
32832305Sstevel window->handle = winp->pcw_handle;
32842305Sstevel winp->pcw_status |= PCW_MAPPED;
32852305Sstevel
32862305Sstevel /* find the register set offset */
32872305Sstevel select = win * PCIC_IO_OFFSET;
32882305Sstevel
32892305Sstevel #if defined(PCIC_DEBUG)
32902305Sstevel if (pcic_debug) {
32912305Sstevel cmn_err(CE_CONT,
32927656SSherry.Moore@Sun.COM "\tenable: window=%d, select=%x, "
32937656SSherry.Moore@Sun.COM "base=%x, handle=%p\n",
32947656SSherry.Moore@Sun.COM win, select,
32957656SSherry.Moore@Sun.COM (unsigned)window->base,
32967656SSherry.Moore@Sun.COM (void *)window->handle);
32972305Sstevel }
32982305Sstevel #endif
32992305Sstevel /*
33002305Sstevel * at this point, the register window indicator has
33012305Sstevel * been converted to be an offset from the first
33022305Sstevel * set of registers that are used for programming
33032305Sstevel * the window mapping and the offset used to select
33042305Sstevel * the correct set of registers to access the
33052305Sstevel * specified socket. This allows basing everything
33062305Sstevel * off the _0 window
33072305Sstevel */
33082305Sstevel
33092305Sstevel /* map the I/O base in */
33102305Sstevel pcic_putb(pcic, socket,
33117656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STARTLOW + select,
33127656SSherry.Moore@Sun.COM LOW_BYTE((uint32_t)winp->pcw_base));
33132305Sstevel pcic_putb(pcic, socket,
33147656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STARTHI + select,
33157656SSherry.Moore@Sun.COM HIGH_BYTE((uint32_t)winp->pcw_base));
33162305Sstevel
33172305Sstevel pcic_putb(pcic, socket,
33187656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STOPLOW + select,
33197656SSherry.Moore@Sun.COM LOW_BYTE((uint32_t)winp->pcw_base +
33207656SSherry.Moore@Sun.COM window->WindowSize - 1));
33212305Sstevel pcic_putb(pcic, socket,
33227656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STOPHI + select,
33237656SSherry.Moore@Sun.COM HIGH_BYTE((uint32_t)winp->pcw_base +
33247656SSherry.Moore@Sun.COM window->WindowSize - 1));
33252305Sstevel
33262305Sstevel /*
33272305Sstevel * We've got the requested IO space, now see if we
33282305Sstevel * need to adjust the IO window offset registers
33292305Sstevel * so that the correct IO address is generated
33302305Sstevel * at the socket. If this window doesn't have
33312305Sstevel * this capability, then we're all done setting
33322305Sstevel * up the IO resources.
33332305Sstevel */
33342305Sstevel if (pcic->pc_flags & PCF_IO_REMAP) {
33352305Sstevel
33362305Sstevel
33372305Sstevel /*
33382305Sstevel * Note that only 16 bits are used to program
33392305Sstevel * the registers but leave 32 bits on pcw_offset
33402305Sstevel * so that we can generate the original base
33412305Sstevel * in get_window()
33422305Sstevel */
33432305Sstevel winp->pcw_offset = (base - winp->pcw_base);
33442305Sstevel
33452305Sstevel pcic_putb(pcic, socket,
33467656SSherry.Moore@Sun.COM PCIC_IO_OFFSET_LOW +
33477656SSherry.Moore@Sun.COM (win * PCIC_IO_OFFSET_OFFSET),
33487656SSherry.Moore@Sun.COM winp->pcw_offset & 0x0ff);
33492305Sstevel pcic_putb(pcic, socket,
33507656SSherry.Moore@Sun.COM PCIC_IO_OFFSET_HI +
33517656SSherry.Moore@Sun.COM (win * PCIC_IO_OFFSET_OFFSET),
33527656SSherry.Moore@Sun.COM (winp->pcw_offset >> 8) & 0x0ff);
33532305Sstevel
33542305Sstevel } /* PCF_IO_REMAP */
33552305Sstevel
33562305Sstevel /* now get the other details (size, etc) right */
33572305Sstevel
33582305Sstevel /*
33592305Sstevel * Set the data size control bits here. Most of the
33602305Sstevel * adapters will ignore IOMEM_16BIT when
33612305Sstevel * IOMEM_IOCS16 is set, except for the Intel
33622305Sstevel * 82092, which only pays attention to the
33632305Sstevel * IOMEM_16BIT bit. Sigh... Intel can't even
33642305Sstevel * make a proper clone of their own chip.
33652305Sstevel * The 82092 also apparently can't set the timing
33662305Sstevel * of I/O windows.
33672305Sstevel */
33682305Sstevel which = (window->state & WS_16BIT) ?
33697656SSherry.Moore@Sun.COM (IOMEM_16BIT | IOMEM_IOCS16) : 0;
33702305Sstevel
33712305Sstevel switch (pcic->pc_type) {
33722305Sstevel case PCIC_CL_PD6729:
33732305Sstevel case PCIC_CL_PD6730:
33742305Sstevel case PCIC_CL_PD6710:
33752305Sstevel case PCIC_CL_PD6722:
33762305Sstevel case PCIC_CL_PD6832:
33772305Sstevel /*
33782305Sstevel * Select Timer Set 1 - this will take
33792305Sstevel * effect when the PCIC_IO_CONTROL
33802305Sstevel * register is written to later on;
33812305Sstevel * the call to pcic_set_cdtimers
33822305Sstevel * just sets up the timer itself.
33832305Sstevel */
33842305Sstevel which |= IOMEM_CLTIMER_SET_1;
33852305Sstevel pcic_set_cdtimers(pcic, socket,
33867656SSherry.Moore@Sun.COM window->speed,
33877656SSherry.Moore@Sun.COM IOMEM_CLTIMER_SET_1);
33882305Sstevel which |= IOMEM_IOCS16;
33892305Sstevel break;
33902305Sstevel case PCIC_TI_PCI1031:
33912305Sstevel
33922305Sstevel if (window->state & WS_16BIT)
33937656SSherry.Moore@Sun.COM which |= IOMEM_WAIT16;
33942305Sstevel
33952305Sstevel break;
33962305Sstevel case PCIC_TI_PCI1130:
33972305Sstevel
33982305Sstevel if (window->state & WS_16BIT)
33997656SSherry.Moore@Sun.COM which |= IOMEM_WAIT16;
34002305Sstevel
34012305Sstevel break;
34022305Sstevel case PCIC_INTEL_i82092:
34032305Sstevel break;
34042305Sstevel default:
34052305Sstevel if (window->speed >
34067656SSherry.Moore@Sun.COM mhztons(pcic->bus_speed) * 3)
34077656SSherry.Moore@Sun.COM which |= IOMEM_WAIT16;
34082305Sstevel #ifdef notdef
34092305Sstevel if (window->speed <
34107656SSherry.Moore@Sun.COM mhztons(pcic->bus_speed) * 6)
34117656SSherry.Moore@Sun.COM which |= IOMEM_ZERO_WAIT;
34122305Sstevel #endif
34132305Sstevel break;
34142305Sstevel } /* switch (pc_type) */
34152305Sstevel
34162305Sstevel /*
34172305Sstevel * Setup the data width and timing
34182305Sstevel */
34192305Sstevel select = pcic_getb(pcic, socket, PCIC_IO_CONTROL);
34202305Sstevel select &= ~(PCIC_IO_WIN_MASK << (win * 4));
34212305Sstevel select |= IOMEM_SETWIN(win, which);
34222305Sstevel pcic_putb(pcic, socket, PCIC_IO_CONTROL, select);
34232305Sstevel
34242305Sstevel /*
34252305Sstevel * Enable the IO window
34262305Sstevel */
34272305Sstevel select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
34282305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE,
34297656SSherry.Moore@Sun.COM select | IOMEM_WINDOW(win));
34302305Sstevel
34312305Sstevel winp->pcw_status |= PCW_ENABLED;
34322305Sstevel
34332305Sstevel #if defined(PCIC_DEBUG)
34342305Sstevel if (pcic_debug) {
34352305Sstevel cmn_err(CE_CONT,
34367656SSherry.Moore@Sun.COM "\twhich = %x, select = %x (%x)\n",
34377656SSherry.Moore@Sun.COM which, select,
34387656SSherry.Moore@Sun.COM IOMEM_SETWIN(win, which));
34392305Sstevel xxdmp_all_regs(pcic, window->socket * 0x40, 24);
34402305Sstevel }
34412305Sstevel #endif
34422305Sstevel } else {
34432305Sstevel /*
34442305Sstevel * not only do we unmap the IO space, the
34452305Sstevel * window has been turned off.
34462305Sstevel */
34472305Sstevel if (winp->pcw_status & PCW_MAPPED) {
34482305Sstevel ddi_regs_map_free(&winp->pcw_handle);
34492305Sstevel res.ra_addr_lo = winp->pcw_base;
34502305Sstevel res.ra_len = winp->pcw_len;
34513664Srw148561 (void) pcmcia_free_io(winp->res_dip, &res);
34522305Sstevel winp->pcw_status &= ~PCW_MAPPED;
34532305Sstevel }
34542305Sstevel
34552305Sstevel /* disable current mapping */
34562305Sstevel select = pcic_getb(pcic, socket,
34577656SSherry.Moore@Sun.COM PCIC_MAPPING_ENABLE);
34582305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE,
34597656SSherry.Moore@Sun.COM select &= ~IOMEM_WINDOW(win));
34602305Sstevel winp->pcw_status &= ~PCW_ENABLED;
34612305Sstevel
34622305Sstevel winp->pcw_base = 0;
34632305Sstevel winp->pcw_len = 0;
34642305Sstevel winp->pcw_offset = 0;
34652305Sstevel window->base = 0;
34662305Sstevel /* now make sure we don't accidentally re-enable */
34672305Sstevel /* find the register set offset */
34682305Sstevel select = win * PCIC_IO_OFFSET;
34692305Sstevel pcic_putb(pcic, socket,
34707656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STARTLOW + select, 0);
34712305Sstevel pcic_putb(pcic, socket,
34727656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STARTHI + select, 0);
34732305Sstevel pcic_putb(pcic, socket,
34747656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STOPLOW + select, 0);
34752305Sstevel pcic_putb(pcic, socket,
34767656SSherry.Moore@Sun.COM PCIC_IO_ADDR_0_STOPHI + select, 0);
34772305Sstevel }
34782305Sstevel }
34792305Sstevel mutex_exit(&pcic->pc_lock);
34802305Sstevel
34812305Sstevel return (SUCCESS);
34822305Sstevel }
34832305Sstevel
34842305Sstevel /*
34852305Sstevel * pcic_card_state()
34862305Sstevel * compute the instantaneous Card State information
34872305Sstevel */
34882305Sstevel static int
pcic_card_state(pcicdev_t * pcic,pcic_socket_t * sockp)34892305Sstevel pcic_card_state(pcicdev_t *pcic, pcic_socket_t *sockp)
34902305Sstevel {
34912305Sstevel int value, result;
34922305Sstevel #if defined(PCIC_DEBUG)
34932305Sstevel int orig_value;
34942305Sstevel #endif
34952305Sstevel
34962305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
34972305Sstevel
34982305Sstevel value = pcic_getb(pcic, sockp->pcs_socket, PCIC_INTERFACE_STATUS);
34992305Sstevel
35002305Sstevel #if defined(PCIC_DEBUG)
35012305Sstevel orig_value = value;
35022305Sstevel if (pcic_debug >= 8)
35032305Sstevel cmn_err(CE_CONT, "pcic_card_state(%p) if status = %b for %d\n",
35047656SSherry.Moore@Sun.COM (void *)sockp,
35057656SSherry.Moore@Sun.COM value,
35067656SSherry.Moore@Sun.COM "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI",
35077656SSherry.Moore@Sun.COM sockp->pcs_socket);
35082305Sstevel #endif
35092305Sstevel /*
35102305Sstevel * Lie to socket services if we are not ready.
35112305Sstevel * This is when we are starting up or during debounce timeouts
35122305Sstevel * or if the card is a cardbus card.
35132305Sstevel */
35142305Sstevel if (!(sockp->pcs_flags & (PCS_STARTING|PCS_CARD_ISCARDBUS)) &&
35152305Sstevel !sockp->pcs_debounce_id &&
35162305Sstevel (value & PCIC_ISTAT_CD_MASK) == PCIC_CD_PRESENT_OK) {
35172305Sstevel result = SBM_CD;
35182305Sstevel
35192305Sstevel if (value & PCIC_WRITE_PROTECT || !(value & PCIC_POWER_ON))
35202305Sstevel result |= SBM_WP;
35212305Sstevel if (value & PCIC_POWER_ON) {
35222305Sstevel if (value & PCIC_READY)
35232305Sstevel result |= SBM_RDYBSY;
35242305Sstevel value = (~value) & (PCIC_BVD1 | PCIC_BVD2);
35252305Sstevel if (value & PCIC_BVD1)
35262305Sstevel result |= SBM_BVD1;
35272305Sstevel if (value & PCIC_BVD2)
35282305Sstevel result |= SBM_BVD2;
35292305Sstevel }
35302305Sstevel } else
35312305Sstevel result = 0;
35322305Sstevel
35332305Sstevel mutex_exit(&pcic->pc_lock);
35342305Sstevel
35352305Sstevel #if defined(PCIC_DEBUG)
35362305Sstevel pcic_err(pcic->dip, 8,
35372305Sstevel "pcic_card_state(%p) if status = %b for %d (rval=0x%x)\n",
35382305Sstevel (void *) sockp, orig_value,
35392305Sstevel "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI",
35402305Sstevel sockp->pcs_socket, result);
35412305Sstevel #endif
35422305Sstevel
35432305Sstevel return (result);
35442305Sstevel }
35452305Sstevel
35462305Sstevel /*
35472305Sstevel * pcic_set_page()
35482305Sstevel * SocketServices SetPage function
35492305Sstevel * set the page of PC Card memory that should be in the mapped
35502305Sstevel * window
35512305Sstevel */
35522305Sstevel /*ARGSUSED*/
35532305Sstevel static int
pcic_set_page(dev_info_t * dip,set_page_t * page)35542305Sstevel pcic_set_page(dev_info_t *dip, set_page_t *page)
35552305Sstevel {
35562305Sstevel anp_t *anp = ddi_get_driver_private(dip);
35572305Sstevel pcicdev_t *pcic = anp->an_private;
35582305Sstevel int select;
35592305Sstevel int which, socket, window;
35602305Sstevel uint32_t base;
35612305Sstevel pcs_memwin_t *memp;
35622305Sstevel
35632305Sstevel /* get real socket/window numbers */
35642305Sstevel window = page->window % PCIC_NUMWINSOCK;
35652305Sstevel socket = page->window / PCIC_NUMWINSOCK;
35662305Sstevel
35672305Sstevel #if defined(PCIC_DEBUG)
35682305Sstevel if (pcic_debug) {
35692305Sstevel cmn_err(CE_CONT,
35707656SSherry.Moore@Sun.COM "pcic_set_page: window=%d, socket=%d, page=%d\n",
35717656SSherry.Moore@Sun.COM window, socket, page->page);
35722305Sstevel }
35732305Sstevel #endif
35742305Sstevel /* only windows 2-6 work on memory */
35752305Sstevel if (window < PCIC_IOWINDOWS)
35762305Sstevel return (BAD_WINDOW);
35772305Sstevel
35782305Sstevel /* only one page supported (but any size) */
35792305Sstevel if (page->page != 0)
35802305Sstevel return (BAD_PAGE);
35812305Sstevel
35822305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
35832305Sstevel
35842305Sstevel memp = &pcic->pc_sockets[socket].pcs_windows[window].mem;
35852305Sstevel window -= PCIC_IOWINDOWS;
35862305Sstevel
35872305Sstevel #if defined(PCIC_DEBUG)
35882305Sstevel if (pcic_debug)
35892305Sstevel cmn_err(CE_CONT, "\tpcw_base=%x, pcw_hostmem=%p, pcw_len=%x\n",
35907656SSherry.Moore@Sun.COM (uint32_t)memp->pcw_base,
35917656SSherry.Moore@Sun.COM (void *)memp->pcw_hostmem, memp->pcw_len);
35922305Sstevel #endif
35932305Sstevel
35942305Sstevel /* window must be enabled */
35952305Sstevel if (!(memp->pcw_status & PCW_ENABLED))
35962305Sstevel return (BAD_ATTRIBUTE);
35972305Sstevel
35982305Sstevel /* find the register set offset */
35992305Sstevel select = window * PCIC_MEM_1_OFFSET;
36002305Sstevel #if defined(PCIC_DEBUG)
36012305Sstevel if (pcic_debug)
36022305Sstevel cmn_err(CE_CONT, "\tselect=%x\n", select);
36032305Sstevel #endif
36042305Sstevel
36052305Sstevel /*
36062305Sstevel * now map the card's memory pages - we start with page 0
36072305Sstevel */
36082305Sstevel
36092305Sstevel which = 0; /* assume simple case */
36102305Sstevel if (page->state & PS_ATTRIBUTE) {
36112305Sstevel which |= CARDMEM_REG_ACTIVE;
36122305Sstevel memp->pcw_status |= PCW_ATTRIBUTE;
36132305Sstevel } else {
36142305Sstevel memp->pcw_status &= ~PCW_ATTRIBUTE;
36152305Sstevel }
36162305Sstevel
36172305Sstevel /*
36182305Sstevel * if caller says Write Protect, enforce it.
36192305Sstevel */
36202305Sstevel if (page->state & PS_WP) {
36212305Sstevel which |= CARDMEM_WRITE_PROTECT;
36222305Sstevel memp->pcw_status |= PCW_WP;
36232305Sstevel } else {
36242305Sstevel memp->pcw_status &= ~PCW_WP;
36252305Sstevel }
36262305Sstevel #if defined(PCIC_DEBUG)
36272305Sstevel if (pcic_debug) {
36282305Sstevel cmn_err(CE_CONT, "\tmemory type = %s\n",
36297656SSherry.Moore@Sun.COM (which & CARDMEM_REG_ACTIVE) ? "attribute" : "common");
36302305Sstevel if (which & CARDMEM_WRITE_PROTECT)
36312305Sstevel cmn_err(CE_CONT, "\twrite protect\n");
36322305Sstevel cmn_err(CE_CONT, "\tpage offset=%x pcw_base=%x (%x)\n",
36337656SSherry.Moore@Sun.COM (unsigned)page->offset,
36347656SSherry.Moore@Sun.COM (unsigned)memp->pcw_base,
36357656SSherry.Moore@Sun.COM (int)page->offset - (int)memp->pcw_base & 0xffffff);
36362305Sstevel }
36372305Sstevel #endif
36382305Sstevel /* address computation based on 64MB range and not larger */
36392305Sstevel base = (uint32_t)memp->pcw_base & 0x3ffffff;
36402305Sstevel pcic_putb(pcic, socket, PCIC_CARDMEM_0_LOW + select,
36412305Sstevel CARDMEM_LOW((int)page->offset - (int)base));
36422305Sstevel (void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_LOW + select);
36432305Sstevel pcic_putb(pcic, socket, PCIC_CARDMEM_0_HI + select,
36442305Sstevel CARDMEM_HIGH((int)page->offset - base) | which);
36452305Sstevel (void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_HI + select);
36462305Sstevel
36472305Sstevel /*
36482305Sstevel * while not really necessary, this just makes sure
36492305Sstevel * nothing turned the window off behind our backs
36502305Sstevel */
36512305Sstevel which = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
36522305Sstevel which |= SYSMEM_WINDOW(window);
36532305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, which);
36542305Sstevel (void) pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
36552305Sstevel
36562305Sstevel memp->pcw_offset = (off_t)page->offset;
36572305Sstevel
36582305Sstevel #if defined(PCIC_DEBUG)
36592305Sstevel if (pcic_debug) {
36602305Sstevel cmn_err(CE_CONT, "\tbase=%p, *base=%x\n",
36617656SSherry.Moore@Sun.COM (void *)memp->pcw_hostmem,
36627656SSherry.Moore@Sun.COM (uint32_t)*memp->pcw_hostmem);
36632305Sstevel
36642305Sstevel xxdmp_all_regs(pcic, socket, -1);
36652305Sstevel
36662305Sstevel cmn_err(CE_CONT, "\tbase=%p, *base=%x\n",
36677656SSherry.Moore@Sun.COM (void *)memp->pcw_hostmem,
36687656SSherry.Moore@Sun.COM (uint32_t)*memp->pcw_hostmem);
36692305Sstevel }
36702305Sstevel #endif
36712305Sstevel
36722305Sstevel if (which & PCW_ATTRIBUTE)
36732305Sstevel pcic_mswait(pcic, socket, 2);
36742305Sstevel
36752305Sstevel mutex_exit(&pcic->pc_lock);
36762305Sstevel
36772305Sstevel return (SUCCESS);
36782305Sstevel }
36792305Sstevel
36802305Sstevel /*
36812305Sstevel * pcic_set_vcc_level()
36822305Sstevel *
36832305Sstevel * set voltage based on adapter information
36842305Sstevel *
36852305Sstevel * this routine implements a limited solution for support of 3.3v cards.
36862305Sstevel * the general solution, which would fully support the pcmcia spec
36872305Sstevel * as far as allowing client drivers to request which voltage levels
36882305Sstevel * to be set, requires more framework support and driver changes - ess
36892305Sstevel */
36902305Sstevel static int
pcic_set_vcc_level(pcicdev_t * pcic,set_socket_t * socket)36912305Sstevel pcic_set_vcc_level(pcicdev_t *pcic, set_socket_t *socket)
36922305Sstevel {
36932305Sstevel uint32_t socket_present_state;
36942305Sstevel
36952305Sstevel #if defined(PCIC_DEBUG)
36962305Sstevel if (pcic_debug) {
36972305Sstevel cmn_err(CE_CONT,
36987656SSherry.Moore@Sun.COM "pcic_set_vcc_level(pcic=%p, VccLevel=%d)\n",
36997656SSherry.Moore@Sun.COM (void *)pcic, socket->VccLevel);
37002305Sstevel }
37012305Sstevel #endif
37022305Sstevel
37032305Sstevel /*
37042305Sstevel * check VccLevel
37052305Sstevel * if this is zero, power is being turned off
37062305Sstevel * if it is non-zero, power is being turned on.
37072305Sstevel */
37082305Sstevel if (socket->VccLevel == 0) {
37092305Sstevel return (0);
37102305Sstevel }
37112305Sstevel
37122305Sstevel /*
37132305Sstevel * range checking for sanity's sake
37142305Sstevel */
37152305Sstevel if (socket->VccLevel >= pcic->pc_numpower) {
37162305Sstevel return (BAD_VCC);
37172305Sstevel }
37182305Sstevel
37192305Sstevel switch (pcic->pc_io_type) {
37202305Sstevel /*
37212305Sstevel * Yenta-compliant adapters have vcc info in the extended registers
37222305Sstevel * Other adapters can be added as needed, but the 'default' case
37232305Sstevel * has been left as it was previously so as not to break existing
37242305Sstevel * adapters.
37252305Sstevel */
37262305Sstevel case PCIC_IO_TYPE_YENTA:
37272305Sstevel /*
37282305Sstevel * Here we ignore the VccLevel passed in and read the
37292305Sstevel * card type from the adapter socket present state register
37302305Sstevel */
37312305Sstevel socket_present_state =
37327656SSherry.Moore@Sun.COM ddi_get32(pcic->handle, (uint32_t *)(pcic->ioaddr +
37337656SSherry.Moore@Sun.COM PCIC_PRESENT_STATE_REG));
37342305Sstevel #if defined(PCIC_DEBUG)
37352305Sstevel if (pcic_debug) {
37362305Sstevel cmn_err(CE_CONT,
37377656SSherry.Moore@Sun.COM "socket present state = 0x%x\n",
37387656SSherry.Moore@Sun.COM socket_present_state);
37392305Sstevel }
37402305Sstevel #endif
37412305Sstevel switch (socket_present_state & PCIC_VCC_MASK) {
37422305Sstevel case PCIC_VCC_3VCARD:
37432305Sstevel /* fall through */
37442305Sstevel case PCIC_VCC_3VCARD|PCIC_VCC_5VCARD:
37452305Sstevel socket->VccLevel = PCIC_VCC_3VLEVEL;
37462305Sstevel return
37472305Sstevel (POWER_3VCARD_ENABLE|POWER_OUTPUT_ENABLE);
37482305Sstevel case PCIC_VCC_5VCARD:
37492305Sstevel socket->VccLevel = PCIC_VCC_5VLEVEL;
37502305Sstevel return
37512305Sstevel (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE);
37522305Sstevel default:
37532305Sstevel /*
37542305Sstevel * if no card is present, this can be the
37552305Sstevel * case of a client making a SetSocket call
37562305Sstevel * after card removal. In this case we return
37572305Sstevel * the current power level
37582305Sstevel */
37592305Sstevel return ((unsigned)ddi_get8(pcic->handle,
37602305Sstevel pcic->ioaddr + CB_R2_OFFSET +
37617656SSherry.Moore@Sun.COM PCIC_POWER_CONTROL));
37622305Sstevel }
37632305Sstevel
37642305Sstevel default:
37652305Sstevel
37662305Sstevel switch (socket->VccLevel) {
37672305Sstevel case PCIC_VCC_3VLEVEL:
37682305Sstevel return (BAD_VCC);
37692305Sstevel case PCIC_VCC_5VLEVEL:
37702305Sstevel /* enable Vcc */
37712305Sstevel return (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE);
37722305Sstevel default:
37732305Sstevel return (BAD_VCC);
37742305Sstevel }
37752305Sstevel }
37762305Sstevel }
37772305Sstevel
37782305Sstevel
37792305Sstevel /*
37802305Sstevel * pcic_set_socket()
37812305Sstevel * Socket Services SetSocket call
37822305Sstevel * sets basic socket configuration
37832305Sstevel */
37842305Sstevel static int
pcic_set_socket(dev_info_t * dip,set_socket_t * socket)37852305Sstevel pcic_set_socket(dev_info_t *dip, set_socket_t *socket)
37862305Sstevel {
37872305Sstevel anp_t *anp = ddi_get_driver_private(dip);
37882305Sstevel pcicdev_t *pcic = anp->an_private;
37892305Sstevel pcic_socket_t *sockp = &pcic->pc_sockets[socket->socket];
37902305Sstevel int irq, interrupt, mirq;
37912305Sstevel int powerlevel = 0;
37922305Sstevel int ind, value, orig_pwrctl;
37932305Sstevel
37942305Sstevel #if defined(PCIC_DEBUG)
37952305Sstevel if (pcic_debug) {
37962305Sstevel cmn_err(CE_CONT,
37972305Sstevel "pcic_set_socket(dip=%p, socket=%d)"
37982305Sstevel " Vcc=%d Vpp1=%d Vpp2=%d\n", (void *)dip,
37992305Sstevel socket->socket, socket->VccLevel, socket->Vpp1Level,
38002305Sstevel socket->Vpp2Level);
38012305Sstevel }
38022305Sstevel #endif
38032305Sstevel /*
38042305Sstevel * check VccLevel, etc. before setting mutex
38052305Sstevel * if this is zero, power is being turned off
38062305Sstevel * if it is non-zero, power is being turned on.
38072305Sstevel * the default case is to assume Vcc only.
38082305Sstevel */
38092305Sstevel
38102305Sstevel /* this appears to be very implementation specific */
38112305Sstevel
38122305Sstevel if (socket->Vpp1Level != socket->Vpp2Level)
38132305Sstevel return (BAD_VPP);
38142305Sstevel
38152305Sstevel if (socket->VccLevel == 0 || !(sockp->pcs_flags & PCS_CARD_PRESENT)) {
38162305Sstevel powerlevel = 0;
38172305Sstevel sockp->pcs_vcc = 0;
38182305Sstevel sockp->pcs_vpp1 = 0;
38192305Sstevel sockp->pcs_vpp2 = 0;
38202305Sstevel } else {
38212305Sstevel #if defined(PCIC_DEBUG)
38222305Sstevel pcic_err(dip, 9, "\tVcc=%d Vpp1Level=%d, Vpp2Level=%d\n",
38232305Sstevel socket->VccLevel, socket->Vpp1Level, socket->Vpp2Level);
38242305Sstevel #endif
38252305Sstevel /* valid Vcc power level? */
38262305Sstevel if (socket->VccLevel >= pcic->pc_numpower)
38272305Sstevel return (BAD_VCC);
38282305Sstevel
38292305Sstevel switch (pcic_power[socket->VccLevel].PowerLevel) {
38302305Sstevel case 33: /* 3.3V */
38312305Sstevel case 60: /* for bad CIS in Option GPRS card */
38322305Sstevel if (!(pcic->pc_flags & PCF_33VCAP)) {
38332305Sstevel cmn_err(CE_WARN,
38342305Sstevel "%s%d: Bad Request for 3.3V "
38352305Sstevel "(Controller incapable)\n",
38362305Sstevel ddi_get_name(pcic->dip),
38372305Sstevel ddi_get_instance(pcic->dip));
38382305Sstevel return (BAD_VCC);
38392305Sstevel }
38402305Sstevel /* FALLTHROUGH */
38412305Sstevel case 50: /* 5V */
38422305Sstevel if ((pcic->pc_io_type == PCIC_IO_TYPE_YENTA) &&
38432305Sstevel pcic_getcb(pcic, CB_PRESENT_STATE) &
38442305Sstevel CB_PS_33VCARD) {
38452305Sstevel /*
38462305Sstevel * This is actually a 3.3V card.
38472305Sstevel * Solaris Card Services
38482305Sstevel * doesn't understand 3.3V
38492305Sstevel * so we cheat and change
38502305Sstevel * the setting to the one appropriate to 3.3V.
38512305Sstevel * Note that this is the entry number
38522305Sstevel * in the pcic_power[] array.
38532305Sstevel */
38542305Sstevel sockp->pcs_vcc = PCIC_VCC_3VLEVEL;
38552305Sstevel } else
38562305Sstevel sockp->pcs_vcc = socket->VccLevel;
38572305Sstevel break;
38582305Sstevel default:
38592305Sstevel return (BAD_VCC);
38602305Sstevel }
38612305Sstevel
38622305Sstevel /* enable Vcc */
38632305Sstevel powerlevel = POWER_CARD_ENABLE;
38642305Sstevel
38652305Sstevel #if defined(PCIC_DEBUG)
38662305Sstevel if (pcic_debug) {
38672305Sstevel cmn_err(CE_CONT, "\tVcc=%d powerlevel=%x\n",
38682305Sstevel socket->VccLevel, powerlevel);
38692305Sstevel }
38702305Sstevel #endif
38712305Sstevel ind = 0; /* default index to 0 power */
38722305Sstevel if ((int)socket->Vpp1Level >= 0 &&
38732305Sstevel socket->Vpp1Level < pcic->pc_numpower) {
38742305Sstevel if (!(pcic_power[socket->Vpp1Level].ValidSignals
38752305Sstevel & VPP1)) {
38762305Sstevel return (BAD_VPP);
38772305Sstevel }
38782305Sstevel ind = pcic_power[socket->Vpp1Level].PowerLevel/10;
38792305Sstevel powerlevel |= pcic_vpp_levels[ind];
38802305Sstevel sockp->pcs_vpp1 = socket->Vpp1Level;
38812305Sstevel }
38822305Sstevel if ((int)socket->Vpp2Level >= 0 &&
38832305Sstevel socket->Vpp2Level < pcic->pc_numpower) {
38842305Sstevel if (!(pcic_power[socket->Vpp2Level].ValidSignals
38852305Sstevel & VPP2)) {
38862305Sstevel return (BAD_VPP);
38872305Sstevel }
38882305Sstevel ind = pcic_power[socket->Vpp2Level].PowerLevel/10;
38892305Sstevel powerlevel |= (pcic_vpp_levels[ind] << 2);
38902305Sstevel sockp->pcs_vpp2 = socket->Vpp2Level;
38912305Sstevel }
38922305Sstevel
38932305Sstevel if (pcic->pc_flags & PCF_VPPX) {
38942305Sstevel /*
38952305Sstevel * this adapter doesn't allow separate Vpp1/Vpp2
38962305Sstevel * if one is turned on, both are turned on and only
38972305Sstevel * the Vpp1 bits should be set
38982305Sstevel */
38992305Sstevel if (sockp->pcs_vpp2 != sockp->pcs_vpp1) {
39002305Sstevel /* must be the same if one not zero */
39012305Sstevel if (sockp->pcs_vpp1 != 0 &&
39022305Sstevel sockp->pcs_vpp2 != 0) {
39032305Sstevel cmn_err(CE_WARN,
39042305Sstevel "%s%d: Bad Power Request "
39052305Sstevel "(Vpp1/2 not the same)\n",
39062305Sstevel ddi_get_name(pcic->dip),
39072305Sstevel ddi_get_instance(pcic->dip));
39082305Sstevel return (BAD_VPP);
39092305Sstevel }
39102305Sstevel }
39112305Sstevel powerlevel &= ~(3<<2);
39122305Sstevel }
39132305Sstevel
39142305Sstevel #if defined(PCIC_DEBUG)
39152305Sstevel if (pcic_debug) {
39162305Sstevel cmn_err(CE_CONT, "\tpowerlevel=%x, ind=%x\n",
39172305Sstevel powerlevel, ind);
39182305Sstevel }
39192305Sstevel #endif
39202305Sstevel }
39212305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
39222305Sstevel
39232305Sstevel /* turn socket->IREQRouting off while programming */
39242305Sstevel interrupt = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
39252305Sstevel interrupt &= ~PCIC_INTR_MASK;
39262305Sstevel if (pcic->pc_flags & PCF_USE_SMI)
39272305Sstevel interrupt |= PCIC_INTR_ENABLE;
39282305Sstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, interrupt);
39292305Sstevel
39302305Sstevel switch (pcic->pc_type) {
39317656SSherry.Moore@Sun.COM case PCIC_INTEL_i82092:
39322305Sstevel pcic_82092_smiirq_ctl(pcic, socket->socket, PCIC_82092_CTL_IRQ,
39337656SSherry.Moore@Sun.COM PCIC_82092_INT_DISABLE);
39342305Sstevel break;
39357656SSherry.Moore@Sun.COM default:
39362305Sstevel break;
39372305Sstevel } /* switch */
39382305Sstevel
39392305Sstevel /* the SCIntMask specifies events to detect */
39402305Sstevel mirq = pcic_getb(pcic, socket->socket, PCIC_MANAGEMENT_INT);
39412305Sstevel
39422305Sstevel #if defined(PCIC_DEBUG)
39432305Sstevel if (pcic_debug)
39442305Sstevel cmn_err(CE_CONT,
39457656SSherry.Moore@Sun.COM "\tSCIntMask=%x, interrupt=%x, mirq=%x\n",
39467656SSherry.Moore@Sun.COM socket->SCIntMask, interrupt, mirq);
39472305Sstevel #endif
39482305Sstevel mirq &= ~(PCIC_BD_DETECT|PCIC_BW_DETECT|PCIC_RD_DETECT);
39492305Sstevel pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT,
39502305Sstevel mirq & ~PCIC_CHANGE_MASK);
39512305Sstevel
39522305Sstevel /* save the mask we want to use */
39532305Sstevel sockp->pcs_intmask = socket->SCIntMask;
39542305Sstevel
39552305Sstevel /*
39562305Sstevel * Until there is a card present it's not worth enabling
39572305Sstevel * any interrupts except "Card detect". This is done
39582305Sstevel * elsewhere in the driver so don't change things if
39592305Sstevel * there is no card!
39602305Sstevel */
39612305Sstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) {
39622305Sstevel
39632305Sstevel /* now update the hardware to reflect events desired */
39642305Sstevel if (sockp->pcs_intmask & SBM_BVD1 || socket->IFType == IF_IO)
39652305Sstevel mirq |= PCIC_BD_DETECT;
39662305Sstevel
39672305Sstevel if (sockp->pcs_intmask & SBM_BVD2)
39682305Sstevel mirq |= PCIC_BW_DETECT;
39692305Sstevel
39702305Sstevel if (sockp->pcs_intmask & SBM_RDYBSY)
39712305Sstevel mirq |= PCIC_RD_DETECT;
39722305Sstevel
39732305Sstevel if (sockp->pcs_intmask & SBM_CD)
39742305Sstevel mirq |= PCIC_CD_DETECT;
39752305Sstevel }
39762305Sstevel
39772305Sstevel if (sockp->pcs_flags & PCS_READY) {
39782305Sstevel /*
39792305Sstevel * card just came ready.
39802305Sstevel * make sure enough time elapses
39812305Sstevel * before touching it.
39822305Sstevel */
39832305Sstevel sockp->pcs_flags &= ~PCS_READY;
39842305Sstevel pcic_mswait(pcic, socket->socket, 10);
39852305Sstevel }
39862305Sstevel
39872305Sstevel #if defined(PCIC_DEBUG)
39882305Sstevel if (pcic_debug) {
39892305Sstevel cmn_err(CE_CONT, "\tstatus change set to %x\n", mirq);
39902305Sstevel }
39912305Sstevel #endif
39922305Sstevel
39932305Sstevel switch (pcic->pc_type) {
39947656SSherry.Moore@Sun.COM case PCIC_I82365SL:
39957656SSherry.Moore@Sun.COM case PCIC_VADEM:
39967656SSherry.Moore@Sun.COM case PCIC_VADEM_VG469:
39972305Sstevel /*
39982305Sstevel * The Intel version has different options. This is a
39992305Sstevel * special case of GPI which might be used for eject
40002305Sstevel */
40012305Sstevel
40022305Sstevel irq = pcic_getb(pcic, socket->socket, PCIC_CARD_DETECT);
40032305Sstevel if (sockp->pcs_intmask & (SBM_EJECT|SBM_INSERT) &&
40042305Sstevel pcic->pc_flags & PCF_GPI_EJECT) {
40052305Sstevel irq |= PCIC_GPI_ENABLE;
40062305Sstevel } else {
40072305Sstevel irq &= ~PCIC_GPI_ENABLE;
40082305Sstevel }
40092305Sstevel pcic_putb(pcic, socket->socket, PCIC_CARD_DETECT, irq);
40102305Sstevel break;
40117656SSherry.Moore@Sun.COM case PCIC_CL_PD6710:
40127656SSherry.Moore@Sun.COM case PCIC_CL_PD6722:
40132305Sstevel if (socket->IFType == IF_IO) {
40142305Sstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_2, 0x0);
40152305Sstevel value = pcic_getb(pcic, socket->socket,
40167656SSherry.Moore@Sun.COM PCIC_MISC_CTL_1);
40172305Sstevel if (pcic->pc_flags & PCF_AUDIO)
40182305Sstevel value |= PCIC_MC_SPEAKER_ENB;
40192305Sstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1,
40207656SSherry.Moore@Sun.COM value);
40212305Sstevel } else {
40222305Sstevel value = pcic_getb(pcic, socket->socket,
40237656SSherry.Moore@Sun.COM PCIC_MISC_CTL_1);
40242305Sstevel value &= ~PCIC_MC_SPEAKER_ENB;
40252305Sstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1,
40267656SSherry.Moore@Sun.COM value);
40272305Sstevel }
40282305Sstevel break;
40297656SSherry.Moore@Sun.COM case PCIC_CL_PD6729:
40307656SSherry.Moore@Sun.COM case PCIC_CL_PD6730:
40317656SSherry.Moore@Sun.COM case PCIC_CL_PD6832:
40322305Sstevel value = pcic_getb(pcic, socket->socket, PCIC_MISC_CTL_1);
40332305Sstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) {
40347656SSherry.Moore@Sun.COM value |= PCIC_MC_SPEAKER_ENB;
40352305Sstevel } else {
40367656SSherry.Moore@Sun.COM value &= ~PCIC_MC_SPEAKER_ENB;
40372305Sstevel }
40382305Sstevel
40392305Sstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40402305Sstevel value |= PCIC_MC_3VCC;
40412305Sstevel else
40422305Sstevel value &= ~PCIC_MC_3VCC;
40432305Sstevel
40442305Sstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, value);
40452305Sstevel break;
40462305Sstevel
40477656SSherry.Moore@Sun.COM case PCIC_O2_OZ6912:
40482305Sstevel value = pcic_getcb(pcic, CB_MISCCTRL);
40492305Sstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO))
40502305Sstevel value |= (1<<25);
40512305Sstevel else
40522305Sstevel value &= ~(1<<25);
40532305Sstevel pcic_putcb(pcic, CB_MISCCTRL, value);
40542305Sstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40552305Sstevel powerlevel |= 0x08;
40562305Sstevel break;
40572305Sstevel
40587656SSherry.Moore@Sun.COM case PCIC_TI_PCI1250:
40597656SSherry.Moore@Sun.COM case PCIC_TI_PCI1221:
40607656SSherry.Moore@Sun.COM case PCIC_TI_PCI1225:
40617656SSherry.Moore@Sun.COM case PCIC_TI_PCI1410:
40627656SSherry.Moore@Sun.COM case PCIC_ENE_1410:
40637656SSherry.Moore@Sun.COM case PCIC_TI_PCI1510:
40647656SSherry.Moore@Sun.COM case PCIC_TI_PCI1520:
40657656SSherry.Moore@Sun.COM case PCIC_TI_PCI1420:
40667656SSherry.Moore@Sun.COM case PCIC_ENE_1420:
40672305Sstevel value = ddi_get8(pcic->cfg_handle,
40682305Sstevel pcic->cfgaddr + PCIC_CRDCTL_REG);
40692305Sstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) {
40702305Sstevel value |= PCIC_CRDCTL_SPKR_ENBL;
40712305Sstevel } else {
40722305Sstevel value &= ~PCIC_CRDCTL_SPKR_ENBL;
40732305Sstevel }
40742305Sstevel ddi_put8(pcic->cfg_handle,
40752305Sstevel pcic->cfgaddr + PCIC_CRDCTL_REG, value);
40762305Sstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33)
40772305Sstevel powerlevel |= 0x08;
40782305Sstevel break;
40792305Sstevel }
40802305Sstevel
40812305Sstevel /*
40822305Sstevel * ctlind processing -- we can ignore this
40832305Sstevel * there aren't any outputs on the chip for this and
40842305Sstevel * the GUI will display what it thinks is correct
40852305Sstevel */
40862305Sstevel
40872305Sstevel /*
40882305Sstevel * If outputs are enabled and the power is going off
40892305Sstevel * turn off outputs first.
40902305Sstevel */
40912305Sstevel
40922305Sstevel /* power setup -- if necessary */
40932305Sstevel orig_pwrctl = pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
40942305Sstevel if ((orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc == 0) {
40952305Sstevel orig_pwrctl &= ~POWER_OUTPUT_ENABLE;
40962305Sstevel pcic_putb(pcic, socket->socket,
40972305Sstevel PCIC_POWER_CONTROL, orig_pwrctl);
40982305Sstevel (void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
40992305Sstevel }
41002305Sstevel
41012305Sstevel if (pcic->pc_flags & PCF_CBPWRCTL) {
41022305Sstevel value = pcic_cbus_powerctl(pcic, socket->socket);
41032305Sstevel powerlevel = 0;
41042305Sstevel } else
41052305Sstevel value = pcic_exca_powerctl(pcic, socket->socket, powerlevel);
41062305Sstevel
41072305Sstevel if (value != SUCCESS) {
41082305Sstevel mutex_exit(&pcic->pc_lock);
41092305Sstevel return (value);
41102305Sstevel }
41112305Sstevel
41122305Sstevel /*
41132305Sstevel * If outputs were disabled and the power is going on
41142305Sstevel * turn on outputs afterwards.
41152305Sstevel */
41162305Sstevel if (!(orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc != 0) {
41172305Sstevel orig_pwrctl = pcic_getb(pcic, socket->socket,
41182305Sstevel PCIC_POWER_CONTROL);
41192305Sstevel orig_pwrctl |= POWER_OUTPUT_ENABLE;
41202305Sstevel pcic_putb(pcic, socket->socket,
41212305Sstevel PCIC_POWER_CONTROL, orig_pwrctl);
41222305Sstevel (void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL);
41232305Sstevel }
41242305Sstevel
41252305Sstevel /*
41262305Sstevel * Once we have done the power stuff can re-enable management
41272305Sstevel * interrupts.
41282305Sstevel */
41292305Sstevel pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, mirq);
41302305Sstevel
41312305Sstevel #if defined(PCIC_DEBUG)
41322305Sstevel pcic_err(dip, 8, "\tmanagement int set to %x pwrctl to 0x%x "
41332305Sstevel "cbctl 0x%x\n",
41342305Sstevel mirq, pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL),
41352305Sstevel pcic_getcb(pcic, CB_CONTROL));
41362305Sstevel #endif
41372305Sstevel
41382305Sstevel /* irq processing */
41392305Sstevel if (socket->IFType == IF_IO) {
41402305Sstevel /* IRQ only for I/O */
41412305Sstevel irq = socket->IREQRouting & PCIC_INTR_MASK;
41422305Sstevel value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
41432305Sstevel value &= ~PCIC_INTR_MASK;
41442305Sstevel
41452305Sstevel /* to enable I/O operation */
41462305Sstevel value |= PCIC_IO_CARD | PCIC_RESET;
41472305Sstevel sockp->pcs_flags |= PCS_CARD_IO;
41482305Sstevel if (irq != sockp->pcs_irq) {
41492305Sstevel if (sockp->pcs_irq != 0)
41502305Sstevel cmn_err(CE_CONT,
41517656SSherry.Moore@Sun.COM "SetSocket: IRQ mismatch %x != %x!\n",
41527656SSherry.Moore@Sun.COM irq, sockp->pcs_irq);
41532305Sstevel else
41542305Sstevel sockp->pcs_irq = irq;
41552305Sstevel }
41562305Sstevel irq = sockp->pcs_irq;
41572305Sstevel
41582305Sstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value);
41592305Sstevel if (socket->IREQRouting & IRQ_ENABLE) {
41602305Sstevel pcic_enable_io_intr(pcic, socket->socket, irq);
41612305Sstevel sockp->pcs_flags |= PCS_IRQ_ENABLED;
41622305Sstevel } else {
41632305Sstevel pcic_disable_io_intr(pcic, socket->socket);
41642305Sstevel sockp->pcs_flags &= ~PCS_IRQ_ENABLED;
41652305Sstevel }
41662305Sstevel #if defined(PCIC_DEBUG)
41672305Sstevel if (pcic_debug) {
41682305Sstevel cmn_err(CE_CONT,
41697656SSherry.Moore@Sun.COM "\tsocket type is I/O and irq %x is %s\n", irq,
41707656SSherry.Moore@Sun.COM (socket->IREQRouting & IRQ_ENABLE) ?
41717656SSherry.Moore@Sun.COM "enabled" : "not enabled");
41722305Sstevel xxdmp_all_regs(pcic, socket->socket, 20);
41732305Sstevel }
41742305Sstevel #endif
41752305Sstevel } else {
41762305Sstevel /* make sure I/O mode is off */
41772305Sstevel
41782305Sstevel sockp->pcs_irq = 0;
41792305Sstevel
41802305Sstevel value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT);
41812305Sstevel value &= ~PCIC_IO_CARD;
41822305Sstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value);
41832305Sstevel pcic_disable_io_intr(pcic, socket->socket);
41842305Sstevel sockp->pcs_flags &= ~(PCS_CARD_IO|PCS_IRQ_ENABLED);
41852305Sstevel }
41862305Sstevel
41872305Sstevel sockp->pcs_state &= ~socket->State;
41882305Sstevel
41892305Sstevel mutex_exit(&pcic->pc_lock);
41902305Sstevel return (SUCCESS);
41912305Sstevel }
41922305Sstevel
41932305Sstevel /*
41942305Sstevel * pcic_inquire_socket()
41952305Sstevel * SocketServices InquireSocket function
41962305Sstevel * returns basic characteristics of the socket
41972305Sstevel */
41982305Sstevel /*ARGSUSED*/
41992305Sstevel static int
pcic_inquire_socket(dev_info_t * dip,inquire_socket_t * socket)42002305Sstevel pcic_inquire_socket(dev_info_t *dip, inquire_socket_t *socket)
42012305Sstevel {
42022305Sstevel anp_t *anp = ddi_get_driver_private(dip);
42032305Sstevel pcicdev_t *pcic = anp->an_private;
42042305Sstevel int value;
42052305Sstevel
42062305Sstevel socket->SCIntCaps = PCIC_DEFAULT_INT_CAPS;
42072305Sstevel socket->SCRptCaps = PCIC_DEFAULT_RPT_CAPS;
42082305Sstevel socket->CtlIndCaps = PCIC_DEFAULT_CTL_CAPS;
42092305Sstevel value = pcic->pc_sockets[socket->socket].pcs_flags;
42102305Sstevel socket->SocketCaps = (value & PCS_SOCKET_IO) ? IF_IO : IF_MEMORY;
42112305Sstevel socket->ActiveHigh = 0;
42122305Sstevel /* these are the usable IRQs */
42132305Sstevel socket->ActiveLow = 0xfff0;
42142305Sstevel return (SUCCESS);
42152305Sstevel }
42162305Sstevel
42172305Sstevel /*
42182305Sstevel * pcic_inquire_window()
42192305Sstevel * SocketServices InquireWindow function
42202305Sstevel * returns detailed characteristics of the window
42212305Sstevel * this is where windows get tied to sockets
42222305Sstevel */
42232305Sstevel /*ARGSUSED*/
42242305Sstevel static int
pcic_inquire_window(dev_info_t * dip,inquire_window_t * window)42252305Sstevel pcic_inquire_window(dev_info_t *dip, inquire_window_t *window)
42262305Sstevel {
42272305Sstevel int type, socket;
42282305Sstevel
42292305Sstevel type = window->window % PCIC_NUMWINSOCK;
42302305Sstevel socket = window->window / PCIC_NUMWINSOCK;
42312305Sstevel
42322305Sstevel #if defined(PCIC_DEBUG)
42332305Sstevel if (pcic_debug >= 8)
42342305Sstevel cmn_err(CE_CONT,
42357656SSherry.Moore@Sun.COM "pcic_inquire_window: window = %d/%d socket=%d\n",
42367656SSherry.Moore@Sun.COM window->window, type, socket);
42372305Sstevel #endif
42382305Sstevel if (type < PCIC_IOWINDOWS) {
42392305Sstevel window->WndCaps = WC_IO|WC_WAIT;
42402305Sstevel type = IF_IO;
42412305Sstevel } else {
42422305Sstevel window->WndCaps = WC_COMMON|WC_ATTRIBUTE|WC_WAIT;
42432305Sstevel type = IF_MEMORY;
42442305Sstevel }
42452305Sstevel
42462305Sstevel /* initialize the socket map - one socket per window */
42472305Sstevel PR_ZERO(window->Sockets);
42482305Sstevel PR_SET(window->Sockets, socket);
42492305Sstevel
42502305Sstevel if (type == IF_IO) {
42512305Sstevel iowin_char_t *io;
42522305Sstevel io = &window->iowin_char;
42532305Sstevel io->IOWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT|
42547656SSherry.Moore@Sun.COM WC_16BIT;
42552305Sstevel io->FirstByte = (baseaddr_t)IOMEM_FIRST;
42562305Sstevel io->LastByte = (baseaddr_t)IOMEM_LAST;
42572305Sstevel io->MinSize = IOMEM_MIN;
42582305Sstevel io->MaxSize = IOMEM_MAX;
42592305Sstevel io->ReqGran = IOMEM_GRAN;
42602305Sstevel io->AddrLines = IOMEM_DECODE;
42612305Sstevel io->EISASlot = 0;
42622305Sstevel } else {
42632305Sstevel mem_win_char_t *mem;
42642305Sstevel mem = &window->mem_win_char;
42652305Sstevel mem->MemWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT|
42667656SSherry.Moore@Sun.COM WC_16BIT|WC_WP;
42672305Sstevel
42682305Sstevel mem->FirstByte = (baseaddr_t)MEM_FIRST;
42692305Sstevel mem->LastByte = (baseaddr_t)MEM_LAST;
42702305Sstevel
42712305Sstevel mem->MinSize = MEM_MIN;
42722305Sstevel mem->MaxSize = MEM_MAX;
42732305Sstevel mem->ReqGran = PCIC_PAGE;
42742305Sstevel mem->ReqBase = 0;
42752305Sstevel mem->ReqOffset = PCIC_PAGE;
42762305Sstevel mem->Slowest = MEM_SPEED_MAX;
42772305Sstevel mem->Fastest = MEM_SPEED_MIN;
42782305Sstevel }
42792305Sstevel return (SUCCESS);
42802305Sstevel }
42812305Sstevel
42822305Sstevel /*
42832305Sstevel * pcic_get_adapter()
42842305Sstevel * SocketServices GetAdapter function
42852305Sstevel * this is nearly a no-op.
42862305Sstevel */
42872305Sstevel /*ARGSUSED*/
42882305Sstevel static int
pcic_get_adapter(dev_info_t * dip,get_adapter_t * adapt)42892305Sstevel pcic_get_adapter(dev_info_t *dip, get_adapter_t *adapt)
42902305Sstevel {
42912305Sstevel anp_t *anp = ddi_get_driver_private(dip);
42922305Sstevel pcicdev_t *pcic = anp->an_private;
42932305Sstevel
42942305Sstevel if (pcic->pc_flags & PCF_INTRENAB)
42952305Sstevel adapt->SCRouting = IRQ_ENABLE;
42962305Sstevel adapt->state = 0;
42972305Sstevel return (SUCCESS);
42982305Sstevel }
42992305Sstevel
43002305Sstevel /*
43012305Sstevel * pcic_get_page()
43022305Sstevel * SocketServices GetPage function
43032305Sstevel * returns info about the window
43042305Sstevel */
43052305Sstevel /*ARGSUSED*/
43062305Sstevel static int
pcic_get_page(dev_info_t * dip,get_page_t * page)43072305Sstevel pcic_get_page(dev_info_t *dip, get_page_t *page)
43082305Sstevel {
43092305Sstevel anp_t *anp = ddi_get_driver_private(dip);
43102305Sstevel pcicdev_t *pcic = anp->an_private;
43112305Sstevel int socket, window;
43122305Sstevel pcs_memwin_t *winp;
43132305Sstevel
43142305Sstevel socket = page->window / PCIC_NUMWINSOCK;
43152305Sstevel window = page->window % PCIC_NUMWINSOCK;
43162305Sstevel
43172305Sstevel /* I/O windows are the first two */
43182305Sstevel if (window < PCIC_IOWINDOWS || socket >= pcic->pc_numsockets) {
43192305Sstevel return (BAD_WINDOW);
43202305Sstevel }
43212305Sstevel
43222305Sstevel winp = &pcic->pc_sockets[socket].pcs_windows[window].mem;
43232305Sstevel
43242305Sstevel if (page->page != 0)
43252305Sstevel return (BAD_PAGE);
43262305Sstevel
43272305Sstevel page->state = 0;
43282305Sstevel if (winp->pcw_status & PCW_ENABLED)
43292305Sstevel page->state |= PS_ENABLED;
43302305Sstevel if (winp->pcw_status & PCW_ATTRIBUTE)
43312305Sstevel page->state |= PS_ATTRIBUTE;
43322305Sstevel if (winp->pcw_status & PCW_WP)
43332305Sstevel page->state |= PS_WP;
43342305Sstevel
43352305Sstevel page->offset = (off_t)winp->pcw_offset;
43362305Sstevel
43372305Sstevel return (SUCCESS);
43382305Sstevel }
43392305Sstevel
43402305Sstevel /*
43412305Sstevel * pcic_get_socket()
43422305Sstevel * SocketServices GetSocket
43432305Sstevel * returns information about the current socket setting
43442305Sstevel */
43452305Sstevel /*ARGSUSED*/
43462305Sstevel static int
pcic_get_socket(dev_info_t * dip,get_socket_t * socket)43472305Sstevel pcic_get_socket(dev_info_t *dip, get_socket_t *socket)
43482305Sstevel {
43492305Sstevel anp_t *anp = ddi_get_driver_private(dip);
43502305Sstevel pcicdev_t *pcic = anp->an_private;
43512305Sstevel int socknum, irq_enabled;
43522305Sstevel pcic_socket_t *sockp;
43532305Sstevel
43542305Sstevel socknum = socket->socket;
43552305Sstevel sockp = &pcic->pc_sockets[socknum];
43562305Sstevel
43572305Sstevel socket->SCIntMask = sockp->pcs_intmask;
43582305Sstevel sockp->pcs_state = pcic_card_state(pcic, sockp);
43592305Sstevel
43602305Sstevel socket->state = sockp->pcs_state;
43612305Sstevel if (socket->state & SBM_CD) {
43622305Sstevel socket->VccLevel = sockp->pcs_vcc;
43632305Sstevel socket->Vpp1Level = sockp->pcs_vpp1;
43642305Sstevel socket->Vpp2Level = sockp->pcs_vpp2;
43652305Sstevel irq_enabled = (sockp->pcs_flags & PCS_IRQ_ENABLED) ?
43662305Sstevel IRQ_ENABLE : 0;
43672305Sstevel socket->IRQRouting = sockp->pcs_irq | irq_enabled;
43682305Sstevel socket->IFType = (sockp->pcs_flags & PCS_CARD_IO) ?
43692305Sstevel IF_IO : IF_MEMORY;
43702305Sstevel } else {
43712305Sstevel socket->VccLevel = 0;
43722305Sstevel socket->Vpp1Level = 0;
43732305Sstevel socket->Vpp2Level = 0;
43742305Sstevel socket->IRQRouting = 0;
43752305Sstevel socket->IFType = IF_MEMORY;
43762305Sstevel }
43772305Sstevel socket->CtlInd = 0; /* no indicators */
43782305Sstevel
43792305Sstevel return (SUCCESS);
43802305Sstevel }
43812305Sstevel
43822305Sstevel /*
43832305Sstevel * pcic_get_status()
43842305Sstevel * SocketServices GetStatus
43852305Sstevel * returns status information about the PC Card in
43862305Sstevel * the selected socket
43872305Sstevel */
43882305Sstevel /*ARGSUSED*/
43892305Sstevel static int
pcic_get_status(dev_info_t * dip,get_ss_status_t * status)43902305Sstevel pcic_get_status(dev_info_t *dip, get_ss_status_t *status)
43912305Sstevel {
43922305Sstevel anp_t *anp = ddi_get_driver_private(dip);
43932305Sstevel pcicdev_t *pcic = anp->an_private;
43942305Sstevel int socknum, irq_enabled;
43952305Sstevel pcic_socket_t *sockp;
43962305Sstevel
43972305Sstevel socknum = status->socket;
43982305Sstevel sockp = &pcic->pc_sockets[socknum];
43992305Sstevel
44002305Sstevel status->CardState = pcic_card_state(pcic, sockp);
44012305Sstevel status->SocketState = sockp->pcs_state;
44022305Sstevel status->CtlInd = 0; /* no indicators */
44032305Sstevel
44042305Sstevel if (sockp->pcs_flags & PCS_CARD_PRESENT)
44052305Sstevel status->SocketState |= SBM_CD;
44062305Sstevel if (status->CardState & SBM_CD) {
44072305Sstevel irq_enabled = (sockp->pcs_flags & PCS_CARD_ENABLED) ?
44082305Sstevel IRQ_ENABLE : 0;
44092305Sstevel status->IRQRouting = sockp->pcs_irq | irq_enabled;
44102305Sstevel status->IFType = (sockp->pcs_flags & PCS_CARD_IO) ?
44112305Sstevel IF_IO : IF_MEMORY;
44122305Sstevel } else {
44132305Sstevel status->IRQRouting = 0;
44142305Sstevel status->IFType = IF_MEMORY;
44152305Sstevel }
44162305Sstevel
44172305Sstevel #if defined(PCIC_DEBUG)
44182305Sstevel if (pcic_debug >= 8)
44192305Sstevel cmn_err(CE_CONT, "pcic_get_status: socket=%d, CardState=%x,"
44207656SSherry.Moore@Sun.COM "SocketState=%x\n",
44217656SSherry.Moore@Sun.COM socknum, status->CardState, status->SocketState);
44222305Sstevel #endif
44232305Sstevel switch (pcic->pc_type) {
44242305Sstevel uint32_t present_state;
44252305Sstevel case PCIC_TI_PCI1410:
44262305Sstevel case PCIC_TI_PCI1520:
44272305Sstevel case PCIC_TI_PCI1420:
44282305Sstevel case PCIC_ENE_1420:
44292305Sstevel case PCIC_TOSHIBA_TOPIC100:
44302305Sstevel case PCIC_TOSHIBA_TOPIC95:
44312305Sstevel case PCIC_TOSHIBA_VENDOR:
44322305Sstevel case PCIC_O2MICRO_VENDOR:
44332305Sstevel case PCIC_TI_VENDOR:
44342305Sstevel case PCIC_RICOH_VENDOR:
44352305Sstevel present_state = pcic_getcb(pcic, CB_PRESENT_STATE);
44362305Sstevel if (present_state & PCIC_CB_CARD)
44372305Sstevel status->IFType = IF_CARDBUS;
44382305Sstevel #if defined(PCIC_DEBUG)
44392305Sstevel if (pcic_debug >= 8)
44407656SSherry.Moore@Sun.COM cmn_err(CE_CONT,
44417656SSherry.Moore@Sun.COM "pcic_get_status: present_state=0x%x\n",
44427656SSherry.Moore@Sun.COM present_state);
44432305Sstevel #endif
44442305Sstevel break;
44452305Sstevel default:
44462305Sstevel break;
44472305Sstevel }
44482305Sstevel
44492305Sstevel return (SUCCESS);
44502305Sstevel }
44512305Sstevel
44522305Sstevel /*
44532305Sstevel * pcic_get_window()
44542305Sstevel * SocketServices GetWindow function
44552305Sstevel * returns state information about the specified window
44562305Sstevel */
44572305Sstevel /*ARGSUSED*/
44582305Sstevel static int
pcic_get_window(dev_info_t * dip,get_window_t * window)44592305Sstevel pcic_get_window(dev_info_t *dip, get_window_t *window)
44602305Sstevel {
44612305Sstevel anp_t *anp = ddi_get_driver_private(dip);
44622305Sstevel pcicdev_t *pcic = anp->an_private;
44632305Sstevel int socket, win;
44642305Sstevel pcic_socket_t *sockp;
44652305Sstevel pcs_memwin_t *winp;
44662305Sstevel
44672305Sstevel socket = window->window / PCIC_NUMWINSOCK;
44682305Sstevel win = window->window % PCIC_NUMWINSOCK;
44692305Sstevel #if defined(PCIC_DEBUG)
44702305Sstevel if (pcic_debug) {
44712305Sstevel cmn_err(CE_CONT, "pcic_get_window(socket=%d, window=%d)\n",
44727656SSherry.Moore@Sun.COM socket, win);
44732305Sstevel }
44742305Sstevel #endif
44752305Sstevel
44762305Sstevel if (socket > pcic->pc_numsockets)
44772305Sstevel return (BAD_WINDOW);
44782305Sstevel
44792305Sstevel sockp = &pcic->pc_sockets[socket];
44802305Sstevel winp = &sockp->pcs_windows[win].mem;
44812305Sstevel
44822305Sstevel window->socket = socket;
44832305Sstevel window->size = winp->pcw_len;
44842305Sstevel window->speed = winp->pcw_speed;
44852305Sstevel window->handle = (ddi_acc_handle_t)winp->pcw_handle;
44862305Sstevel window->base = (uint32_t)winp->pcw_base + winp->pcw_offset;
44872305Sstevel
44882305Sstevel if (win >= PCIC_IOWINDOWS) {
44892305Sstevel window->state = 0;
44902305Sstevel } else {
44912305Sstevel window->state = WS_IO;
44922305Sstevel }
44932305Sstevel if (winp->pcw_status & PCW_ENABLED)
44942305Sstevel window->state |= WS_ENABLED;
44952305Sstevel
44962305Sstevel if (winp->pcw_status & PCS_CARD_16BIT)
44972305Sstevel window->state |= WS_16BIT;
44982305Sstevel #if defined(PCIC_DEBUG)
44992305Sstevel if (pcic_debug)
45002305Sstevel cmn_err(CE_CONT, "\tsize=%d, speed=%d, base=%p, state=%x\n",
45017656SSherry.Moore@Sun.COM window->size, (unsigned)window->speed,
45027656SSherry.Moore@Sun.COM (void *)window->handle, window->state);
45032305Sstevel #endif
45042305Sstevel
45052305Sstevel return (SUCCESS);
45062305Sstevel }
45072305Sstevel
45082305Sstevel /*
45092305Sstevel * pcic_ll_reset
45102305Sstevel * low level reset
45112305Sstevel * separated out so it can be called when already locked
45122305Sstevel *
45132305Sstevel * There are two variables that control the RESET timing:
45142305Sstevel * pcic_prereset_time - time in mS before asserting RESET
45152305Sstevel * pcic_reset_time - time in mS to assert RESET
45162305Sstevel *
45172305Sstevel */
45182305Sstevel int pcic_prereset_time = 1;
45192305Sstevel int pcic_reset_time = 10;
45202305Sstevel int pcic_postreset_time = 20;
45212305Sstevel int pcic_vpp_is_vcc_during_reset = 0;
45222305Sstevel
45232305Sstevel static int
pcic_ll_reset(pcicdev_t * pcic,int socket)45242305Sstevel pcic_ll_reset(pcicdev_t *pcic, int socket)
45252305Sstevel {
45262305Sstevel int windowbits, iobits;
45272305Sstevel uint32_t pwr;
45282305Sstevel
45292305Sstevel /* save windows that were on */
45302305Sstevel windowbits = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE);
45312305Sstevel if (pcic_reset_time == 0)
45327656SSherry.Moore@Sun.COM return (windowbits);
45332305Sstevel /* turn all windows off */
45342305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 0);
45352305Sstevel
45362305Sstevel #if defined(PCIC_DEBUG)
45372305Sstevel pcic_err(pcic->dip, 6,
45387656SSherry.Moore@Sun.COM "pcic_ll_reset(socket %d) powerlevel=%x cbctl 0x%x cbps 0x%x\n",
45397656SSherry.Moore@Sun.COM socket, pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
45407656SSherry.Moore@Sun.COM pcic_getcb(pcic, CB_CONTROL),
45417656SSherry.Moore@Sun.COM pcic_getcb(pcic, CB_PRESENT_STATE));
45422305Sstevel #endif
45432305Sstevel
45442305Sstevel if (pcic_vpp_is_vcc_during_reset) {
45452305Sstevel
45462305Sstevel /*
45472305Sstevel * Set VPP to VCC for the duration of the reset - for aironet
45482305Sstevel * card.
45492305Sstevel */
45507656SSherry.Moore@Sun.COM if (pcic->pc_flags & PCF_CBPWRCTL) {
45512305Sstevel pwr = pcic_getcb(pcic, CB_CONTROL);
45522305Sstevel pcic_putcb(pcic, CB_CONTROL, (pwr&~CB_C_VPPMASK)|CB_C_VPPVCC);
45532305Sstevel (void) pcic_getcb(pcic, CB_CONTROL);
45547656SSherry.Moore@Sun.COM } else {
45552305Sstevel pwr = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
45562305Sstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL,
45572305Sstevel pwr | 1);
45582305Sstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
45597656SSherry.Moore@Sun.COM }
45602305Sstevel }
45612305Sstevel
45622305Sstevel if (pcic_prereset_time > 0) {
45632305Sstevel pcic_err(pcic->dip, 8, "pcic_ll_reset pre_wait %d mS\n",
45642305Sstevel pcic_prereset_time);
45652305Sstevel pcic_mswait(pcic, socket, pcic_prereset_time);
45662305Sstevel }
45672305Sstevel
45682305Sstevel /* turn interrupts off and start a reset */
45692305Sstevel pcic_err(pcic->dip, 8,
45707656SSherry.Moore@Sun.COM "pcic_ll_reset turn interrupts off and start a reset\n");
45712305Sstevel iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT);
45722305Sstevel iobits &= ~(PCIC_INTR_MASK | PCIC_RESET);
45732305Sstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
45742305Sstevel (void) pcic_getb(pcic, socket, PCIC_INTERRUPT);
45752305Sstevel
45762305Sstevel switch (pcic->pc_type) {
45777656SSherry.Moore@Sun.COM case PCIC_INTEL_i82092:
45782305Sstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
45797656SSherry.Moore@Sun.COM PCIC_82092_INT_DISABLE);
45802305Sstevel break;
45817656SSherry.Moore@Sun.COM default:
45822305Sstevel break;
45832305Sstevel } /* switch */
45842305Sstevel
45852305Sstevel pcic->pc_sockets[socket].pcs_state = 0;
45862305Sstevel
45872305Sstevel if (pcic_reset_time > 0) {
45882305Sstevel pcic_err(pcic->dip, 8, "pcic_ll_reset reset_wait %d mS\n",
45892305Sstevel pcic_reset_time);
45902305Sstevel pcic_mswait(pcic, socket, pcic_reset_time);
45912305Sstevel }
45922305Sstevel
45932305Sstevel pcic_err(pcic->dip, 8, "pcic_ll_reset take it out of reset now\n");
45942305Sstevel
45952305Sstevel /* take it out of RESET now */
45962305Sstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, PCIC_RESET | iobits);
45972305Sstevel (void) pcic_getb(pcic, socket, PCIC_INTERRUPT);
45982305Sstevel
45992305Sstevel /*
46002305Sstevel * can't access the card for 20ms, but we really don't
46012305Sstevel * want to sit around that long. The pcic is still usable.
46022305Sstevel * memory accesses must wait for RDY to come up.
46032305Sstevel */
46042305Sstevel if (pcic_postreset_time > 0) {
46052305Sstevel pcic_err(pcic->dip, 8, "pcic_ll_reset post_wait %d mS\n",
46062305Sstevel pcic_postreset_time);
46072305Sstevel pcic_mswait(pcic, socket, pcic_postreset_time);
46082305Sstevel }
46092305Sstevel
46102305Sstevel if (pcic_vpp_is_vcc_during_reset > 1) {
46112305Sstevel
46122305Sstevel /*
46132305Sstevel * Return VPP power to whatever it was before.
46142305Sstevel */
46157656SSherry.Moore@Sun.COM if (pcic->pc_flags & PCF_CBPWRCTL) {
46162305Sstevel pcic_putcb(pcic, CB_CONTROL, pwr);
46172305Sstevel (void) pcic_getcb(pcic, CB_CONTROL);
46187656SSherry.Moore@Sun.COM } else {
46192305Sstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, pwr);
46202305Sstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
46217656SSherry.Moore@Sun.COM }
46222305Sstevel }
46232305Sstevel
46242305Sstevel pcic_err(pcic->dip, 7, "pcic_ll_reset returning 0x%x\n", windowbits);
46252305Sstevel
46262305Sstevel return (windowbits);
46272305Sstevel }
46282305Sstevel
46292305Sstevel /*
46302305Sstevel * pcic_reset_socket()
46312305Sstevel * SocketServices ResetSocket function
46322305Sstevel * puts the PC Card in the socket into the RESET state
46332305Sstevel * and then takes it out after the the cycle time
46342305Sstevel * The socket is back to initial state when done
46352305Sstevel */
46362305Sstevel static int
pcic_reset_socket(dev_info_t * dip,int socket,int mode)46372305Sstevel pcic_reset_socket(dev_info_t *dip, int socket, int mode)
46382305Sstevel {
46392305Sstevel anp_t *anp = ddi_get_driver_private(dip);
46402305Sstevel pcicdev_t *pcic = anp->an_private;
46412305Sstevel int value;
46422305Sstevel int i, mint;
46432305Sstevel pcic_socket_t *sockp;
46442305Sstevel
46452305Sstevel #if defined(PCIC_DEBUG)
46462305Sstevel if (pcic_debug >= 8)
46472305Sstevel cmn_err(CE_CONT, "pcic_reset_socket(%p, %d, %d/%s)\n",
46482305Sstevel (void *)dip, socket, mode,
46497656SSherry.Moore@Sun.COM mode == RESET_MODE_FULL ? "full" : "partial");
46502305Sstevel #endif
46512305Sstevel
46522305Sstevel mutex_enter(&pcic->pc_lock); /* protect the registers */
46532305Sstevel
46542305Sstevel /* Turn off management interupts. */
46552305Sstevel mint = pcic_getb(pcic, socket, PCIC_MANAGEMENT_INT);
46562305Sstevel pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint & ~PCIC_CHANGE_MASK);
46572305Sstevel
46582305Sstevel sockp = &pcic->pc_sockets[socket];
46592305Sstevel
46602305Sstevel value = pcic_ll_reset(pcic, socket);
46612305Sstevel if (mode == RESET_MODE_FULL) {
46622305Sstevel /* disable and unmap all mapped windows */
46632305Sstevel for (i = 0; i < PCIC_NUMWINSOCK; i++) {
46642305Sstevel if (i < PCIC_IOWINDOWS) {
46652305Sstevel if (sockp->pcs_windows[i].io.pcw_status &
46662305Sstevel PCW_MAPPED) {
46672305Sstevel pcs_iowin_t *io;
46682305Sstevel io = &sockp->pcs_windows[i].io;
46692305Sstevel io->pcw_status &= ~PCW_ENABLED;
46702305Sstevel }
46712305Sstevel } else {
46722305Sstevel if (sockp->pcs_windows[i].mem.pcw_status &
46732305Sstevel PCW_MAPPED) {
46742305Sstevel pcs_memwin_t *mem;
46752305Sstevel mem = &sockp->pcs_windows[i].mem;
46762305Sstevel mem->pcw_status &= ~PCW_ENABLED;
46772305Sstevel }
46782305Sstevel }
46792305Sstevel }
46802305Sstevel } else {
46812305Sstevel /* turn windows back on */
46822305Sstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, value);
46832305Sstevel /* wait the rest of the time here */
46842305Sstevel pcic_mswait(pcic, socket, 10);
46852305Sstevel }
46862305Sstevel pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint);
46872305Sstevel mutex_exit(&pcic->pc_lock);
46882305Sstevel return (SUCCESS);
46892305Sstevel }
46902305Sstevel
46912305Sstevel /*
46922305Sstevel * pcic_set_interrupt()
46932305Sstevel * SocketServices SetInterrupt function
46942305Sstevel */
46952305Sstevel static int
pcic_set_interrupt(dev_info_t * dip,set_irq_handler_t * handler)46962305Sstevel pcic_set_interrupt(dev_info_t *dip, set_irq_handler_t *handler)
46972305Sstevel {
46982305Sstevel anp_t *anp = ddi_get_driver_private(dip);
46992305Sstevel pcicdev_t *pcic = anp->an_private;
47002305Sstevel int value = DDI_SUCCESS;
47012305Sstevel inthandler_t *intr;
47022305Sstevel
47032305Sstevel #if defined(PCIC_DEBUG)
47042305Sstevel if (pcic_debug) {
47052305Sstevel cmn_err(CE_CONT,
47067656SSherry.Moore@Sun.COM "pcic_set_interrupt: entered pc_intr_mode=0x%x\n",
47077656SSherry.Moore@Sun.COM pcic->pc_intr_mode);
47082305Sstevel cmn_err(CE_CONT,
47097656SSherry.Moore@Sun.COM "\t irq_top=%p handler=%p handler_id=%x\n",
47107656SSherry.Moore@Sun.COM (void *)pcic->irq_top, (void *)handler->handler,
47117656SSherry.Moore@Sun.COM handler->handler_id);
47122305Sstevel }
47132305Sstevel #endif
47142305Sstevel
47152305Sstevel /*
47162305Sstevel * If we're on a PCI bus, we route all IO IRQs through a single
47172305Sstevel * PCI interrupt (typically INT A#) so we don't have to do
47182305Sstevel * much other than add the caller to general interrupt handler
47192305Sstevel * and set some state.
47202305Sstevel */
47212305Sstevel
47222305Sstevel intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP);
47232305Sstevel if (intr == NULL)
47242305Sstevel return (NO_RESOURCE);
47252305Sstevel
47262305Sstevel switch (pcic->pc_intr_mode) {
47272305Sstevel case PCIC_INTR_MODE_PCI_1:
47282305Sstevel /*
47292305Sstevel * We only allow above-lock-level IO IRQ handlers
47302305Sstevel * in the PCI bus case.
47312305Sstevel */
47322305Sstevel
47332305Sstevel mutex_enter(&pcic->intr_lock);
47342305Sstevel
47352305Sstevel if (pcic->irq_top == NULL) {
47367656SSherry.Moore@Sun.COM pcic->irq_top = intr;
47377656SSherry.Moore@Sun.COM pcic->irq_current = pcic->irq_top;
47382305Sstevel } else {
47397656SSherry.Moore@Sun.COM while (pcic->irq_current->next != NULL)
47402305Sstevel pcic->irq_current = pcic->irq_current->next;
47417656SSherry.Moore@Sun.COM pcic->irq_current->next = intr;
47427656SSherry.Moore@Sun.COM pcic->irq_current = pcic->irq_current->next;
47432305Sstevel }
47442305Sstevel
47452305Sstevel pcic->irq_current->intr =
47462305Sstevel (ddi_intr_handler_t *)handler->handler;
47472305Sstevel pcic->irq_current->handler_id = handler->handler_id;
47482305Sstevel pcic->irq_current->arg1 = handler->arg1;
47492305Sstevel pcic->irq_current->arg2 = handler->arg2;
47502305Sstevel pcic->irq_current->socket = handler->socket;
47512305Sstevel
47522305Sstevel mutex_exit(&pcic->intr_lock);
47532305Sstevel
47542305Sstevel handler->iblk_cookie = &pcic->pc_pri;
47552305Sstevel handler->idev_cookie = &pcic->pc_dcookie;
47562305Sstevel break;
47572305Sstevel
47582305Sstevel default:
47592305Sstevel intr->intr = (ddi_intr_handler_t *)handler->handler;
47602305Sstevel intr->handler_id = handler->handler_id;
47612305Sstevel intr->arg1 = handler->arg1;
47622305Sstevel intr->arg2 = handler->arg2;
47632305Sstevel intr->socket = handler->socket;
47642305Sstevel intr->irq = handler->irq;
47652305Sstevel
47662305Sstevel /*
47672305Sstevel * need to revisit this to see if interrupts can be
47682305Sstevel * shared someday. Note that IRQ is set in the common
47692305Sstevel * code.
47702305Sstevel */
47712305Sstevel mutex_enter(&pcic->pc_lock);
47722305Sstevel if (pcic->pc_handlers == NULL) {
47732305Sstevel pcic->pc_handlers = intr;
47742305Sstevel intr->next = intr->prev = intr;
47752305Sstevel } else {
47762305Sstevel insque(intr, pcic->pc_handlers);
47772305Sstevel }
47782305Sstevel mutex_exit(&pcic->pc_lock);
47792305Sstevel
47802305Sstevel break;
47812305Sstevel }
47822305Sstevel
47832305Sstevel /*
47842305Sstevel * need to fill in cookies in event of multiple high priority
47852305Sstevel * interrupt handlers on same IRQ
47862305Sstevel */
47872305Sstevel
47882305Sstevel #if defined(PCIC_DEBUG)
47892305Sstevel if (pcic_debug) {
47902305Sstevel cmn_err(CE_CONT,
47917656SSherry.Moore@Sun.COM "pcic_set_interrupt: exit irq_top=%p value=%d\n",
47927656SSherry.Moore@Sun.COM (void *)pcic->irq_top, value);
47932305Sstevel }
47942305Sstevel #endif
47952305Sstevel
47962305Sstevel if (value == DDI_SUCCESS) {
47972305Sstevel return (SUCCESS);
47982305Sstevel } else {
47992305Sstevel return (BAD_IRQ);
48002305Sstevel }
48012305Sstevel }
48022305Sstevel
48032305Sstevel /*
48042305Sstevel * pcic_clear_interrupt()
48052305Sstevel * SocketServices ClearInterrupt function
48062305Sstevel *
48072305Sstevel * Interrupts for PCIC are complicated by the fact that we must
48082305Sstevel * follow several different models for interrupts.
48092305Sstevel * ISA: there is an interrupt per adapter and per socket and
48102305Sstevel * they can't be shared.
48112305Sstevel * PCI: some adapters have one PCI interrupt available while others
48122305Sstevel * have up to 4. Solaris may or may not allow us to use more
48132305Sstevel * than 1 so we essentially share them all at this point.
48142305Sstevel * Hybrid: PCI bridge but interrupts wired to host interrupt controller.
48152305Sstevel * This is like ISA but we have to fudge and create an intrspec
48162305Sstevel * that PCI's parent understands and bypass the PCI nexus.
48172305Sstevel * multifunction: this requires sharing the interrupts on a per-socket
48182305Sstevel * basis.
48192305Sstevel */
48202305Sstevel static int
pcic_clear_interrupt(dev_info_t * dip,clear_irq_handler_t * handler)48212305Sstevel pcic_clear_interrupt(dev_info_t *dip, clear_irq_handler_t *handler)
48222305Sstevel {
48232305Sstevel anp_t *anp = ddi_get_driver_private(dip);
48242305Sstevel pcicdev_t *pcic = anp->an_private;
48252305Sstevel inthandler_t *intr, *prev, *current;
48262305Sstevel int i;
48272305Sstevel
48282305Sstevel /*
48292305Sstevel * If we're on a PCI bus, we route all IO IRQs through a single
48302305Sstevel * PCI interrupt (typically INT A#) so we don't have to do
48312305Sstevel * much other than remove the caller from the general
48322305Sstevel * interrupt handler callout list.
48332305Sstevel */
48342305Sstevel
48352305Sstevel #if defined(PCIC_DEBUG)
48362305Sstevel if (pcic_debug) {
48372305Sstevel cmn_err(CE_CONT,
48387656SSherry.Moore@Sun.COM "pcic_clear_interrupt: entered pc_intr_mode=0x%x\n",
48397656SSherry.Moore@Sun.COM pcic->pc_intr_mode);
48402305Sstevel cmn_err(CE_CONT,
48417656SSherry.Moore@Sun.COM "\t irq_top=%p handler=%p handler_id=%x\n",
48427656SSherry.Moore@Sun.COM (void *)pcic->irq_top, (void *)handler->handler,
48437656SSherry.Moore@Sun.COM handler->handler_id);
48442305Sstevel }
48452305Sstevel #endif
48462305Sstevel
48472305Sstevel switch (pcic->pc_intr_mode) {
48482305Sstevel case PCIC_INTR_MODE_PCI_1:
48492305Sstevel
48502305Sstevel mutex_enter(&pcic->intr_lock);
48512305Sstevel if (pcic->irq_top == NULL) {
48522305Sstevel mutex_exit(&pcic->intr_lock);
48532305Sstevel return (BAD_IRQ);
48542305Sstevel }
48552305Sstevel
48562305Sstevel intr = NULL;
48572305Sstevel pcic->irq_current = pcic->irq_top;
48582305Sstevel
48592305Sstevel while ((pcic->irq_current != NULL) &&
48607656SSherry.Moore@Sun.COM (pcic->irq_current->handler_id !=
48617656SSherry.Moore@Sun.COM handler->handler_id)) {
48622305Sstevel intr = pcic->irq_current;
48632305Sstevel pcic->irq_current = pcic->irq_current->next;
48642305Sstevel }
48652305Sstevel
48662305Sstevel if (pcic->irq_current == NULL) {
48672305Sstevel mutex_exit(&pcic->intr_lock);
48682305Sstevel return (BAD_IRQ);
48692305Sstevel }
48702305Sstevel
48712305Sstevel if (intr != NULL) {
48722305Sstevel intr->next = pcic->irq_current->next;
48732305Sstevel } else {
48742305Sstevel pcic->irq_top = pcic->irq_current->next;
48752305Sstevel }
48762305Sstevel
48772305Sstevel current = pcic->irq_current;
48782305Sstevel pcic->irq_current = pcic->irq_top;
48792305Sstevel mutex_exit(&pcic->intr_lock);
48802305Sstevel kmem_free(current, sizeof (inthandler_t));
48812305Sstevel
48822305Sstevel break;
48832305Sstevel
48842305Sstevel default:
48852305Sstevel
48862305Sstevel mutex_enter(&pcic->pc_lock);
48872305Sstevel intr = pcic_handlers;
48882305Sstevel prev = (inthandler_t *)&pcic_handlers;
48892305Sstevel
48902305Sstevel while (intr != NULL) {
48917656SSherry.Moore@Sun.COM if (intr->handler_id == handler->handler_id) {
48922305Sstevel i = intr->irq & PCIC_INTR_MASK;
48932305Sstevel if (--pcic_irq_map[i].count == 0) {
48942305Sstevel /* multi-handler form */
48952305Sstevel (void) ddi_intr_disable(pcic->pc_intr_htblp[i]);
48962305Sstevel (void) ddi_intr_remove_handler(
48972305Sstevel pcic->pc_intr_htblp[i]);
48982305Sstevel (void) ddi_intr_free(pcic->pc_intr_htblp[i]);
48992305Sstevel (void) pcmcia_return_intr(pcic->dip, i);
49002305Sstevel #if defined(PCIC_DEBUG)
49012305Sstevel if (pcic_debug) {
49022305Sstevel cmn_err(CE_CONT,
49037656SSherry.Moore@Sun.COM "removing interrupt %d at %s "
49047656SSherry.Moore@Sun.COM "priority\n", i, "high");
49052305Sstevel cmn_err(CE_CONT,
49067656SSherry.Moore@Sun.COM "ddi_remove_intr(%p, %x, %p)\n",
49077656SSherry.Moore@Sun.COM (void *)dip,
49087656SSherry.Moore@Sun.COM 0,
49097656SSherry.Moore@Sun.COM (void *)intr->iblk_cookie);
49102305Sstevel }
49112305Sstevel #endif
49122305Sstevel }
49132305Sstevel prev->next = intr->next;
49142305Sstevel kmem_free(intr, sizeof (inthandler_t));
49152305Sstevel intr = prev->next;
49167656SSherry.Moore@Sun.COM } else {
49172305Sstevel prev = intr;
49182305Sstevel intr = intr->next;
49197656SSherry.Moore@Sun.COM } /* if (handler_id) */
49202305Sstevel } /* while */
49212305Sstevel
49222305Sstevel mutex_exit(&pcic->pc_lock);
49232305Sstevel }
49242305Sstevel
49252305Sstevel #if defined(PCIC_DEBUG)
49262305Sstevel if (pcic_debug) {
49272305Sstevel cmn_err(CE_CONT,
49287656SSherry.Moore@Sun.COM "pcic_clear_interrupt: exit irq_top=%p\n",
49297656SSherry.Moore@Sun.COM (void *)pcic->irq_top);
49302305Sstevel }
49312305Sstevel #endif
49322305Sstevel
49332305Sstevel
49342305Sstevel return (SUCCESS);
49352305Sstevel }
49362305Sstevel
49372305Sstevel struct intel_regs {
49382305Sstevel char *name;
49392305Sstevel int off;
49402305Sstevel char *fmt;
49412305Sstevel } iregs[] = {
49422305Sstevel {"ident ", 0},
49432305Sstevel {"if-status ", 1, "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI"},
49442305Sstevel {"power ", 2, "\020\1Vpp1c0\2Vpp1c1\3Vpp2c0\4Vpp2c1\5PE\6AUTO"
49452305Sstevel "\7DRD\10OE"},
49462305Sstevel {"cardstatus", 4, "\020\1BD\2BW\3RC\4CD\5GPI\6R1\7R2\010R3"},
49472305Sstevel {"enable ", 6, "\020\1MW0\2MW1\3MW2\4MW3\5MW4\6MEM16\7IO0\10IO1"},
49482305Sstevel {"cd-gcr ", 0x16, "\020\1MDI16\2CRE\3GPIE\4GPIT\5CDR\6S/W"},
49492305Sstevel {"GCR ", 0x1e, "\020\1PD\2LEVEL\3WCSC\4PLS14"},
49502305Sstevel {"int-gcr ", 3, "\020\5INTR\6IO\7~RST\10RI"},
49512305Sstevel {"management", 5, "\020\1BDE\2BWE\3RE\4CDE"},
49522305Sstevel {"volt-sense", 0x1f, "\020\1A_VS1\2A_VS2\3B_VS1\4B_VS2"},
49532305Sstevel {"volt-sel ", 0x2f, "\020\5EXTCONF\6BUSSELECT\7MIXEDV\10ISAV"},
49542305Sstevel {"VG ext A ", 0x3c, "\20\3IVS\4CABLE\5CSTEP\6TEST\7RIO"},
49552305Sstevel {"io-ctrl ", 7, "\020\1DS0\2IOCS0\3ZWS0\4WS0\5DS1\6IOS1\7ZWS1\10WS1"},
49562305Sstevel {"io0-slow ", 8},
49572305Sstevel {"io0-shi ", 9},
49582305Sstevel {"io0-elow ", 0xa},
49592305Sstevel {"io0-ehi ", 0xb},
49602305Sstevel {"io1-slow ", 0xc},
49612305Sstevel {"io1-shi ", 0xd},
49622305Sstevel {"io1-elow ", 0xe},
49632305Sstevel {"io1-ehi ", 0xf},
49642305Sstevel {"mem0-slow ", 0x10},
49652305Sstevel {"mem0-shi ", 0x11, "\020\7ZW\10DS"},
49662305Sstevel {"mem0-elow ", 0x12},
49672305Sstevel {"mem0-ehi ", 0x13, "\020\7WS0\10WS1"},
49682305Sstevel {"card0-low ", 0x14},
49692305Sstevel {"card0-hi ", 0x15, "\020\7AM\10WP"},
49702305Sstevel {"mem1-slow ", 0x18},
49712305Sstevel {"mem1-shi ", 0x19, "\020\7ZW\10DS"},
49722305Sstevel {"mem1-elow ", 0x1a},
49732305Sstevel {"mem1-ehi ", 0x1b, "\020\7WS0\10WS1"},
49742305Sstevel {"card1-low ", 0x1c},
49752305Sstevel {"card1-hi ", 0x1d, "\020\7AM\10WP"},
49762305Sstevel {"mem2-slow ", 0x20},
49772305Sstevel {"mem2-shi ", 0x21, "\020\7ZW\10DS"},
49782305Sstevel {"mem2-elow ", 0x22},
49792305Sstevel {"mem2-ehi ", 0x23, "\020\7WS0\10WS1"},
49802305Sstevel {"card2-low ", 0x24},
49812305Sstevel {"card2-hi ", 0x25, "\020\7AM\10WP"},
49822305Sstevel {"mem3-slow ", 0x28},
49832305Sstevel {"mem3-shi ", 0x29, "\020\7ZW\10DS"},
49842305Sstevel {"mem3-elow ", 0x2a},
49852305Sstevel {"mem3-ehi ", 0x2b, "\020\7WS0\10WS1"},
49862305Sstevel {"card3-low ", 0x2c},
49872305Sstevel {"card3-hi ", 0x2d, "\020\7AM\10WP"},
49882305Sstevel
49892305Sstevel {"mem4-slow ", 0x30},
49902305Sstevel {"mem4-shi ", 0x31, "\020\7ZW\10DS"},
49912305Sstevel {"mem4-elow ", 0x32},
49922305Sstevel {"mem4-ehi ", 0x33, "\020\7WS0\10WS1"},
49932305Sstevel {"card4-low ", 0x34},
49942305Sstevel {"card4-hi ", 0x35, "\020\7AM\10WP"},
49952305Sstevel {"mpage0 ", 0x40},
49962305Sstevel {"mpage1 ", 0x41},
49972305Sstevel {"mpage2 ", 0x42},
49982305Sstevel {"mpage3 ", 0x43},
49992305Sstevel {"mpage4 ", 0x44},
50002305Sstevel {NULL},
50012305Sstevel };
50022305Sstevel
50032305Sstevel static struct intel_regs cregs[] = {
50042305Sstevel {"misc-ctl1 ", 0x16, "\20\2VCC3\3PMI\4PSI\5SPKR\10INPACK"},
50052305Sstevel {"fifo ", 0x17, "\20\6DIOP\7DMEMP\10EMPTY"},
50062305Sstevel {"misc-ctl2 ", 0x1e, "\20\1XCLK\2LOW\3SUSP\4CORE5V\5TCD\10RIOUT"},
50072305Sstevel {"chip-info ", 0x1f, "\20\6DUAL"},
50082305Sstevel {"IO-offlow0", 0x36},
50092305Sstevel {"IO-offhi0 ", 0x37},
50102305Sstevel {"IO-offlow1", 0x38},
50112305Sstevel {"IO-offhi1 ", 0x39},
50122305Sstevel NULL,
50132305Sstevel };
50142305Sstevel
50152305Sstevel static struct intel_regs cxregs[] = {
50162305Sstevel {"ext-ctl-1 ", 0x03,
50172305Sstevel "\20\1VCCLCK\2AUTOCLR\3LED\4INVIRQC\5INVIRQM\6PUC"},
50182305Sstevel {"misc-ctl3 ", 0x25, "\20\5HWSUSP"},
50192305Sstevel {"mem0-up ", 0x05},
50202305Sstevel {"mem1-up ", 0x06},
50212305Sstevel {"mem2-up ", 0x07},
50222305Sstevel {"mem3-up ", 0x08},
50232305Sstevel {"mem4-up ", 0x09},
50242305Sstevel {NULL}
50252305Sstevel };
50262305Sstevel
50272305Sstevel void
xxdmp_cl_regs(pcicdev_t * pcic,int socket,uint32_t len)50282305Sstevel xxdmp_cl_regs(pcicdev_t *pcic, int socket, uint32_t len)
50292305Sstevel {
50302305Sstevel int i, value, j;
50312305Sstevel char buff[256];
50322305Sstevel char *fmt;
50332305Sstevel
50342305Sstevel cmn_err(CE_CONT, "--------- Cirrus Logic Registers --------\n");
50352305Sstevel for (buff[0] = '\0', i = 0; cregs[i].name != NULL && len-- != 0; i++) {
50362305Sstevel int sval;
50372305Sstevel if (cregs[i].off == PCIC_MISC_CTL_2)
50382305Sstevel sval = 0;
50392305Sstevel else
50402305Sstevel sval = socket;
50412305Sstevel value = pcic_getb(pcic, sval, cregs[i].off);
50422305Sstevel if (i & 1) {
50432305Sstevel if (cregs[i].fmt)
50442305Sstevel fmt = "%s\t%s\t%b\n";
50452305Sstevel else
50462305Sstevel fmt = "%s\t%s\t%x\n";
50472305Sstevel cmn_err(CE_CONT, fmt, buff,
50487656SSherry.Moore@Sun.COM cregs[i].name, value, cregs[i].fmt);
50492305Sstevel buff[0] = '\0';
50502305Sstevel } else {
50512305Sstevel if (cregs[i].fmt)
50522305Sstevel fmt = "\t%s\t%b";
50532305Sstevel else
50542305Sstevel fmt = "\t%s\t%x";
50552305Sstevel (void) sprintf(buff, fmt,
50567656SSherry.Moore@Sun.COM cregs[i].name, value, cregs[i].fmt);
50572305Sstevel for (j = strlen(buff); j < 40; j++)
50582305Sstevel buff[j] = ' ';
50592305Sstevel buff[40] = '\0';
50602305Sstevel }
50612305Sstevel }
50622305Sstevel cmn_err(CE_CONT, "%s\n", buff);
50632305Sstevel
50642305Sstevel i = pcic_getb(pcic, socket, PCIC_TIME_SETUP_0);
50652305Sstevel j = pcic_getb(pcic, socket, PCIC_TIME_SETUP_1);
50662305Sstevel cmn_err(CE_CONT, "\tsetup-tim0\t%x\tsetup-tim1\t%x\n", i, j);
50672305Sstevel
50682305Sstevel i = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_0);
50692305Sstevel j = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_1);
50702305Sstevel cmn_err(CE_CONT, "\tcmd-tim0 \t%x\tcmd-tim1 \t%x\n", i, j);
50712305Sstevel
50722305Sstevel i = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_0);
50732305Sstevel j = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_1);
50742305Sstevel cmn_err(CE_CONT, "\trcvr-tim0 \t%x\trcvr-tim1 \t%x\n", i, j);
50752305Sstevel
50762305Sstevel cmn_err(CE_CONT, "--------- Extended Registers --------\n");
50772305Sstevel
50782305Sstevel for (buff[0] = '\0', i = 0; cxregs[i].name != NULL && len-- != 0; i++) {
50792305Sstevel value = clext_reg_read(pcic, socket, cxregs[i].off);
50802305Sstevel if (i & 1) {
50812305Sstevel if (cxregs[i].fmt)
50822305Sstevel fmt = "%s\t%s\t%b\n";
50832305Sstevel else
50842305Sstevel fmt = "%s\t%s\t%x\n";
50852305Sstevel cmn_err(CE_CONT, fmt, buff,
50867656SSherry.Moore@Sun.COM cxregs[i].name, value, cxregs[i].fmt);
50872305Sstevel buff[0] = '\0';
50882305Sstevel } else {
50892305Sstevel if (cxregs[i].fmt)
50902305Sstevel fmt = "\t%s\t%b";
50912305Sstevel else
50922305Sstevel fmt = "\t%s\t%x";
50932305Sstevel (void) sprintf(buff, fmt,
50947656SSherry.Moore@Sun.COM cxregs[i].name, value, cxregs[i].fmt);
50952305Sstevel for (j = strlen(buff); j < 40; j++)
50962305Sstevel buff[j] = ' ';
50972305Sstevel buff[40] = '\0';
50982305Sstevel }
50992305Sstevel }
51002305Sstevel }
51012305Sstevel
51022305Sstevel #if defined(PCIC_DEBUG)
51032305Sstevel static void
xxdmp_all_regs(pcicdev_t * pcic,int socket,uint32_t len)51042305Sstevel xxdmp_all_regs(pcicdev_t *pcic, int socket, uint32_t len)
51052305Sstevel {
51062305Sstevel int i, value, j;
51072305Sstevel char buff[256];
51082305Sstevel char *fmt;
51092305Sstevel
51102305Sstevel #if defined(PCIC_DEBUG)
51112305Sstevel if (pcic_debug < 2)
51122305Sstevel return;
51132305Sstevel #endif
51142305Sstevel cmn_err(CE_CONT,
51157656SSherry.Moore@Sun.COM "----------- PCIC Registers for socket %d---------\n",
51167656SSherry.Moore@Sun.COM socket);
51172305Sstevel cmn_err(CE_CONT,
51187656SSherry.Moore@Sun.COM "\tname value name value\n");
51192305Sstevel
51202305Sstevel for (buff[0] = '\0', i = 0; iregs[i].name != NULL && len-- != 0; i++) {
51212305Sstevel value = pcic_getb(pcic, socket, iregs[i].off);
51222305Sstevel if (i & 1) {
51232305Sstevel if (iregs[i].fmt)
51242305Sstevel fmt = "%s\t%s\t%b\n";
51252305Sstevel else
51262305Sstevel fmt = "%s\t%s\t%x\n";
51272305Sstevel cmn_err(CE_CONT, fmt, buff,
51287656SSherry.Moore@Sun.COM iregs[i].name, value, iregs[i].fmt);
51292305Sstevel buff[0] = '\0';
51302305Sstevel } else {
51312305Sstevel if (iregs[i].fmt)
51322305Sstevel fmt = "\t%s\t%b";
51332305Sstevel else
51342305Sstevel fmt = "\t%s\t%x";
51352305Sstevel (void) sprintf(buff, fmt,
51367656SSherry.Moore@Sun.COM iregs[i].name, value, iregs[i].fmt);
51372305Sstevel for (j = strlen(buff); j < 40; j++)
51382305Sstevel buff[j] = ' ';
51392305Sstevel buff[40] = '\0';
51402305Sstevel }
51412305Sstevel }
51422305Sstevel switch (pcic->pc_type) {
51432305Sstevel case PCIC_CL_PD6710:
51442305Sstevel case PCIC_CL_PD6722:
51452305Sstevel case PCIC_CL_PD6729:
51462305Sstevel case PCIC_CL_PD6832:
51472305Sstevel (void) xxdmp_cl_regs(pcic, socket, 0xFFFF);
51482305Sstevel break;
51492305Sstevel }
51502305Sstevel cmn_err(CE_CONT, "%s\n", buff);
51512305Sstevel }
51522305Sstevel #endif
51532305Sstevel
51542305Sstevel /*
51552305Sstevel * pcic_mswait(ms)
51562305Sstevel * sleep ms milliseconds
51572305Sstevel * call drv_usecwait once for each ms
51582305Sstevel */
51592305Sstevel static void
pcic_mswait(pcicdev_t * pcic,int socket,int ms)51602305Sstevel pcic_mswait(pcicdev_t *pcic, int socket, int ms)
51612305Sstevel {
51622305Sstevel if (ms) {
51632305Sstevel pcic->pc_sockets[socket].pcs_flags |= PCS_WAITING;
51642305Sstevel pcic_mutex_exit(&pcic->pc_lock);
51652305Sstevel delay(drv_usectohz(ms*1000));
51662305Sstevel pcic_mutex_enter(&pcic->pc_lock);
51672305Sstevel pcic->pc_sockets[socket].pcs_flags &= ~PCS_WAITING;
51682305Sstevel }
51692305Sstevel }
51702305Sstevel
51712305Sstevel /*
51722305Sstevel * pcic_check_ready(pcic, index, off)
51732305Sstevel * Wait for card to come ready
51742305Sstevel * We only wait if the card is NOT in RESET
51752305Sstevel * and power is on.
51762305Sstevel */
51772305Sstevel static boolean_t
pcic_check_ready(pcicdev_t * pcic,int socket)51782305Sstevel pcic_check_ready(pcicdev_t *pcic, int socket)
51792305Sstevel {
51802305Sstevel int ifstate, intstate;
51812305Sstevel
51822305Sstevel intstate = pcic_getb(pcic, socket, PCIC_INTERRUPT);
51832305Sstevel ifstate = pcic_getb(pcic, socket, PCIC_INTERFACE_STATUS);
51842305Sstevel
51852305Sstevel if ((intstate & PCIC_RESET) &&
51862305Sstevel ((ifstate & (PCIC_READY|PCIC_POWER_ON|PCIC_ISTAT_CD_MASK)) ==
51872305Sstevel (PCIC_READY|PCIC_POWER_ON|PCIC_CD_PRESENT_OK)))
51882305Sstevel return (B_TRUE);
51892305Sstevel
51902305Sstevel #ifdef PCIC_DEBUG
51912305Sstevel pcic_err(NULL, 5, "pcic_check_read: Card not ready, intstate = 0x%x, "
51922305Sstevel "ifstate = 0x%x\n", intstate, ifstate);
51932305Sstevel if (pcic_debug) {
51942305Sstevel pcic_debug += 4;
51952305Sstevel xxdmp_all_regs(pcic, socket, -1);
51962305Sstevel pcic_debug -= 4;
51972305Sstevel }
51982305Sstevel #endif
51992305Sstevel return (B_FALSE);
52002305Sstevel }
52012305Sstevel
52022305Sstevel /*
52032305Sstevel * Cirrus Logic extended register read/write routines
52042305Sstevel */
52052305Sstevel static int
clext_reg_read(pcicdev_t * pcic,int sn,uchar_t ext_reg)52062305Sstevel clext_reg_read(pcicdev_t *pcic, int sn, uchar_t ext_reg)
52072305Sstevel {
52082305Sstevel int val;
52092305Sstevel
52102305Sstevel switch (pcic->pc_io_type) {
52112305Sstevel case PCIC_IO_TYPE_YENTA:
52122305Sstevel val = ddi_get8(pcic->handle,
52132305Sstevel pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg);
52142305Sstevel break;
52152305Sstevel default:
52162305Sstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg);
52172305Sstevel val = pcic_getb(pcic, sn, PCIC_CL_EXINDEX + 1);
52182305Sstevel break;
52192305Sstevel }
52202305Sstevel
52212305Sstevel return (val);
52222305Sstevel }
52232305Sstevel
52242305Sstevel static void
clext_reg_write(pcicdev_t * pcic,int sn,uchar_t ext_reg,uchar_t value)52252305Sstevel clext_reg_write(pcicdev_t *pcic, int sn, uchar_t ext_reg, uchar_t value)
52262305Sstevel {
52272305Sstevel switch (pcic->pc_io_type) {
52282305Sstevel case PCIC_IO_TYPE_YENTA:
52292305Sstevel ddi_put8(pcic->handle,
52302305Sstevel pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg, value);
52312305Sstevel break;
52322305Sstevel default:
52332305Sstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg);
52342305Sstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX + 1, value);
52352305Sstevel break;
52362305Sstevel }
52372305Sstevel }
52382305Sstevel
52392305Sstevel /*
52402305Sstevel * Misc PCI functions
52412305Sstevel */
52422305Sstevel static void
pcic_iomem_pci_ctl(ddi_acc_handle_t handle,uchar_t * cfgaddr,unsigned flags)52432305Sstevel pcic_iomem_pci_ctl(ddi_acc_handle_t handle, uchar_t *cfgaddr, unsigned flags)
52442305Sstevel {
52452305Sstevel unsigned cmd;
52462305Sstevel
52472305Sstevel if (flags & (PCIC_ENABLE_IO | PCIC_ENABLE_MEM)) {
52482305Sstevel cmd = ddi_get16(handle, (ushort_t *)(cfgaddr + 4));
52492305Sstevel if ((cmd & (PCI_COMM_IO|PCI_COMM_MAE)) ==
52502305Sstevel (PCI_COMM_IO|PCI_COMM_MAE))
52512305Sstevel return;
52522305Sstevel
52532305Sstevel if (flags & PCIC_ENABLE_IO)
52547656SSherry.Moore@Sun.COM cmd |= PCI_COMM_IO;
52552305Sstevel
52562305Sstevel if (flags & PCIC_ENABLE_MEM)
52577656SSherry.Moore@Sun.COM cmd |= PCI_COMM_MAE;
52582305Sstevel
52592305Sstevel ddi_put16(handle, (ushort_t *)(cfgaddr + 4), cmd);
52602305Sstevel } /* if (PCIC_ENABLE_IO | PCIC_ENABLE_MEM) */
52612305Sstevel }
52622305Sstevel
52632305Sstevel /*
52642305Sstevel * pcic_find_pci_type - Find and return PCI-PCMCIA adapter type
52652305Sstevel */
52662305Sstevel static int
pcic_find_pci_type(pcicdev_t * pcic)52672305Sstevel pcic_find_pci_type(pcicdev_t *pcic)
52682305Sstevel {
52692305Sstevel uint32_t vend, device;
52702305Sstevel
52712305Sstevel vend = ddi_getprop(DDI_DEV_T_ANY, pcic->dip,
52727656SSherry.Moore@Sun.COM DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
52737656SSherry.Moore@Sun.COM "vendor-id", -1);
52742305Sstevel device = ddi_getprop(DDI_DEV_T_ANY, pcic->dip,
52757656SSherry.Moore@Sun.COM DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
52767656SSherry.Moore@Sun.COM "device-id", -1);
52772305Sstevel
52782305Sstevel device = PCI_ID(vend, device);
52792305Sstevel pcic->pc_type = device;
52802305Sstevel pcic->pc_chipname = "PCI:unknown";
52812305Sstevel
52822305Sstevel switch (device) {
52832305Sstevel case PCIC_INTEL_i82092:
52842305Sstevel pcic->pc_chipname = PCIC_TYPE_i82092;
52852305Sstevel break;
52862305Sstevel case PCIC_CL_PD6729:
52872305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6729;
52882305Sstevel /*
52892305Sstevel * Some 6730's incorrectly identify themselves
52902305Sstevel * as a 6729, so we need to do some more tests
52912305Sstevel * here to see if the device that's claiming
52922305Sstevel * to be a 6729 is really a 6730.
52932305Sstevel */
52942305Sstevel if ((clext_reg_read(pcic, 0, PCIC_CLEXT_MISC_CTL_3) &
52957656SSherry.Moore@Sun.COM PCIC_CLEXT_MISC_CTL_3_REV_MASK) ==
52967656SSherry.Moore@Sun.COM 0) {
52972305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6730;
52982305Sstevel pcic->pc_type = PCIC_CL_PD6730;
52992305Sstevel }
53002305Sstevel break;
53012305Sstevel case PCIC_CL_PD6730:
53022305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6730;
53032305Sstevel break;
53042305Sstevel case PCIC_CL_PD6832:
53052305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6832;
53062305Sstevel break;
53072305Sstevel case PCIC_SMC_34C90:
53082305Sstevel pcic->pc_chipname = PCIC_TYPE_34C90;
53092305Sstevel break;
53102305Sstevel case PCIC_TOSHIBA_TOPIC95:
53112305Sstevel pcic->pc_chipname = PCIC_TYPE_TOPIC95;
53122305Sstevel break;
53132305Sstevel case PCIC_TOSHIBA_TOPIC100:
53142305Sstevel pcic->pc_chipname = PCIC_TYPE_TOPIC100;
53152305Sstevel break;
53162305Sstevel case PCIC_TI_PCI1031:
53172305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1031;
53182305Sstevel break;
53192305Sstevel case PCIC_TI_PCI1130:
53202305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1130;
53212305Sstevel break;
53222305Sstevel case PCIC_TI_PCI1131:
53232305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1131;
53242305Sstevel break;
53252305Sstevel case PCIC_TI_PCI1250:
53262305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1250;
53272305Sstevel break;
53282305Sstevel case PCIC_TI_PCI1225:
53292305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1225;
53302305Sstevel break;
53312305Sstevel case PCIC_TI_PCI1410:
53322305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1410;
53332305Sstevel break;
53342305Sstevel case PCIC_TI_PCI1510:
53352305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1510;
53362305Sstevel break;
53372305Sstevel case PCIC_TI_PCI1520:
53382305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1520;
53392305Sstevel break;
53402305Sstevel case PCIC_TI_PCI1221:
53412305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1221;
53422305Sstevel break;
53432305Sstevel case PCIC_TI_PCI1050:
53442305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1050;
53452305Sstevel break;
53462305Sstevel case PCIC_ENE_1410:
53472305Sstevel pcic->pc_chipname = PCIC_TYPE_1410;
53482305Sstevel break;
53492305Sstevel case PCIC_O2_OZ6912:
53502305Sstevel pcic->pc_chipname = PCIC_TYPE_OZ6912;
53512305Sstevel break;
53522305Sstevel case PCIC_RICOH_RL5C466:
53532305Sstevel pcic->pc_chipname = PCIC_TYPE_RL5C466;
53542305Sstevel break;
53552305Sstevel case PCIC_TI_PCI1420:
53562305Sstevel pcic->pc_chipname = PCIC_TYPE_PCI1420;
53572305Sstevel break;
53582305Sstevel case PCIC_ENE_1420:
53592305Sstevel pcic->pc_chipname = PCIC_TYPE_1420;
53602305Sstevel break;
53612305Sstevel default:
53622305Sstevel switch (PCI_ID(vend, (uint32_t)0)) {
53632305Sstevel case PCIC_TOSHIBA_VENDOR:
53642305Sstevel pcic->pc_chipname = PCIC_TYPE_TOSHIBA;
53652305Sstevel pcic->pc_type = PCIC_TOSHIBA_VENDOR;
53662305Sstevel break;
53672305Sstevel case PCIC_TI_VENDOR:
53682305Sstevel pcic->pc_chipname = PCIC_TYPE_TI;
53692305Sstevel pcic->pc_type = PCIC_TI_VENDOR;
53702305Sstevel break;
53712305Sstevel case PCIC_O2MICRO_VENDOR:
53722305Sstevel pcic->pc_chipname = PCIC_TYPE_O2MICRO;
53732305Sstevel pcic->pc_type = PCIC_O2MICRO_VENDOR;
53742305Sstevel break;
53752305Sstevel case PCIC_RICOH_VENDOR:
53762305Sstevel pcic->pc_chipname = PCIC_TYPE_RICOH;
53772305Sstevel pcic->pc_type = PCIC_RICOH_VENDOR;
53782305Sstevel break;
53792305Sstevel default:
53802305Sstevel if (!(pcic->pc_flags & PCF_CARDBUS))
53812305Sstevel return (DDI_FAILURE);
53822305Sstevel pcic->pc_chipname = PCIC_TYPE_YENTA;
53832305Sstevel break;
53842305Sstevel }
53852305Sstevel }
53862305Sstevel return (DDI_SUCCESS);
53872305Sstevel }
53882305Sstevel
53892305Sstevel static void
pcic_82092_smiirq_ctl(pcicdev_t * pcic,int socket,int intr,int state)53902305Sstevel pcic_82092_smiirq_ctl(pcicdev_t *pcic, int socket, int intr, int state)
53912305Sstevel {
53922305Sstevel uchar_t ppirr = ddi_get8(pcic->cfg_handle,
53937656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_82092_PPIRR);
53942305Sstevel uchar_t val;
53952305Sstevel
53962305Sstevel if (intr == PCIC_82092_CTL_SMI) {
53972305Sstevel val = PCIC_82092_SMI_CTL(socket,
53987656SSherry.Moore@Sun.COM PCIC_82092_INT_DISABLE);
53992305Sstevel ppirr &= ~val;
54002305Sstevel val = PCIC_82092_SMI_CTL(socket, state);
54012305Sstevel ppirr |= val;
54022305Sstevel } else {
54032305Sstevel val = PCIC_82092_IRQ_CTL(socket,
54047656SSherry.Moore@Sun.COM PCIC_82092_INT_DISABLE);
54052305Sstevel ppirr &= ~val;
54062305Sstevel val = PCIC_82092_IRQ_CTL(socket, state);
54072305Sstevel ppirr |= val;
54082305Sstevel }
54092305Sstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_82092_PPIRR,
54107656SSherry.Moore@Sun.COM ppirr);
54112305Sstevel }
54122305Sstevel
54132305Sstevel static uint_t
pcic_cd_softint(caddr_t arg1,caddr_t arg2)54142305Sstevel pcic_cd_softint(caddr_t arg1, caddr_t arg2)
54152305Sstevel {
54162305Sstevel pcic_socket_t *sockp = (pcic_socket_t *)arg1;
54172305Sstevel uint_t rc = DDI_INTR_UNCLAIMED;
54182305Sstevel
54192305Sstevel _NOTE(ARGUNUSED(arg2))
54202305Sstevel
54212305Sstevel mutex_enter(&sockp->pcs_pcic->pc_lock);
54222305Sstevel if (sockp->pcs_cd_softint_flg) {
54232305Sstevel uint8_t status;
54242305Sstevel sockp->pcs_cd_softint_flg = 0;
54252305Sstevel rc = DDI_INTR_CLAIMED;
54262305Sstevel status = pcic_getb(sockp->pcs_pcic, sockp->pcs_socket,
54277656SSherry.Moore@Sun.COM PCIC_INTERFACE_STATUS);
54282305Sstevel pcic_handle_cd_change(sockp->pcs_pcic, sockp, status);
54292305Sstevel }
54302305Sstevel mutex_exit(&sockp->pcs_pcic->pc_lock);
54312305Sstevel return (rc);
54322305Sstevel }
54332305Sstevel
54342305Sstevel int pcic_debounce_cnt = PCIC_REM_DEBOUNCE_CNT;
54352305Sstevel int pcic_debounce_intr_time = PCIC_REM_DEBOUNCE_TIME;
54362305Sstevel int pcic_debounce_cnt_ok = PCIC_DEBOUNCE_OK_CNT;
54372305Sstevel
54382305Sstevel #ifdef CARDBUS
54392305Sstevel static uint32_t pcic_cbps_on = 0;
54402305Sstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK |
54412305Sstevel CB_PS_XVCARD | CB_PS_YVCARD;
54422305Sstevel #else
54432305Sstevel static uint32_t pcic_cbps_on = CB_PS_16BITCARD;
54442305Sstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK |
54452305Sstevel CB_PS_CBCARD |
54462305Sstevel CB_PS_XVCARD | CB_PS_YVCARD;
54472305Sstevel #endif
54482305Sstevel static void
pcic_handle_cd_change(pcicdev_t * pcic,pcic_socket_t * sockp,uint8_t status)54492305Sstevel pcic_handle_cd_change(pcicdev_t *pcic, pcic_socket_t *sockp, uint8_t status)
54502305Sstevel {
54512305Sstevel boolean_t do_debounce = B_FALSE;
54522305Sstevel int debounce_time = drv_usectohz(pcic_debounce_time);
54532305Sstevel uint8_t irq;
54542305Sstevel timeout_id_t debounce;
54552305Sstevel
54562305Sstevel /*
54572305Sstevel * Always reset debounce but may need to check original state later.
54582305Sstevel */
54592305Sstevel debounce = sockp->pcs_debounce_id;
54602305Sstevel sockp->pcs_debounce_id = 0;
54612305Sstevel
54622305Sstevel /*
54632305Sstevel * Check to see whether a card is present or not. There are
54642305Sstevel * only two states that we are concerned with - the state
54652305Sstevel * where both CD pins are asserted, which means that the
54662305Sstevel * card is fully seated, and the state where neither CD
54672305Sstevel * pin is asserted, which means that the card is not
54682305Sstevel * present.
54692305Sstevel * The CD signals are generally very noisy and cause a lot of
54702305Sstevel * contact bounce as the card is being inserted and
54712305Sstevel * removed, so we need to do some software debouncing.
54722305Sstevel */
54732305Sstevel
54742305Sstevel #ifdef PCIC_DEBUG
54757656SSherry.Moore@Sun.COM pcic_err(pcic->dip, 6,
54762305Sstevel "pcic%d handle_cd_change: socket %d card status 0x%x"
54772305Sstevel " deb 0x%p\n", ddi_get_instance(pcic->dip),
54782305Sstevel sockp->pcs_socket, status, debounce);
54792305Sstevel #endif
54802305Sstevel switch (status & PCIC_ISTAT_CD_MASK) {
54812305Sstevel case PCIC_CD_PRESENT_OK:
54827656SSherry.Moore@Sun.COM sockp->pcs_flags &= ~(PCS_CARD_REMOVED|PCS_CARD_CBREM);
54837656SSherry.Moore@Sun.COM if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) {
54842305Sstevel uint32_t cbps;
54852305Sstevel #ifdef PCIC_DEBUG
54862305Sstevel pcic_err(pcic->dip, 8, "New card (0x%x)\n", sockp->pcs_flags);
54872305Sstevel #endif
54882305Sstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
54892305Sstevel #ifdef PCIC_DEBUG
54902305Sstevel pcic_err(pcic->dip, 8, "CBus PS (0x%x)\n", cbps);
54912305Sstevel #endif
54922305Sstevel /*
54932305Sstevel * Check the CB bits are sane.
54942305Sstevel */
54952305Sstevel if ((cbps & pcic_cbps_on) != pcic_cbps_on ||
54962305Sstevel cbps & pcic_cbps_off) {
54977656SSherry.Moore@Sun.COM cmn_err(CE_WARN,
54982305Sstevel "%s%d: Odd Cardbus Present State 0x%x\n",
54992305Sstevel ddi_get_name(pcic->dip),
55002305Sstevel ddi_get_instance(pcic->dip),
55012305Sstevel cbps);
55027656SSherry.Moore@Sun.COM pcic_putcb(pcic, CB_EVENT_FORCE, CB_EF_CVTEST);
55037656SSherry.Moore@Sun.COM debounce = 0;
55047656SSherry.Moore@Sun.COM debounce_time = drv_usectohz(1000000);
55052305Sstevel }
55062305Sstevel if (debounce) {
55077656SSherry.Moore@Sun.COM sockp->pcs_flags |= PCS_CARD_PRESENT;
55087656SSherry.Moore@Sun.COM if (pcic_do_insertion) {
55097656SSherry.Moore@Sun.COM
55107656SSherry.Moore@Sun.COM cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
55117656SSherry.Moore@Sun.COM
55127656SSherry.Moore@Sun.COM if (cbps & CB_PS_16BITCARD) {
55137656SSherry.Moore@Sun.COM pcic_err(pcic->dip,
55147656SSherry.Moore@Sun.COM 8, "16 bit card inserted\n");
55157656SSherry.Moore@Sun.COM sockp->pcs_flags |= PCS_CARD_IS16BIT;
55167656SSherry.Moore@Sun.COM /* calls pcm_adapter_callback() */
55177656SSherry.Moore@Sun.COM if (pcic->pc_callback) {
55187656SSherry.Moore@Sun.COM
55197656SSherry.Moore@Sun.COM (void) ddi_prop_update_string(
55207656SSherry.Moore@Sun.COM DDI_DEV_T_NONE,
55217656SSherry.Moore@Sun.COM pcic->dip, PCM_DEVICETYPE,
55227656SSherry.Moore@Sun.COM "pccard");
55237656SSherry.Moore@Sun.COM PC_CALLBACK(pcic->dip,
55247656SSherry.Moore@Sun.COM pcic->pc_cb_arg,
55257656SSherry.Moore@Sun.COM PCE_CARD_INSERT,
55267656SSherry.Moore@Sun.COM sockp->pcs_socket);
55277656SSherry.Moore@Sun.COM }
55287656SSherry.Moore@Sun.COM } else if (cbps & CB_PS_CBCARD) {
55297656SSherry.Moore@Sun.COM pcic_err(pcic->dip,
55307656SSherry.Moore@Sun.COM 8, "32 bit card inserted\n");
55317656SSherry.Moore@Sun.COM
55327656SSherry.Moore@Sun.COM if (pcic->pc_flags & PCF_CARDBUS) {
55337656SSherry.Moore@Sun.COM sockp->pcs_flags |=
55347656SSherry.Moore@Sun.COM PCS_CARD_ISCARDBUS;
55352305Sstevel #ifdef CARDBUS
55367656SSherry.Moore@Sun.COM if (!pcic_load_cardbus(pcic,
55377656SSherry.Moore@Sun.COM sockp)) {
55387656SSherry.Moore@Sun.COM pcic_unload_cardbus(
55397656SSherry.Moore@Sun.COM pcic, sockp);
55407656SSherry.Moore@Sun.COM }
55412305Sstevel
55422305Sstevel #else
55437656SSherry.Moore@Sun.COM cmn_err(CE_NOTE,
55447656SSherry.Moore@Sun.COM "32 bit Cardbus not"
55457656SSherry.Moore@Sun.COM " supported in"
55467656SSherry.Moore@Sun.COM " this device driver\n");
55472305Sstevel #endif
55487656SSherry.Moore@Sun.COM } else {
55497656SSherry.Moore@Sun.COM /*
55507656SSherry.Moore@Sun.COM * Ignore the card
55517656SSherry.Moore@Sun.COM */
55527656SSherry.Moore@Sun.COM cmn_err(CE_NOTE,
55537656SSherry.Moore@Sun.COM "32 bit Cardbus not"
55547656SSherry.Moore@Sun.COM " supported on this"
55557656SSherry.Moore@Sun.COM " device\n");
55567656SSherry.Moore@Sun.COM }
55577656SSherry.Moore@Sun.COM } else {
55587656SSherry.Moore@Sun.COM cmn_err(CE_NOTE,
55597656SSherry.Moore@Sun.COM "Unsupported PCMCIA card"
55607656SSherry.Moore@Sun.COM " inserted\n");
55617656SSherry.Moore@Sun.COM }
55622305Sstevel }
55632305Sstevel } else {
55647656SSherry.Moore@Sun.COM do_debounce = B_TRUE;
55652305Sstevel }
55667656SSherry.Moore@Sun.COM } else {
55672305Sstevel /*
55682305Sstevel * It is possible to come through here if the system
55692305Sstevel * starts up with cards already inserted. Do nothing
55702305Sstevel * and don't worry about it.
55712305Sstevel */
55722305Sstevel #ifdef PCIC_DEBUG
55732305Sstevel pcic_err(pcic->dip, 5,
55747656SSherry.Moore@Sun.COM "pcic%d: Odd card insertion indication on socket %d\n",
55757656SSherry.Moore@Sun.COM ddi_get_instance(pcic->dip),
55767656SSherry.Moore@Sun.COM sockp->pcs_socket);
55772305Sstevel #endif
55787656SSherry.Moore@Sun.COM }
55797656SSherry.Moore@Sun.COM break;
55802305Sstevel
55812305Sstevel default:
55827656SSherry.Moore@Sun.COM if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) {
55832305Sstevel /*
55842305Sstevel * Someone has started to insert a card so delay a while.
55852305Sstevel */
55862305Sstevel do_debounce = B_TRUE;
55872305Sstevel break;
55887656SSherry.Moore@Sun.COM }
55892305Sstevel /*
55902305Sstevel * Otherwise this is basically the same as not present
55912305Sstevel * so fall through.
55922305Sstevel */
55932305Sstevel
55942305Sstevel /* FALLTHRU */
55952305Sstevel case 0:
55967656SSherry.Moore@Sun.COM if (sockp->pcs_flags & PCS_CARD_PRESENT) {
55977656SSherry.Moore@Sun.COM if (pcic->pc_flags & PCF_CBPWRCTL) {
55987656SSherry.Moore@Sun.COM pcic_putcb(pcic, CB_CONTROL, 0);
55997656SSherry.Moore@Sun.COM } else {
56007656SSherry.Moore@Sun.COM pcic_putb(pcic, sockp->pcs_socket,
56017656SSherry.Moore@Sun.COM PCIC_POWER_CONTROL, 0);
56027656SSherry.Moore@Sun.COM (void) pcic_getb(pcic, sockp->pcs_socket,
56037656SSherry.Moore@Sun.COM PCIC_POWER_CONTROL);
56042305Sstevel }
56052305Sstevel #ifdef PCIC_DEBUG
56062305Sstevel pcic_err(pcic->dip, 8, "Card removed\n");
56072305Sstevel #endif
56082305Sstevel sockp->pcs_flags &= ~PCS_CARD_PRESENT;
56092305Sstevel
56102305Sstevel if (sockp->pcs_flags & PCS_CARD_IS16BIT) {
56117656SSherry.Moore@Sun.COM sockp->pcs_flags &= ~PCS_CARD_IS16BIT;
56127656SSherry.Moore@Sun.COM if (pcic_do_removal && pcic->pc_callback) {
56137656SSherry.Moore@Sun.COM PC_CALLBACK(pcic->dip, pcic->pc_cb_arg,
56142305Sstevel PCE_CARD_REMOVAL, sockp->pcs_socket);
56157656SSherry.Moore@Sun.COM }
56162305Sstevel }
56172305Sstevel if (sockp->pcs_flags & PCS_CARD_ISCARDBUS) {
56187656SSherry.Moore@Sun.COM sockp->pcs_flags &= ~PCS_CARD_ISCARDBUS;
56197656SSherry.Moore@Sun.COM sockp->pcs_flags |= PCS_CARD_CBREM;
56202305Sstevel }
56212305Sstevel sockp->pcs_flags |= PCS_CARD_REMOVED;
56222305Sstevel
56232305Sstevel do_debounce = B_TRUE;
56247656SSherry.Moore@Sun.COM }
56257656SSherry.Moore@Sun.COM if (debounce && (sockp->pcs_flags & PCS_CARD_REMOVED)) {
56267656SSherry.Moore@Sun.COM if (sockp->pcs_flags & PCS_CARD_CBREM) {
56272305Sstevel /*
56282305Sstevel * Ensure that we do the unloading in the
56292305Sstevel * debounce handler, that way we're not doing
56302305Sstevel * nasty things in an interrupt handler. e.g.
56312305Sstevel * a USB device will wait for data which will
56322305Sstevel * obviously never come because we've
56332305Sstevel * unplugged the device, but the wait will
56342305Sstevel * wait forever because no interrupts can
56352305Sstevel * come in...
56362305Sstevel */
56372305Sstevel #ifdef CARDBUS
56387656SSherry.Moore@Sun.COM pcic_unload_cardbus(pcic, sockp);
56397656SSherry.Moore@Sun.COM /* pcic_dump_all(pcic); */
56402305Sstevel #endif
56417656SSherry.Moore@Sun.COM sockp->pcs_flags &= ~PCS_CARD_CBREM;
56427656SSherry.Moore@Sun.COM }
56437656SSherry.Moore@Sun.COM sockp->pcs_flags &= ~PCS_CARD_REMOVED;
56442305Sstevel }
56457656SSherry.Moore@Sun.COM break;
56462305Sstevel } /* switch */
56472305Sstevel
56482305Sstevel if (do_debounce) {
56492305Sstevel /*
56502305Sstevel * Delay doing
56512305Sstevel * anything for a while so that things can settle
56522305Sstevel * down a little. Interrupts are already disabled.
56532305Sstevel * Reset the state and we'll reevaluate the
56542305Sstevel * whole kit 'n kaboodle when the timeout fires
56552305Sstevel */
56562305Sstevel #ifdef PCIC_DEBUG
56572305Sstevel pcic_err(pcic->dip, 8, "Queueing up debounce timeout for "
56587656SSherry.Moore@Sun.COM "socket %d.%d\n",
56597656SSherry.Moore@Sun.COM ddi_get_instance(pcic->dip),
56607656SSherry.Moore@Sun.COM sockp->pcs_socket);
56612305Sstevel #endif
56627656SSherry.Moore@Sun.COM sockp->pcs_debounce_id =
56637656SSherry.Moore@Sun.COM pcic_add_debqueue(sockp, debounce_time);
56642305Sstevel
56652305Sstevel /*
56662305Sstevel * We bug out here without re-enabling interrupts. They will
56672305Sstevel * be re-enabled when the debounce timeout swings through
56682305Sstevel * here.
56692305Sstevel */
56707656SSherry.Moore@Sun.COM return;
56712305Sstevel }
56722305Sstevel
56732305Sstevel /*
56742305Sstevel * Turn on Card detect interrupts. Other interrupts will be
56752305Sstevel * enabled during set_socket calls.
56762305Sstevel *
56772305Sstevel * Note that set_socket only changes interrupt settings when there
56782305Sstevel * is a card present.
56792305Sstevel */
56802305Sstevel irq = pcic_getb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT);
56812305Sstevel irq |= PCIC_CD_DETECT;
56822305Sstevel pcic_putb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT, irq);
56832325Srw148561 pcic_putcb(pcic, CB_STATUS_MASK, CB_SE_CCDMASK);
56842305Sstevel
56852451Srw148561 /* Out from debouncing state */
56862451Srw148561 sockp->pcs_flags &= ~PCS_DEBOUNCING;
56872451Srw148561
56882305Sstevel pcic_err(pcic->dip, 7, "Leaving pcic_handle_cd_change\n");
56892305Sstevel }
56902305Sstevel
56912305Sstevel /*
56922305Sstevel * pcic_getb()
56932305Sstevel * get an I/O byte based on the yardware decode method
56942305Sstevel */
56952305Sstevel static uint8_t
pcic_getb(pcicdev_t * pcic,int socket,int reg)56962305Sstevel pcic_getb(pcicdev_t *pcic, int socket, int reg)
56972305Sstevel {
56982305Sstevel int work;
56992305Sstevel
57002305Sstevel #if defined(PCIC_DEBUG)
57012305Sstevel if (pcic_debug == 0x7fff) {
57022305Sstevel cmn_err(CE_CONT, "pcic_getb0: pcic=%p socket=%d reg=%d\n",
57037656SSherry.Moore@Sun.COM (void *)pcic, socket, reg);
57042305Sstevel cmn_err(CE_CONT, "pcic_getb1: type=%d handle=%p ioaddr=%p \n",
57057656SSherry.Moore@Sun.COM pcic->pc_io_type, (void *)pcic->handle,
57067656SSherry.Moore@Sun.COM (void *)pcic->ioaddr);
57072305Sstevel }
57082305Sstevel #endif
57092305Sstevel
57102305Sstevel switch (pcic->pc_io_type) {
57112305Sstevel case PCIC_IO_TYPE_YENTA:
57122305Sstevel return (ddi_get8(pcic->handle,
57132305Sstevel pcic->ioaddr + CB_R2_OFFSET + reg));
57142305Sstevel default:
57152305Sstevel work = (socket * PCIC_SOCKET_1) | reg;
57162305Sstevel ddi_put8(pcic->handle, pcic->ioaddr, work);
57172305Sstevel return (ddi_get8(pcic->handle, pcic->ioaddr + 1));
57182305Sstevel }
57192305Sstevel }
57202305Sstevel
57212305Sstevel static void
pcic_putb(pcicdev_t * pcic,int socket,int reg,int8_t value)57222305Sstevel pcic_putb(pcicdev_t *pcic, int socket, int reg, int8_t value)
57232305Sstevel {
57242305Sstevel int work;
57252305Sstevel
57262305Sstevel #if defined(PCIC_DEBUG)
57272305Sstevel if (pcic_debug == 0x7fff) {
57282305Sstevel cmn_err(CE_CONT,
57297656SSherry.Moore@Sun.COM "pcic_putb0: pcic=%p socket=%d reg=%d value=%x \n",
57307656SSherry.Moore@Sun.COM (void *)pcic, socket, reg, value);
57312305Sstevel cmn_err(CE_CONT,
57327656SSherry.Moore@Sun.COM "pcic_putb1: type=%d handle=%p ioaddr=%p \n",
57337656SSherry.Moore@Sun.COM pcic->pc_io_type, (void *)pcic->handle,
57347656SSherry.Moore@Sun.COM (void *)pcic->ioaddr);
57352305Sstevel }
57362305Sstevel #endif
57372305Sstevel
57382305Sstevel
57392305Sstevel switch (pcic->pc_io_type) {
57402305Sstevel case PCIC_IO_TYPE_YENTA:
57412305Sstevel ddi_put8(pcic->handle, pcic->ioaddr + CB_R2_OFFSET + reg,
57427656SSherry.Moore@Sun.COM value);
57432305Sstevel break;
57442305Sstevel default:
57452305Sstevel work = (socket * PCIC_SOCKET_1) | reg;
57462305Sstevel ddi_put8(pcic->handle, pcic->ioaddr, work);
57472305Sstevel ddi_put8(pcic->handle, pcic->ioaddr + 1, value);
57482305Sstevel break;
57492305Sstevel }
57502305Sstevel }
57512305Sstevel
57522305Sstevel /*
57532305Sstevel * chip identification functions
57542305Sstevel */
57552305Sstevel
57562305Sstevel /*
57572305Sstevel * chip identification: Cirrus Logic PD6710/6720/6722
57582305Sstevel */
57592305Sstevel static int
pcic_ci_cirrus(pcicdev_t * pcic)57602305Sstevel pcic_ci_cirrus(pcicdev_t *pcic)
57612305Sstevel {
57622305Sstevel int value1, value2;
57632305Sstevel
57642305Sstevel /* Init the CL id mode */
57652305Sstevel value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57662305Sstevel pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0);
57672305Sstevel value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57682305Sstevel value2 = pcic_getb(pcic, 0, PCIC_CHIP_INFO);
57692305Sstevel
57702305Sstevel if ((value1 & PCIC_CI_ID) == PCIC_CI_ID &&
57712305Sstevel (value2 & PCIC_CI_ID) == 0) {
57722305Sstevel /* chip is a Cirrus Logic and not Intel */
57732305Sstevel pcic->pc_type = PCIC_CL_PD6710;
57742305Sstevel if (value1 & PCIC_CI_SLOTS)
57752305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6720;
57762305Sstevel else
57772305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6710;
57782305Sstevel /* now fine tune things just in case a 6722 */
57792305Sstevel value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_DMASK_0);
57802305Sstevel if (value1 == 0) {
57812305Sstevel clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0x55);
57822305Sstevel value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_SCRATCH);
57832305Sstevel if (value1 == 0x55) {
57842305Sstevel pcic->pc_chipname = PCIC_TYPE_PD6722;
57852305Sstevel pcic->pc_type = PCIC_CL_PD6722;
57862305Sstevel clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0);
57872305Sstevel }
57882305Sstevel }
57892305Sstevel return (1);
57902305Sstevel }
57912305Sstevel return (0);
57922305Sstevel }
57932305Sstevel
57942305Sstevel /*
57952305Sstevel * chip identification: Vadem (VG365/465/468/469)
57962305Sstevel */
57972305Sstevel
57982305Sstevel static void
pcic_vadem_enable(pcicdev_t * pcic)57992305Sstevel pcic_vadem_enable(pcicdev_t *pcic)
58002305Sstevel {
58012305Sstevel ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P1);
58022305Sstevel ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P2);
58032305Sstevel ddi_put8(pcic->handle, pcic->ioaddr, pcic->pc_lastreg);
58042305Sstevel }
58052305Sstevel
58062305Sstevel static int
pcic_ci_vadem(pcicdev_t * pcic)58072305Sstevel pcic_ci_vadem(pcicdev_t *pcic)
58082305Sstevel {
58092305Sstevel int value;
58102305Sstevel
58112305Sstevel pcic_vadem_enable(pcic);
58122305Sstevel value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION);
58132305Sstevel pcic_putb(pcic, 0, PCIC_CHIP_REVISION, 0xFF);
58142305Sstevel if (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) ==
58152305Sstevel (value | PCIC_VADEM_D3) ||
58162305Sstevel (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) & PCIC_REV_MASK) ==
58172305Sstevel PCIC_VADEM_469) {
58182305Sstevel int vadem, new;
58192305Sstevel pcic_vadem_enable(pcic);
58202305Sstevel vadem = pcic_getb(pcic, 0, PCIC_VG_DMA) &
58217656SSherry.Moore@Sun.COM ~(PCIC_V_UNLOCK | PCIC_V_VADEMREV);
58222305Sstevel new = vadem | (PCIC_V_VADEMREV|PCIC_V_UNLOCK);
58232305Sstevel pcic_putb(pcic, 0, PCIC_VG_DMA, new);
58242305Sstevel value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION);
58252305Sstevel
58262305Sstevel /* want to lock but leave mouse or other on */
58272305Sstevel pcic_putb(pcic, 0, PCIC_VG_DMA, vadem);
58282305Sstevel switch (value & PCIC_REV_MASK) {
58292305Sstevel case PCIC_VADEM_365:
58302305Sstevel pcic->pc_chipname = PCIC_VG_365;
58312305Sstevel pcic->pc_type = PCIC_VADEM;
58322305Sstevel break;
58332305Sstevel case PCIC_VADEM_465:
58342305Sstevel pcic->pc_chipname = PCIC_VG_465;
58352305Sstevel pcic->pc_type = PCIC_VADEM;
58362305Sstevel pcic->pc_flags |= PCF_1SOCKET;
58372305Sstevel break;
58382305Sstevel case PCIC_VADEM_468:
58392305Sstevel pcic->pc_chipname = PCIC_VG_468;
58402305Sstevel pcic->pc_type = PCIC_VADEM;
58412305Sstevel break;
58422305Sstevel case PCIC_VADEM_469:
58432305Sstevel pcic->pc_chipname = PCIC_VG_469;
58442305Sstevel pcic->pc_type = PCIC_VADEM_VG469;
58452305Sstevel break;
58462305Sstevel }
58472305Sstevel return (1);
58482305Sstevel }
58492305Sstevel return (0);
58502305Sstevel }
58512305Sstevel
58522305Sstevel /*
58532305Sstevel * chip identification: Ricoh
58542305Sstevel */
58552305Sstevel static int
pcic_ci_ricoh(pcicdev_t * pcic)58562305Sstevel pcic_ci_ricoh(pcicdev_t *pcic)
58572305Sstevel {
58582305Sstevel int value;
58592305Sstevel
58602305Sstevel value = pcic_getb(pcic, 0, PCIC_RF_CHIP_IDENT);
58612305Sstevel switch (value) {
58622305Sstevel case PCIC_RF_296:
58632305Sstevel pcic->pc_type = PCIC_RICOH;
58642305Sstevel pcic->pc_chipname = PCIC_TYPE_RF5C296;
58652305Sstevel return (1);
58662305Sstevel case PCIC_RF_396:
58672305Sstevel pcic->pc_type = PCIC_RICOH;
58682305Sstevel pcic->pc_chipname = PCIC_TYPE_RF5C396;
58692305Sstevel return (1);
58702305Sstevel }
58712305Sstevel return (0);
58722305Sstevel }
58732305Sstevel
58742305Sstevel
58752305Sstevel /*
58762305Sstevel * set up available address spaces in busra
58772305Sstevel */
58782305Sstevel static void
pcic_init_assigned(dev_info_t * dip)58792305Sstevel pcic_init_assigned(dev_info_t *dip)
58802305Sstevel {
58812305Sstevel pcm_regs_t *pcic_avail_p;
58822305Sstevel pci_regspec_t *pci_avail_p, *regs;
58832305Sstevel int len, entries, rlen;
58842305Sstevel dev_info_t *pdip;
58852305Sstevel
58862305Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
58872305Sstevel "available", (caddr_t)&pcic_avail_p, &len) == DDI_PROP_SUCCESS) {
58882305Sstevel /*
58892305Sstevel * found "available" property at the cardbus/pcmcia node
58902305Sstevel * need to translate address space entries from pcmcia
58912305Sstevel * format to pci format
58922305Sstevel */
58932305Sstevel entries = len / sizeof (pcm_regs_t);
58942305Sstevel pci_avail_p = kmem_alloc(sizeof (pci_regspec_t) * entries,
58957656SSherry.Moore@Sun.COM KM_SLEEP);
58962305Sstevel if (pcic_apply_avail_ranges(dip, pcic_avail_p, pci_avail_p,
58972305Sstevel entries) == DDI_SUCCESS)
58982305Sstevel (void) pci_resource_setup_avail(dip, pci_avail_p,
58997656SSherry.Moore@Sun.COM entries);
59002305Sstevel kmem_free(pcic_avail_p, len);
59012305Sstevel kmem_free(pci_avail_p, entries * sizeof (pci_regspec_t));
59022305Sstevel return;
59032305Sstevel }
59042305Sstevel
59052305Sstevel /*
59062305Sstevel * "legacy" platforms will have "available" property in pci node
59072305Sstevel */
59082305Sstevel for (pdip = ddi_get_parent(dip); pdip; pdip = ddi_get_parent(pdip)) {
59092305Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
59102305Sstevel "available", (caddr_t)&pci_avail_p, &len) ==
59112305Sstevel DDI_PROP_SUCCESS) {
59122305Sstevel /* (void) pci_resource_setup(pdip); */
59132305Sstevel kmem_free(pci_avail_p, len);
59142305Sstevel break;
59152305Sstevel }
59162305Sstevel }
59172305Sstevel
59182305Sstevel if (pdip == NULL) {
59192305Sstevel int len;
59202305Sstevel char bus_type[16] = "(unknown)";
59212305Sstevel dev_info_t *par;
59222305Sstevel
59232305Sstevel cmn_err(CE_CONT,
59242305Sstevel "?pcic_init_assigned: no available property for pcmcia\n");
59252305Sstevel
59262305Sstevel /*
59272305Sstevel * This code is taken from pci_resource_setup() but does
59282305Sstevel * not attempt to use the "available" property to populate
59292305Sstevel * the ndi maps that are created.
59302305Sstevel * The fact that we will actually
59312305Sstevel * free some resource below (that was allocated by OBP)
59322305Sstevel * should be enough to be going on with.
59332305Sstevel */
59342305Sstevel for (par = dip; par != NULL; par = ddi_get_parent(par)) {
59352305Sstevel len = sizeof (bus_type);
59362305Sstevel
59372305Sstevel if ((ddi_prop_op(DDI_DEV_T_ANY, par,
59382305Sstevel PROP_LEN_AND_VAL_BUF,
59392305Sstevel DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
59402305Sstevel "device_type",
59412305Sstevel (caddr_t)&bus_type, &len) == DDI_SUCCESS) &&
59423664Srw148561 (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 ||
59437656SSherry.Moore@Sun.COM strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0))
59442305Sstevel break;
59452305Sstevel }
59462305Sstevel if (par != NULL &&
59472305Sstevel (ndi_ra_map_setup(par, NDI_RA_TYPE_MEM) != NDI_SUCCESS ||
59482305Sstevel ndi_ra_map_setup(par, NDI_RA_TYPE_IO) != NDI_SUCCESS))
59492305Sstevel par = NULL;
59502305Sstevel } else {
59512305Sstevel #ifdef CARDBUS
59522305Sstevel cardbus_bus_range_t *bus_range;
59532305Sstevel int k;
59542305Sstevel
59552305Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "bus-range",
59562305Sstevel (caddr_t)&bus_range, &k) == DDI_PROP_SUCCESS) {
59572305Sstevel if (bus_range->lo != bus_range->hi)
59582305Sstevel pcic_err(pdip, 9, "allowable bus range is "
59592305Sstevel "%u->%u\n", bus_range->lo, bus_range->hi);
59602305Sstevel else {
59612305Sstevel pcic_err(pdip, 0,
59622305Sstevel "!No spare PCI bus numbers, range is "
59632305Sstevel "%u->%u, cardbus isn't usable\n",
59642305Sstevel bus_range->lo, bus_range->hi);
59652305Sstevel }
59662305Sstevel kmem_free(bus_range, k);
59672305Sstevel } else
59682305Sstevel pcic_err(pdip, 0, "!No bus-range property seems to "
59692305Sstevel "have been set up\n");
59702305Sstevel #endif
59712305Sstevel /*
59722305Sstevel * Have a valid parent with the "available" property
59732305Sstevel */
59742305Sstevel (void) pci_resource_setup(pdip);
59752305Sstevel }
59762305Sstevel
59772305Sstevel if ((strcmp(ddi_get_name(dip), "pcma") == 0) &&
59782305Sstevel ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
59792305Sstevel "assigned-addresses",
59802305Sstevel (caddr_t)®s, &rlen) == DDI_SUCCESS) {
59812305Sstevel ra_return_t ra;
59822305Sstevel
59832305Sstevel /*
59842305Sstevel * On the UltraBook IIi the ranges are assigned under
59852305Sstevel * openboot. If we don't free them here the first I/O
59862305Sstevel * space that can be used is up above 0x10000 which
59872305Sstevel * doesn't work for this driver due to restrictions
59882305Sstevel * on the PCI I/O addresses the controllers can cope with.
59892305Sstevel * They are never going to be used by anything else
59902305Sstevel * so free them up to the general pool. AG.
59912305Sstevel */
59922305Sstevel pcic_err(dip, 1, "Free assigned addresses\n");
59932305Sstevel
59942305Sstevel if ((PCI_REG_ADDR_G(regs[0].pci_phys_hi) ==
59952305Sstevel PCI_REG_ADDR_G(PCI_ADDR_MEM32)) &&
59962305Sstevel regs[0].pci_size_low == 0x1000000) {
59972305Sstevel ra.ra_addr_lo = regs[0].pci_phys_low;
59982305Sstevel ra.ra_len = regs[0].pci_size_low;
59992305Sstevel (void) pcmcia_free_mem(dip, &ra);
60002305Sstevel }
60012305Sstevel if ((PCI_REG_ADDR_G(regs[1].pci_phys_hi) ==
60022305Sstevel PCI_REG_ADDR_G(PCI_ADDR_IO)) &&
60032305Sstevel (regs[1].pci_size_low == 0x8000 ||
60042305Sstevel regs[1].pci_size_low == 0x4000)) /* UB-IIi || UB-I */
60052305Sstevel {
60062305Sstevel ra.ra_addr_lo = regs[1].pci_phys_low;
60072305Sstevel ra.ra_len = regs[1].pci_size_low;
60082305Sstevel (void) pcmcia_free_io(dip, &ra);
60092305Sstevel }
60102305Sstevel kmem_free((caddr_t)regs, rlen);
60112305Sstevel }
60122305Sstevel }
60132305Sstevel
60142305Sstevel /*
60152305Sstevel * translate "available" from pcmcia format to pci format
60162305Sstevel */
60172305Sstevel static int
pcic_apply_avail_ranges(dev_info_t * dip,pcm_regs_t * pcic_p,pci_regspec_t * pci_p,int entries)60182305Sstevel pcic_apply_avail_ranges(dev_info_t *dip, pcm_regs_t *pcic_p,
60192305Sstevel pci_regspec_t *pci_p, int entries)
60202305Sstevel {
60212305Sstevel int i, range_len, range_entries;
60222305Sstevel pcic_ranges_t *pcic_range_p;
60232305Sstevel
60242305Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
60257656SSherry.Moore@Sun.COM (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) {
60262305Sstevel cmn_err(CE_CONT, "?pcic_apply_avail_ranges: "
60277656SSherry.Moore@Sun.COM "no ranges property for pcmcia\n");
60282305Sstevel return (DDI_FAILURE);
60292305Sstevel }
60302305Sstevel
60312305Sstevel range_entries = range_len / sizeof (pcic_ranges_t);
60322305Sstevel
60332305Sstevel /* for each "available" entry to be translated */
60342305Sstevel for (i = 0; i < entries; i++, pcic_p++, pci_p++) {
60352305Sstevel int j;
60362305Sstevel pcic_ranges_t *range_p = pcic_range_p;
60372305Sstevel pci_p->pci_phys_hi = -1u; /* default invalid value */
60382305Sstevel
60392305Sstevel /* for each "ranges" entry to be searched */
60402305Sstevel for (j = 0; j < range_entries; j++, range_p++) {
60412305Sstevel uint64_t range_end = range_p->pcic_range_caddrlo +
60427656SSherry.Moore@Sun.COM range_p->pcic_range_size;
60432305Sstevel uint64_t avail_end = pcic_p->phys_lo + pcic_p->phys_len;
60442305Sstevel
60452305Sstevel if ((range_p->pcic_range_caddrhi != pcic_p->phys_hi) ||
60462305Sstevel (range_p->pcic_range_caddrlo > pcic_p->phys_lo) ||
60472305Sstevel (range_end < avail_end))
60482305Sstevel continue;
60492305Sstevel
60502305Sstevel pci_p->pci_phys_hi = range_p->pcic_range_paddrhi;
60512305Sstevel pci_p->pci_phys_mid = range_p->pcic_range_paddrmid;
60522305Sstevel pci_p->pci_phys_low = range_p->pcic_range_paddrlo
60532305Sstevel + (pcic_p->phys_lo - range_p->pcic_range_caddrlo);
60542305Sstevel pci_p->pci_size_hi = 0;
60552305Sstevel pci_p->pci_size_low = pcic_p->phys_len;
60562305Sstevel }
60572305Sstevel }
60582305Sstevel kmem_free(pcic_range_p, range_len);
60592305Sstevel return (DDI_SUCCESS);
60602305Sstevel }
60612305Sstevel
60622305Sstevel static int
pcic_open(dev_t * dev,int flag,int otyp,cred_t * cred)60632305Sstevel pcic_open(dev_t *dev, int flag, int otyp, cred_t *cred)
60642305Sstevel {
60652305Sstevel #ifdef CARDBUS
60662305Sstevel if (cardbus_is_cb_minor(*dev))
60672305Sstevel return (cardbus_open(dev, flag, otyp, cred));
60682305Sstevel #endif
60692305Sstevel return (EINVAL);
60702305Sstevel }
60712305Sstevel
60722305Sstevel static int
pcic_close(dev_t dev,int flag,int otyp,cred_t * cred)60732305Sstevel pcic_close(dev_t dev, int flag, int otyp, cred_t *cred)
60742305Sstevel {
60752305Sstevel #ifdef CARDBUS
60762305Sstevel if (cardbus_is_cb_minor(dev))
60772305Sstevel return (cardbus_close(dev, flag, otyp, cred));
60782305Sstevel #endif
60792305Sstevel return (EINVAL);
60802305Sstevel }
60812305Sstevel
60822305Sstevel static int
pcic_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred,int * rval)60832305Sstevel pcic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred,
60842305Sstevel int *rval)
60852305Sstevel {
60862305Sstevel #ifdef CARDBUS
60872305Sstevel if (cardbus_is_cb_minor(dev))
60882305Sstevel return (cardbus_ioctl(dev, cmd, arg, mode, cred, rval));
60892305Sstevel #endif
60902305Sstevel return (EINVAL);
60912305Sstevel }
60922305Sstevel
60932305Sstevel
60942305Sstevel static boolean_t
pcic_load_cardbus(pcicdev_t * pcic,const pcic_socket_t * sockp)60952305Sstevel pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp)
60962305Sstevel {
60972305Sstevel uint32_t present_state;
60982305Sstevel dev_info_t *dip = pcic->dip;
60992305Sstevel set_socket_t s;
61002305Sstevel get_socket_t g;
61012305Sstevel boolean_t retval;
61022305Sstevel unsigned vccLevel;
61032305Sstevel
61042305Sstevel pcic_err(dip, 8, "entering pcic_load_cardbus\n");
61052305Sstevel
61062305Sstevel pcic_mutex_exit(&pcic->pc_lock);
61072305Sstevel
61082305Sstevel bzero(&s, sizeof (set_socket_t));
61092305Sstevel s.socket = sockp->pcs_socket;
61102305Sstevel s.SCIntMask = SBM_CD|SBM_RDYBSY;
61112305Sstevel s.IFType = IF_CARDBUS;
61122305Sstevel s.State = (unsigned)~0;
61132305Sstevel
61142305Sstevel present_state = pcic_getcb(pcic, CB_PRESENT_STATE);
61152305Sstevel if (present_state & PCIC_VCC_3VCARD)
61162305Sstevel s.VccLevel = PCIC_VCC_3VLEVEL;
61172305Sstevel else if (present_state & PCIC_VCC_5VCARD)
61182305Sstevel s.VccLevel = PCIC_VCC_5VLEVEL;
61192305Sstevel else {
61202305Sstevel cmn_err(CE_CONT,
61212305Sstevel "pcic_load_cardbus: unsupported card voltage\n");
61222305Sstevel goto failure;
61232305Sstevel }
61242305Sstevel vccLevel = s.VccLevel;
61252305Sstevel s.Vpp1Level = s.Vpp2Level = 0;
61262305Sstevel
61272305Sstevel if (pcic_set_socket(dip, &s) != SUCCESS)
61282305Sstevel goto failure;
61292305Sstevel
61302305Sstevel if (pcic_reset_socket(dip, sockp->pcs_socket,
61312305Sstevel RESET_MODE_CARD_ONLY) != SUCCESS)
61322305Sstevel goto failure;
61332305Sstevel
61342305Sstevel bzero(&g, sizeof (get_socket_t));
61352305Sstevel g.socket = sockp->pcs_socket;
61362305Sstevel if (pcic_get_socket(dip, &g) != SUCCESS)
61372305Sstevel goto failure;
61382305Sstevel
61392305Sstevel bzero(&s, sizeof (set_socket_t));
61402305Sstevel s.socket = sockp->pcs_socket;
61412305Sstevel s.SCIntMask = SBM_CD;
61422305Sstevel s.IREQRouting = g.IRQRouting;
61432305Sstevel s.IFType = g.IFType;
61442305Sstevel s.CtlInd = g.CtlInd;
61452305Sstevel s.State = (unsigned)~0;
61462305Sstevel s.VccLevel = vccLevel;
61472305Sstevel s.Vpp1Level = s.Vpp2Level = 0;
61482305Sstevel
61497151Srw148561 retval = pcic_set_socket(dip, &s);
61507151Srw148561 pcmcia_cb_resumed(s.socket);
61517151Srw148561 if (retval != SUCCESS)
61522305Sstevel goto failure;
61532305Sstevel
61542305Sstevel retval = cardbus_load_cardbus(dip, sockp->pcs_socket, pcic->pc_base);
61552305Sstevel goto exit;
61562305Sstevel
61572305Sstevel failure:
61582305Sstevel retval = B_FALSE;
61592305Sstevel
61602305Sstevel exit:
61612305Sstevel pcic_mutex_enter(&pcic->pc_lock);
61622305Sstevel pcic_err(dip, 8, "exit pcic_load_cardbus (%s)\n",
61632305Sstevel retval ? "success" : "failure");
61642305Sstevel return (retval);
61652305Sstevel }
61662305Sstevel
61672305Sstevel static void
pcic_unload_cardbus(pcicdev_t * pcic,const pcic_socket_t * sockp)61682305Sstevel pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp)
61692305Sstevel {
61702305Sstevel dev_info_t *dip = pcic->dip;
61712305Sstevel set_socket_t s;
61722305Sstevel
61732305Sstevel pcic_mutex_exit(&pcic->pc_lock);
61742305Sstevel
61752305Sstevel cardbus_unload_cardbus(dip);
61762305Sstevel
61772305Sstevel bzero(&s, sizeof (set_socket_t));
61782305Sstevel s.socket = sockp->pcs_socket;
61792305Sstevel s.SCIntMask = SBM_CD|SBM_RDYBSY;
61802305Sstevel s.IREQRouting = 0;
61812305Sstevel s.IFType = IF_MEMORY;
61822305Sstevel s.CtlInd = 0;
61832305Sstevel s.State = 0;
61842305Sstevel s.VccLevel = s.Vpp1Level = s.Vpp2Level = 0;
61852305Sstevel
61862305Sstevel (void) pcic_set_socket(dip, &s);
61872305Sstevel
61882305Sstevel pcic_mutex_enter(&pcic->pc_lock);
61892305Sstevel }
61902305Sstevel
61912305Sstevel static uint32_t
pcic_getcb(pcicdev_t * pcic,int reg)61922305Sstevel pcic_getcb(pcicdev_t *pcic, int reg)
61932305Sstevel {
61942305Sstevel ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA);
61952305Sstevel
61962305Sstevel return (ddi_get32(pcic->handle,
61972305Sstevel (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg)));
61982305Sstevel }
61992305Sstevel
62002305Sstevel static void
pcic_putcb(pcicdev_t * pcic,int reg,uint32_t value)62012305Sstevel pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value)
62022305Sstevel {
62032305Sstevel ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA);
62042305Sstevel
62052305Sstevel ddi_put32(pcic->handle,
62062305Sstevel (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg), value);
62072305Sstevel }
62082305Sstevel
62092305Sstevel static void
pcic_enable_io_intr(pcicdev_t * pcic,int socket,int irq)62102305Sstevel pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq)
62112305Sstevel {
62122305Sstevel uint8_t value;
62132305Sstevel uint16_t brdgctl;
62142305Sstevel
62152305Sstevel value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK;
62162305Sstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, value | irq);
62172305Sstevel
62182305Sstevel switch (pcic->pc_type) {
62192305Sstevel case PCIC_INTEL_i82092:
62202305Sstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
62212305Sstevel PCIC_82092_INT_ENABLE);
62222305Sstevel break;
62232305Sstevel case PCIC_O2_OZ6912:
62242305Sstevel value = pcic_getb(pcic, 0, PCIC_CENTDMA);
62252305Sstevel value |= 0x8;
62262305Sstevel pcic_putb(pcic, 0, PCIC_CENTDMA, value);
62272305Sstevel break;
62282305Sstevel case PCIC_CL_PD6832:
62292305Sstevel case PCIC_TI_PCI1250:
62302305Sstevel case PCIC_TI_PCI1221:
62312305Sstevel case PCIC_TI_PCI1225:
62322305Sstevel case PCIC_TI_PCI1410:
62332305Sstevel case PCIC_ENE_1410:
62342305Sstevel case PCIC_TI_PCI1510:
62352305Sstevel case PCIC_TI_PCI1520:
62362305Sstevel case PCIC_TI_PCI1420:
62372305Sstevel case PCIC_ENE_1420:
62382305Sstevel /* route card functional interrupts to PCI interrupts */
62392305Sstevel brdgctl = ddi_get16(pcic->cfg_handle,
62402305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62412305Sstevel pcic_err(NULL, 1,
62422305Sstevel "pcic_enable_io_intr brdgctl(0x%x) was: 0x%x\n",
62432305Sstevel PCI_CBUS_BRIDGE_CTRL, brdgctl);
62442305Sstevel brdgctl &= ~PCIC_BRDGCTL_INTR_MASK;
62452305Sstevel ddi_put16(pcic->cfg_handle,
62462305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL),
62472305Sstevel brdgctl);
62482305Sstevel /* Flush the write */
62492305Sstevel (void) ddi_get16(pcic->cfg_handle,
62502305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62512305Sstevel break;
62522305Sstevel default:
62532305Sstevel break;
62542305Sstevel }
62552305Sstevel }
62562305Sstevel
62572305Sstevel static void
pcic_disable_io_intr(pcicdev_t * pcic,int socket)62582305Sstevel pcic_disable_io_intr(pcicdev_t *pcic, int socket)
62592305Sstevel {
62602305Sstevel uint8_t value;
62612305Sstevel uint16_t brdgctl;
62622305Sstevel
62632305Sstevel value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK;
62642305Sstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, value);
62652305Sstevel
62662305Sstevel switch (pcic->pc_type) {
62672305Sstevel case PCIC_INTEL_i82092:
62682305Sstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ,
62692305Sstevel PCIC_82092_INT_DISABLE);
62702305Sstevel break;
62712305Sstevel case PCIC_O2_OZ6912:
62722305Sstevel value = pcic_getb(pcic, 0, PCIC_CENTDMA);
62732305Sstevel value &= ~0x8;
62742305Sstevel pcic_putb(pcic, 0, PCIC_CENTDMA, value);
62752305Sstevel /* Flush the write */
62762305Sstevel (void) pcic_getb(pcic, 0, PCIC_CENTDMA);
62772305Sstevel break;
62782305Sstevel case PCIC_CL_PD6832:
62792305Sstevel case PCIC_TI_PCI1250:
62802305Sstevel case PCIC_TI_PCI1221:
62812305Sstevel case PCIC_TI_PCI1225:
62822305Sstevel case PCIC_TI_PCI1410:
62832305Sstevel case PCIC_ENE_1410:
62842305Sstevel case PCIC_TI_PCI1510:
62852305Sstevel case PCIC_TI_PCI1520:
62862305Sstevel case PCIC_TI_PCI1420:
62872305Sstevel case PCIC_ENE_1420:
62882305Sstevel /*
62892305Sstevel * This maps I/O interrupts to ExCA which
62902305Sstevel * have been turned off by the write to
62912305Sstevel * PCIC_INTERRUPT above. It would appear to
62922305Sstevel * be the only way to actually turn I/O Ints off
62932305Sstevel * while retaining CS Ints.
62942305Sstevel */
62952305Sstevel brdgctl = ddi_get16(pcic->cfg_handle,
62962305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
62972305Sstevel pcic_err(NULL, 1,
62982305Sstevel "pcic_disable_io_intr brdgctl(0x%x) was: 0x%x\n",
62992305Sstevel PCI_CBUS_BRIDGE_CTRL, brdgctl);
63002305Sstevel brdgctl |= PCIC_BRDGCTL_INTR_MASK;
63012305Sstevel ddi_put16(pcic->cfg_handle,
63022305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL),
63032305Sstevel brdgctl);
63042305Sstevel /* Flush the write */
63052305Sstevel (void) ddi_get16(pcic->cfg_handle,
63062305Sstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL));
63072305Sstevel break;
63082305Sstevel default:
63092305Sstevel break;
63102305Sstevel }
63112305Sstevel }
63122305Sstevel
63132305Sstevel static void
pcic_cb_enable_intr(dev_info_t * dip)63142305Sstevel pcic_cb_enable_intr(dev_info_t *dip)
63152305Sstevel {
63162305Sstevel anp_t *anp = ddi_get_driver_private(dip);
63172305Sstevel pcicdev_t *pcic = anp->an_private;
63182305Sstevel
63192305Sstevel mutex_enter(&pcic->pc_lock);
63202305Sstevel pcic_enable_io_intr(pcic, 0, pcic->pc_sockets[0].pcs_irq);
63212305Sstevel mutex_exit(&pcic->pc_lock);
63222305Sstevel }
63232305Sstevel
63242305Sstevel static void
pcic_cb_disable_intr(dev_info_t * dip)63252305Sstevel pcic_cb_disable_intr(dev_info_t *dip)
63262305Sstevel {
63272305Sstevel anp_t *anp = ddi_get_driver_private(dip);
63282305Sstevel pcicdev_t *pcic = anp->an_private;
63292305Sstevel
63302305Sstevel mutex_enter(&pcic->pc_lock);
63312305Sstevel pcic_disable_io_intr(pcic, 0);
63322305Sstevel mutex_exit(&pcic->pc_lock);
63332305Sstevel }
63342305Sstevel
63352305Sstevel static int
log_pci_cfg_err(ushort_t e,int bridge_secondary)63362305Sstevel log_pci_cfg_err(ushort_t e, int bridge_secondary)
63372305Sstevel {
63382305Sstevel int nerr = 0;
63392305Sstevel if (e & PCI_STAT_PERROR) {
63402305Sstevel nerr++;
63412305Sstevel cmn_err(CE_CONT, "detected parity error.\n");
63422305Sstevel }
63432305Sstevel if (e & PCI_STAT_S_SYSERR) {
63442305Sstevel nerr++;
63452305Sstevel if (bridge_secondary)
63462305Sstevel cmn_err(CE_CONT, "received system error.\n");
63472305Sstevel else
63482305Sstevel cmn_err(CE_CONT, "signalled system error.\n");
63492305Sstevel }
63502305Sstevel if (e & PCI_STAT_R_MAST_AB) {
63512305Sstevel nerr++;
63522305Sstevel cmn_err(CE_CONT, "received master abort.\n");
63532305Sstevel }
63542305Sstevel if (e & PCI_STAT_R_TARG_AB)
63552305Sstevel cmn_err(CE_CONT, "received target abort.\n");
63562305Sstevel if (e & PCI_STAT_S_TARG_AB)
63572305Sstevel cmn_err(CE_CONT, "signalled target abort\n");
63582305Sstevel if (e & PCI_STAT_S_PERROR) {
63592305Sstevel nerr++;
63602305Sstevel cmn_err(CE_CONT, "signalled parity error\n");
63612305Sstevel }
63622305Sstevel return (nerr);
63632305Sstevel }
63642305Sstevel
63652305Sstevel #if defined(__sparc)
63662305Sstevel static int
pcic_fault(enum pci_fault_ops op,void * arg)63672305Sstevel pcic_fault(enum pci_fault_ops op, void *arg)
63682305Sstevel {
63692305Sstevel pcicdev_t *pcic = (pcicdev_t *)arg;
63702305Sstevel ushort_t pci_cfg_stat =
63712305Sstevel pci_config_get16(pcic->cfg_handle, PCI_CONF_STAT);
63722305Sstevel ushort_t pci_cfg_sec_stat =
63732305Sstevel pci_config_get16(pcic->cfg_handle, 0x16);
63742305Sstevel char nm[24];
63752305Sstevel int nerr = 0;
63762305Sstevel
63772305Sstevel cardbus_dump_pci_config(pcic->dip);
63782305Sstevel
63792305Sstevel switch (op) {
63802305Sstevel case FAULT_LOG:
63812305Sstevel (void) sprintf(nm, "%s-%d", ddi_driver_name(pcic->dip),
63822305Sstevel ddi_get_instance(pcic->dip));
63832305Sstevel
63842305Sstevel cmn_err(CE_WARN, "%s: PCIC fault log start:\n", nm);
63852305Sstevel cmn_err(CE_WARN, "%s: primary err (%x):\n", nm, pci_cfg_stat);
63862305Sstevel nerr += log_pci_cfg_err(pci_cfg_stat, 0);
63872305Sstevel cmn_err(CE_WARN, "%s: sec err (%x):\n", nm, pci_cfg_sec_stat);
63882305Sstevel nerr += log_pci_cfg_err(pci_cfg_sec_stat, 1);
63892305Sstevel cmn_err(CE_CONT, "%s: PCI fault log end.\n", nm);
63902305Sstevel return (nerr);
63912305Sstevel case FAULT_POKEFINI:
63922305Sstevel case FAULT_RESET:
63932305Sstevel pci_config_put16(pcic->cfg_handle,
63942305Sstevel PCI_CONF_STAT, pci_cfg_stat);
63952305Sstevel pci_config_put16(pcic->cfg_handle, 0x16, pci_cfg_sec_stat);
63962305Sstevel break;
63972305Sstevel case FAULT_POKEFLT:
63982305Sstevel if (!(pci_cfg_stat & PCI_STAT_S_SYSERR))
63992305Sstevel return (1);
64002305Sstevel if (!(pci_cfg_sec_stat & PCI_STAT_R_MAST_AB))
64012305Sstevel return (1);
64022305Sstevel break;
64032305Sstevel default:
64042305Sstevel break;
64052305Sstevel }
64062305Sstevel return (DDI_SUCCESS);
64072305Sstevel }
64082305Sstevel #endif
64092305Sstevel
64102305Sstevel static void
pcic_do_resume(pcicdev_t * pcic)64117151Srw148561 pcic_do_resume(pcicdev_t *pcic)
64122305Sstevel {
64137151Srw148561 int i, interrupt;
64147151Srw148561 uint8_t cfg;
64157151Srw148561
64162305Sstevel
64172305Sstevel #if defined(PCIC_DEBUG)
64187151Srw148561 pcic_err(NULL, 6, "pcic_do_resume(): entered\n");
64192305Sstevel #endif
64207151Srw148561
64217151Srw148561 pcic_mutex_enter(&pcic->pc_lock); /* protect the registers */
64227151Srw148561 for (i = 0; i < pcic->pc_numsockets; i++) {
64237151Srw148561 /* Enable interrupts on PCI if needs be */
64247151Srw148561 interrupt = pcic_getb(pcic, i, PCIC_INTERRUPT);
64257151Srw148561 if (pcic->pc_flags & PCF_USE_SMI)
64267151Srw148561 interrupt |= PCIC_INTR_ENABLE;
64277151Srw148561 pcic_putb(pcic, i, PCIC_INTERRUPT,
64287151Srw148561 PCIC_RESET | interrupt);
64297151Srw148561 pcic->pc_sockets[i].pcs_debounce_id =
64307151Srw148561 pcic_add_debqueue(&pcic->pc_sockets[i],
64317151Srw148561 drv_usectohz(pcic_debounce_time));
64327151Srw148561 }
64337151Srw148561 pcic_mutex_exit(&pcic->pc_lock); /* protect the registers */
64347151Srw148561 if (pcic_do_pcmcia_sr)
64357151Srw148561 (void) pcmcia_wait_insert(pcic->dip);
64367151Srw148561 /*
64377151Srw148561 * The CardBus controller may be in RESET state after the
64387151Srw148561 * system is resumed from sleeping. The RESET bit is in
64397151Srw148561 * the Bridge Control register. This is true for all(TI,
64407151Srw148561 * Toshiba ToPIC95/97, RICOH, and O2Micro) CardBus
64417151Srw148561 * controllers. Need to clear the RESET bit explicitly.
64427151Srw148561 */
64437151Srw148561 cfg = ddi_get8(pcic->cfg_handle,
64447656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
64457151Srw148561 if (cfg & (1<<6)) {
64467151Srw148561 cfg &= ~(1<<6);
64477151Srw148561 ddi_put8(pcic->cfg_handle,
64487656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG,
64497656SSherry.Moore@Sun.COM cfg);
64507151Srw148561 cfg = ddi_get8(pcic->cfg_handle,
64517656SSherry.Moore@Sun.COM pcic->cfgaddr + PCIC_BRIDGE_CTL_REG);
64527151Srw148561 if (cfg & (1<<6)) {
64537656SSherry.Moore@Sun.COM pcic_err(pcic->dip, 1,
64547656SSherry.Moore@Sun.COM "Failed to take pcic out of reset");
64552305Sstevel }
64562305Sstevel }
64577151Srw148561
64582305Sstevel }
64592305Sstevel
64602305Sstevel static void
pcic_debounce(pcic_socket_t * pcs)64612305Sstevel pcic_debounce(pcic_socket_t *pcs)
64622305Sstevel {
64632305Sstevel uint8_t status, stschng;
64642305Sstevel
64652305Sstevel pcic_mutex_enter(&pcs->pcs_pcic->pc_lock);
64662305Sstevel pcs->pcs_flags &= ~PCS_STARTING;
64672305Sstevel stschng = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket,
64682305Sstevel PCIC_CARD_STATUS_CHANGE);
64692305Sstevel status = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket,
64702305Sstevel PCIC_INTERFACE_STATUS);
64712305Sstevel #ifdef PCIC_DEBUG
64722305Sstevel pcic_err(pcs->pcs_pcic->dip, 8,
64732305Sstevel "pcic_debounce(0x%p, dip=0x%p) socket %d st 0x%x "
64742305Sstevel "chg 0x%x flg 0x%x\n",
64752305Sstevel (void *)pcs, (void *) pcs->pcs_pcic->dip, pcs->pcs_socket,
64762305Sstevel status, stschng, pcs->pcs_flags);
64772305Sstevel #endif
64782305Sstevel
64792305Sstevel pcic_putb(pcs->pcs_pcic, pcs->pcs_socket, PCIC_CARD_STATUS_CHANGE,
64802305Sstevel PCIC_CD_DETECT);
64812305Sstevel pcic_handle_cd_change(pcs->pcs_pcic, pcs, status);
64822305Sstevel pcic_mutex_exit(&pcs->pcs_pcic->pc_lock);
64832305Sstevel }
64842305Sstevel
64852305Sstevel static void
pcic_deb_thread()64862305Sstevel pcic_deb_thread()
64872305Sstevel {
64882305Sstevel callb_cpr_t cprinfo;
64892305Sstevel struct debounce *debp;
64902305Sstevel clock_t lastt;
64912305Sstevel
64922305Sstevel CALLB_CPR_INIT(&cprinfo, &pcic_deb_mtx,
64932305Sstevel callb_generic_cpr, "pcic debounce thread");
64942305Sstevel mutex_enter(&pcic_deb_mtx);
64952305Sstevel while (pcic_deb_threadid) {
64962305Sstevel while (pcic_deb_queue) {
64972305Sstevel #ifdef PCIC_DEBUG
64982305Sstevel pcic_dump_debqueue("Thread");
64992305Sstevel #endif
65002305Sstevel debp = pcic_deb_queue;
65012305Sstevel (void) drv_getparm(LBOLT, &lastt);
65022305Sstevel if (lastt >= debp->expire) {
65032305Sstevel pcic_deb_queue = debp->next;
65042305Sstevel mutex_exit(&pcic_deb_mtx);
65052305Sstevel pcic_debounce(debp->pcs);
65062305Sstevel mutex_enter(&pcic_deb_mtx);
65072305Sstevel kmem_free(debp, sizeof (*debp));
65082305Sstevel } else {
65092305Sstevel (void) cv_timedwait(&pcic_deb_cv,
65102305Sstevel &pcic_deb_mtx, debp->expire);
65112305Sstevel }
65122305Sstevel }
65132305Sstevel CALLB_CPR_SAFE_BEGIN(&cprinfo);
65142305Sstevel cv_wait(&pcic_deb_cv, &pcic_deb_mtx);
65152305Sstevel CALLB_CPR_SAFE_END(&cprinfo, &pcic_deb_mtx);
65162305Sstevel }
65172305Sstevel pcic_deb_threadid = (kthread_t *)1;
65182305Sstevel cv_signal(&pcic_deb_cv);
65192305Sstevel CALLB_CPR_EXIT(&cprinfo); /* Also exits the mutex */
65202305Sstevel thread_exit();
65212305Sstevel }
65222305Sstevel
65232305Sstevel static void *
pcic_add_debqueue(pcic_socket_t * pcs,int clocks)65242305Sstevel pcic_add_debqueue(pcic_socket_t *pcs, int clocks)
65252305Sstevel {
65262305Sstevel clock_t lbolt;
65272305Sstevel struct debounce *dbp, **dbpp = &pcic_deb_queue;
65282305Sstevel
65292305Sstevel (void) drv_getparm(LBOLT, &lbolt);
65303664Srw148561 dbp = kmem_alloc(sizeof (struct debounce), KM_SLEEP);
65312305Sstevel
65322305Sstevel dbp->expire = lbolt + clocks;
65332305Sstevel dbp->pcs = pcs;
65342305Sstevel mutex_enter(&pcic_deb_mtx);
65352305Sstevel while (*dbpp) {
65362305Sstevel if (dbp->expire > (*dbpp)->expire)
65372305Sstevel dbpp = &((*dbpp)->next);
65382305Sstevel else
65392305Sstevel break;
65402305Sstevel }
65412305Sstevel dbp->next = *dbpp;
65422305Sstevel *dbpp = dbp;
65432305Sstevel #ifdef PCIC_DEBUG
65442305Sstevel pcic_dump_debqueue("Add");
65452305Sstevel #endif
65462305Sstevel cv_signal(&pcic_deb_cv);
65472305Sstevel mutex_exit(&pcic_deb_mtx);
65482305Sstevel return (dbp);
65492305Sstevel }
65502305Sstevel
65512305Sstevel static void
pcic_rm_debqueue(void * id)65522305Sstevel pcic_rm_debqueue(void *id)
65532305Sstevel {
65542305Sstevel struct debounce *dbp, **dbpp = &pcic_deb_queue;
65552305Sstevel
65562305Sstevel dbp = (struct debounce *)id;
65572305Sstevel mutex_enter(&pcic_deb_mtx);
65582305Sstevel while (*dbpp) {
65592305Sstevel if (*dbpp == dbp) {
65602305Sstevel *dbpp = dbp->next;
65612305Sstevel kmem_free(dbp, sizeof (*dbp));
65622305Sstevel #ifdef PCIC_DEBUG
65632305Sstevel pcic_dump_debqueue("Remove");
65642305Sstevel #endif
65652305Sstevel cv_signal(&pcic_deb_cv);
65662305Sstevel mutex_exit(&pcic_deb_mtx);
65672305Sstevel return;
65682305Sstevel }
65692305Sstevel dbpp = &((*dbpp)->next);
65702305Sstevel }
65712305Sstevel pcic_err(NULL, 6, "pcic: Failed to find debounce id 0x%p\n", id);
65722305Sstevel mutex_exit(&pcic_deb_mtx);
65732305Sstevel }
65742305Sstevel
65752305Sstevel
65762305Sstevel static int pcic_powerdelay = 0;
65772305Sstevel
65782305Sstevel static int
pcic_exca_powerctl(pcicdev_t * pcic,int socket,int powerlevel)65792305Sstevel pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel)
65802305Sstevel {
65812305Sstevel int ind, value, orig_pwrctl;
65822305Sstevel
65832305Sstevel /* power setup -- if necessary */
65842305Sstevel orig_pwrctl = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
65852305Sstevel
65862305Sstevel #if defined(PCIC_DEBUG)
65872305Sstevel pcic_err(pcic->dip, 6,
65882305Sstevel "pcic_exca_powerctl(socket %d) powerlevel=%x orig 0x%x\n",
65892305Sstevel socket, powerlevel, orig_pwrctl);
65902305Sstevel #endif
65912305Sstevel /* Preserve the PCIC_OUTPUT_ENABLE (control lines output enable) bit. */
65922305Sstevel powerlevel = (powerlevel & ~POWER_OUTPUT_ENABLE) |
65932305Sstevel (orig_pwrctl & POWER_OUTPUT_ENABLE);
65942305Sstevel if (powerlevel != orig_pwrctl) {
65952305Sstevel if (powerlevel & ~POWER_OUTPUT_ENABLE) {
65962305Sstevel int ifs;
65972305Sstevel /*
65982305Sstevel * set power to socket
65992305Sstevel * note that the powerlevel was calculated earlier
66002305Sstevel */
66012305Sstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
66022305Sstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
66032305Sstevel
66042305Sstevel /*
66052305Sstevel * this second write to the power control register
66062305Sstevel * is needed to resolve a problem on
66072305Sstevel * the IBM ThinkPad 750
66082305Sstevel * where the first write doesn't latch.
66092305Sstevel * The second write appears to always work and
66102305Sstevel * doesn't hurt the operation of other chips
66112305Sstevel * so we can just use it -- this is good since we can't
66122305Sstevel * determine what chip the 750 actually uses
66132305Sstevel * (I suspect an early Ricoh).
66142305Sstevel */
66152305Sstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
66162305Sstevel
66172305Sstevel value = pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
66182305Sstevel pcic_mswait(pcic, socket, pcic_powerdelay);
66192305Sstevel #if defined(PCIC_DEBUG)
66202305Sstevel pcic_err(pcic->dip, 8,
66212305Sstevel "\tpowerlevel reg = %x (ifs %x)\n",
66222305Sstevel value, pcic_getb(pcic, socket,
66232305Sstevel PCIC_INTERFACE_STATUS));
66242305Sstevel pcic_err(pcic->dip, 8,
66252305Sstevel "CBus regs: PS 0x%x, Control 0x%x\n",
66262305Sstevel pcic_getcb(pcic, CB_PRESENT_STATE),
66272305Sstevel pcic_getcb(pcic, CB_CONTROL));
66282305Sstevel #endif
66292305Sstevel /*
66302305Sstevel * since power was touched, make sure it says it
66312305Sstevel * is on. This lets it become stable.
66322305Sstevel */
66332305Sstevel for (ind = 0; ind < 20; ind++) {
66342305Sstevel ifs = pcic_getb(pcic, socket,
66352305Sstevel PCIC_INTERFACE_STATUS);
66362305Sstevel if (ifs & PCIC_POWER_ON)
66372305Sstevel break;
66382305Sstevel else {
66392305Sstevel pcic_putb(pcic, socket,
66402305Sstevel PCIC_POWER_CONTROL, 0);
66412305Sstevel (void) pcic_getb(pcic, socket,
66422305Sstevel PCIC_POWER_CONTROL);
66432305Sstevel pcic_mswait(pcic, socket, 40);
66442305Sstevel if (ind == 10) {
66452305Sstevel pcic_putcb(pcic, CB_EVENT_FORCE,
66462305Sstevel CB_EF_CVTEST);
66472305Sstevel pcic_mswait(pcic, socket, 100);
66482305Sstevel }
66492305Sstevel pcic_putb(pcic, socket,
66502305Sstevel PCIC_POWER_CONTROL,
66512305Sstevel powerlevel & ~POWER_OUTPUT_ENABLE);
66522305Sstevel (void) pcic_getb(pcic, socket,
66532305Sstevel PCIC_POWER_CONTROL);
66542305Sstevel pcic_mswait(pcic, socket,
66552305Sstevel pcic_powerdelay);
66562305Sstevel pcic_putb(pcic, socket,
66572305Sstevel PCIC_POWER_CONTROL, powerlevel);
66582305Sstevel (void) pcic_getb(pcic, socket,
66592305Sstevel PCIC_POWER_CONTROL);
66602305Sstevel pcic_mswait(pcic, socket,
66612305Sstevel pcic_powerdelay);
66622305Sstevel }
66632305Sstevel }
66642305Sstevel
66652305Sstevel if (!(ifs & PCIC_POWER_ON)) {
66662305Sstevel cmn_err(CE_WARN,
66672305Sstevel "pcic socket %d: Power didn't get turned"
66682305Sstevel "on!\nif status 0x%x pwrc 0x%x(x%x) "
66692305Sstevel "misc1 0x%x igc 0x%x ind %d\n",
66702305Sstevel socket, ifs,
66712305Sstevel pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
66722305Sstevel orig_pwrctl,
66732305Sstevel pcic_getb(pcic, socket, PCIC_MISC_CTL_1),
66742305Sstevel pcic_getb(pcic, socket, PCIC_INTERRUPT),
66752305Sstevel ind);
66762305Sstevel return (BAD_VCC);
66772305Sstevel }
66782305Sstevel #if defined(PCIC_DEBUG)
66792305Sstevel pcic_err(pcic->dip, 8,
66802305Sstevel "\tind = %d, if status %x pwrc 0x%x "
66812305Sstevel "misc1 0x%x igc 0x%x\n",
66822305Sstevel ind, ifs,
66832305Sstevel pcic_getb(pcic, socket, PCIC_POWER_CONTROL),
66842305Sstevel pcic_getb(pcic, socket, PCIC_MISC_CTL_1),
66852305Sstevel pcic_getb(pcic, socket, PCIC_INTERRUPT));
66862305Sstevel #endif
66872305Sstevel } else {
66882305Sstevel /* explicitly turned off the power */
66892305Sstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel);
66902305Sstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL);
66912305Sstevel }
66922305Sstevel }
66932305Sstevel return (SUCCESS);
66942305Sstevel }
66952305Sstevel
66962305Sstevel static int pcic_cbdoreset_during_poweron = 1;
66972305Sstevel static int
pcic_cbus_powerctl(pcicdev_t * pcic,int socket)66982305Sstevel pcic_cbus_powerctl(pcicdev_t *pcic, int socket)
66992305Sstevel {
67002305Sstevel uint32_t cbctl = 0, orig_cbctl, cbstev, cbps;
67012305Sstevel int ind, iobits;
67022305Sstevel pcic_socket_t *sockp = &pcic->pc_sockets[socket];
67032305Sstevel
67042305Sstevel pcic_putcb(pcic, CB_STATUS_EVENT, CB_SE_POWER_CYCLE);
67052305Sstevel
67062305Sstevel ind = pcic_power[sockp->pcs_vpp1].PowerLevel/10;
67072305Sstevel cbctl |= pcic_cbv_levels[ind];
67082305Sstevel
67092305Sstevel ind = pcic_power[sockp->pcs_vcc].PowerLevel/10;
67102305Sstevel cbctl |= (pcic_cbv_levels[ind]<<4);
67112305Sstevel
67122305Sstevel orig_cbctl = pcic_getcb(pcic, CB_CONTROL);
67132305Sstevel
67142305Sstevel #if defined(PCIC_DEBUG)
67152305Sstevel pcic_err(pcic->dip, 6,
67162305Sstevel "pcic_cbus_powerctl(socket %d) vcc %d vpp1 %d "
67172305Sstevel "cbctl 0x%x->0x%x\n",
67182305Sstevel socket, sockp->pcs_vcc, sockp->pcs_vpp1, orig_cbctl, cbctl);
67192305Sstevel #endif
67202305Sstevel if (cbctl != orig_cbctl) {
67217656SSherry.Moore@Sun.COM if (pcic_cbdoreset_during_poweron &&
67227656SSherry.Moore@Sun.COM (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
67237656SSherry.Moore@Sun.COM iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT);
67247656SSherry.Moore@Sun.COM pcic_putb(pcic, socket, PCIC_INTERRUPT,
67257656SSherry.Moore@Sun.COM iobits & ~PCIC_RESET);
67267656SSherry.Moore@Sun.COM }
67277656SSherry.Moore@Sun.COM pcic_putcb(pcic, CB_CONTROL, cbctl);
67287656SSherry.Moore@Sun.COM
67297656SSherry.Moore@Sun.COM if ((cbctl & CB_C_VCCMASK) == (orig_cbctl & CB_C_VCCMASK)) {
67302305Sstevel pcic_mswait(pcic, socket, pcic_powerdelay);
67312305Sstevel return (SUCCESS);
67327656SSherry.Moore@Sun.COM }
67337656SSherry.Moore@Sun.COM for (ind = 0; ind < 20; ind++) {
67342305Sstevel cbstev = pcic_getcb(pcic, CB_STATUS_EVENT);
67352305Sstevel
67362305Sstevel if (cbstev & CB_SE_POWER_CYCLE) {
67372305Sstevel
67382305Sstevel /*
67392305Sstevel * delay 400 ms: though the standard defines that the Vcc
67402305Sstevel * set-up time is 20 ms, some PC-Card bridge requires longer
67412305Sstevel * duration.
67422305Sstevel * Note: We should check the status AFTER the delay to give time
67432305Sstevel * for things to stabilize.
67442305Sstevel */
67457656SSherry.Moore@Sun.COM pcic_mswait(pcic, socket, 400);
67467656SSherry.Moore@Sun.COM
67477656SSherry.Moore@Sun.COM cbps = pcic_getcb(pcic, CB_PRESENT_STATE);
67487656SSherry.Moore@Sun.COM if (cbctl && !(cbps & CB_PS_POWER_CYCLE)) {
67492305Sstevel /* break; */
67502305Sstevel cmn_err(CE_WARN, "cbus_powerctl: power off??\n");
67517656SSherry.Moore@Sun.COM }
67527656SSherry.Moore@Sun.COM if (cbctl & CB_PS_BADVCC) {
67532305Sstevel cmn_err(CE_WARN, "cbus_powerctl: bad power request\n");
67542305Sstevel break;
67557656SSherry.Moore@Sun.COM }
67562305Sstevel
67572305Sstevel #if defined(PCIC_DEBUG)
67587656SSherry.Moore@Sun.COM pcic_err(pcic->dip, 8,
67597656SSherry.Moore@Sun.COM "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x)",
67607656SSherry.Moore@Sun.COM cbstev, pcic_getcb(pcic, CB_PRESENT_STATE),
67617656SSherry.Moore@Sun.COM cbctl, orig_cbctl);
67622305Sstevel #endif
67637656SSherry.Moore@Sun.COM if (pcic_cbdoreset_during_poweron &&
67647656SSherry.Moore@Sun.COM (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
67657656SSherry.Moore@Sun.COM pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
67667656SSherry.Moore@Sun.COM }
67677656SSherry.Moore@Sun.COM return (SUCCESS);
67682305Sstevel }
67692305Sstevel pcic_mswait(pcic, socket, 40);
67707656SSherry.Moore@Sun.COM }
67717656SSherry.Moore@Sun.COM if (pcic_cbdoreset_during_poweron &&
67727656SSherry.Moore@Sun.COM (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) {
67737656SSherry.Moore@Sun.COM pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits);
67747656SSherry.Moore@Sun.COM }
67757656SSherry.Moore@Sun.COM cmn_err(CE_WARN,
67762305Sstevel "pcic socket %d: Power didn't get turned on/off!\n"
67772305Sstevel "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x) "
67782305Sstevel "vcc %d vpp1 %d", socket, cbstev,
67792305Sstevel pcic_getcb(pcic, CB_PRESENT_STATE),
67802305Sstevel cbctl, orig_cbctl, sockp->pcs_vcc, sockp->pcs_vpp1);
67817656SSherry.Moore@Sun.COM return (BAD_VCC);
67822305Sstevel }
67832305Sstevel return (SUCCESS);
67842305Sstevel }
67852305Sstevel
67862305Sstevel static int pcic_do_pprintf = 0;
67872305Sstevel
67882305Sstevel static void
pcic_dump_debqueue(char * msg)67892305Sstevel pcic_dump_debqueue(char *msg)
67902305Sstevel {
67912305Sstevel struct debounce *debp = pcic_deb_queue;
67922305Sstevel clock_t lbolt;
67932305Sstevel
67942305Sstevel (void) drv_getparm(LBOLT, &lbolt);
67952305Sstevel pcic_err(NULL, 6, debp ? "pcic debounce list (%s) lbolt 0x%x:\n" :
67962305Sstevel "pcic debounce_list (%s) EMPTY lbolt 0x%x\n", msg, lbolt);
67972305Sstevel while (debp) {
67982305Sstevel pcic_err(NULL, 6, "%p: exp 0x%x next 0x%p id 0x%p\n",
67992305Sstevel (void *) debp, (int)debp->expire, (void *) debp->next,
68002305Sstevel debp->pcs->pcs_debounce_id);
68012305Sstevel debp = debp->next;
68022305Sstevel }
68032305Sstevel }
68042305Sstevel
68052305Sstevel
68062305Sstevel /* PRINTFLIKE3 */
68072305Sstevel static void
pcic_err(dev_info_t * dip,int level,const char * fmt,...)68082305Sstevel pcic_err(dev_info_t *dip, int level, const char *fmt, ...)
68092305Sstevel {
68102305Sstevel if (pcic_debug && (level <= pcic_debug)) {
68112305Sstevel va_list adx;
68122305Sstevel int instance;
68132305Sstevel char buf[256];
68142305Sstevel const char *name;
68152305Sstevel #if !defined(PCIC_DEBUG)
68162305Sstevel int ce;
68172305Sstevel char qmark = 0;
68182305Sstevel
68192305Sstevel if (level <= 3)
68202305Sstevel ce = CE_WARN;
68212305Sstevel else
68222305Sstevel ce = CE_CONT;
68232305Sstevel if (level == 4)
68242305Sstevel qmark = 1;
68252305Sstevel #endif
68262305Sstevel
68272305Sstevel if (dip) {
68282305Sstevel instance = ddi_get_instance(dip);
68292305Sstevel /* name = ddi_binding_name(dip); */
68302305Sstevel name = ddi_driver_name(dip);
68312305Sstevel } else {
68322305Sstevel instance = 0;
68332305Sstevel name = "";
68342305Sstevel }
68352305Sstevel
68362305Sstevel va_start(adx, fmt);
68372305Sstevel (void) vsprintf(buf, fmt, adx);
68382305Sstevel va_end(adx);
68392305Sstevel
68402305Sstevel #if defined(PCIC_DEBUG)
68412305Sstevel if (pcic_do_pprintf) {
68422305Sstevel if (dip) {
68432305Sstevel if (instance >= 0)
68442305Sstevel prom_printf("%s(%d),0x%p: %s", name,
68457240Srh87107 instance, (void *)dip, buf);
68462305Sstevel else
68472305Sstevel prom_printf("%s,0x%p: %s",
68487240Srh87107 name, (void *)dip, buf);
68492305Sstevel } else
68502305Sstevel prom_printf(buf);
68512305Sstevel } else {
68522305Sstevel if (dip) {
68532305Sstevel if (instance >= 0)
68542305Sstevel cmn_err(CE_CONT, "%s(%d),0x%p: %s",
68552305Sstevel name, instance, (void *) dip, buf);
68562305Sstevel else
68572305Sstevel cmn_err(CE_CONT, "%s,0x%p: %s",
68582305Sstevel name, (void *) dip, buf);
68592305Sstevel } else
68602305Sstevel cmn_err(CE_CONT, buf);
68612305Sstevel }
68622305Sstevel #else
68632305Sstevel if (dip)
68642305Sstevel cmn_err(ce, qmark ? "?%s%d: %s" : "%s%d: %s", name,
68652305Sstevel instance, buf);
68662305Sstevel else
68672305Sstevel cmn_err(ce, qmark ? "?%s" : buf, buf);
68682305Sstevel #endif
68692305Sstevel }
68702305Sstevel }
6871