13db86aabSstevel /* 23db86aabSstevel * CDDL HEADER START 33db86aabSstevel * 43db86aabSstevel * The contents of this file are subject to the terms of the 53db86aabSstevel * Common Development and Distribution License (the "License"). 63db86aabSstevel * You may not use this file except in compliance with the License. 73db86aabSstevel * 83db86aabSstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93db86aabSstevel * or http://www.opensolaris.org/os/licensing. 103db86aabSstevel * See the License for the specific language governing permissions 113db86aabSstevel * and limitations under the License. 123db86aabSstevel * 133db86aabSstevel * When distributing Covered Code, include this CDDL HEADER in each 143db86aabSstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153db86aabSstevel * If applicable, add the following below this CDDL HEADER, with the 163db86aabSstevel * fields enclosed by brackets "[]" replaced with your own identifying 173db86aabSstevel * information: Portions Copyright [yyyy] [name of copyright owner] 183db86aabSstevel * 193db86aabSstevel * CDDL HEADER END 203db86aabSstevel */ 213db86aabSstevel 223db86aabSstevel /* 238134ee03Srw148561 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243db86aabSstevel * Use is subject to license terms. 253db86aabSstevel */ 263db86aabSstevel 273db86aabSstevel #pragma ident "%Z%%M% %I% %E% SMI" 283db86aabSstevel 293db86aabSstevel /* 303db86aabSstevel * PCIC device/interrupt handler 313db86aabSstevel * The "pcic" driver handles the Intel 82365SL, Cirrus Logic 323db86aabSstevel * and Toshiba (and possibly other clones) PCMCIA adapter chip 333db86aabSstevel * sets. It implements a subset of Socket Services as defined 343db86aabSstevel * in the Solaris PCMCIA design documents 353db86aabSstevel */ 363db86aabSstevel 373db86aabSstevel /* 383db86aabSstevel * currently defined "properties" 393db86aabSstevel * 403db86aabSstevel * clock-frequency bus clock frequency 413db86aabSstevel * smi system management interrupt override 423db86aabSstevel * need-mult-irq need status IRQ for each pair of sockets 433db86aabSstevel * disable-audio don't route audio signal to speaker 443db86aabSstevel */ 453db86aabSstevel 463db86aabSstevel 473db86aabSstevel #include <sys/types.h> 483db86aabSstevel #include <sys/inttypes.h> 493db86aabSstevel #include <sys/param.h> 503db86aabSstevel #include <sys/systm.h> 513db86aabSstevel #include <sys/user.h> 523db86aabSstevel #include <sys/buf.h> 533db86aabSstevel #include <sys/file.h> 543db86aabSstevel #include <sys/uio.h> 553db86aabSstevel #include <sys/conf.h> 563db86aabSstevel #include <sys/stat.h> 573db86aabSstevel #include <sys/autoconf.h> 583db86aabSstevel #include <sys/vtoc.h> 593db86aabSstevel #include <sys/dkio.h> 603db86aabSstevel #include <sys/ddi.h> 613db86aabSstevel #include <sys/sunddi.h> 623db86aabSstevel #include <sys/sunndi.h> 633db86aabSstevel #include <sys/var.h> 643db86aabSstevel #include <sys/callb.h> 653db86aabSstevel #include <sys/open.h> 663db86aabSstevel #include <sys/ddidmareq.h> 673db86aabSstevel #include <sys/dma_engine.h> 683db86aabSstevel #include <sys/kstat.h> 693db86aabSstevel #include <sys/kmem.h> 703db86aabSstevel #include <sys/modctl.h> 713db86aabSstevel #include <sys/pci.h> 723db86aabSstevel #include <sys/pci_impl.h> 733db86aabSstevel 743db86aabSstevel #include <sys/pctypes.h> 753db86aabSstevel #include <sys/pcmcia.h> 763db86aabSstevel #include <sys/sservice.h> 773db86aabSstevel 783db86aabSstevel #include <sys/note.h> 793db86aabSstevel 803db86aabSstevel #include <sys/pcic_reg.h> 813db86aabSstevel #include <sys/pcic_var.h> 823db86aabSstevel 833db86aabSstevel #if defined(__sparc) 843db86aabSstevel #include <sys/pci/pci_nexus.h> 853db86aabSstevel #endif 863db86aabSstevel 870d282d13Srw148561 #include <sys/hotplug/hpcsvc.h> 883db86aabSstevel #include <sys/syshw.h> 893db86aabSstevel #include "cardbus/cardbus.h" 903db86aabSstevel 913db86aabSstevel #define SOFTC_SIZE (sizeof (anp_t)) 923db86aabSstevel 933db86aabSstevel static int pcic_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 943db86aabSstevel static int pcic_attach(dev_info_t *, ddi_attach_cmd_t); 953db86aabSstevel static int pcic_detach(dev_info_t *, ddi_detach_cmd_t); 963db86aabSstevel static uint_t pcic_intr(caddr_t, caddr_t); 973db86aabSstevel static int pcic_do_io_intr(pcicdev_t *, uint32_t); 983db86aabSstevel static int pcic_probe(dev_info_t *); 993db86aabSstevel 1003db86aabSstevel static int pcic_open(dev_t *, int, int, cred_t *); 1013db86aabSstevel static int pcic_close(dev_t, int, int, cred_t *); 1023db86aabSstevel static int pcic_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1033db86aabSstevel 1043db86aabSstevel typedef struct pcm_regs pcm_regs_t; 1053db86aabSstevel 1063db86aabSstevel static void pcic_init_assigned(dev_info_t *); 1073db86aabSstevel static int pcic_apply_avail_ranges(dev_info_t *, pcm_regs_t *, 1083db86aabSstevel pci_regspec_t *, int); 1093db86aabSstevel int pci_resource_setup_avail(dev_info_t *, pci_regspec_t *, int); 1103db86aabSstevel 1113db86aabSstevel /* 1123db86aabSstevel * On x86 platforms the ddi_iobp_alloc(9F) and ddi_mem_alloc(9F) calls 1133db86aabSstevel * are xlated into DMA ctlops. To make this nexus work on x86, we 1143db86aabSstevel * need to have the default ddi_dma_mctl ctlops in the bus_ops 1153db86aabSstevel * structure, just to pass the request to the parent. The correct 1163db86aabSstevel * ctlops should be ddi_no_dma_mctl because so far we don't do DMA. 1173db86aabSstevel */ 1183db86aabSstevel static 1193db86aabSstevel struct bus_ops pcmciabus_ops = { 1203db86aabSstevel BUSO_REV, 1213db86aabSstevel pcmcia_bus_map, 1223db86aabSstevel NULL, 1233db86aabSstevel NULL, 1243db86aabSstevel NULL, 1253db86aabSstevel i_ddi_map_fault, 1263db86aabSstevel ddi_no_dma_map, 1273db86aabSstevel ddi_no_dma_allochdl, 1283db86aabSstevel ddi_no_dma_freehdl, 1293db86aabSstevel ddi_no_dma_bindhdl, 1303db86aabSstevel ddi_no_dma_unbindhdl, 1313db86aabSstevel ddi_no_dma_flush, 1323db86aabSstevel ddi_no_dma_win, 1333db86aabSstevel ddi_dma_mctl, 1343db86aabSstevel pcmcia_ctlops, 1353db86aabSstevel pcmcia_prop_op, 1363db86aabSstevel NULL, /* (*bus_get_eventcookie)(); */ 1373db86aabSstevel NULL, /* (*bus_add_eventcall)(); */ 1383db86aabSstevel NULL, /* (*bus_remove_eventcall)(); */ 1393db86aabSstevel NULL, /* (*bus_post_event)(); */ 1403db86aabSstevel NULL, /* (*bus_intr_ctl)(); */ 1413db86aabSstevel NULL, /* (*bus_config)(); */ 1423db86aabSstevel NULL, /* (*bus_unconfig)(); */ 1433db86aabSstevel NULL, /* (*bus_fm_init)(); */ 1443db86aabSstevel NULL, /* (*bus_fm_fini)(); */ 1453db86aabSstevel NULL, /* (*bus_enter)() */ 1463db86aabSstevel NULL, /* (*bus_exit)() */ 1473db86aabSstevel NULL, /* (*bus_power)() */ 1483db86aabSstevel pcmcia_intr_ops /* (*bus_intr_op)(); */ 1493db86aabSstevel }; 1503db86aabSstevel 1513db86aabSstevel static struct cb_ops pcic_cbops = { 1523db86aabSstevel pcic_open, 1533db86aabSstevel pcic_close, 1543db86aabSstevel nodev, 1553db86aabSstevel nodev, 1563db86aabSstevel nodev, 1573db86aabSstevel nodev, 1583db86aabSstevel nodev, 1593db86aabSstevel pcic_ioctl, 1603db86aabSstevel nodev, 1613db86aabSstevel nodev, 1623db86aabSstevel nodev, 1633db86aabSstevel nochpoll, 1643db86aabSstevel ddi_prop_op, 1653db86aabSstevel NULL, 1663db86aabSstevel #ifdef CARDBUS 1673db86aabSstevel D_NEW | D_MP | D_HOTPLUG 1683db86aabSstevel #else 1693db86aabSstevel D_NEW | D_MP 1703db86aabSstevel #endif 1713db86aabSstevel }; 1723db86aabSstevel 1733db86aabSstevel static struct dev_ops pcic_devops = { 1743db86aabSstevel DEVO_REV, 1753db86aabSstevel 0, 1763db86aabSstevel pcic_getinfo, 1773db86aabSstevel nulldev, 1783db86aabSstevel pcic_probe, 1793db86aabSstevel pcic_attach, 1803db86aabSstevel pcic_detach, 1813db86aabSstevel nulldev, 1823db86aabSstevel &pcic_cbops, 1833db86aabSstevel &pcmciabus_ops, 1843db86aabSstevel NULL 1853db86aabSstevel }; 1863db86aabSstevel 1873db86aabSstevel void *pcic_soft_state_p = NULL; 1883db86aabSstevel static int pcic_maxinst = -1; 1893db86aabSstevel static timeout_id_t pcic_delayed_resume_toid; 1903db86aabSstevel 1913db86aabSstevel int pcic_do_insertion = 1; 1923db86aabSstevel int pcic_do_removal = 1; 1933db86aabSstevel 1943db86aabSstevel struct irqmap { 1953db86aabSstevel int irq; 1963db86aabSstevel int count; 1973db86aabSstevel } pcic_irq_map[16]; 1983db86aabSstevel 1993db86aabSstevel 2003db86aabSstevel int pcic_debug = 0x0; 2013db86aabSstevel static void pcic_err(dev_info_t *dip, int level, const char *fmt, ...); 2023db86aabSstevel extern void cardbus_dump_pci_config(dev_info_t *dip); 2033db86aabSstevel extern void cardbus_dump_socket(dev_info_t *dip); 2043db86aabSstevel extern int cardbus_validate_iline(dev_info_t *dip, ddi_acc_handle_t handle); 2053db86aabSstevel static void pcic_dump_debqueue(char *msg); 2063db86aabSstevel 2073db86aabSstevel #if defined(PCIC_DEBUG) 2083db86aabSstevel static void xxdmp_all_regs(pcicdev_t *, int, uint32_t); 2093db86aabSstevel 2103db86aabSstevel #define pcic_mutex_enter(a) \ 2113db86aabSstevel { \ 2123db86aabSstevel pcic_err(NULL, 10, "Set lock at %d\n", __LINE__); \ 2133db86aabSstevel mutex_enter(a); \ 2143db86aabSstevel }; 2153db86aabSstevel 2163db86aabSstevel #define pcic_mutex_exit(a) \ 2173db86aabSstevel { \ 2183db86aabSstevel pcic_err(NULL, 10, "Clear lock at %d\n", __LINE__); \ 2193db86aabSstevel mutex_exit(a); \ 2203db86aabSstevel }; 2213db86aabSstevel 2223db86aabSstevel #else 2233db86aabSstevel #define pcic_mutex_enter(a) mutex_enter(a) 2243db86aabSstevel #define pcic_mutex_exit(a) mutex_exit(a) 2253db86aabSstevel #endif 2263db86aabSstevel 2273db86aabSstevel #define PCIC_VCC_3VLEVEL 1 2283db86aabSstevel #define PCIC_VCC_5VLEVEL 2 2293db86aabSstevel #define PCIC_VCC_12LEVEL 3 2303db86aabSstevel 2313db86aabSstevel /* bit patterns to select voltage levels */ 2323db86aabSstevel int pcic_vpp_levels[13] = { 2333db86aabSstevel 0, 0, 0, 2343db86aabSstevel 1, /* 3.3V */ 2353db86aabSstevel 0, 2363db86aabSstevel 1, /* 5V */ 2373db86aabSstevel 0, 0, 0, 0, 0, 0, 2383db86aabSstevel 2 /* 12V */ 2393db86aabSstevel }; 2403db86aabSstevel 2413db86aabSstevel uint8_t pcic_cbv_levels[13] = { 2423db86aabSstevel 0, 0, 0, 2433db86aabSstevel 3, /* 3.3V */ 2443db86aabSstevel 0, 2453db86aabSstevel 2, /* 5V */ 2463db86aabSstevel 0, 0, 0, 0, 0, 0, 2473db86aabSstevel 1 /* 12V */ 2483db86aabSstevel }; 2493db86aabSstevel 2503db86aabSstevel struct power_entry pcic_power[4] = { 2513db86aabSstevel { 2523db86aabSstevel 0, VCC|VPP1|VPP2 2533db86aabSstevel }, 2543db86aabSstevel { 2553db86aabSstevel 33, /* 3.3Volt */ 2563db86aabSstevel VCC|VPP1|VPP2 2573db86aabSstevel }, 2583db86aabSstevel { 2593db86aabSstevel 5*10, /* 5Volt */ 2603db86aabSstevel VCC|VPP1|VPP2 /* currently only know about this */ 2613db86aabSstevel }, 2623db86aabSstevel { 2633db86aabSstevel 12*10, /* 12Volt */ 2643db86aabSstevel VPP1|VPP2 2653db86aabSstevel } 2663db86aabSstevel }; 2673db86aabSstevel 2683db86aabSstevel /* 2693db86aabSstevel * Base used to allocate ranges of PCI memory on x86 systems 2703db86aabSstevel * Each instance gets a chunk above the base that is used to map 2713db86aabSstevel * in the memory and I/O windows for that device. 2723db86aabSstevel * Pages below the base are also allocated for the EXCA registers, 2733db86aabSstevel * one per instance. 2743db86aabSstevel */ 2753db86aabSstevel #define PCIC_PCI_MEMCHUNK 0x1000000 2763db86aabSstevel 2773db86aabSstevel static int pcic_wait_insert_time = 5000000; /* In micro-seconds */ 2783db86aabSstevel static int pcic_debounce_time = 200000; /* In micro-seconds */ 2793db86aabSstevel 2803db86aabSstevel struct debounce { 2813db86aabSstevel pcic_socket_t *pcs; 2823db86aabSstevel clock_t expire; 2833db86aabSstevel struct debounce *next; 2843db86aabSstevel }; 2853db86aabSstevel 2863db86aabSstevel static syshw_t pcic_syshw = { 2873db86aabSstevel 0, "PC Card Socket 0", SH_CONNECTION, 2883db86aabSstevel SYSHW_CAN_SIGNAL_CHANGE|SYSHW_STATE_VALID|SYSHW_VAL0_VALID, 2893db86aabSstevel B_FALSE, {2, 0, 0, 0} 2903db86aabSstevel }; 2913db86aabSstevel 2923db86aabSstevel static struct debounce *pcic_deb_queue = NULL; 2933db86aabSstevel static kmutex_t pcic_deb_mtx; 2943db86aabSstevel static kcondvar_t pcic_deb_cv; 2953db86aabSstevel static kthread_t *pcic_deb_threadid; 2963db86aabSstevel 2973db86aabSstevel static inthandler_t *pcic_handlers; 2983db86aabSstevel 2993db86aabSstevel static void pcic_setup_adapter(pcicdev_t *); 3003db86aabSstevel static int pcic_change(pcicdev_t *, int); 3013db86aabSstevel static int pcic_ll_reset(pcicdev_t *, int); 3023db86aabSstevel static void pcic_mswait(pcicdev_t *, int, int); 3033db86aabSstevel static boolean_t pcic_check_ready(pcicdev_t *, int); 3043db86aabSstevel static void pcic_set_cdtimers(pcicdev_t *, int, uint32_t, int); 3053db86aabSstevel static void pcic_ready_wait(pcicdev_t *, int); 3063db86aabSstevel extern int pcmcia_get_intr(dev_info_t *, int); 3073db86aabSstevel extern int pcmcia_return_intr(dev_info_t *, int); 3083db86aabSstevel 3093db86aabSstevel static int pcic_callback(dev_info_t *, int (*)(), int); 3103db86aabSstevel static int pcic_inquire_adapter(dev_info_t *, inquire_adapter_t *); 3113db86aabSstevel static int pcic_get_adapter(dev_info_t *, get_adapter_t *); 3123db86aabSstevel static int pcic_get_page(dev_info_t *, get_page_t *); 3133db86aabSstevel static int pcic_get_socket(dev_info_t *, get_socket_t *); 3143db86aabSstevel static int pcic_get_status(dev_info_t *, get_ss_status_t *); 3153db86aabSstevel static int pcic_get_window(dev_info_t *, get_window_t *); 3163db86aabSstevel static int pcic_inquire_socket(dev_info_t *, inquire_socket_t *); 3173db86aabSstevel static int pcic_inquire_window(dev_info_t *, inquire_window_t *); 3183db86aabSstevel static int pcic_reset_socket(dev_info_t *, int, int); 3193db86aabSstevel static int pcic_set_page(dev_info_t *, set_page_t *); 3203db86aabSstevel static int pcic_set_window(dev_info_t *, set_window_t *); 3213db86aabSstevel static int pcic_set_socket(dev_info_t *, set_socket_t *); 3223db86aabSstevel static int pcic_set_interrupt(dev_info_t *, set_irq_handler_t *); 3233db86aabSstevel static int pcic_clear_interrupt(dev_info_t *, clear_irq_handler_t *); 3243db86aabSstevel static void pcic_pm_detection(void *); 3253db86aabSstevel static void pcic_iomem_pci_ctl(ddi_acc_handle_t, uchar_t *, unsigned); 3263db86aabSstevel static int clext_reg_read(pcicdev_t *, int, uchar_t); 3273db86aabSstevel static void clext_reg_write(pcicdev_t *, int, uchar_t, uchar_t); 3283db86aabSstevel static int pcic_calc_speed(pcicdev_t *, uint32_t); 3293db86aabSstevel static int pcic_card_state(pcicdev_t *, pcic_socket_t *); 3303db86aabSstevel static int pcic_find_pci_type(pcicdev_t *); 3313db86aabSstevel static void pcic_82092_smiirq_ctl(pcicdev_t *, int, int, int); 3323db86aabSstevel static void pcic_handle_cd_change(pcicdev_t *, pcic_socket_t *, uint8_t); 3333db86aabSstevel static uint_t pcic_cd_softint(caddr_t, caddr_t); 3343db86aabSstevel static uint8_t pcic_getb(pcicdev_t *, int, int); 3353db86aabSstevel static void pcic_putb(pcicdev_t *, int, int, int8_t); 3363db86aabSstevel static int pcic_set_vcc_level(pcicdev_t *, set_socket_t *); 3373db86aabSstevel static uint_t pcic_softintr(caddr_t, caddr_t); 3383db86aabSstevel 3393db86aabSstevel static void pcic_debounce(pcic_socket_t *); 3403db86aabSstevel static void pcic_delayed_resume(void *); 3413db86aabSstevel static void *pcic_add_debqueue(pcic_socket_t *, int); 3423db86aabSstevel static void pcic_rm_debqueue(void *); 3433db86aabSstevel static void pcic_deb_thread(); 3443db86aabSstevel 3453db86aabSstevel static boolean_t pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp); 3463db86aabSstevel static void pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp); 3473db86aabSstevel static uint32_t pcic_getcb(pcicdev_t *pcic, int reg); 3483db86aabSstevel static void pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value); 3493db86aabSstevel static void pcic_cb_enable_intr(dev_info_t *); 3503db86aabSstevel static void pcic_cb_disable_intr(dev_info_t *); 3513db86aabSstevel static void pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq); 3523db86aabSstevel static void pcic_disable_io_intr(pcicdev_t *pcic, int socket); 3533db86aabSstevel 3543db86aabSstevel static cb_nexus_cb_t pcic_cbnexus_ops = { 3553db86aabSstevel pcic_cb_enable_intr, 3563db86aabSstevel pcic_cb_disable_intr 3573db86aabSstevel }; 3583db86aabSstevel 3593db86aabSstevel static int pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel); 3603db86aabSstevel static int pcic_cbus_powerctl(pcicdev_t *pcic, int socket); 3613db86aabSstevel 3623db86aabSstevel static void pcic_syshw_cardstate(syshw_t *, void *); 3633db86aabSstevel 3643db86aabSstevel #if defined(__sparc) 3653db86aabSstevel static int pcic_fault(enum pci_fault_ops op, void *arg); 3663db86aabSstevel #endif 3673db86aabSstevel 3683db86aabSstevel /* 3693db86aabSstevel * Default to support for Voyager IIi if sparc is defined. 3703db86aabSstevel * Appart from the PCI base addresses this only effect the TI1250. 3713db86aabSstevel */ 3723db86aabSstevel #if defined(sparc) 3733db86aabSstevel #define VOYAGER 3743db86aabSstevel #endif 3753db86aabSstevel 3763db86aabSstevel 3773db86aabSstevel /* 3783db86aabSstevel * pcmcia_attach() uses 0 and 128 upwards for the initpcmcia and devctl 3793db86aabSstevel * interfaces so we use 254. 3803db86aabSstevel */ 3813db86aabSstevel #define SYSHW_MINOR 254 3823db86aabSstevel 3833db86aabSstevel /* 3843db86aabSstevel * Forward declarations for syshw interface (See end of file). 3853db86aabSstevel */ 3863db86aabSstevel static void syshw_attach(pcicdev_t *); 3873db86aabSstevel static void syshw_detach(pcicdev_t *); 3883db86aabSstevel static void syshw_resume(pcicdev_t *); 3893db86aabSstevel 3903db86aabSstevel #ifdef VOYAGER 3913db86aabSstevel static uint_t syshw_intr(caddr_t); 3923db86aabSstevel static uint_t syshw_intr_hi(pcicdev_t *); 3933db86aabSstevel #endif 3943db86aabSstevel 3953db86aabSstevel static int syshw_open(dev_t *, int, int, cred_t *); 3963db86aabSstevel static int syshw_close(dev_t, int, int, cred_t *); 3973db86aabSstevel static int syshw_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 3983db86aabSstevel static uint32_t syshw_add2map(syshw_t *, void (*)(syshw_t *, void *), void *); 3993db86aabSstevel static void syshw_send_signal(int); 4003db86aabSstevel 4013db86aabSstevel /* 4023db86aabSstevel * pcmcia interface operations structure 4033db86aabSstevel * this is the private interface that is exported to the nexus 4043db86aabSstevel */ 4053db86aabSstevel pcmcia_if_t pcic_if_ops = { 4063db86aabSstevel PCIF_MAGIC, 4073db86aabSstevel PCIF_VERSION, 4083db86aabSstevel pcic_callback, 4093db86aabSstevel pcic_get_adapter, 4103db86aabSstevel pcic_get_page, 4113db86aabSstevel pcic_get_socket, 4123db86aabSstevel pcic_get_status, 4133db86aabSstevel pcic_get_window, 4143db86aabSstevel pcic_inquire_adapter, 4153db86aabSstevel pcic_inquire_socket, 4163db86aabSstevel pcic_inquire_window, 4173db86aabSstevel pcic_reset_socket, 4183db86aabSstevel pcic_set_page, 4193db86aabSstevel pcic_set_window, 4203db86aabSstevel pcic_set_socket, 4213db86aabSstevel pcic_set_interrupt, 4223db86aabSstevel pcic_clear_interrupt, 4233db86aabSstevel NULL, 4243db86aabSstevel }; 4253db86aabSstevel 4263db86aabSstevel /* 4273db86aabSstevel * chip type identification routines 4283db86aabSstevel * this list of functions is searched until one of them succeeds 4293db86aabSstevel * or all fail. i82365SL is assumed if failed. 4303db86aabSstevel */ 4313db86aabSstevel static int pcic_ci_cirrus(pcicdev_t *); 4323db86aabSstevel static int pcic_ci_vadem(pcicdev_t *); 4333db86aabSstevel static int pcic_ci_ricoh(pcicdev_t *); 4343db86aabSstevel 4353db86aabSstevel int (*pcic_ci_funcs[])(pcicdev_t *) = { 4363db86aabSstevel pcic_ci_cirrus, 4373db86aabSstevel pcic_ci_vadem, 4383db86aabSstevel pcic_ci_ricoh, 4393db86aabSstevel NULL 4403db86aabSstevel }; 4413db86aabSstevel 4423db86aabSstevel static struct modldrv modldrv = { 4433db86aabSstevel &mod_driverops, /* Type of module. This one is a driver */ 4443db86aabSstevel "PCIC PCMCIA adapter driver %I%", /* Name of the module. */ 4453db86aabSstevel &pcic_devops, /* driver ops */ 4463db86aabSstevel }; 4473db86aabSstevel 4483db86aabSstevel static struct modlinkage modlinkage = { 4493db86aabSstevel MODREV_1, (void *)&modldrv, NULL 4503db86aabSstevel }; 4513db86aabSstevel 4523db86aabSstevel int 4533db86aabSstevel _init() 4543db86aabSstevel { 4553db86aabSstevel int stat; 4563db86aabSstevel 4573db86aabSstevel /* Allocate soft state */ 4583db86aabSstevel if ((stat = ddi_soft_state_init(&pcic_soft_state_p, 4593db86aabSstevel SOFTC_SIZE, 2)) != DDI_SUCCESS) 4603db86aabSstevel return (stat); 4613db86aabSstevel 4623db86aabSstevel if ((stat = mod_install(&modlinkage)) != 0) 4633db86aabSstevel ddi_soft_state_fini(&pcic_soft_state_p); 4643db86aabSstevel 4653db86aabSstevel return (stat); 4663db86aabSstevel } 4673db86aabSstevel 4683db86aabSstevel int 4693db86aabSstevel _fini() 4703db86aabSstevel { 4713db86aabSstevel int stat = 0; 4723db86aabSstevel 4733db86aabSstevel if ((stat = mod_remove(&modlinkage)) != 0) 4743db86aabSstevel return (stat); 4753db86aabSstevel 4763db86aabSstevel if (pcic_deb_threadid) { 4773db86aabSstevel mutex_enter(&pcic_deb_mtx); 4783db86aabSstevel pcic_deb_threadid = 0; 4793db86aabSstevel while (!pcic_deb_threadid) 4803db86aabSstevel cv_wait(&pcic_deb_cv, &pcic_deb_mtx); 4813db86aabSstevel pcic_deb_threadid = 0; 4823db86aabSstevel mutex_exit(&pcic_deb_mtx); 4833db86aabSstevel 4843db86aabSstevel mutex_destroy(&pcic_deb_mtx); 4853db86aabSstevel cv_destroy(&pcic_deb_cv); 4863db86aabSstevel } 4873db86aabSstevel 4883db86aabSstevel ddi_soft_state_fini(&pcic_soft_state_p); 4893db86aabSstevel 4903db86aabSstevel return (stat); 4913db86aabSstevel } 4923db86aabSstevel 4933db86aabSstevel int 4943db86aabSstevel _info(struct modinfo *modinfop) 4953db86aabSstevel { 4963db86aabSstevel return (mod_info(&modlinkage, modinfop)); 4973db86aabSstevel } 4983db86aabSstevel 4993db86aabSstevel /* 5003db86aabSstevel * pcic_getinfo() 5013db86aabSstevel * provide instance/device information about driver 5023db86aabSstevel */ 5033db86aabSstevel /*ARGSUSED*/ 5043db86aabSstevel static int 5053db86aabSstevel pcic_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 5063db86aabSstevel { 5073db86aabSstevel anp_t *anp; 5083db86aabSstevel int error = DDI_SUCCESS; 5093db86aabSstevel minor_t minor; 5103db86aabSstevel 5113db86aabSstevel switch (cmd) { 5123db86aabSstevel case DDI_INFO_DEVT2DEVINFO: 5133db86aabSstevel minor = getminor((dev_t)arg); 5143db86aabSstevel if (minor == SYSHW_MINOR) 5153db86aabSstevel minor = 0; 5163db86aabSstevel else 5173db86aabSstevel minor &= 0x7f; 5183db86aabSstevel if (!(anp = ddi_get_soft_state(pcic_soft_state_p, minor))) 5193db86aabSstevel *result = NULL; 5203db86aabSstevel else 5213db86aabSstevel *result = anp->an_dip; 5223db86aabSstevel break; 5233db86aabSstevel case DDI_INFO_DEVT2INSTANCE: 5243db86aabSstevel minor = getminor((dev_t)arg); 5253db86aabSstevel if (minor == SYSHW_MINOR) 5263db86aabSstevel minor = 0; 5273db86aabSstevel else 5283db86aabSstevel minor &= 0x7f; 5293db86aabSstevel *result = (void *)((long)minor); 5303db86aabSstevel break; 5313db86aabSstevel default: 5323db86aabSstevel error = DDI_FAILURE; 5333db86aabSstevel break; 5343db86aabSstevel } 5353db86aabSstevel return (error); 5363db86aabSstevel } 5373db86aabSstevel 5383db86aabSstevel static int 5393db86aabSstevel pcic_probe(dev_info_t *dip) 5403db86aabSstevel { 5413db86aabSstevel int value; 5423db86aabSstevel ddi_device_acc_attr_t attr; 5433db86aabSstevel ddi_acc_handle_t handle; 5443db86aabSstevel uchar_t *index, *data; 5453db86aabSstevel 5463db86aabSstevel if (ddi_dev_is_sid(dip) == DDI_SUCCESS) 5473db86aabSstevel return (DDI_PROBE_DONTCARE); 5483db86aabSstevel 5493db86aabSstevel /* 5503db86aabSstevel * find a PCIC device (any vendor) 5513db86aabSstevel * while there can be up to 4 such devices in 5523db86aabSstevel * a system, we currently only look for 1 5533db86aabSstevel * per probe. There will be up to 2 chips per 5543db86aabSstevel * instance since they share I/O space 5553db86aabSstevel */ 5563db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 5573db86aabSstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 5583db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 5593db86aabSstevel 5603db86aabSstevel if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM, 5613db86aabSstevel (caddr_t *)&index, 5623db86aabSstevel PCIC_ISA_CONTROL_REG_OFFSET, 5633db86aabSstevel PCIC_ISA_CONTROL_REG_LENGTH, 5643db86aabSstevel &attr, &handle) != DDI_SUCCESS) 5653db86aabSstevel return (DDI_PROBE_FAILURE); 5663db86aabSstevel 5673db86aabSstevel data = index + 1; 5683db86aabSstevel 5693db86aabSstevel #if defined(PCIC_DEBUG) 5703db86aabSstevel if (pcic_debug) 5713db86aabSstevel cmn_err(CE_CONT, "pcic_probe: entered\n"); 5723db86aabSstevel if (pcic_debug) 5733db86aabSstevel cmn_err(CE_CONT, "\tindex=%p\n", (void *)index); 5743db86aabSstevel #endif 5753db86aabSstevel ddi_put8(handle, index, PCIC_CHIP_REVISION); 5763db86aabSstevel ddi_put8(handle, data, 0); 5773db86aabSstevel value = ddi_get8(handle, data); 5783db86aabSstevel #if defined(PCIC_DEBUG) 5793db86aabSstevel if (pcic_debug) 5803db86aabSstevel cmn_err(CE_CONT, "\tchip revision register = %x\n", value); 5813db86aabSstevel #endif 5823db86aabSstevel if ((value & PCIC_REV_MASK) >= PCIC_REV_LEVEL_LOW && 5833db86aabSstevel (value & 0x30) == 0) { 5843db86aabSstevel /* 5853db86aabSstevel * we probably have a PCIC chip in the system 5863db86aabSstevel * do a little more checking. If we find one, 5873db86aabSstevel * reset everything in case of softboot 5883db86aabSstevel */ 5893db86aabSstevel ddi_put8(handle, index, PCIC_MAPPING_ENABLE); 5903db86aabSstevel ddi_put8(handle, data, 0); 5913db86aabSstevel value = ddi_get8(handle, data); 5923db86aabSstevel #if defined(PCIC_DEBUG) 5933db86aabSstevel if (pcic_debug) 5943db86aabSstevel cmn_err(CE_CONT, "\tzero test = %x\n", value); 5953db86aabSstevel #endif 5963db86aabSstevel /* should read back as zero */ 5973db86aabSstevel if (value == 0) { 5983db86aabSstevel /* 5993db86aabSstevel * we do have one and it is off the bus 6003db86aabSstevel */ 6013db86aabSstevel #if defined(PCIC_DEBUG) 6023db86aabSstevel if (pcic_debug) 6033db86aabSstevel cmn_err(CE_CONT, "pcic_probe: success\n"); 6043db86aabSstevel #endif 6053db86aabSstevel ddi_regs_map_free(&handle); 6063db86aabSstevel return (DDI_PROBE_SUCCESS); 6073db86aabSstevel } 6083db86aabSstevel } 6093db86aabSstevel #if defined(PCIC_DEBUG) 6103db86aabSstevel if (pcic_debug) 6113db86aabSstevel cmn_err(CE_CONT, "pcic_probe: failed\n"); 6123db86aabSstevel #endif 6133db86aabSstevel ddi_regs_map_free(&handle); 6143db86aabSstevel return (DDI_PROBE_FAILURE); 6153db86aabSstevel } 6163db86aabSstevel 6173db86aabSstevel /* 6183db86aabSstevel * These are just defaults they can also be changed via a property in the 6193db86aabSstevel * conf file. 6203db86aabSstevel */ 6213db86aabSstevel static int pci_config_reg_num = PCIC_PCI_CONFIG_REG_NUM; 6223db86aabSstevel static int pci_control_reg_num = PCIC_PCI_CONTROL_REG_NUM; 6233db86aabSstevel static int pcic_do_pcmcia_sr = 0; 6243db86aabSstevel static int pcic_use_cbpwrctl = PCF_CBPWRCTL; 6253db86aabSstevel 6263db86aabSstevel /* 6273db86aabSstevel * enable insertion/removal interrupt for 32bit cards 6283db86aabSstevel */ 6293db86aabSstevel static int 6303db86aabSstevel cardbus_enable_cd_intr(dev_info_t *dip) 6313db86aabSstevel { 6323db86aabSstevel ddi_acc_handle_t iohandle; 6333db86aabSstevel caddr_t ioaddr; 6343db86aabSstevel ddi_device_acc_attr_t attr; 6353db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 6363db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 6373db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 6383db86aabSstevel (void) ddi_regs_map_setup(dip, 1, 6393db86aabSstevel (caddr_t *)&ioaddr, 6403db86aabSstevel 0, 6413db86aabSstevel 4096, 6423db86aabSstevel &attr, &iohandle); 6433db86aabSstevel 6443db86aabSstevel /* CSC Interrupt: Card detect interrupt on */ 6453db86aabSstevel ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK), 6463db86aabSstevel ddi_get32(iohandle, 6473db86aabSstevel (uint32_t *)(ioaddr+CB_STATUS_MASK)) | CB_SE_CCDMASK); 6483db86aabSstevel 6493db86aabSstevel ddi_put32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT), 6503db86aabSstevel ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT))); 6513db86aabSstevel 6523db86aabSstevel ddi_regs_map_free(&iohandle); 6533db86aabSstevel return (1); 6543db86aabSstevel } 6553db86aabSstevel 6563db86aabSstevel /* 6573db86aabSstevel * pcic_attach() 6583db86aabSstevel * attach the PCIC (Intel 82365SL/CirrusLogic/Toshiba) driver 6593db86aabSstevel * to the system. This is a child of "sysbus" since that is where 6603db86aabSstevel * the hardware lives, but it provides services to the "pcmcia" 6613db86aabSstevel * nexus driver. It gives a pointer back via its private data 6623db86aabSstevel * structure which contains both the dip and socket services entry 6633db86aabSstevel * points 6643db86aabSstevel */ 6653db86aabSstevel static int 6663db86aabSstevel pcic_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 6673db86aabSstevel { 6683db86aabSstevel anp_t *pcic_nexus; 6693db86aabSstevel pcicdev_t *pcic; 6703db86aabSstevel int irqlevel, value; 6713db86aabSstevel int pci_cfrn, pci_ctrn; 6723db86aabSstevel int i, j, smi, actual; 6733db86aabSstevel char *typename; 6743db86aabSstevel char bus_type[16] = "(unknown)"; 6753db86aabSstevel int len = sizeof (bus_type); 6763db86aabSstevel ddi_device_acc_attr_t attr; 6773db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 6783db86aabSstevel uint_t pri; 6793db86aabSstevel syshw_t *shwp; 6803db86aabSstevel 6813db86aabSstevel #if defined(PCIC_DEBUG) 6823db86aabSstevel if (pcic_debug) { 6833db86aabSstevel cmn_err(CE_CONT, "pcic_attach: entered\n"); 6843db86aabSstevel } 6853db86aabSstevel #endif 6863db86aabSstevel switch (cmd) { 6873db86aabSstevel case DDI_ATTACH: 6883db86aabSstevel break; 6893db86aabSstevel case DDI_RESUME: 6903db86aabSstevel pcic = anp->an_private; 6913db86aabSstevel /* 6923db86aabSstevel * for now, this is a simulated resume. 6933db86aabSstevel * a real one may need different things. 6943db86aabSstevel */ 6953db86aabSstevel if (pcic != NULL && pcic->pc_flags & PCF_SUSPENDED) { 6963db86aabSstevel mutex_enter(&pcic->pc_lock); 6973db86aabSstevel /* should probe for new sockets showing up */ 6983db86aabSstevel pcic_setup_adapter(pcic); 6993db86aabSstevel syshw_resume(pcic); 7003db86aabSstevel pcic->pc_flags &= ~PCF_SUSPENDED; 7013db86aabSstevel mutex_exit(&pcic->pc_lock); 7023db86aabSstevel (void) pcmcia_begin_resume(dip); 7033db86aabSstevel /* 7043db86aabSstevel * this will do the CARD_INSERTION 7053db86aabSstevel * due to needing time for threads to 7063db86aabSstevel * run, it must be delayed for a short amount 7073db86aabSstevel * of time. pcmcia_wait_insert checks for all 7083db86aabSstevel * children to be removed and then triggers insert. 7093db86aabSstevel */ 7103db86aabSstevel /* 7113db86aabSstevel * The reason for having a single timeout here 7123db86aabSstevel * rather than seperate timeout()s for each instance 7133db86aabSstevel * is due to the limited number (2) of callout threads 7143db86aabSstevel * available in Solaris 2.6. A single 1250A ends up 7153db86aabSstevel * as two instances of the interface with one slot each. 7163db86aabSstevel * The pcic_delayed_resume() function ends by calling 7173db86aabSstevel * pcmcia_wait_insert() which at one point does a 7183db86aabSstevel * delay(). delay() is implemented with a timeout() 7193db86aabSstevel * call so you end up with both the callout() 7203db86aabSstevel * threads waiting to be woken up by another callout(). 7213db86aabSstevel * This situation locks up the machine hence the 7223db86aabSstevel * convolution here to only use one timeout. 7233db86aabSstevel */ 7243db86aabSstevel if (!pcic_delayed_resume_toid) 7253db86aabSstevel pcic_delayed_resume_toid = 7263db86aabSstevel timeout(pcic_delayed_resume, (caddr_t)0, 7273db86aabSstevel drv_usectohz(pcic_wait_insert_time)); 7283db86aabSstevel 7293db86aabSstevel /* 7303db86aabSstevel * for complete implementation need END_RESUME (later) 7313db86aabSstevel */ 7323db86aabSstevel return (DDI_SUCCESS); 7333db86aabSstevel 7343db86aabSstevel } 7353db86aabSstevel return (DDI_SUCCESS); 7363db86aabSstevel default: 7373db86aabSstevel return (DDI_FAILURE); 7383db86aabSstevel } 7393db86aabSstevel 7403db86aabSstevel /* 7413db86aabSstevel * Allocate soft state associated with this instance. 7423db86aabSstevel */ 7433db86aabSstevel if (ddi_soft_state_zalloc(pcic_soft_state_p, 7443db86aabSstevel ddi_get_instance(dip)) != DDI_SUCCESS) { 7453db86aabSstevel cmn_err(CE_CONT, "pcic%d: Unable to alloc state\n", 7463db86aabSstevel ddi_get_instance(dip)); 7473db86aabSstevel return (DDI_FAILURE); 7483db86aabSstevel } 7493db86aabSstevel 7503db86aabSstevel pcic_nexus = ddi_get_soft_state(pcic_soft_state_p, 7513db86aabSstevel ddi_get_instance(dip)); 7523db86aabSstevel 7533db86aabSstevel pcic = kmem_zalloc(sizeof (pcicdev_t), KM_SLEEP); 7543db86aabSstevel 7553db86aabSstevel pcic->dip = dip; 7563db86aabSstevel pcic_nexus->an_dip = dip; 7573db86aabSstevel pcic_nexus->an_if = &pcic_if_ops; 7583db86aabSstevel pcic_nexus->an_private = pcic; 7593db86aabSstevel pcic->pc_numpower = sizeof (pcic_power)/sizeof (pcic_power[0]); 7603db86aabSstevel pcic->pc_power = pcic_power; 7613db86aabSstevel 7623db86aabSstevel pci_ctrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 7633db86aabSstevel "pci-control-reg-number", pci_control_reg_num); 7643db86aabSstevel pci_cfrn = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 7653db86aabSstevel "pci-config-reg-number", pci_config_reg_num); 7663db86aabSstevel 7673db86aabSstevel ddi_set_driver_private(dip, pcic_nexus); 7683db86aabSstevel 7693db86aabSstevel /* 7703db86aabSstevel * pcic->pc_irq is really the IPL level we want to run at 7713db86aabSstevel * set the default values here and override from intr spec 7723db86aabSstevel */ 7733db86aabSstevel pcic->pc_irq = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 7743db86aabSstevel "interrupt-priorities", -1); 7753db86aabSstevel 7763db86aabSstevel if (pcic->pc_irq == -1) { 7773db86aabSstevel int actual; 7783db86aabSstevel uint_t pri; 7793db86aabSstevel ddi_intr_handle_t hdl; 7803db86aabSstevel 7813db86aabSstevel /* see if intrspec tells us different */ 7823db86aabSstevel if (ddi_intr_alloc(dip, &hdl, DDI_INTR_TYPE_FIXED, 7833db86aabSstevel 0, 1, &actual, DDI_INTR_ALLOC_NORMAL) == DDI_SUCCESS) { 7843db86aabSstevel if (ddi_intr_get_pri(hdl, &pri) == DDI_SUCCESS) 7853db86aabSstevel pcic->pc_irq = pri; 7863db86aabSstevel else 7873db86aabSstevel pcic->pc_irq = LOCK_LEVEL + 1; 7883db86aabSstevel (void) ddi_intr_free(hdl); 7893db86aabSstevel } 7903db86aabSstevel } 7913db86aabSstevel pcic_nexus->an_ipl = pcic->pc_irq; 7923db86aabSstevel 7933db86aabSstevel /* 7943db86aabSstevel * Check our parent bus type. We do different things based on which 7953db86aabSstevel * bus we're on. 7963db86aabSstevel */ 7973db86aabSstevel if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip), 7983db86aabSstevel PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP, 7993db86aabSstevel "device_type", (caddr_t)&bus_type[0], &len) != 8003db86aabSstevel DDI_PROP_SUCCESS) { 8013db86aabSstevel if (ddi_prop_op(DDI_DEV_T_ANY, ddi_get_parent(dip), 8023db86aabSstevel PROP_LEN_AND_VAL_BUF, DDI_PROP_CANSLEEP, 8033db86aabSstevel "bus-type", (caddr_t)&bus_type[0], &len) != 8043db86aabSstevel DDI_PROP_SUCCESS) { 8053db86aabSstevel 8063db86aabSstevel cmn_err(CE_CONT, 8073db86aabSstevel "pcic%d: can't find parent bus type\n", 8083db86aabSstevel ddi_get_instance(dip)); 8093db86aabSstevel 8103db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 811*b8a60a54Srw148561 ddi_soft_state_free(pcic_soft_state_p, 812*b8a60a54Srw148561 ddi_get_instance(dip)); 8133db86aabSstevel return (DDI_FAILURE); 8143db86aabSstevel } 8153db86aabSstevel } /* ddi_prop_op("device_type") */ 8163db86aabSstevel 8178134ee03Srw148561 if (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 || 8188134ee03Srw148561 strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0) { 8193db86aabSstevel pcic->pc_flags = PCF_PCIBUS; 8203db86aabSstevel } else { 821*b8a60a54Srw148561 cmn_err(CE_WARN, "!pcic%d: non-pci mode (%s) not supported, " 822*b8a60a54Srw148561 "set BIOS to yenta mode if applicable\n", 8233db86aabSstevel ddi_get_instance(dip), bus_type); 8243db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 825*b8a60a54Srw148561 ddi_soft_state_free(pcic_soft_state_p, 826*b8a60a54Srw148561 ddi_get_instance(dip)); 8273db86aabSstevel return (DDI_FAILURE); 8283db86aabSstevel } 8293db86aabSstevel 8303db86aabSstevel if ((pcic->bus_speed = ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), 8313db86aabSstevel DDI_PROP_CANSLEEP, 8323db86aabSstevel "clock-frequency", 0)) == 0) { 8333db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) 8343db86aabSstevel pcic->bus_speed = PCIC_PCI_DEF_SYSCLK; 8353db86aabSstevel else 8363db86aabSstevel pcic->bus_speed = PCIC_ISA_DEF_SYSCLK; 8373db86aabSstevel } else { 8383db86aabSstevel /* 8393db86aabSstevel * OBP can declare the speed in Hz... 8403db86aabSstevel */ 8413db86aabSstevel if (pcic->bus_speed > 1000000) 8423db86aabSstevel pcic->bus_speed /= 1000000; 8433db86aabSstevel } /* ddi_prop_op("clock-frequency") */ 8443db86aabSstevel 8453db86aabSstevel pcic->pc_io_type = PCIC_IO_TYPE_82365SL; /* default mode */ 8463db86aabSstevel 8473db86aabSstevel #ifdef PCIC_DEBUG 8483db86aabSstevel if (pcic_debug) { 8493db86aabSstevel cmn_err(CE_CONT, 8503db86aabSstevel "pcic%d: parent bus type = [%s], speed = %d MHz\n", 8513db86aabSstevel ddi_get_instance(dip), 8523db86aabSstevel bus_type, pcic->bus_speed); 8533db86aabSstevel } 8543db86aabSstevel #endif 8553db86aabSstevel 8563db86aabSstevel /* 8573db86aabSstevel * The reg properties on a PCI node are different than those 8583db86aabSstevel * on a non-PCI node. Handle that difference here. 8593db86aabSstevel * If it turns out to be a CardBus chip, we have even more 8603db86aabSstevel * differences. 8613db86aabSstevel */ 8623db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) { 8633db86aabSstevel int class_code; 8643db86aabSstevel #if defined(__i386) || defined(__amd64) 8653db86aabSstevel pcic->pc_base = 0x1000000; 8663db86aabSstevel pcic->pc_bound = (uint32_t)~0; 8673db86aabSstevel pcic->pc_iobase = 0x1000; 8683db86aabSstevel pcic->pc_iobound = 0xefff; 8693db86aabSstevel #elif defined(__sparc) 8703db86aabSstevel pcic->pc_base = 0x0; 8713db86aabSstevel pcic->pc_bound = (uint32_t)~0; 8723db86aabSstevel pcic->pc_iobase = 0x00000; 8733db86aabSstevel pcic->pc_iobound = 0xffff; 8743db86aabSstevel #endif 8753db86aabSstevel 8763db86aabSstevel /* usually need to get at config space so map first */ 8773db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 8783db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 8793db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 8803db86aabSstevel 8813db86aabSstevel if (ddi_regs_map_setup(dip, pci_cfrn, 8823db86aabSstevel (caddr_t *)&pcic->cfgaddr, 8833db86aabSstevel PCIC_PCI_CONFIG_REG_OFFSET, 8843db86aabSstevel PCIC_PCI_CONFIG_REG_LENGTH, 8853db86aabSstevel &attr, 8863db86aabSstevel &pcic->cfg_handle) != 8873db86aabSstevel DDI_SUCCESS) { 8883db86aabSstevel cmn_err(CE_CONT, 8893db86aabSstevel "pcic%d: unable to map config space" 8903db86aabSstevel "regs\n", 8913db86aabSstevel ddi_get_instance(dip)); 8923db86aabSstevel 8933db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 8943db86aabSstevel return (DDI_FAILURE); 8953db86aabSstevel } /* ddi_regs_map_setup */ 8963db86aabSstevel 8973db86aabSstevel class_code = ddi_getprop(DDI_DEV_T_ANY, dip, 8983db86aabSstevel DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 8993db86aabSstevel "class-code", -1); 9003db86aabSstevel #ifdef PCIC_DEBUG 9013db86aabSstevel if (pcic_debug) { 9023db86aabSstevel cmn_err(CE_CONT, "pcic_attach class_code=%x\n", 9033db86aabSstevel class_code); 9043db86aabSstevel } 9053db86aabSstevel #endif 9063db86aabSstevel 9073db86aabSstevel switch (class_code) { 9083db86aabSstevel case PCIC_PCI_CARDBUS: 9093db86aabSstevel pcic->pc_flags |= PCF_CARDBUS; 9103db86aabSstevel pcic->pc_io_type = PCIC_IO_TYPE_YENTA; 9113db86aabSstevel /* 9123db86aabSstevel * Get access to the adapter registers on the 9133db86aabSstevel * PCI bus. A 4K memory page 9143db86aabSstevel */ 9153db86aabSstevel #if defined(PCIC_DEBUG) 9163db86aabSstevel pcic_err(dip, 8, "Is Cardbus device\n"); 9173db86aabSstevel if (pcic_debug) { 9183db86aabSstevel int nr; 9193db86aabSstevel long rs; 9203db86aabSstevel (void) ddi_dev_nregs(dip, &nr); 9213db86aabSstevel pcic_err(dip, 9, "\tdev, cfgaddr 0x%p," 9223db86aabSstevel "cfghndl 0x%p nregs %d", 9233db86aabSstevel (void *)pcic->cfgaddr, 9243db86aabSstevel (void *)pcic->cfg_handle, nr); 9253db86aabSstevel 9263db86aabSstevel (void) ddi_dev_regsize(dip, 9273db86aabSstevel PCIC_PCI_CONTROL_REG_NUM, &rs); 9283db86aabSstevel 9293db86aabSstevel pcic_err(dip, 9, "\tsize of reg %d is 0x%x\n", 9303db86aabSstevel PCIC_PCI_CONTROL_REG_NUM, (int)rs); 9313db86aabSstevel } 9323db86aabSstevel #endif 9333db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 9343db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 9353db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 9363db86aabSstevel 9373db86aabSstevel if (ddi_regs_map_setup(dip, pci_ctrn, 9383db86aabSstevel (caddr_t *)&pcic->ioaddr, 9393db86aabSstevel PCIC_PCI_CONTROL_REG_OFFSET, 9403db86aabSstevel PCIC_CB_CONTROL_REG_LENGTH, 9413db86aabSstevel &attr, &pcic->handle) != 9423db86aabSstevel DDI_SUCCESS) { 9433db86aabSstevel cmn_err(CE_CONT, 9443db86aabSstevel "pcic%d: unable to map PCI regs\n", 9453db86aabSstevel ddi_get_instance(dip)); 9463db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 9473db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 9483db86aabSstevel return (DDI_FAILURE); 9493db86aabSstevel } /* ddi_regs_map_setup */ 9503db86aabSstevel 9513db86aabSstevel /* 9523db86aabSstevel * Find out the chip type - If we're on a PCI bus, 9533db86aabSstevel * the adapter has that information in the PCI 9543db86aabSstevel * config space. 9553db86aabSstevel * Note that we call pcic_find_pci_type here since 9563db86aabSstevel * it needs a valid mapped pcic->handle to 9573db86aabSstevel * access some of the adapter registers in 9583db86aabSstevel * some cases. 9593db86aabSstevel */ 9603db86aabSstevel if (pcic_find_pci_type(pcic) != DDI_SUCCESS) { 9613db86aabSstevel ddi_regs_map_free(&pcic->handle); 9623db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 9633db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 9643db86aabSstevel cmn_err(CE_WARN, "pcic: %s: unsupported " 9653db86aabSstevel "bridge\n", 9663db86aabSstevel ddi_get_name_addr(dip)); 9673db86aabSstevel return (DDI_FAILURE); 9683db86aabSstevel } 9693db86aabSstevel break; 9703db86aabSstevel 9713db86aabSstevel default: 9723db86aabSstevel case PCIC_PCI_PCMCIA: 9733db86aabSstevel /* 9743db86aabSstevel * Get access to the adapter IO registers on the 9753db86aabSstevel * PCI bus config space. 9763db86aabSstevel */ 9773db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 9783db86aabSstevel attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 9793db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 9803db86aabSstevel 9813db86aabSstevel /* 9823db86aabSstevel * We need a default mapping to the adapter's IO 9833db86aabSstevel * control register space. For most adapters 9843db86aabSstevel * that are of class PCIC_PCI_PCMCIA (or of 9853db86aabSstevel * a default class) the control registers 9863db86aabSstevel * will be using the 82365-type control/data 9873db86aabSstevel * format. 9883db86aabSstevel */ 9893db86aabSstevel if (ddi_regs_map_setup(dip, pci_ctrn, 9903db86aabSstevel (caddr_t *)&pcic->ioaddr, 9913db86aabSstevel PCIC_PCI_CONTROL_REG_OFFSET, 9923db86aabSstevel PCIC_PCI_CONTROL_REG_LENGTH, 9933db86aabSstevel &attr, 9943db86aabSstevel &pcic->handle) != DDI_SUCCESS) { 9953db86aabSstevel cmn_err(CE_CONT, 9963db86aabSstevel "pcic%d: unable to map PCI regs\n", 9973db86aabSstevel ddi_get_instance(dip)); 9983db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 9993db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 10003db86aabSstevel return (DDI_FAILURE); 10013db86aabSstevel } /* ddi_regs_map_setup */ 10023db86aabSstevel 10033db86aabSstevel /* 10043db86aabSstevel * Find out the chip type - If we're on a PCI bus, 10053db86aabSstevel * the adapter has that information in the PCI 10063db86aabSstevel * config space. 10073db86aabSstevel * Note that we call pcic_find_pci_type here since 10083db86aabSstevel * it needs a valid mapped pcic->handle to 10093db86aabSstevel * access some of the adapter registers in 10103db86aabSstevel * some cases. 10113db86aabSstevel */ 10123db86aabSstevel if (pcic_find_pci_type(pcic) != DDI_SUCCESS) { 10133db86aabSstevel ddi_regs_map_free(&pcic->handle); 10143db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 10153db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 10163db86aabSstevel cmn_err(CE_WARN, "pcic: %s: unsupported " 10173db86aabSstevel "bridge\n", 10183db86aabSstevel ddi_get_name_addr(dip)); 10193db86aabSstevel return (DDI_FAILURE); 10203db86aabSstevel } 10213db86aabSstevel 10223db86aabSstevel /* 10233db86aabSstevel * Some PCI-PCMCIA(R2) adapters are Yenta-compliant 10243db86aabSstevel * for extended registers even though they are 10253db86aabSstevel * not CardBus adapters. For those adapters, 10263db86aabSstevel * re-map pcic->handle to be large enough to 10273db86aabSstevel * encompass the Yenta registers. 10283db86aabSstevel */ 10293db86aabSstevel switch (pcic->pc_type) { 10303db86aabSstevel case PCIC_TI_PCI1031: 10313db86aabSstevel ddi_regs_map_free(&pcic->handle); 10323db86aabSstevel 10333db86aabSstevel if (ddi_regs_map_setup(dip, 10343db86aabSstevel PCIC_PCI_CONTROL_REG_NUM, 10353db86aabSstevel (caddr_t *)&pcic->ioaddr, 10363db86aabSstevel PCIC_PCI_CONTROL_REG_OFFSET, 10373db86aabSstevel PCIC_CB_CONTROL_REG_LENGTH, 10383db86aabSstevel &attr, 10393db86aabSstevel &pcic->handle) != DDI_SUCCESS) { 10403db86aabSstevel cmn_err(CE_CONT, 10413db86aabSstevel "pcic%d: unable to map " 10423db86aabSstevel "PCI regs\n", 10433db86aabSstevel ddi_get_instance(dip)); 10443db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 10453db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 10463db86aabSstevel return (DDI_FAILURE); 10473db86aabSstevel } /* ddi_regs_map_setup */ 10483db86aabSstevel break; 10493db86aabSstevel default: 10503db86aabSstevel break; 10513db86aabSstevel } /* switch (pcic->pc_type) */ 10523db86aabSstevel break; 10533db86aabSstevel } /* switch (class_code) */ 10543db86aabSstevel } else { 10553db86aabSstevel /* 10563db86aabSstevel * We're not on a PCI bus, so assume an ISA bus type 10573db86aabSstevel * register property. Get access to the adapter IO 10583db86aabSstevel * registers on a non-PCI bus. 10593db86aabSstevel */ 10603db86aabSstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 10613db86aabSstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 10623db86aabSstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 10633db86aabSstevel pcic->mem_reg_num = PCIC_ISA_MEM_REG_NUM; 10643db86aabSstevel pcic->io_reg_num = PCIC_ISA_IO_REG_NUM; 10653db86aabSstevel 10663db86aabSstevel if (ddi_regs_map_setup(dip, PCIC_ISA_CONTROL_REG_NUM, 10673db86aabSstevel (caddr_t *)&pcic->ioaddr, 10683db86aabSstevel PCIC_ISA_CONTROL_REG_OFFSET, 10693db86aabSstevel PCIC_ISA_CONTROL_REG_LENGTH, 10703db86aabSstevel &attr, 10713db86aabSstevel &pcic->handle) != DDI_SUCCESS) { 10723db86aabSstevel cmn_err(CE_CONT, 10733db86aabSstevel "pcic%d: unable to map ISA registers\n", 10743db86aabSstevel ddi_get_instance(dip)); 10753db86aabSstevel 10763db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 10773db86aabSstevel return (DDI_FAILURE); 10783db86aabSstevel } /* ddi_regs_map_setup */ 10793db86aabSstevel 10803db86aabSstevel /* ISA bus is limited to 24-bits, but not first 640K */ 10813db86aabSstevel pcic->pc_base = 0xd0000; 10823db86aabSstevel pcic->pc_bound = (uint32_t)~0; 10833db86aabSstevel pcic->pc_iobase = 0x1000; 10843db86aabSstevel pcic->pc_iobound = 0xefff; 10853db86aabSstevel } /* !PCF_PCIBUS */ 10863db86aabSstevel 10873db86aabSstevel #ifdef PCIC_DEBUG 10883db86aabSstevel if (pcic_debug) { 10893db86aabSstevel cmn_err(CE_CONT, "pcic_attach pc_flags=%x pc_type=%x\n", 10903db86aabSstevel pcic->pc_flags, pcic->pc_type); 10913db86aabSstevel } 10923db86aabSstevel #endif 10933db86aabSstevel 10943db86aabSstevel /* 10953db86aabSstevel * Setup various adapter registers for the PCI case. For the 10963db86aabSstevel * non-PCI case, find out the chip type. 10973db86aabSstevel */ 10983db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) { 10993db86aabSstevel int iline; 11003db86aabSstevel #if defined(__sparc) 11013db86aabSstevel iline = 0; 11023db86aabSstevel #else 11033db86aabSstevel iline = cardbus_validate_iline(dip, pcic->cfg_handle); 11043db86aabSstevel #endif 11053db86aabSstevel 11063db86aabSstevel /* set flags and socket counts based on chip type */ 11073db86aabSstevel switch (pcic->pc_type) { 11083db86aabSstevel uint32_t cfg; 11093db86aabSstevel case PCIC_INTEL_i82092: 11103db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 11113db86aabSstevel pcic->cfgaddr + PCIC_82092_PCICON); 11123db86aabSstevel /* we can only support 4 Socket version */ 11133db86aabSstevel if (cfg & PCIC_82092_4_SOCKETS) { 11143db86aabSstevel pcic->pc_numsockets = 4; 11153db86aabSstevel pcic->pc_type = PCIC_INTEL_i82092; 11163db86aabSstevel if (iline != 0xFF) 11173db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 11183db86aabSstevel else 11193db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA; 11203db86aabSstevel } else { 11213db86aabSstevel cmn_err(CE_CONT, 11223db86aabSstevel "pcic%d: Intel 82092 adapter " 11233db86aabSstevel "in unsupported configuration: 0x%x", 11243db86aabSstevel ddi_get_instance(pcic->dip), cfg); 11253db86aabSstevel pcic->pc_numsockets = 0; 11263db86aabSstevel } /* PCIC_82092_4_SOCKETS */ 11273db86aabSstevel break; 11283db86aabSstevel case PCIC_CL_PD6730: 11293db86aabSstevel case PCIC_CL_PD6729: 11303db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 11313db86aabSstevel cfg = ddi_getprop(DDI_DEV_T_ANY, dip, 11323db86aabSstevel DDI_PROP_CANSLEEP, 11333db86aabSstevel "interrupts", 0); 11343db86aabSstevel /* if not interrupt pin then must use ISA style IRQs */ 11353db86aabSstevel if (cfg == 0 || iline == 0xFF) 11363db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA; 11373db86aabSstevel else { 11383db86aabSstevel /* 11393db86aabSstevel * we have the option to use PCI interrupts. 11403db86aabSstevel * this might not be optimal but in some cases 11413db86aabSstevel * is the only thing possible (sparc case). 11423db86aabSstevel * we now deterine what is possible. 11433db86aabSstevel */ 11443db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 11453db86aabSstevel } 11463db86aabSstevel pcic->pc_numsockets = 2; 11473db86aabSstevel pcic->pc_flags |= PCF_IO_REMAP; 11483db86aabSstevel break; 11493db86aabSstevel case PCIC_TI_PCI1031: 11503db86aabSstevel /* this chip doesn't do CardBus but looks like one */ 11513db86aabSstevel pcic->pc_flags &= ~PCF_CARDBUS; 11523db86aabSstevel /* FALLTHROUGH */ 11533db86aabSstevel default: 11543db86aabSstevel pcic->pc_flags |= PCF_IO_REMAP; 11553db86aabSstevel /* FALLTHROUGH */ 11563db86aabSstevel /* indicate feature even if not supported */ 11573db86aabSstevel pcic->pc_flags |= PCF_DMA | PCF_ZV; 11583db86aabSstevel /* Not sure if these apply to all these chips */ 11593db86aabSstevel pcic->pc_flags |= (PCF_VPPX|PCF_33VCAP); 11603db86aabSstevel pcic->pc_flags |= pcic_use_cbpwrctl; 11613db86aabSstevel 11623db86aabSstevel pcic->pc_numsockets = 1; /* one per function */ 11633db86aabSstevel if (iline != 0xFF) { 11643db86aabSstevel uint8_t cfg; 11653db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_PCI_1; 11663db86aabSstevel 11673db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 11683db86aabSstevel (pcic->cfgaddr + PCIC_BRIDGE_CTL_REG)); 11693db86aabSstevel cfg &= (~PCIC_FUN_INT_MOD_ISA); 11703db86aabSstevel ddi_put8(pcic->cfg_handle, (pcic->cfgaddr + 11713db86aabSstevel PCIC_BRIDGE_CTL_REG), cfg); 11723db86aabSstevel } 11733db86aabSstevel else 11743db86aabSstevel pcic->pc_intr_mode = PCIC_INTR_MODE_ISA; 11753db86aabSstevel pcic->pc_io_type = PCIC_IOTYPE_YENTA; 11763db86aabSstevel break; 11773db86aabSstevel } 11783db86aabSstevel } else { 11793db86aabSstevel /* 11803db86aabSstevel * We're not on a PCI bus so do some more 11813db86aabSstevel * checking for adapter type here. 11823db86aabSstevel * For the non-PCI bus case: 11833db86aabSstevel * It could be any one of a number of different chips 11843db86aabSstevel * If we can't determine anything else, it is assumed 11853db86aabSstevel * to be an Intel 82365SL. The Cirrus Logic PD6710 11863db86aabSstevel * has an extension register that provides unique 11873db86aabSstevel * identification. Toshiba chip isn't detailed as yet. 11883db86aabSstevel */ 11893db86aabSstevel 11903db86aabSstevel /* Init the CL id mode */ 11913db86aabSstevel pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0); 11923db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 11933db86aabSstevel 11943db86aabSstevel /* default to Intel i82365SL and then refine */ 11953db86aabSstevel pcic->pc_type = PCIC_I82365SL; 11963db86aabSstevel pcic->pc_chipname = PCIC_TYPE_I82365SL; 11973db86aabSstevel for (value = 0; pcic_ci_funcs[value] != NULL; value++) { 11983db86aabSstevel /* go until one succeeds or none left */ 11993db86aabSstevel if (pcic_ci_funcs[value](pcic)) 12003db86aabSstevel break; 12013db86aabSstevel } 12023db86aabSstevel 12033db86aabSstevel /* any chip specific flags get set here */ 12043db86aabSstevel switch (pcic->pc_type) { 12053db86aabSstevel case PCIC_CL_PD6722: 12063db86aabSstevel pcic->pc_flags |= PCF_DMA; 12073db86aabSstevel } 12083db86aabSstevel 12093db86aabSstevel for (i = 0; i < PCIC_MAX_SOCKETS; i++) { 12103db86aabSstevel /* 12113db86aabSstevel * look for total number of sockets. 12123db86aabSstevel * basically check each possible socket for 12133db86aabSstevel * presence like in probe 12143db86aabSstevel */ 12153db86aabSstevel 12163db86aabSstevel /* turn all windows off */ 12173db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 12183db86aabSstevel value = pcic_getb(pcic, i, PCIC_MAPPING_ENABLE); 12193db86aabSstevel 12203db86aabSstevel /* 12213db86aabSstevel * if a zero is read back, then this socket 12223db86aabSstevel * might be present. It would be except for 12233db86aabSstevel * some systems that map the secondary PCIC 12243db86aabSstevel * chip space back to the first. 12253db86aabSstevel */ 12263db86aabSstevel if (value != 0) { 12273db86aabSstevel /* definitely not so skip */ 12283db86aabSstevel /* note: this is for Compaq support */ 12293db86aabSstevel continue; 12303db86aabSstevel } 12313db86aabSstevel 12323db86aabSstevel /* further tests */ 12333db86aabSstevel value = pcic_getb(pcic, i, PCIC_CHIP_REVISION) & 12343db86aabSstevel PCIC_REV_MASK; 12353db86aabSstevel if (!(value >= PCIC_REV_LEVEL_LOW && 12363db86aabSstevel value <= PCIC_REV_LEVEL_HI)) 12373db86aabSstevel break; 12383db86aabSstevel 12393db86aabSstevel pcic_putb(pcic, i, PCIC_SYSMEM_0_STARTLOW, 0xaa); 12403db86aabSstevel pcic_putb(pcic, i, PCIC_SYSMEM_1_STARTLOW, 0x55); 12413db86aabSstevel value = pcic_getb(pcic, i, PCIC_SYSMEM_0_STARTLOW); 12423db86aabSstevel 12433db86aabSstevel j = pcic_getb(pcic, i, PCIC_SYSMEM_1_STARTLOW); 12443db86aabSstevel if (value != 0xaa || j != 0x55) 12453db86aabSstevel break; 12463db86aabSstevel 12473db86aabSstevel /* 12483db86aabSstevel * at this point we know if we have hardware 12493db86aabSstevel * of some type and not just the bus holding 12503db86aabSstevel * a pattern for us. We still have to determine 12513db86aabSstevel * the case where more than 2 sockets are 12523db86aabSstevel * really the same due to peculiar mappings of 12533db86aabSstevel * hardware. 12543db86aabSstevel */ 12553db86aabSstevel j = pcic->pc_numsockets++; 12563db86aabSstevel pcic->pc_sockets[j].pcs_flags = 0; 12573db86aabSstevel pcic->pc_sockets[j].pcs_io = pcic->ioaddr; 12583db86aabSstevel pcic->pc_sockets[j].pcs_socket = i; 12593db86aabSstevel 12603db86aabSstevel /* put PC Card into RESET, just in case */ 12613db86aabSstevel value = pcic_getb(pcic, i, PCIC_INTERRUPT); 12623db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 12633db86aabSstevel value & ~PCIC_RESET); 12643db86aabSstevel } 12653db86aabSstevel 12663db86aabSstevel #if defined(PCIC_DEBUG) 12673db86aabSstevel if (pcic_debug) 12683db86aabSstevel cmn_err(CE_CONT, "num sockets = %d\n", 12693db86aabSstevel pcic->pc_numsockets); 12703db86aabSstevel #endif 12713db86aabSstevel if (pcic->pc_numsockets == 0) { 12723db86aabSstevel ddi_regs_map_free(&pcic->handle); 12733db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 12743db86aabSstevel return (DDI_FAILURE); 12753db86aabSstevel } 12763db86aabSstevel 12773db86aabSstevel /* 12783db86aabSstevel * need to think this through again in light of 12793db86aabSstevel * Compaq not following the model that all the 12803db86aabSstevel * chip vendors recommend. IBM 755 seems to be 12813db86aabSstevel * afflicted as well. Basically, if the vendor 12823db86aabSstevel * wired things wrong, socket 0 responds for socket 2 12833db86aabSstevel * accesses, etc. 12843db86aabSstevel */ 12853db86aabSstevel if (pcic->pc_numsockets > 2) { 12863db86aabSstevel int count = pcic->pc_numsockets / 4; 12873db86aabSstevel for (i = 0; i < count; i++) { 12883db86aabSstevel /* put pattern into socket 0 */ 12893db86aabSstevel pcic_putb(pcic, i, 12903db86aabSstevel PCIC_SYSMEM_0_STARTLOW, 0x11); 12913db86aabSstevel 12923db86aabSstevel /* put pattern into socket 2 */ 12933db86aabSstevel pcic_putb(pcic, i + 2, 12943db86aabSstevel PCIC_SYSMEM_0_STARTLOW, 0x33); 12953db86aabSstevel 12963db86aabSstevel /* read back socket 0 */ 12973db86aabSstevel value = pcic_getb(pcic, i, 12983db86aabSstevel PCIC_SYSMEM_0_STARTLOW); 12993db86aabSstevel 13003db86aabSstevel /* read back chip 1 socket 0 */ 13013db86aabSstevel j = pcic_getb(pcic, i + 2, 13023db86aabSstevel PCIC_SYSMEM_0_STARTLOW); 13033db86aabSstevel if (j == value) { 13043db86aabSstevel pcic->pc_numsockets -= 2; 13053db86aabSstevel } 13063db86aabSstevel } 13073db86aabSstevel } 13083db86aabSstevel 13093db86aabSstevel smi = 0xff; /* no more override */ 13103db86aabSstevel 13113db86aabSstevel if (ddi_getprop(DDI_DEV_T_NONE, dip, 13123db86aabSstevel DDI_PROP_DONTPASS, "need-mult-irq", 13133db86aabSstevel 0xffff) != 0xffff) 13143db86aabSstevel pcic->pc_flags |= PCF_MULT_IRQ; 13153db86aabSstevel 13163db86aabSstevel } /* !PCF_PCIBUS */ 13173db86aabSstevel 13183db86aabSstevel /* 13193db86aabSstevel * some platforms/busses need to have resources setup 13203db86aabSstevel * this is temporary until a real resource allocator is 13213db86aabSstevel * implemented. 13223db86aabSstevel */ 13233db86aabSstevel 13243db86aabSstevel pcic_init_assigned(dip); 13253db86aabSstevel 13263db86aabSstevel typename = pcic->pc_chipname; 13273db86aabSstevel 13283db86aabSstevel #ifdef PCIC_DEBUG 13293db86aabSstevel if (pcic_debug) { 13303db86aabSstevel int nregs, nintrs; 13313db86aabSstevel 13323db86aabSstevel if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS) 13333db86aabSstevel nregs = 0; 13343db86aabSstevel 13353db86aabSstevel if (ddi_dev_nintrs(dip, &nintrs) != DDI_SUCCESS) 13363db86aabSstevel nintrs = 0; 13373db86aabSstevel 13383db86aabSstevel cmn_err(CE_CONT, 13393db86aabSstevel "pcic%d: %d register sets, %d interrupts\n", 13403db86aabSstevel ddi_get_instance(dip), nregs, nintrs); 13413db86aabSstevel 13423db86aabSstevel nintrs = 0; 13433db86aabSstevel while (nregs--) { 13443db86aabSstevel off_t size; 13453db86aabSstevel 13463db86aabSstevel if (ddi_dev_regsize(dip, nintrs, &size) == 13473db86aabSstevel DDI_SUCCESS) { 13483db86aabSstevel cmn_err(CE_CONT, 13493db86aabSstevel "\tregnum %d size %ld (0x%lx)" 13503db86aabSstevel "bytes", 13513db86aabSstevel nintrs, size, size); 13523db86aabSstevel if (nintrs == 13533db86aabSstevel (pcic->pc_io_type == PCIC_IO_TYPE_82365SL ? 13543db86aabSstevel PCIC_ISA_CONTROL_REG_NUM : 13553db86aabSstevel PCIC_PCI_CONTROL_REG_NUM)) 13563db86aabSstevel cmn_err(CE_CONT, 13573db86aabSstevel " mapped at: 0x%p\n", 13583db86aabSstevel (void *)pcic->ioaddr); 13593db86aabSstevel else 13603db86aabSstevel cmn_err(CE_CONT, "\n"); 13613db86aabSstevel } else { 13623db86aabSstevel cmn_err(CE_CONT, 13633db86aabSstevel "\tddi_dev_regsize(rnumber" 13643db86aabSstevel "= %d) returns DDI_FAILURE\n", 13653db86aabSstevel nintrs); 13663db86aabSstevel } 13673db86aabSstevel nintrs++; 13683db86aabSstevel } /* while */ 13693db86aabSstevel } /* if (pcic_debug) */ 13703db86aabSstevel #endif 13713db86aabSstevel 13723db86aabSstevel cv_init(&pcic->pm_cv, NULL, CV_DRIVER, NULL); 13733db86aabSstevel 13743db86aabSstevel if (!ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 13753db86aabSstevel "disable-audio", 0)) 13763db86aabSstevel pcic->pc_flags |= PCF_AUDIO; 13773db86aabSstevel 13783db86aabSstevel if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_CANSLEEP, 13793db86aabSstevel "disable-cardbus", 0)) 13803db86aabSstevel pcic->pc_flags &= ~PCF_CARDBUS; 13813db86aabSstevel 13823db86aabSstevel (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, PCICPROP_CTL, 13833db86aabSstevel typename); 13843db86aabSstevel 13853db86aabSstevel /* 13863db86aabSstevel * Init all socket SMI levels to 0 (no SMI) 13873db86aabSstevel */ 13883db86aabSstevel for (i = 0; i < PCIC_MAX_SOCKETS; i++) { 13893db86aabSstevel pcic->pc_sockets[i].pcs_smi = 0; 13903db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 0; 13913db86aabSstevel pcic->pc_sockets[i].pcs_pcic = pcic; 13923db86aabSstevel } 13933db86aabSstevel pcic->pc_lastreg = -1; /* just to make sure we are in sync */ 13943db86aabSstevel 13953db86aabSstevel /* 13963db86aabSstevel * Setup the IRQ handler(s) 13973db86aabSstevel */ 13983db86aabSstevel switch (pcic->pc_intr_mode) { 13993db86aabSstevel int xx; 14003db86aabSstevel case PCIC_INTR_MODE_ISA: 14013db86aabSstevel /* 14023db86aabSstevel * On a non-PCI bus, we just use whatever SMI IRQ level was 14033db86aabSstevel * specified above, and the IO IRQ levels are allocated 14043db86aabSstevel * dynamically. 14053db86aabSstevel */ 14063db86aabSstevel for (xx = 15, smi = 0; xx >= 0; xx--) { 14073db86aabSstevel if (PCIC_IRQ(xx) & 14083db86aabSstevel PCIC_AVAIL_IRQS) { 14093db86aabSstevel smi = pcmcia_get_intr(dip, xx); 14103db86aabSstevel if (smi >= 0) 14113db86aabSstevel break; 14123db86aabSstevel } 14133db86aabSstevel } 14143db86aabSstevel #if defined(PCIC_DEBUG) 14153db86aabSstevel if (pcic_debug) 14163db86aabSstevel cmn_err(CE_NOTE, "\tselected IRQ %d as SMI\n", smi); 14173db86aabSstevel #endif 14183db86aabSstevel /* init to same so share is easy */ 14193db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) 14203db86aabSstevel pcic->pc_sockets[i].pcs_smi = smi; 14213db86aabSstevel /* any special handling of IRQ levels */ 14223db86aabSstevel if (pcic->pc_flags & PCF_MULT_IRQ) { 14233db86aabSstevel for (i = 2; i < pcic->pc_numsockets; i++) { 14243db86aabSstevel if ((i & 1) == 0) { 14253db86aabSstevel int xx; 14263db86aabSstevel for (xx = 15, smi = 0; xx >= 0; xx--) { 14273db86aabSstevel if (PCIC_IRQ(xx) & 14283db86aabSstevel PCIC_AVAIL_IRQS) { 14293db86aabSstevel smi = 14303db86aabSstevel pcmcia_get_intr(dip, 14313db86aabSstevel xx); 14323db86aabSstevel if (smi >= 0) 14333db86aabSstevel break; 14343db86aabSstevel } 14353db86aabSstevel } 14363db86aabSstevel } 14373db86aabSstevel if (smi >= 0) 14383db86aabSstevel pcic->pc_sockets[i].pcs_smi = smi; 14393db86aabSstevel } 14403db86aabSstevel } 14413db86aabSstevel pcic->pc_intr_htblp = kmem_alloc(pcic->pc_numsockets * 14423db86aabSstevel sizeof (ddi_intr_handle_t), KM_SLEEP); 14433db86aabSstevel for (i = 0, irqlevel = -1; i < pcic->pc_numsockets; i++) { 14443db86aabSstevel struct intrspec *ispecp; 14453db86aabSstevel struct ddi_parent_private_data *pdp; 14463db86aabSstevel 14473db86aabSstevel if (irqlevel == pcic->pc_sockets[i].pcs_smi) 14483db86aabSstevel continue; 14493db86aabSstevel else { 14503db86aabSstevel irqlevel = pcic->pc_sockets[i].pcs_smi; 14513db86aabSstevel } 14523db86aabSstevel /* 14533db86aabSstevel * now convert the allocated IRQ into an intrspec 14543db86aabSstevel * and ask our parent to add it. Don't use 14553db86aabSstevel * the ddi_add_intr since we don't have a 14563db86aabSstevel * default intrspec in all cases. 14573db86aabSstevel * 14583db86aabSstevel * note: this sort of violates DDI but we don't 14593db86aabSstevel * get hardware intrspecs for many of the devices. 14603db86aabSstevel * at the same time, we know how to allocate them 14613db86aabSstevel * so we do the right thing. 14623db86aabSstevel */ 14633db86aabSstevel if (ddi_intr_alloc(dip, &pcic->pc_intr_htblp[i], 14643db86aabSstevel DDI_INTR_TYPE_FIXED, 0, 1, &actual, 14653db86aabSstevel DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) { 14663db86aabSstevel cmn_err(CE_WARN, "%s: ddi_intr_alloc failed", 14673db86aabSstevel ddi_get_name(dip)); 14683db86aabSstevel goto isa_exit1; 14693db86aabSstevel } 14703db86aabSstevel 14713db86aabSstevel /* 14723db86aabSstevel * See earlier note: 14733db86aabSstevel * Since some devices don't have 'intrspec' 14743db86aabSstevel * we make one up in rootnex. 14753db86aabSstevel * 14763db86aabSstevel * However, it is not properly initialized as 14773db86aabSstevel * the data it needs is present in this driver 14783db86aabSstevel * and there is no interface to pass that up. 14793db86aabSstevel * Specially 'irqlevel' is very important and 14803db86aabSstevel * it is part of pcic struct. 14813db86aabSstevel * 14823db86aabSstevel * Set 'intrspec' up here; otherwise adding the 14833db86aabSstevel * interrupt will fail. 14843db86aabSstevel */ 14853db86aabSstevel pdp = ddi_get_parent_data(dip); 14863db86aabSstevel ispecp = (struct intrspec *)&pdp->par_intr[0]; 14873db86aabSstevel ispecp->intrspec_vec = irqlevel; 14883db86aabSstevel ispecp->intrspec_pri = pcic->pc_irq; 14893db86aabSstevel 14903db86aabSstevel /* Stay compatible w/ PCMCIA */ 14913db86aabSstevel pcic->pc_pri = (ddi_iblock_cookie_t) 14923db86aabSstevel (uintptr_t)pcic->pc_irq; 14933db86aabSstevel pcic->pc_dcookie.idev_priority = 14943db86aabSstevel (uintptr_t)pcic->pc_pri; 14953db86aabSstevel pcic->pc_dcookie.idev_vector = (ushort_t)irqlevel; 14963db86aabSstevel 14973db86aabSstevel (void) ddi_intr_set_pri(pcic->pc_intr_htblp[i], 14983db86aabSstevel pcic->pc_irq); 14993db86aabSstevel 15003db86aabSstevel if (i == 0) { 15013db86aabSstevel mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, 15023db86aabSstevel DDI_INTR_PRI(pcic->pc_irq)); 15033db86aabSstevel mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, 15043db86aabSstevel NULL); 15053db86aabSstevel } 15063db86aabSstevel 15073db86aabSstevel if (ddi_intr_add_handler(pcic->pc_intr_htblp[i], 15083db86aabSstevel pcic_intr, (caddr_t)pcic, NULL)) { 15093db86aabSstevel cmn_err(CE_WARN, 15103db86aabSstevel "%s: ddi_intr_add_handler failed", 15113db86aabSstevel ddi_get_name(dip)); 15123db86aabSstevel goto isa_exit2; 15133db86aabSstevel } 15143db86aabSstevel 15153db86aabSstevel if (ddi_intr_enable(pcic->pc_intr_htblp[i])) { 15163db86aabSstevel cmn_err(CE_WARN, "%s: ddi_intr_enable failed", 15173db86aabSstevel ddi_get_name(dip)); 15183db86aabSstevel for (j = i; j < 0; j--) 15193db86aabSstevel (void) ddi_intr_remove_handler( 15203db86aabSstevel pcic->pc_intr_htblp[j]); 15213db86aabSstevel goto isa_exit2; 15223db86aabSstevel } 15233db86aabSstevel } 15243db86aabSstevel break; 15253db86aabSstevel case PCIC_INTR_MODE_PCI_1: 15263db86aabSstevel case PCIC_INTR_MODE_PCI: 15273db86aabSstevel /* 15283db86aabSstevel * If we're on a PCI bus, we route all interrupts, both SMI 15293db86aabSstevel * and IO interrupts, through a single interrupt line. 15303db86aabSstevel * Assign the SMI IRQ level to the IO IRQ level here. 15313db86aabSstevel */ 15323db86aabSstevel pcic->pc_pci_intr_hdlp = kmem_alloc(sizeof (ddi_intr_handle_t), 15333db86aabSstevel KM_SLEEP); 15343db86aabSstevel if (ddi_intr_alloc(dip, pcic->pc_pci_intr_hdlp, 15353db86aabSstevel DDI_INTR_TYPE_FIXED, 0, 1, &actual, 15363db86aabSstevel DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) 15373db86aabSstevel goto pci_exit1; 15383db86aabSstevel 15393db86aabSstevel if (ddi_intr_get_pri(pcic->pc_pci_intr_hdlp[0], 15403db86aabSstevel &pri) != DDI_SUCCESS) { 15413db86aabSstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]); 15423db86aabSstevel goto pci_exit1; 15433db86aabSstevel } 15443db86aabSstevel 15453db86aabSstevel pcic->pc_pri = (void *)(uintptr_t)pri; 15463db86aabSstevel mutex_init(&pcic->intr_lock, NULL, MUTEX_DRIVER, pcic->pc_pri); 15473db86aabSstevel mutex_init(&pcic->pc_lock, NULL, MUTEX_DRIVER, NULL); 15483db86aabSstevel 15493db86aabSstevel if (ddi_intr_add_handler(pcic->pc_pci_intr_hdlp[0], 15503db86aabSstevel pcic_intr, (caddr_t)pcic, NULL)) 15513db86aabSstevel goto pci_exit2; 15523db86aabSstevel 15533db86aabSstevel if (ddi_intr_enable(pcic->pc_pci_intr_hdlp[0])) { 15543db86aabSstevel (void) ddi_intr_remove_handler( 15553db86aabSstevel pcic->pc_pci_intr_hdlp[0]); 15563db86aabSstevel goto pci_exit2; 15573db86aabSstevel } 15583db86aabSstevel 15593db86aabSstevel /* Stay compatible w/ PCMCIA */ 15603db86aabSstevel pcic->pc_dcookie.idev_priority = (ushort_t)pri; 15613db86aabSstevel 15623db86aabSstevel /* init to same (PCI) so share is easy */ 15633db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) 15643db86aabSstevel pcic->pc_sockets[i].pcs_smi = 0xF; /* any valid */ 15653db86aabSstevel break; 15663db86aabSstevel } 15673db86aabSstevel 15683db86aabSstevel /* 15693db86aabSstevel * Setup the adapter hardware to some reasonable defaults. 15703db86aabSstevel */ 15713db86aabSstevel mutex_enter(&pcic->pc_lock); 15723db86aabSstevel /* mark the driver state as attached */ 15733db86aabSstevel pcic->pc_flags |= PCF_ATTACHED; 15743db86aabSstevel pcic_setup_adapter(pcic); 15753db86aabSstevel 15763db86aabSstevel for (j = 0; j < pcic->pc_numsockets; j++) 15773db86aabSstevel if (ddi_intr_add_softint(dip, 15783db86aabSstevel &pcic->pc_sockets[j].pcs_cd_softint_hdl, 15793db86aabSstevel PCIC_SOFTINT_PRI_VAL, pcic_cd_softint, 15803db86aabSstevel (caddr_t)&pcic->pc_sockets[j]) != DDI_SUCCESS) 15813db86aabSstevel goto pci_exit2; 15823db86aabSstevel 15833db86aabSstevel #if defined(PCIC_DEBUG) 15843db86aabSstevel if (pcic_debug) 15853db86aabSstevel cmn_err(CE_CONT, "type = %s sockets = %d\n", typename, 15863db86aabSstevel pcic->pc_numsockets); 15873db86aabSstevel #endif 15883db86aabSstevel 15893db86aabSstevel pcic_nexus->an_iblock = &pcic->pc_pri; 15903db86aabSstevel pcic_nexus->an_idev = &pcic->pc_dcookie; 15913db86aabSstevel 15923db86aabSstevel mutex_exit(&pcic->pc_lock); 15933db86aabSstevel 15943db86aabSstevel #ifdef CARDBUS 15953db86aabSstevel (void) cardbus_enable_cd_intr(dip); 15963db86aabSstevel if (pcic_debug) { 15973db86aabSstevel 15983db86aabSstevel cardbus_dump_pci_config(dip); 15993db86aabSstevel cardbus_dump_socket(dip); 16003db86aabSstevel } 16013db86aabSstevel 16023db86aabSstevel /* 16033db86aabSstevel * Give the Cardbus misc module a chance to do it's per-adapter 16043db86aabSstevel * instance setup. Note that there is no corresponding detach() 16053db86aabSstevel * call. 16063db86aabSstevel */ 16073db86aabSstevel if (pcic->pc_flags & PCF_CARDBUS) 16083db86aabSstevel if (cardbus_attach(dip, &pcic_cbnexus_ops) != DDI_SUCCESS) { 16093db86aabSstevel cmn_err(CE_CONT, 16103db86aabSstevel "pcic_attach: cardbus_attach failed\n"); 16113db86aabSstevel goto pci_exit2; 16123db86aabSstevel } 16133db86aabSstevel #endif 16143db86aabSstevel 16153db86aabSstevel /* 16163db86aabSstevel * Give the PCMCIA misc module a chance to do it's per-adapter 16173db86aabSstevel * instance setup. 16183db86aabSstevel */ 16193db86aabSstevel if ((i = pcmcia_attach(dip, pcic_nexus)) != DDI_SUCCESS) 16203db86aabSstevel goto pci_exit2; 16213db86aabSstevel 16223db86aabSstevel syshw_attach(pcic); 16233db86aabSstevel if (pcic_maxinst == -1) { 16243db86aabSstevel /* This assumes that all instances run at the same IPL. */ 16253db86aabSstevel mutex_init(&pcic_deb_mtx, NULL, MUTEX_DRIVER, NULL); 16263db86aabSstevel cv_init(&pcic_deb_cv, NULL, CV_DRIVER, NULL); 16273db86aabSstevel pcic_deb_threadid = thread_create((caddr_t)NULL, 0, 16283db86aabSstevel pcic_deb_thread, (caddr_t)NULL, 0, &p0, TS_RUN, 16293db86aabSstevel v.v_maxsyspri - 2); 16303db86aabSstevel } 16313db86aabSstevel pcic_maxinst = max(pcic_maxinst, ddi_get_instance(dip)); 16323db86aabSstevel /* 16333db86aabSstevel * Setup a debounce timeout to do an initial card detect 16343db86aabSstevel * and enable interrupts. 16353db86aabSstevel */ 16363db86aabSstevel for (j = 0; j < pcic->pc_numsockets; j++) { 16373db86aabSstevel shwp = kmem_alloc(sizeof (syshw_t), KM_SLEEP); 16383db86aabSstevel if (shwp) { 16393db86aabSstevel bcopy(&pcic_syshw, shwp, sizeof (pcic_syshw)); 16403db86aabSstevel pcic_syshw.id_string[15]++; 16413db86aabSstevel pcic->pc_sockets[j].pcs_syshwsig = 16423db86aabSstevel syshw_add2map(shwp, pcic_syshw_cardstate, 16433db86aabSstevel &pcic->pc_sockets[j]); 16443db86aabSstevel } 16453db86aabSstevel pcic->pc_sockets[j].pcs_debounce_id = 16463db86aabSstevel pcic_add_debqueue(&pcic->pc_sockets[j], 16473db86aabSstevel drv_usectohz(pcic_debounce_time)); 16483db86aabSstevel } 16493db86aabSstevel 16503db86aabSstevel return (i); 16513db86aabSstevel 16523db86aabSstevel isa_exit2: 16533db86aabSstevel mutex_destroy(&pcic->intr_lock); 16543db86aabSstevel mutex_destroy(&pcic->pc_lock); 16553db86aabSstevel for (j = i; j < 0; j--) 16563db86aabSstevel (void) ddi_intr_free(pcic->pc_intr_htblp[j]); 16573db86aabSstevel isa_exit1: 16583db86aabSstevel (void) pcmcia_return_intr(dip, pcic->pc_sockets[i].pcs_smi); 16593db86aabSstevel ddi_regs_map_free(&pcic->handle); 16603db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) 16613db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 16623db86aabSstevel kmem_free(pcic->pc_intr_htblp, pcic->pc_numsockets * 16633db86aabSstevel sizeof (ddi_intr_handle_t)); 16643db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 16653db86aabSstevel return (DDI_FAILURE); 16663db86aabSstevel 16673db86aabSstevel pci_exit2: 16683db86aabSstevel mutex_destroy(&pcic->intr_lock); 16693db86aabSstevel mutex_destroy(&pcic->pc_lock); 16703db86aabSstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]); 16713db86aabSstevel pci_exit1: 16723db86aabSstevel ddi_regs_map_free(&pcic->handle); 16733db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) 16743db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 16753db86aabSstevel kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t)); 16763db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 16773db86aabSstevel return (DDI_FAILURE); 16783db86aabSstevel } 16793db86aabSstevel 16803db86aabSstevel /* 16813db86aabSstevel * pcic_detach() 16823db86aabSstevel * request to detach from the system 16833db86aabSstevel */ 16843db86aabSstevel static int 16853db86aabSstevel pcic_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 16863db86aabSstevel { 16873db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 16883db86aabSstevel pcicdev_t *pcic = anp->an_private; 16893db86aabSstevel int i; 16903db86aabSstevel 16913db86aabSstevel switch (cmd) { 16923db86aabSstevel case DDI_DETACH: 16933db86aabSstevel /* don't detach if the nexus still talks to us */ 16943db86aabSstevel if (pcic->pc_callback != NULL) 16953db86aabSstevel return (DDI_FAILURE); 16963db86aabSstevel syshw_detach(pcic); 16973db86aabSstevel 16983db86aabSstevel /* kill off the pm simulation */ 16993db86aabSstevel if (pcic->pc_pmtimer) 17003db86aabSstevel (void) untimeout(pcic->pc_pmtimer); 17013db86aabSstevel 17023db86aabSstevel /* turn everything off for all sockets and chips */ 17033db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) { 17043db86aabSstevel if (pcic->pc_sockets[i].pcs_debounce_id) 17053db86aabSstevel pcic_rm_debqueue( 17063db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id); 17073db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 0; 17083db86aabSstevel 17093db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0); 17103db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_DETECT, 0); 17113db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 17123db86aabSstevel /* disable interrupts and put card into RESET */ 17133db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 0); 17143db86aabSstevel } 17153db86aabSstevel (void) ddi_intr_disable(pcic->pc_pci_intr_hdlp[0]); 17163db86aabSstevel (void) ddi_intr_remove_handler(pcic->pc_pci_intr_hdlp[0]); 17173db86aabSstevel (void) ddi_intr_free(pcic->pc_pci_intr_hdlp[0]); 17183db86aabSstevel kmem_free(pcic->pc_pci_intr_hdlp, sizeof (ddi_intr_handle_t)); 17193db86aabSstevel pcic->pc_flags = 0; 17203db86aabSstevel mutex_destroy(&pcic->pc_lock); 17213db86aabSstevel mutex_destroy(&pcic->intr_lock); 17223db86aabSstevel cv_destroy(&pcic->pm_cv); 17233db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) 17243db86aabSstevel ddi_regs_map_free(&pcic->cfg_handle); 17253db86aabSstevel if (pcic->handle) 17263db86aabSstevel ddi_regs_map_free(&pcic->handle); 17273db86aabSstevel kmem_free(pcic, sizeof (pcicdev_t)); 17283db86aabSstevel ddi_soft_state_free(pcic_soft_state_p, ddi_get_instance(dip)); 17293db86aabSstevel return (DDI_SUCCESS); 17303db86aabSstevel 17313db86aabSstevel case DDI_SUSPEND: 17323db86aabSstevel case DDI_PM_SUSPEND: 17333db86aabSstevel /* 17343db86aabSstevel * we got a suspend event (either real or imagined) 17353db86aabSstevel * so notify the nexus proper that all existing cards 17363db86aabSstevel * should go away. 17373db86aabSstevel */ 17383db86aabSstevel mutex_enter(&pcic->pc_lock); 17393db86aabSstevel #ifdef CARDBUS 17403db86aabSstevel if (pcic->pc_flags & PCF_CARDBUS) 17413db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) 17423db86aabSstevel if ((pcic->pc_sockets[i].pcs_flags & 17433db86aabSstevel (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) == 17443db86aabSstevel (PCS_CARD_PRESENT|PCS_CARD_ISCARDBUS)) 17453db86aabSstevel if (!cardbus_can_suspend(dip)) { 17463db86aabSstevel mutex_exit(&pcic->pc_lock); 17473db86aabSstevel cmn_err(CE_WARN, 17483db86aabSstevel "Please unconfigure all " 17493db86aabSstevel "CardBus devices before " 17503db86aabSstevel "attempting to suspend\n"); 17513db86aabSstevel return (DDI_FAILURE); 17523db86aabSstevel } 17533db86aabSstevel #endif 17543db86aabSstevel /* turn everything off for all sockets and chips */ 17553db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) { 17563db86aabSstevel if (pcic->pc_sockets[i].pcs_debounce_id) 17573db86aabSstevel pcic_rm_debqueue( 17583db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id); 17593db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 0; 17603db86aabSstevel 17613db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 0); 17623db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_DETECT, 0); 17633db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 17643db86aabSstevel /* disable interrupts and put card into RESET */ 17653db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 0); 17663db86aabSstevel pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0); 17673db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) 17683db86aabSstevel pcic_putcb(pcic, CB_CONTROL, 0); 17693db86aabSstevel 17703db86aabSstevel if (pcic->pc_sockets[i].pcs_flags & PCS_CARD_PRESENT) { 17713db86aabSstevel pcic->pc_sockets[i].pcs_flags = PCS_STARTING; 17723db86aabSstevel /* 17733db86aabSstevel * Because we are half way through a save 17743db86aabSstevel * all this does is schedule a removal event 17753db86aabSstevel * to cs for when the system comes back. 17763db86aabSstevel * This doesn't actually matter. 17773db86aabSstevel */ 17783db86aabSstevel if (!pcic_do_pcmcia_sr && pcic_do_removal && 17793db86aabSstevel pcic->pc_callback) { 17803db86aabSstevel PC_CALLBACK(pcic->dip, pcic->pc_cb_arg, 17813db86aabSstevel PCE_CARD_REMOVAL, 17823db86aabSstevel pcic->pc_sockets[i].pcs_socket); 17833db86aabSstevel } 17843db86aabSstevel } 17853db86aabSstevel } 17863db86aabSstevel 17873db86aabSstevel pcic->pc_flags |= PCF_SUSPENDED; 17883db86aabSstevel mutex_exit(&pcic->pc_lock); 17893db86aabSstevel pcic_delayed_resume_toid = 0; 17903db86aabSstevel 17913db86aabSstevel /* 17923db86aabSstevel * when true power management exists, save the adapter 17933db86aabSstevel * state here to enable a recovery. For the emulation 17943db86aabSstevel * condition, the state is gone 17953db86aabSstevel */ 17963db86aabSstevel return (DDI_SUCCESS); 17973db86aabSstevel 17983db86aabSstevel default: 17993db86aabSstevel return (EINVAL); 18003db86aabSstevel } 18013db86aabSstevel } 18023db86aabSstevel 18033db86aabSstevel static uint32_t pcic_tisysctl_onbits = ((1<<27) | (1<<15) | (1<<14)); 18043db86aabSstevel static uint32_t pcic_tisysctl_offbits = 0; 18053db86aabSstevel static uint32_t pcic_default_latency = 0x40; 18063db86aabSstevel 18073db86aabSstevel static void 18083db86aabSstevel pcic_setup_adapter(pcicdev_t *pcic) 18093db86aabSstevel { 18103db86aabSstevel int i; 18113db86aabSstevel int value, flags; 18123db86aabSstevel 18133db86aabSstevel if (pcic->pc_flags & PCF_PCIBUS) { 18143db86aabSstevel /* 18153db86aabSstevel * all PCI-to-PCMCIA bus bridges need memory and I/O enabled 18163db86aabSstevel */ 18173db86aabSstevel flags = (PCIC_ENABLE_IO | PCIC_ENABLE_MEM); 18183db86aabSstevel pcic_iomem_pci_ctl(pcic->cfg_handle, pcic->cfgaddr, flags); 18193db86aabSstevel } 18203db86aabSstevel /* enable each socket */ 18213db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) { 18223db86aabSstevel pcic->pc_sockets[i].pcs_flags = 0; 18233db86aabSstevel /* find out the socket capabilities (I/O vs memory) */ 18243db86aabSstevel value = pcic_getb(pcic, i, 18253db86aabSstevel PCIC_CHIP_REVISION) & PCIC_REV_ID_MASK; 18263db86aabSstevel if (value == PCIC_REV_ID_IO || value == PCIC_REV_ID_BOTH) 18273db86aabSstevel pcic->pc_sockets[i].pcs_flags |= PCS_SOCKET_IO; 18283db86aabSstevel 18293db86aabSstevel /* disable all windows just in case */ 18303db86aabSstevel pcic_putb(pcic, i, PCIC_MAPPING_ENABLE, 0); 18313db86aabSstevel 18323db86aabSstevel switch (pcic->pc_type) { 18333db86aabSstevel uint32_t cfg32; 18343db86aabSstevel uint16_t cfg16; 18353db86aabSstevel uint8_t cfg; 18363db86aabSstevel 18373db86aabSstevel /* enable extended registers for Vadem */ 18383db86aabSstevel case PCIC_VADEM_VG469: 18393db86aabSstevel case PCIC_VADEM: 18403db86aabSstevel 18413db86aabSstevel /* enable card status change interrupt for socket */ 18423db86aabSstevel break; 18433db86aabSstevel 18443db86aabSstevel case PCIC_I82365SL: 18453db86aabSstevel break; 18463db86aabSstevel 18473db86aabSstevel case PCIC_CL_PD6710: 18483db86aabSstevel pcic_putb(pcic, 0, PCIC_MISC_CTL_2, PCIC_LED_ENABLE); 18493db86aabSstevel break; 18503db86aabSstevel 18513db86aabSstevel /* 18523db86aabSstevel * On the CL_6730, we need to set up the interrupt 18533db86aabSstevel * signalling mode (PCI mode) and set the SMI and 18543db86aabSstevel * IRQ interrupt lines to PCI/level-mode. 18553db86aabSstevel */ 18563db86aabSstevel case PCIC_CL_PD6730: 18573db86aabSstevel switch (pcic->pc_intr_mode) { 18583db86aabSstevel case PCIC_INTR_MODE_PCI_1: 18593db86aabSstevel clext_reg_write(pcic, i, PCIC_CLEXT_MISC_CTL_3, 18603db86aabSstevel ((clext_reg_read(pcic, i, 18613db86aabSstevel PCIC_CLEXT_MISC_CTL_3) & 18623db86aabSstevel ~PCIC_CLEXT_INT_PCI) | 18633db86aabSstevel PCIC_CLEXT_INT_PCI)); 18643db86aabSstevel clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1, 18653db86aabSstevel (PCIC_CLEXT_IRQ_LVL_MODE | 18663db86aabSstevel PCIC_CLEXT_SMI_LVL_MODE)); 18673db86aabSstevel cfg = PCIC_CL_LP_DYN_MODE; 18683db86aabSstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg); 18693db86aabSstevel break; 18703db86aabSstevel case PCIC_INTR_MODE_ISA: 18713db86aabSstevel break; 18723db86aabSstevel } 18733db86aabSstevel break; 18743db86aabSstevel /* 18753db86aabSstevel * On the CL_6729, we set the SMI and IRQ interrupt 18763db86aabSstevel * lines to PCI/level-mode. as well as program the 18773db86aabSstevel * correct clock speed divider bit. 18783db86aabSstevel */ 18793db86aabSstevel case PCIC_CL_PD6729: 18803db86aabSstevel switch (pcic->pc_intr_mode) { 18813db86aabSstevel case PCIC_INTR_MODE_PCI_1: 18823db86aabSstevel clext_reg_write(pcic, i, PCIC_CLEXT_EXT_CTL_1, 18833db86aabSstevel (PCIC_CLEXT_IRQ_LVL_MODE | 18843db86aabSstevel PCIC_CLEXT_SMI_LVL_MODE)); 18853db86aabSstevel 18863db86aabSstevel break; 18873db86aabSstevel case PCIC_INTR_MODE_ISA: 18883db86aabSstevel break; 18893db86aabSstevel } 18903db86aabSstevel if (pcic->bus_speed > PCIC_PCI_25MHZ && i == 0) { 18913db86aabSstevel cfg = 0; 18923db86aabSstevel cfg |= PCIC_CL_TIMER_CLK_DIV; 18933db86aabSstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, cfg); 18943db86aabSstevel } 18953db86aabSstevel break; 18963db86aabSstevel case PCIC_INTEL_i82092: 18973db86aabSstevel cfg = PCIC_82092_EN_TIMING; 18983db86aabSstevel if (pcic->bus_speed < PCIC_SYSCLK_33MHZ) 18993db86aabSstevel cfg |= PCIC_82092_PCICLK_25MHZ; 19003db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + 19013db86aabSstevel PCIC_82092_PCICON, cfg); 19023db86aabSstevel break; 19033db86aabSstevel case PCIC_TI_PCI1130: 19043db86aabSstevel case PCIC_TI_PCI1131: 19053db86aabSstevel case PCIC_TI_PCI1250: 19063db86aabSstevel case PCIC_TI_PCI1031: 19073db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 19083db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG); 19093db86aabSstevel cfg &= ~PCIC_DEVCTL_INTR_MASK; 19103db86aabSstevel switch (pcic->pc_intr_mode) { 19113db86aabSstevel case PCIC_INTR_MODE_ISA: 19123db86aabSstevel cfg |= PCIC_DEVCTL_INTR_ISA; 19133db86aabSstevel break; 19143db86aabSstevel } 19153db86aabSstevel #ifdef PCIC_DEBUG 19163db86aabSstevel if (pcic_debug) { 19173db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 19183db86aabSstevel "write reg 0x%x=%x \n", 19193db86aabSstevel PCIC_DEVCTL_REG, cfg); 19203db86aabSstevel } 19213db86aabSstevel #endif 19223db86aabSstevel ddi_put8(pcic->cfg_handle, 19233db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG, 19243db86aabSstevel cfg); 19253db86aabSstevel 19263db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 19273db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG); 19283db86aabSstevel cfg &= ~(PCIC_CRDCTL_PCIINTR|PCIC_CRDCTL_PCICSC| 19293db86aabSstevel PCIC_CRDCTL_PCIFUNC); 19303db86aabSstevel switch (pcic->pc_intr_mode) { 19313db86aabSstevel case PCIC_INTR_MODE_PCI_1: 19323db86aabSstevel cfg |= PCIC_CRDCTL_PCIINTR | 19333db86aabSstevel PCIC_CRDCTL_PCICSC | 19343db86aabSstevel PCIC_CRDCTL_PCIFUNC; 19353db86aabSstevel pcic->pc_flags |= PCF_USE_SMI; 19363db86aabSstevel break; 19373db86aabSstevel } 19383db86aabSstevel #ifdef PCIC_DEBUG 19393db86aabSstevel if (pcic_debug) { 19403db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 19413db86aabSstevel " write reg 0x%x=%x \n", 19423db86aabSstevel PCIC_CRDCTL_REG, cfg); 19433db86aabSstevel } 19443db86aabSstevel #endif 19453db86aabSstevel ddi_put8(pcic->cfg_handle, 19463db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG, 19473db86aabSstevel cfg); 19483db86aabSstevel break; 19493db86aabSstevel case PCIC_TI_PCI1221: 19503db86aabSstevel case PCIC_TI_PCI1225: 19513db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 19523db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG); 19533db86aabSstevel cfg |= (PCIC_DEVCTL_INTR_DFLT | PCIC_DEVCTL_3VCAPABLE); 19543db86aabSstevel #ifdef PCIC_DEBUG 19553db86aabSstevel if (pcic_debug) { 19563db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 19573db86aabSstevel " write reg 0x%x=%x \n", 19583db86aabSstevel PCIC_DEVCTL_REG, cfg); 19593db86aabSstevel } 19603db86aabSstevel #endif 19613db86aabSstevel ddi_put8(pcic->cfg_handle, 19623db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG, cfg); 19633db86aabSstevel 19643db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 19653db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG); 19663db86aabSstevel if (pcic->pc_type == PCIC_TI_PCI1225) { 19673db86aabSstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC); 19683db86aabSstevel } else { 19693db86aabSstevel cfg |= PCIC_DIAG_ASYNC; 19703db86aabSstevel } 19713db86aabSstevel pcic->pc_flags |= PCF_USE_SMI; 19723db86aabSstevel #ifdef PCIC_DEBUG 19733db86aabSstevel if (pcic_debug) { 19743db86aabSstevel cmn_err(CE_CONT, "pcic_setup_adapter: " 19753db86aabSstevel " write reg 0x%x=%x \n", 19763db86aabSstevel PCIC_DIAG_REG, cfg); 19773db86aabSstevel } 19783db86aabSstevel #endif 19793db86aabSstevel ddi_put8(pcic->cfg_handle, 19803db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg); 19813db86aabSstevel break; 19823db86aabSstevel case PCIC_TI_PCI1520: 19830e995c33Srw148561 case PCIC_TI_PCI1510: 19843db86aabSstevel case PCIC_TI_VENDOR: 19853db86aabSstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) { 19863db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 19873db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 19883db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA; 19893db86aabSstevel ddi_put8(pcic->cfg_handle, 19903db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 19913db86aabSstevel cfg); 19923db86aabSstevel } 19933db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 19943db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG); 19953db86aabSstevel cfg &= ~PCIC_DEVCTL_INTR_MASK; 19963db86aabSstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) 19973db86aabSstevel cfg |= PCIC_DEVCTL_INTR_ISA; 19983db86aabSstevel ddi_put8(pcic->cfg_handle, 19993db86aabSstevel pcic->cfgaddr + PCIC_DEVCTL_REG, 20003db86aabSstevel cfg); 20013db86aabSstevel 20023db86aabSstevel /* tie INTA and INTB together */ 20033db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 20043db86aabSstevel (pcic->cfgaddr + PCIC_SYSCTL_REG + 3)); 20053db86aabSstevel cfg |= PCIC_SYSCTL_INTRTIE; 20063db86aabSstevel ddi_put8(pcic->cfg_handle, (pcic->cfgaddr + 20073db86aabSstevel PCIC_SYSCTL_REG + 3), cfg); 20083db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 20093db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG); 20103db86aabSstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC); 20113db86aabSstevel ddi_put8(pcic->cfg_handle, 20123db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg); 20133db86aabSstevel break; 20143db86aabSstevel case PCIC_TI_PCI1410: 20153db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 20163db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG); 20173db86aabSstevel cfg |= (PCIC_DIAG_CSC | PCIC_DIAG_ASYNC); 20183db86aabSstevel ddi_put8(pcic->cfg_handle, 20193db86aabSstevel pcic->cfgaddr + PCIC_DIAG_REG, cfg); 20203db86aabSstevel break; 20213db86aabSstevel case PCIC_TOSHIBA_TOPIC100: 20223db86aabSstevel case PCIC_TOSHIBA_TOPIC95: 20233db86aabSstevel case PCIC_TOSHIBA_VENDOR: 20243db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr + 20253db86aabSstevel PCIC_TOSHIBA_SLOT_CTL_REG); 20263db86aabSstevel cfg |= (PCIC_TOSHIBA_SCR_SLOTON | 20273db86aabSstevel PCIC_TOSHIBA_SCR_SLOTEN); 20283db86aabSstevel cfg &= (~PCIC_TOSHIBA_SCR_PRT_MASK); 20293db86aabSstevel cfg |= PCIC_TOSHIBA_SCR_PRT_3E2; 20303db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + 20313db86aabSstevel PCIC_TOSHIBA_SLOT_CTL_REG, cfg); 20323db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, pcic->cfgaddr + 20333db86aabSstevel PCIC_TOSHIBA_INTR_CTL_REG); 20343db86aabSstevel switch (pcic->pc_intr_mode) { 20353db86aabSstevel case PCIC_INTR_MODE_ISA: 20363db86aabSstevel cfg &= ~PCIC_TOSHIBA_ICR_SRC; 20373db86aabSstevel ddi_put8(pcic->cfg_handle, 20383db86aabSstevel pcic->cfgaddr + 20393db86aabSstevel PCIC_TOSHIBA_INTR_CTL_REG, cfg); 20403db86aabSstevel 20413db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 20423db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 20433db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA; 20443db86aabSstevel ddi_put8(pcic->cfg_handle, 20453db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 20463db86aabSstevel cfg); 20473db86aabSstevel break; 20483db86aabSstevel case PCIC_INTR_MODE_PCI_1: 20493db86aabSstevel cfg |= PCIC_TOSHIBA_ICR_SRC; 20503db86aabSstevel cfg &= (~PCIC_TOSHIBA_ICR_PIN_MASK); 20513db86aabSstevel cfg |= PCIC_TOSHIBA_ICR_PIN_INTA; 20523db86aabSstevel ddi_put8(pcic->cfg_handle, 20533db86aabSstevel pcic->cfgaddr + 20543db86aabSstevel PCIC_TOSHIBA_INTR_CTL_REG, cfg); 20553db86aabSstevel break; 20563db86aabSstevel } 20573db86aabSstevel break; 20583db86aabSstevel case PCIC_O2MICRO_VENDOR: 20593db86aabSstevel cfg32 = ddi_get32(pcic->cfg_handle, 20603db86aabSstevel (uint32_t *)(pcic->cfgaddr + 20613db86aabSstevel PCIC_O2MICRO_MISC_CTL)); 20623db86aabSstevel switch (pcic->pc_intr_mode) { 20633db86aabSstevel case PCIC_INTR_MODE_ISA: 20643db86aabSstevel cfg32 |= (PCIC_O2MICRO_ISA_LEGACY | 20653db86aabSstevel PCIC_O2MICRO_INT_MOD_PCI); 20663db86aabSstevel ddi_put32(pcic->cfg_handle, 20673db86aabSstevel (uint32_t *)(pcic->cfgaddr + 20683db86aabSstevel PCIC_O2MICRO_MISC_CTL), 20693db86aabSstevel cfg32); 20703db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 20713db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 20723db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA; 20733db86aabSstevel ddi_put8(pcic->cfg_handle, 20743db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 20753db86aabSstevel cfg); 20763db86aabSstevel break; 20773db86aabSstevel case PCIC_INTR_MODE_PCI_1: 20783db86aabSstevel cfg32 &= ~PCIC_O2MICRO_ISA_LEGACY; 20793db86aabSstevel cfg32 |= PCIC_O2MICRO_INT_MOD_PCI; 20803db86aabSstevel ddi_put32(pcic->cfg_handle, 20813db86aabSstevel (uint32_t *)(pcic->cfgaddr + 20823db86aabSstevel PCIC_O2MICRO_MISC_CTL), 20833db86aabSstevel cfg32); 20843db86aabSstevel break; 20853db86aabSstevel } 20863db86aabSstevel break; 20873db86aabSstevel case PCIC_RICOH_VENDOR: 20883db86aabSstevel if (pcic->pc_intr_mode == PCIC_INTR_MODE_ISA) { 20893db86aabSstevel cfg16 = ddi_get16(pcic->cfg_handle, 20903db86aabSstevel (uint16_t *)(pcic->cfgaddr + 20913db86aabSstevel PCIC_RICOH_MISC_CTL_2)); 20923db86aabSstevel cfg16 |= (PCIC_RICOH_CSC_INT_MOD | 20933db86aabSstevel PCIC_RICOH_FUN_INT_MOD); 20943db86aabSstevel ddi_put16(pcic->cfg_handle, 20953db86aabSstevel (uint16_t *)(pcic->cfgaddr + 20963db86aabSstevel PCIC_RICOH_MISC_CTL_2), 20973db86aabSstevel cfg16); 20983db86aabSstevel 20993db86aabSstevel cfg16 = ddi_get16(pcic->cfg_handle, 21003db86aabSstevel (uint16_t *)(pcic->cfgaddr + 21013db86aabSstevel PCIC_RICOH_MISC_CTL)); 21023db86aabSstevel cfg16 |= PCIC_RICOH_SIRQ_EN; 21033db86aabSstevel ddi_put16(pcic->cfg_handle, 21043db86aabSstevel (uint16_t *)(pcic->cfgaddr + 21053db86aabSstevel PCIC_RICOH_MISC_CTL), 21063db86aabSstevel cfg16); 21073db86aabSstevel 21083db86aabSstevel cfg = ddi_get8(pcic->cfg_handle, 21093db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG); 21103db86aabSstevel cfg |= PCIC_FUN_INT_MOD_ISA; 21113db86aabSstevel ddi_put8(pcic->cfg_handle, 21123db86aabSstevel pcic->cfgaddr + PCIC_BRIDGE_CTL_REG, 21133db86aabSstevel cfg); 21143db86aabSstevel } 21153db86aabSstevel break; 21163db86aabSstevel default: 21173db86aabSstevel break; 21183db86aabSstevel } /* switch */ 21193db86aabSstevel 2120bb3a048dSrw148561 /* 2121bb3a048dSrw148561 * The default value in the EEPROM (loaded on reset) for 2122bb3a048dSrw148561 * MFUNC0/MFUNC1 may be incorrect. Here we make sure that 2123bb3a048dSrw148561 * MFUNC0 is connected to INTA, and MFUNC1 is connected to 2124bb3a048dSrw148561 * INTB. This applies to all TI CardBus controllers. 2125bb3a048dSrw148561 */ 2126bb3a048dSrw148561 if ((pcic->pc_type >> 16) == PCIC_TI_VENDORID && 2127bb3a048dSrw148561 pcic->pc_intr_mode == PCIC_INTR_MODE_PCI_1) { 2128bb3a048dSrw148561 value = ddi_get32(pcic->cfg_handle, 2129bb3a048dSrw148561 (uint32_t *)(pcic->cfgaddr + PCIC_MFROUTE_REG)); 2130bb3a048dSrw148561 value &= ~0xff; 2131bb3a048dSrw148561 ddi_put32(pcic->cfg_handle, (uint32_t *)(pcic->cfgaddr + 21328134ee03Srw148561 PCIC_MFROUTE_REG), value|PCIC_TI_MFUNC_SEL); 2133bb3a048dSrw148561 } 2134bb3a048dSrw148561 21353db86aabSstevel /* setup general card status change interrupt */ 21363db86aabSstevel switch (pcic->pc_type) { 21373db86aabSstevel case PCIC_TI_PCI1225: 21383db86aabSstevel case PCIC_TI_PCI1221: 21393db86aabSstevel case PCIC_TI_PCI1031: 21403db86aabSstevel case PCIC_TI_PCI1520: 21413db86aabSstevel case PCIC_TI_PCI1410: 21423db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 21433db86aabSstevel PCIC_CHANGE_DEFAULT); 21443db86aabSstevel break; 21453db86aabSstevel default: 21463db86aabSstevel if (pcic->pc_intr_mode == 21473db86aabSstevel PCIC_INTR_MODE_PCI_1) { 21483db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 21493db86aabSstevel PCIC_CHANGE_DEFAULT); 21503db86aabSstevel break; 21513db86aabSstevel } else { 21523db86aabSstevel pcic_putb(pcic, i, PCIC_MANAGEMENT_INT, 21533db86aabSstevel PCIC_CHANGE_DEFAULT | 21543db86aabSstevel (pcic->pc_sockets[i].pcs_smi << 4)); 21553db86aabSstevel break; 21563db86aabSstevel } 21573db86aabSstevel } 21583db86aabSstevel 21593db86aabSstevel pcic->pc_flags |= PCF_INTRENAB; 21603db86aabSstevel 21613db86aabSstevel /* take card out of RESET */ 21623db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, PCIC_RESET); 21633db86aabSstevel /* turn power off and let CS do this */ 21643db86aabSstevel pcic_putb(pcic, i, PCIC_POWER_CONTROL, 0); 21653db86aabSstevel 21663db86aabSstevel /* final chip specific initialization */ 21673db86aabSstevel switch (pcic->pc_type) { 21683db86aabSstevel case PCIC_VADEM: 21693db86aabSstevel pcic_putb(pcic, i, PCIC_VG_CONTROL, 21703db86aabSstevel PCIC_VC_DELAYENABLE); 21713db86aabSstevel pcic->pc_flags |= PCF_DEBOUNCE; 21723db86aabSstevel /* FALLTHROUGH */ 21733db86aabSstevel case PCIC_I82365SL: 21743db86aabSstevel pcic_putb(pcic, i, PCIC_GLOBAL_CONTROL, 21753db86aabSstevel PCIC_GC_CSC_WRITE); 21763db86aabSstevel /* clear any pending interrupts */ 21773db86aabSstevel value = pcic_getb(pcic, i, PCIC_CARD_STATUS_CHANGE); 21783db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, value); 21793db86aabSstevel break; 21803db86aabSstevel /* The 82092 uses PCI config space to enable interrupts */ 21813db86aabSstevel case PCIC_INTEL_i82092: 21823db86aabSstevel pcic_82092_smiirq_ctl(pcic, i, PCIC_82092_CTL_SMI, 21833db86aabSstevel PCIC_82092_INT_ENABLE); 21843db86aabSstevel break; 21853db86aabSstevel case PCIC_CL_PD6729: 21863db86aabSstevel if (pcic->bus_speed >= PCIC_PCI_DEF_SYSCLK && i == 0) { 21873db86aabSstevel value = pcic_getb(pcic, i, PCIC_MISC_CTL_2); 21883db86aabSstevel pcic_putb(pcic, i, PCIC_MISC_CTL_2, 21893db86aabSstevel value | PCIC_CL_TIMER_CLK_DIV); 21903db86aabSstevel } 21913db86aabSstevel break; 21923db86aabSstevel } /* switch */ 21933db86aabSstevel 21943db86aabSstevel #if defined(PCIC_DEBUG) 21953db86aabSstevel if (pcic_debug) 21963db86aabSstevel cmn_err(CE_CONT, 21973db86aabSstevel "socket %d value=%x, flags = %x (%s)\n", 21983db86aabSstevel i, value, pcic->pc_sockets[i].pcs_flags, 21993db86aabSstevel (pcic->pc_sockets[i].pcs_flags & 22003db86aabSstevel PCS_CARD_PRESENT) ? 22013db86aabSstevel "card present" : "no card"); 22023db86aabSstevel #endif 22033db86aabSstevel } 22043db86aabSstevel } 22053db86aabSstevel 22063db86aabSstevel /* 22073db86aabSstevel * pcic_intr(caddr_t, caddr_t) 22083db86aabSstevel * interrupt handler for the PCIC style adapter 22093db86aabSstevel * handles all basic interrupts and also checks 22103db86aabSstevel * for status changes and notifies the nexus if 22113db86aabSstevel * necessary 22123db86aabSstevel * 22133db86aabSstevel * On PCI bus adapters, also handles all card 22143db86aabSstevel * IO interrupts. 22153db86aabSstevel */ 22163db86aabSstevel /*ARGSUSED*/ 22173db86aabSstevel uint32_t 22183db86aabSstevel pcic_intr(caddr_t arg1, caddr_t arg2) 22193db86aabSstevel { 22203db86aabSstevel pcicdev_t *pcic = (pcicdev_t *)arg1; 22213db86aabSstevel int value = 0, i, ret = DDI_INTR_UNCLAIMED; 22223db86aabSstevel uint8_t status; 22233db86aabSstevel uint_t io_ints; 22243db86aabSstevel 22253db86aabSstevel #if defined(PCIC_DEBUG) 22263db86aabSstevel pcic_err(pcic->dip, 0xf, 22273db86aabSstevel "pcic_intr: enter pc_flags=0x%x PCF_ATTACHED=0x%x" 22283db86aabSstevel " pc_numsockets=%d \n", 22293db86aabSstevel pcic->pc_flags, PCF_ATTACHED, pcic->pc_numsockets); 22303db86aabSstevel #endif 22313db86aabSstevel 22323db86aabSstevel if (!(pcic->pc_flags & PCF_ATTACHED)) 22333db86aabSstevel return (DDI_INTR_UNCLAIMED); 22343db86aabSstevel 22353db86aabSstevel mutex_enter(&pcic->intr_lock); 22363db86aabSstevel 22373db86aabSstevel if (pcic->pc_flags & PCF_SUSPENDED) { 22383db86aabSstevel mutex_exit(&pcic->intr_lock); 22393db86aabSstevel return (ret); 22403db86aabSstevel } 22413db86aabSstevel 22423db86aabSstevel /* 22433db86aabSstevel * need to change to only ACK and touch the slot that 22443db86aabSstevel * actually caused the interrupt. Currently everything 22453db86aabSstevel * is acked 22463db86aabSstevel * 22473db86aabSstevel * we need to look at all known sockets to determine 22483db86aabSstevel * what might have happened, so step through the list 22493db86aabSstevel * of them 22503db86aabSstevel */ 22513db86aabSstevel #ifdef VOYAGER 22523db86aabSstevel ret = syshw_intr_hi(pcic); 22533db86aabSstevel #endif 22543db86aabSstevel 22553db86aabSstevel /* 22563db86aabSstevel * Set the bitmask for IO interrupts to initially include all sockets 22573db86aabSstevel */ 22583db86aabSstevel io_ints = (1 << pcic->pc_numsockets) - 1; 22593db86aabSstevel 22603db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) { 22613db86aabSstevel int card_type; 22623db86aabSstevel pcic_socket_t *sockp; 22633db86aabSstevel int value_cb = 0; 22643db86aabSstevel 22653db86aabSstevel sockp = &pcic->pc_sockets[i]; 22663db86aabSstevel /* get the socket's I/O addresses */ 22673db86aabSstevel 22683db86aabSstevel if (sockp->pcs_flags & PCS_WAITING) { 22693db86aabSstevel io_ints &= ~(1 << i); 22703db86aabSstevel continue; 22713db86aabSstevel } 22723db86aabSstevel 22733db86aabSstevel if (sockp->pcs_flags & PCS_CARD_IO) 22743db86aabSstevel card_type = IF_IO; 22753db86aabSstevel else 22763db86aabSstevel card_type = IF_MEMORY; 22773db86aabSstevel 22783db86aabSstevel if (pcic->pc_io_type == PCIC_IO_TYPE_YENTA) 22793db86aabSstevel value_cb = pcic_getcb(pcic, CB_STATUS_EVENT); 22803db86aabSstevel 22813db86aabSstevel value = pcic_change(pcic, i); 22823db86aabSstevel 22833db86aabSstevel if ((value != 0) || (value_cb != 0)) { 22843db86aabSstevel int x = pcic->pc_cb_arg; 22853db86aabSstevel 22863db86aabSstevel ret = DDI_INTR_CLAIMED; 22873db86aabSstevel 22883db86aabSstevel #if defined(PCIC_DEBUG) 22893db86aabSstevel pcic_err(pcic->dip, 0x9, 22903db86aabSstevel "card_type = %d, value_cb = 0x%x\n", 22913db86aabSstevel card_type, 22923db86aabSstevel value_cb ? value_cb : 22933db86aabSstevel pcic_getcb(pcic, CB_STATUS_EVENT)); 22943db86aabSstevel if (pcic_debug) 22953db86aabSstevel cmn_err(CE_CONT, 22963db86aabSstevel "\tchange on socket %d (%x)\n", i, 22973db86aabSstevel value); 22983db86aabSstevel #endif 22993db86aabSstevel /* find out what happened */ 23003db86aabSstevel status = pcic_getb(pcic, i, PCIC_INTERFACE_STATUS); 23013db86aabSstevel 23023db86aabSstevel /* acknowledge the interrupt */ 23033db86aabSstevel if (value_cb) 23043db86aabSstevel pcic_putcb(pcic, CB_STATUS_EVENT, value_cb); 23053db86aabSstevel 23063db86aabSstevel if (value) 23073db86aabSstevel pcic_putb(pcic, i, PCIC_CARD_STATUS_CHANGE, 23083db86aabSstevel value); 23093db86aabSstevel 23103db86aabSstevel if (pcic->pc_callback == NULL) { 23113db86aabSstevel /* if not callback handler, nothing to do */ 23123db86aabSstevel continue; 23133db86aabSstevel } 23143db86aabSstevel 23153db86aabSstevel /* Card Detect */ 23163db86aabSstevel if (value & PCIC_CD_DETECT || 23173db86aabSstevel value_cb & CB_PS_CCDMASK) { 23183db86aabSstevel uint8_t irq; 23193db86aabSstevel #if defined(PCIC_DEBUG) 23203db86aabSstevel if (pcic_debug) 23213db86aabSstevel cmn_err(CE_CONT, 23223db86aabSstevel "\tcd_detect: status=%x," 23233db86aabSstevel " flags=%x\n", 23243db86aabSstevel status, sockp->pcs_flags); 23253db86aabSstevel #else 23263db86aabSstevel #ifdef lint 23273db86aabSstevel if (status == 0) 23283db86aabSstevel status++; 23293db86aabSstevel #endif 23303db86aabSstevel #endif 23313db86aabSstevel /* 23323db86aabSstevel * Turn off all interrupts for this socket here. 23333db86aabSstevel */ 23343db86aabSstevel irq = pcic_getb(pcic, sockp->pcs_socket, 23353db86aabSstevel PCIC_MANAGEMENT_INT); 23363db86aabSstevel irq &= ~PCIC_CHANGE_MASK; 23373db86aabSstevel pcic_putb(pcic, sockp->pcs_socket, 23383db86aabSstevel PCIC_MANAGEMENT_INT, irq); 23393db86aabSstevel 23403db86aabSstevel pcic_putcb(pcic, CB_STATUS_MASK, 0x0); 23413db86aabSstevel 23420d282d13Srw148561 /* 23430d282d13Srw148561 * Put the socket in debouncing state so that 23440d282d13Srw148561 * the leaf driver won't receive interrupts. 23450d282d13Srw148561 * Crucial for handling surprise-removal. 23460d282d13Srw148561 */ 23470d282d13Srw148561 sockp->pcs_flags |= PCS_DEBOUNCING; 23480d282d13Srw148561 23493db86aabSstevel if (!sockp->pcs_cd_softint_flg) { 23503db86aabSstevel sockp->pcs_cd_softint_flg = 1; 23513db86aabSstevel (void) ddi_intr_trigger_softint( 23523db86aabSstevel sockp->pcs_cd_softint_hdl, NULL); 23533db86aabSstevel } 23543db86aabSstevel 23553db86aabSstevel io_ints &= ~(1 << i); 23563db86aabSstevel } /* PCIC_CD_DETECT */ 23573db86aabSstevel 23583db86aabSstevel /* Ready/Change Detect */ 23593db86aabSstevel sockp->pcs_state ^= SBM_RDYBSY; 23603db86aabSstevel if (card_type == IF_MEMORY && value & PCIC_RD_DETECT) { 23613db86aabSstevel sockp->pcs_flags |= PCS_READY; 23623db86aabSstevel PC_CALLBACK(pcic->dip, x, PCE_CARD_READY, i); 23633db86aabSstevel } 23643db86aabSstevel 23653db86aabSstevel /* Battery Warn Detect */ 23663db86aabSstevel if (card_type == IF_MEMORY && 23673db86aabSstevel value & PCIC_BW_DETECT && 23683db86aabSstevel !(sockp->pcs_state & SBM_BVD2)) { 23693db86aabSstevel sockp->pcs_state |= SBM_BVD2; 23703db86aabSstevel PC_CALLBACK(pcic->dip, x, 23713db86aabSstevel PCE_CARD_BATTERY_WARN, i); 23723db86aabSstevel } 23733db86aabSstevel 23743db86aabSstevel /* Battery Dead Detect */ 23753db86aabSstevel if (value & PCIC_BD_DETECT) { 23763db86aabSstevel /* 23773db86aabSstevel * need to work out event if RI not enabled 23783db86aabSstevel * and card_type == IF_IO 23793db86aabSstevel */ 23803db86aabSstevel if (card_type == IF_MEMORY && 23813db86aabSstevel !(sockp->pcs_state & SBM_BVD1)) { 23823db86aabSstevel sockp->pcs_state |= SBM_BVD1; 23833db86aabSstevel PC_CALLBACK(pcic->dip, x, 23843db86aabSstevel PCE_CARD_BATTERY_DEAD, 23853db86aabSstevel i); 23863db86aabSstevel } else { 23873db86aabSstevel /* 23883db86aabSstevel * information in pin replacement 23893db86aabSstevel * register if one is available 23903db86aabSstevel */ 23913db86aabSstevel PC_CALLBACK(pcic->dip, x, 23923db86aabSstevel PCE_CARD_STATUS_CHANGE, 23933db86aabSstevel i); 23943db86aabSstevel } /* IF_MEMORY */ 23953db86aabSstevel } /* PCIC_BD_DETECT */ 23963db86aabSstevel } /* if pcic_change */ 23973db86aabSstevel /* 23983db86aabSstevel * for any controllers that we can detect whether a socket 23993db86aabSstevel * had an interrupt for the PC Card, we should sort that out 24003db86aabSstevel * here. 24013db86aabSstevel */ 24023db86aabSstevel } /* for pc_numsockets */ 24033db86aabSstevel 24043db86aabSstevel /* 24053db86aabSstevel * If we're on a PCI bus, we may need to cycle through each IO 24063db86aabSstevel * interrupt handler that is registered since they all 24073db86aabSstevel * share the same interrupt line. 24083db86aabSstevel */ 24093db86aabSstevel 24103db86aabSstevel 24113db86aabSstevel #if defined(PCIC_DEBUG) 24123db86aabSstevel pcic_err(pcic->dip, 0xf, 24133db86aabSstevel "pcic_intr: pc_intr_mode=%d pc_type=%x io_ints=0x%x\n", 24143db86aabSstevel pcic->pc_intr_mode, pcic->pc_type, io_ints); 24153db86aabSstevel #endif 24163db86aabSstevel 24170d282d13Srw148561 if (io_ints) { 24180d282d13Srw148561 if (pcic_do_io_intr(pcic, io_ints) == DDI_INTR_CLAIMED) 24193db86aabSstevel ret = DDI_INTR_CLAIMED; 24203db86aabSstevel } 24213db86aabSstevel 24223db86aabSstevel mutex_exit(&pcic->intr_lock); 24233db86aabSstevel 24243db86aabSstevel #if defined(PCIC_DEBUG) 24253db86aabSstevel pcic_err(pcic->dip, 0xf, 24263db86aabSstevel "pcic_intr: ret=%d value=%d DDI_INTR_CLAIMED=%d\n", 24273db86aabSstevel ret, value, DDI_INTR_CLAIMED); 24283db86aabSstevel #endif 24293db86aabSstevel 24303db86aabSstevel return (ret); 24313db86aabSstevel } 24323db86aabSstevel 24333db86aabSstevel /* 24343db86aabSstevel * pcic_change() 24353db86aabSstevel * check to see if this socket had a change in state 24363db86aabSstevel * by checking the status change register 24373db86aabSstevel */ 24383db86aabSstevel static int 24393db86aabSstevel pcic_change(pcicdev_t *pcic, int socket) 24403db86aabSstevel { 24413db86aabSstevel return (pcic_getb(pcic, socket, PCIC_CARD_STATUS_CHANGE)); 24423db86aabSstevel } 24433db86aabSstevel 24443db86aabSstevel /* 24453db86aabSstevel * pcic_do_io_intr - calls client interrupt handlers 24463db86aabSstevel */ 24473db86aabSstevel static int 24483db86aabSstevel pcic_do_io_intr(pcicdev_t *pcic, uint32_t sockets) 24493db86aabSstevel { 24503db86aabSstevel inthandler_t *tmp; 24513db86aabSstevel int ret = DDI_INTR_UNCLAIMED; 24523db86aabSstevel 24533db86aabSstevel #if defined(PCIC_DEBUG) 24543db86aabSstevel pcic_err(pcic->dip, 0xf, 24553db86aabSstevel "pcic_do_io_intr: pcic=%p sockets=%d irq_top=%p\n", 24563db86aabSstevel (void *)pcic, (int)sockets, (void *)pcic->irq_top); 24573db86aabSstevel #endif 24583db86aabSstevel 24593db86aabSstevel if (pcic->irq_top != NULL) { 24603db86aabSstevel tmp = pcic->irq_current; 24613db86aabSstevel 24623db86aabSstevel do { 24633db86aabSstevel int cur = pcic->irq_current->socket; 24643db86aabSstevel pcic_socket_t *sockp = 24653db86aabSstevel &pcic->pc_sockets[cur]; 24663db86aabSstevel 24673db86aabSstevel #if defined(PCIC_DEBUG) 24683db86aabSstevel pcic_err(pcic->dip, 0xf, 24693db86aabSstevel "\t pcs_flags=0x%x PCS_CARD_PRESENT=0x%x\n", 24703db86aabSstevel sockp->pcs_flags, PCS_CARD_PRESENT); 24713db86aabSstevel pcic_err(pcic->dip, 0xf, 24723db86aabSstevel "\t sockets=%d cur=%d intr=%p arg1=%p " 24733db86aabSstevel "arg2=%p\n", 24743db86aabSstevel sockets, cur, (void *)pcic->irq_current->intr, 24753db86aabSstevel pcic->irq_current->arg1, 24763db86aabSstevel pcic->irq_current->arg2); 24773db86aabSstevel #endif 24780d282d13Srw148561 if ((sockp->pcs_flags & PCS_CARD_PRESENT) && 24790d282d13Srw148561 !(sockp->pcs_flags & PCS_DEBOUNCING) && 24800d282d13Srw148561 (sockets & (1 << cur))) { 24813db86aabSstevel 24823db86aabSstevel if ((*pcic->irq_current->intr)(pcic->irq_current->arg1, 24833db86aabSstevel pcic->irq_current->arg2) == DDI_INTR_CLAIMED) 24843db86aabSstevel ret = DDI_INTR_CLAIMED; 24853db86aabSstevel 24863db86aabSstevel #if defined(PCIC_DEBUG) 24873db86aabSstevel pcic_err(pcic->dip, 0xf, 24883db86aabSstevel "\t ret=%d DDI_INTR_CLAIMED=%d\n", 24893db86aabSstevel ret, DDI_INTR_CLAIMED); 24903db86aabSstevel #endif 24913db86aabSstevel } 24923db86aabSstevel 24933db86aabSstevel 24943db86aabSstevel if ((pcic->irq_current = pcic->irq_current->next) == NULL) 24953db86aabSstevel pcic->irq_current = pcic->irq_top; 24963db86aabSstevel 24973db86aabSstevel } while (pcic->irq_current != tmp); 24983db86aabSstevel 24993db86aabSstevel if ((pcic->irq_current = pcic->irq_current->next) == NULL) 25003db86aabSstevel pcic->irq_current = pcic->irq_top; 25013db86aabSstevel 25023db86aabSstevel } else { 25033db86aabSstevel ret = DDI_INTR_UNCLAIMED; 25043db86aabSstevel } 25053db86aabSstevel 25063db86aabSstevel #if defined(PCIC_DEBUG) 25073db86aabSstevel pcic_err(pcic->dip, 0xf, 25083db86aabSstevel "pcic_do_io_intr: exit ret=%d DDI_INTR_CLAIMED=%d\n", 25093db86aabSstevel ret, DDI_INTR_CLAIMED); 25103db86aabSstevel #endif 25113db86aabSstevel 25123db86aabSstevel return (ret); 25133db86aabSstevel 25143db86aabSstevel } 25153db86aabSstevel 25163db86aabSstevel /* 25173db86aabSstevel * pcic_inquire_adapter() 25183db86aabSstevel * SocketServices InquireAdapter function 25193db86aabSstevel * get characteristics of the physical adapter 25203db86aabSstevel */ 25213db86aabSstevel /*ARGSUSED*/ 25223db86aabSstevel static int 25233db86aabSstevel pcic_inquire_adapter(dev_info_t *dip, inquire_adapter_t *config) 25243db86aabSstevel { 25253db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 25263db86aabSstevel pcicdev_t *pcic = anp->an_private; 25273db86aabSstevel 25283db86aabSstevel config->NumSockets = pcic->pc_numsockets; 25293db86aabSstevel config->NumWindows = pcic->pc_numsockets * PCIC_NUMWINSOCK; 25303db86aabSstevel config->NumEDCs = 0; 25313db86aabSstevel config->AdpCaps = 0; 25323db86aabSstevel config->ActiveHigh = 0; 25333db86aabSstevel config->ActiveLow = PCIC_AVAIL_IRQS; 25343db86aabSstevel config->NumPower = pcic->pc_numpower; 25353db86aabSstevel config->power_entry = pcic->pc_power; /* until we resolve this */ 25363db86aabSstevel #if defined(PCIC_DEBUG) 25373db86aabSstevel if (pcic_debug) { 25383db86aabSstevel cmn_err(CE_CONT, "pcic_inquire_adapter:\n"); 25393db86aabSstevel cmn_err(CE_CONT, "\tNumSockets=%d\n", config->NumSockets); 25403db86aabSstevel cmn_err(CE_CONT, "\tNumWindows=%d\n", config->NumWindows); 25413db86aabSstevel } 25423db86aabSstevel #endif 25433db86aabSstevel config->ResourceFlags = 0; 25443db86aabSstevel switch (pcic->pc_intr_mode) { 25453db86aabSstevel case PCIC_INTR_MODE_PCI_1: 25463db86aabSstevel config->ResourceFlags |= RES_OWN_IRQ | RES_IRQ_NEXUS | 25473db86aabSstevel RES_IRQ_SHAREABLE; 25483db86aabSstevel break; 25493db86aabSstevel } 25503db86aabSstevel return (SUCCESS); 25513db86aabSstevel } 25523db86aabSstevel 25533db86aabSstevel /* 25543db86aabSstevel * pcic_callback() 25553db86aabSstevel * The PCMCIA nexus calls us via this function 25563db86aabSstevel * in order to set the callback function we are 25573db86aabSstevel * to call the nexus with 25583db86aabSstevel */ 25593db86aabSstevel /*ARGSUSED*/ 25603db86aabSstevel static int 25613db86aabSstevel pcic_callback(dev_info_t *dip, int (*handler)(), int arg) 25623db86aabSstevel { 25633db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 25643db86aabSstevel pcicdev_t *pcic = anp->an_private; 25653db86aabSstevel 25663db86aabSstevel if (handler != NULL) { 25673db86aabSstevel pcic->pc_callback = handler; 25683db86aabSstevel pcic->pc_cb_arg = arg; 25693db86aabSstevel pcic->pc_flags |= PCF_CALLBACK; 25703db86aabSstevel } else { 25713db86aabSstevel pcic->pc_callback = NULL; 25723db86aabSstevel pcic->pc_cb_arg = 0; 25733db86aabSstevel pcic->pc_flags &= ~PCF_CALLBACK; 25743db86aabSstevel } 25753db86aabSstevel /* 25763db86aabSstevel * we're now registered with the nexus 25773db86aabSstevel * it is acceptable to do callbacks at this point. 25783db86aabSstevel * don't call back from here though since it could block 25793db86aabSstevel */ 25803db86aabSstevel return (PC_SUCCESS); 25813db86aabSstevel } 25823db86aabSstevel 25833db86aabSstevel /* 25843db86aabSstevel * pcic_calc_speed (pcicdev_t *pcic, uint32_t speed) 25853db86aabSstevel * calculate the speed bits from the specified memory speed 25863db86aabSstevel * there may be more to do here 25873db86aabSstevel */ 25883db86aabSstevel 25893db86aabSstevel static int 25903db86aabSstevel pcic_calc_speed(pcicdev_t *pcic, uint32_t speed) 25913db86aabSstevel { 25923db86aabSstevel uint32_t wspeed = 1; /* assume 1 wait state when unknown */ 25933db86aabSstevel uint32_t bspeed = PCIC_ISA_DEF_SYSCLK; 25943db86aabSstevel 25953db86aabSstevel switch (pcic->pc_type) { 25963db86aabSstevel case PCIC_I82365SL: 25973db86aabSstevel case PCIC_VADEM: 25983db86aabSstevel case PCIC_VADEM_VG469: 25993db86aabSstevel default: 26003db86aabSstevel /* Intel chip wants it in waitstates */ 26013db86aabSstevel wspeed = mhztons(PCIC_ISA_DEF_SYSCLK) * 3; 26023db86aabSstevel if (speed <= wspeed) 26033db86aabSstevel wspeed = 0; 26043db86aabSstevel else if (speed <= (wspeed += mhztons(bspeed))) 26053db86aabSstevel wspeed = 1; 26063db86aabSstevel else if (speed <= (wspeed += mhztons(bspeed))) 26073db86aabSstevel wspeed = 2; 26083db86aabSstevel else 26093db86aabSstevel wspeed = 3; 26103db86aabSstevel wspeed <<= 6; /* put in right bit positions */ 26113db86aabSstevel break; 26123db86aabSstevel 26133db86aabSstevel case PCIC_INTEL_i82092: 26143db86aabSstevel wspeed = SYSMEM_82092_80NS; 26153db86aabSstevel if (speed > 80) 26163db86aabSstevel wspeed = SYSMEM_82092_100NS; 26173db86aabSstevel if (speed > 100) 26183db86aabSstevel wspeed = SYSMEM_82092_150NS; 26193db86aabSstevel if (speed > 150) 26203db86aabSstevel wspeed = SYSMEM_82092_200NS; 26213db86aabSstevel if (speed > 200) 26223db86aabSstevel wspeed = SYSMEM_82092_250NS; 26233db86aabSstevel if (speed > 250) 26243db86aabSstevel wspeed = SYSMEM_82092_600NS; 26253db86aabSstevel wspeed <<= 5; /* put in right bit positions */ 26263db86aabSstevel break; 26273db86aabSstevel 26283db86aabSstevel } /* switch */ 26293db86aabSstevel 26303db86aabSstevel return (wspeed); 26313db86aabSstevel } 26323db86aabSstevel 26333db86aabSstevel /* 26343db86aabSstevel * These values are taken from the PC Card Standard Electrical Specification. 26353db86aabSstevel * Generally the larger value is taken if 2 are possible. 26363db86aabSstevel */ 26373db86aabSstevel static struct pcic_card_times { 26383db86aabSstevel uint16_t cycle; /* Speed as found in the atribute space of he card. */ 26393db86aabSstevel uint16_t setup; /* Corresponding address setup time. */ 26403db86aabSstevel uint16_t width; /* Corresponding width, OE or WE. */ 26413db86aabSstevel uint16_t hold; /* Corresponding data or address hold time. */ 26423db86aabSstevel } pcic_card_times[] = { 26433db86aabSstevel 26443db86aabSstevel /* 26453db86aabSstevel * Note: The rounded up times for 250, 200 & 150 have been increased 26463db86aabSstevel * due to problems with the 3-Com ethernet cards (pcelx) on UBIIi. 26473db86aabSstevel * See BugID 00663. 26483db86aabSstevel */ 26493db86aabSstevel 26503db86aabSstevel /* 26513db86aabSstevel * Rounded up times Original times from 26523db86aabSstevel * that add up to the the PCMCIA Spec. 26533db86aabSstevel * cycle time. 26543db86aabSstevel */ 26553db86aabSstevel {600, 180, 370, 140}, /* 100, 300, 70 */ 26563db86aabSstevel {400, 120, 300, 90}, /* Made this one up */ 26573db86aabSstevel {250, 100, 190, 70}, /* 30, 150, 30 */ 26583db86aabSstevel {200, 80, 170, 70}, /* 20, 120, 30 */ 26593db86aabSstevel {150, 50, 110, 40}, /* 20, 80, 20 */ 26603db86aabSstevel {100, 40, 80, 40}, /* 10, 60, 15 */ 26613db86aabSstevel {0, 10, 60, 15} /* 10, 60, 15 */ 26623db86aabSstevel }; 26633db86aabSstevel 26643db86aabSstevel /* 26653db86aabSstevel * pcic_set_cdtimers 26663db86aabSstevel * This is specific to several Cirrus Logic chips 26673db86aabSstevel */ 26683db86aabSstevel static void 26693db86aabSstevel pcic_set_cdtimers(pcicdev_t *pcic, int socket, uint32_t speed, int tset) 26703db86aabSstevel { 26713db86aabSstevel int cmd, set, rec, offset, clk_pulse; 26723db86aabSstevel struct pcic_card_times *ctp; 26733db86aabSstevel 26743db86aabSstevel if ((tset == IOMEM_CLTIMER_SET_1) || (tset == SYSMEM_CLTIMER_SET_1)) 26753db86aabSstevel offset = 3; 26763db86aabSstevel else 26773db86aabSstevel offset = 0; 26783db86aabSstevel 26793db86aabSstevel clk_pulse = mhztons(pcic->bus_speed); 26803db86aabSstevel for (ctp = pcic_card_times; speed < ctp->cycle; ctp++); 26813db86aabSstevel 26823db86aabSstevel /* 26833db86aabSstevel * Add (clk_pulse/2) and an extra 1 to account for rounding errors. 26843db86aabSstevel */ 26853db86aabSstevel set = ((ctp->setup + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1; 26863db86aabSstevel if (set < 0) 26873db86aabSstevel set = 0; 26883db86aabSstevel 26893db86aabSstevel cmd = ((ctp->width + 10 + 1 + (clk_pulse/2))/clk_pulse) - 1; 26903db86aabSstevel if (cmd < 0) 26913db86aabSstevel cmd = 0; 26923db86aabSstevel 26933db86aabSstevel rec = ((ctp->hold + 10 + 1 + (clk_pulse/2))/clk_pulse) - 2; 26943db86aabSstevel if (rec < 0) 26953db86aabSstevel rec = 0; 26963db86aabSstevel 26973db86aabSstevel #if defined(PCIC_DEBUG) 26983db86aabSstevel pcic_err(pcic->dip, 8, "pcic_set_cdtimers(%d, Timer Set %d)\n" 26993db86aabSstevel "ct=%d, cp=%d, cmd=0x%x, setup=0x%x, rec=0x%x\n", 27003db86aabSstevel (unsigned)speed, offset == 3 ? 1 : 0, 27013db86aabSstevel ctp->cycle, clk_pulse, cmd, set, rec); 27023db86aabSstevel #endif 27033db86aabSstevel 27043db86aabSstevel pcic_putb(pcic, socket, PCIC_TIME_COMMAND_0 + offset, cmd); 27053db86aabSstevel pcic_putb(pcic, socket, PCIC_TIME_SETUP_0 + offset, set); 27063db86aabSstevel pcic_putb(pcic, socket, PCIC_TIME_RECOVER_0 + offset, rec); 27073db86aabSstevel } 27083db86aabSstevel 27093db86aabSstevel /* 27103db86aabSstevel * pcic_set_window 27113db86aabSstevel * essentially the same as the Socket Services specification 27123db86aabSstevel * We use socket and not adapter since they are identifiable 27133db86aabSstevel * but the rest is the same 27143db86aabSstevel * 27153db86aabSstevel * dip pcic driver's device information 27163db86aabSstevel * window parameters for the request 27173db86aabSstevel */ 27183db86aabSstevel static int 27193db86aabSstevel pcic_set_window(dev_info_t *dip, set_window_t *window) 27203db86aabSstevel { 27213db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 27223db86aabSstevel pcicdev_t *pcic = anp->an_private; 27233db86aabSstevel int select; 27243db86aabSstevel int socket, pages, which, ret; 27253db86aabSstevel pcic_socket_t *sockp = &pcic->pc_sockets[window->socket]; 27263db86aabSstevel ra_return_t res; 27273db86aabSstevel ndi_ra_request_t req; 27283db86aabSstevel uint32_t base = window->base; 27293db86aabSstevel 27303db86aabSstevel #if defined(PCIC_DEBUG) 27313db86aabSstevel if (pcic_debug) { 27323db86aabSstevel cmn_err(CE_CONT, "pcic_set_window: entered\n"); 27333db86aabSstevel cmn_err(CE_CONT, 27343db86aabSstevel "\twindow=%d, socket=%d, WindowSize=%d, speed=%d\n", 27353db86aabSstevel window->window, window->socket, window->WindowSize, 27363db86aabSstevel window->speed); 27373db86aabSstevel cmn_err(CE_CONT, 27383db86aabSstevel "\tbase=%x, state=%x\n", (unsigned)window->base, 27393db86aabSstevel (unsigned)window->state); 27403db86aabSstevel } 27413db86aabSstevel #endif 27423db86aabSstevel 27433db86aabSstevel /* 27443db86aabSstevel * do some basic sanity checking on what we support 27453db86aabSstevel * we don't do paged mode 27463db86aabSstevel */ 27473db86aabSstevel if (window->state & WS_PAGED) { 27483db86aabSstevel cmn_err(CE_WARN, "pcic_set_window: BAD_ATTRIBUTE\n"); 27493db86aabSstevel return (BAD_ATTRIBUTE); 27503db86aabSstevel } 27513db86aabSstevel 27523db86aabSstevel /* 27533db86aabSstevel * we don't care about previous mappings. 27543db86aabSstevel * Card Services will deal with that so don't 27553db86aabSstevel * even check 27563db86aabSstevel */ 27573db86aabSstevel 27583db86aabSstevel socket = window->socket; 27593db86aabSstevel 27603db86aabSstevel if (!(window->state & WS_IO)) { 27613db86aabSstevel int win, tmp; 27623db86aabSstevel pcs_memwin_t *memp; 27633db86aabSstevel #if defined(PCIC_DEBUG) 27643db86aabSstevel if (pcic_debug) 27653db86aabSstevel cmn_err(CE_CONT, "\twindow type is memory\n"); 27663db86aabSstevel #endif 27673db86aabSstevel /* this is memory window mapping */ 27683db86aabSstevel win = window->window % PCIC_NUMWINSOCK; 27693db86aabSstevel tmp = window->window / PCIC_NUMWINSOCK; 27703db86aabSstevel 27713db86aabSstevel /* only windows 2-6 can do memory mapping */ 27723db86aabSstevel if (tmp != window->socket || win < PCIC_IOWINDOWS) { 27733db86aabSstevel cmn_err(CE_CONT, 27743db86aabSstevel "\tattempt to map to non-mem window\n"); 27753db86aabSstevel return (BAD_WINDOW); 27763db86aabSstevel } 27773db86aabSstevel 27783db86aabSstevel if (window->WindowSize == 0) 27793db86aabSstevel window->WindowSize = MEM_MIN; 27803db86aabSstevel else if ((window->WindowSize & (PCIC_PAGE-1)) != 0) { 27813db86aabSstevel cmn_err(CE_WARN, "pcic_set_window: BAD_SIZE\n"); 27823db86aabSstevel return (BAD_SIZE); 27833db86aabSstevel } 27843db86aabSstevel 27853db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 27863db86aabSstevel 27873db86aabSstevel memp = &sockp->pcs_windows[win].mem; 27883db86aabSstevel memp->pcw_speed = window->speed; 27893db86aabSstevel 27903db86aabSstevel win -= PCIC_IOWINDOWS; /* put in right range */ 27913db86aabSstevel 27923db86aabSstevel if (window->WindowSize != memp->pcw_len) 27933db86aabSstevel which = memp->pcw_len; 27943db86aabSstevel else 27953db86aabSstevel which = 0; 27963db86aabSstevel 27973db86aabSstevel if (window->state & WS_ENABLED) { 27983db86aabSstevel uint32_t wspeed; 27993db86aabSstevel #if defined(PCIC_DEBUG) 28003db86aabSstevel if (pcic_debug) { 28013db86aabSstevel cmn_err(CE_CONT, 28023db86aabSstevel "\tbase=%x, win=%d\n", (unsigned)base, 28033db86aabSstevel win); 28043db86aabSstevel if (which) 28053db86aabSstevel cmn_err(CE_CONT, 28063db86aabSstevel "\tneed to remap window\n"); 28073db86aabSstevel } 28083db86aabSstevel #endif 28093db86aabSstevel 28103db86aabSstevel if (which && (memp->pcw_status & PCW_MAPPED)) { 28113db86aabSstevel ddi_regs_map_free(&memp->pcw_handle); 28123db86aabSstevel res.ra_addr_lo = memp->pcw_base; 28133db86aabSstevel res.ra_len = memp->pcw_len; 28148134ee03Srw148561 (void) pcmcia_free_mem(memp->res_dip, &res); 28153db86aabSstevel memp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED); 28163db86aabSstevel memp->pcw_hostmem = NULL; 28173db86aabSstevel memp->pcw_base = NULL; 28183db86aabSstevel memp->pcw_len = 0; 28193db86aabSstevel } 28203db86aabSstevel 28213db86aabSstevel which = window->WindowSize >> PAGE_SHIFT; 28223db86aabSstevel 28233db86aabSstevel if (!(memp->pcw_status & PCW_MAPPED)) { 28243db86aabSstevel ret = 0; 28253db86aabSstevel 28263db86aabSstevel memp->pcw_base = base; 28273db86aabSstevel bzero(&req, sizeof (req)); 28283db86aabSstevel req.ra_len = which << PAGE_SHIFT; 28293db86aabSstevel req.ra_addr = (uint64_t)memp->pcw_base; 28303db86aabSstevel req.ra_boundbase = pcic->pc_base; 28313db86aabSstevel req.ra_boundlen = pcic->pc_bound; 28323db86aabSstevel req.ra_flags = (memp->pcw_base ? 28333db86aabSstevel NDI_RA_ALLOC_SPECIFIED : 0) | 28343db86aabSstevel NDI_RA_ALLOC_BOUNDED; 28353db86aabSstevel req.ra_align_mask = 28363db86aabSstevel (PAGESIZE - 1) | (PCIC_PAGE - 1); 28373db86aabSstevel #if defined(PCIC_DEBUG) 28383db86aabSstevel pcic_err(dip, 8, 28393db86aabSstevel "\tlen 0x%"PRIx64 28403db86aabSstevel "addr 0x%"PRIx64"bbase 0x%"PRIx64 28413db86aabSstevel " blen 0x%"PRIx64" flags 0x%x" 28423db86aabSstevel " algn 0x%"PRIx64"\n", 28433db86aabSstevel req.ra_len, req.ra_addr, 28443db86aabSstevel req.ra_boundbase, 28453db86aabSstevel req.ra_boundlen, req.ra_flags, 28463db86aabSstevel req.ra_align_mask); 28473db86aabSstevel #endif 28483db86aabSstevel 28498134ee03Srw148561 ret = pcmcia_alloc_mem(dip, &req, &res, 28508134ee03Srw148561 &memp->res_dip); 28513db86aabSstevel if (ret == DDI_FAILURE) { 28523db86aabSstevel mutex_exit(&pcic->pc_lock); 28533db86aabSstevel cmn_err(CE_WARN, 28543db86aabSstevel "\tpcmcia_alloc_mem() failed\n"); 28553db86aabSstevel return (BAD_SIZE); 28563db86aabSstevel } 28573db86aabSstevel memp->pcw_base = res.ra_addr_lo; 28583db86aabSstevel base = memp->pcw_base; 28593db86aabSstevel 28603db86aabSstevel #if defined(PCIC_DEBUG) 28613db86aabSstevel if (pcic_debug) 28623db86aabSstevel cmn_err(CE_CONT, 28633db86aabSstevel "\tsetwindow: new base=%x\n", 28643db86aabSstevel (unsigned)memp->pcw_base); 28653db86aabSstevel #endif 28663db86aabSstevel memp->pcw_len = window->WindowSize; 28673db86aabSstevel 28683db86aabSstevel which = pcmcia_map_reg(pcic->dip, 28693db86aabSstevel window->child, 28703db86aabSstevel &res, 28713db86aabSstevel (uint32_t)(window->state & 28723db86aabSstevel 0xffff) | 28733db86aabSstevel (window->socket << 16), 28743db86aabSstevel (caddr_t *)&memp->pcw_hostmem, 28753db86aabSstevel &memp->pcw_handle, 28763db86aabSstevel &window->attr, NULL); 28773db86aabSstevel 28783db86aabSstevel if (which != DDI_SUCCESS) { 28793db86aabSstevel 28803db86aabSstevel cmn_err(CE_WARN, "\tpcmcia_map_reg() " 28813db86aabSstevel "failed\n"); 28823db86aabSstevel 28833db86aabSstevel res.ra_addr_lo = memp->pcw_base; 28843db86aabSstevel res.ra_len = memp->pcw_len; 28858134ee03Srw148561 (void) pcmcia_free_mem(memp->res_dip, &res); 28863db86aabSstevel 28873db86aabSstevel mutex_exit(&pcic->pc_lock); 28883db86aabSstevel 28893db86aabSstevel return (BAD_WINDOW); 28903db86aabSstevel } 28913db86aabSstevel memp->pcw_status |= PCW_MAPPED; 28923db86aabSstevel #if defined(PCIC_DEBUG) 28933db86aabSstevel if (pcic_debug) 28943db86aabSstevel cmn_err(CE_CONT, 28953db86aabSstevel "\tmap=%x, hostmem=%p\n", 28963db86aabSstevel which, 28973db86aabSstevel (void *)memp->pcw_hostmem); 28983db86aabSstevel #endif 28993db86aabSstevel } else { 29003db86aabSstevel base = memp->pcw_base; 29013db86aabSstevel } 29023db86aabSstevel 29033db86aabSstevel /* report the handle back to caller */ 29043db86aabSstevel window->handle = memp->pcw_handle; 29053db86aabSstevel 29063db86aabSstevel #if defined(PCIC_DEBUG) 29073db86aabSstevel if (pcic_debug) { 29083db86aabSstevel cmn_err(CE_CONT, 29093db86aabSstevel "\twindow mapped to %x@%x len=%d\n", 29103db86aabSstevel (unsigned)window->base, 29113db86aabSstevel (unsigned)memp->pcw_base, 29123db86aabSstevel memp->pcw_len); 29133db86aabSstevel } 29143db86aabSstevel #endif 29153db86aabSstevel 29163db86aabSstevel /* find the register set offset */ 29173db86aabSstevel select = win * PCIC_MEM_1_OFFSET; 29183db86aabSstevel #if defined(PCIC_DEBUG) 29193db86aabSstevel if (pcic_debug) 29203db86aabSstevel cmn_err(CE_CONT, "\tselect=%x\n", select); 29213db86aabSstevel #endif 29223db86aabSstevel 29233db86aabSstevel /* 29243db86aabSstevel * at this point, the register window indicator has 29253db86aabSstevel * been converted to be an offset from the first 29263db86aabSstevel * set of registers that are used for programming 29273db86aabSstevel * the window mapping and the offset used to select 29283db86aabSstevel * the correct set of registers to access the 29293db86aabSstevel * specified socket. This allows basing everything 29303db86aabSstevel * off the _0 window 29313db86aabSstevel */ 29323db86aabSstevel 29333db86aabSstevel /* map the physical page base address */ 29343db86aabSstevel which = (window->state & WS_16BIT) ? SYSMEM_DATA_16 : 0; 29353db86aabSstevel which |= (window->speed <= MEM_SPEED_MIN) ? 29363db86aabSstevel SYSMEM_ZERO_WAIT : 0; 29373db86aabSstevel 29383db86aabSstevel /* need to select register set */ 29393db86aabSstevel select = PCIC_MEM_1_OFFSET * win; 29403db86aabSstevel 29413db86aabSstevel pcic_putb(pcic, socket, 29423db86aabSstevel PCIC_SYSMEM_0_STARTLOW + select, 29433db86aabSstevel SYSMEM_LOW(base)); 29443db86aabSstevel pcic_putb(pcic, socket, 29453db86aabSstevel PCIC_SYSMEM_0_STARTHI + select, 29463db86aabSstevel SYSMEM_HIGH(base) | which); 29473db86aabSstevel 29483db86aabSstevel /* 29493db86aabSstevel * Some adapters can decode window addresses greater 29503db86aabSstevel * than 16-bits worth, so handle them here. 29513db86aabSstevel */ 29523db86aabSstevel switch (pcic->pc_type) { 29533db86aabSstevel case PCIC_INTEL_i82092: 29543db86aabSstevel pcic_putb(pcic, socket, 29553db86aabSstevel PCIC_82092_CPAGE, 29563db86aabSstevel SYSMEM_EXT(base)); 29573db86aabSstevel break; 29583db86aabSstevel case PCIC_CL_PD6729: 29593db86aabSstevel case PCIC_CL_PD6730: 29603db86aabSstevel clext_reg_write(pcic, socket, 29613db86aabSstevel PCIC_CLEXT_MMAP0_UA + win, 29623db86aabSstevel SYSMEM_EXT(base)); 29633db86aabSstevel break; 29643db86aabSstevel case PCIC_TI_PCI1130: 29653db86aabSstevel /* 29663db86aabSstevel * Note that the TI chip has one upper byte 29673db86aabSstevel * per socket so all windows get bound to a 29683db86aabSstevel * 16MB segment. This must be detected and 29693db86aabSstevel * handled appropriately. We can detect that 29703db86aabSstevel * it is done by seeing if the pc_base has 29713db86aabSstevel * changed and changing when the register 29723db86aabSstevel * is first set. This will force the bounds 29733db86aabSstevel * to be correct. 29743db86aabSstevel */ 29753db86aabSstevel if (pcic->pc_bound == 0xffffffff) { 29763db86aabSstevel pcic_putb(pcic, socket, 29773db86aabSstevel PCIC_TI_WINDOW_PAGE_PCI, 29783db86aabSstevel SYSMEM_EXT(base)); 29793db86aabSstevel pcic->pc_base = SYSMEM_EXT(base) << 24; 29803db86aabSstevel pcic->pc_bound = 0x1000000; 29813db86aabSstevel } 29823db86aabSstevel break; 29833db86aabSstevel case PCIC_TI_PCI1031: 29843db86aabSstevel case PCIC_TI_PCI1131: 29853db86aabSstevel case PCIC_TI_PCI1250: 29863db86aabSstevel case PCIC_TI_PCI1225: 29873db86aabSstevel case PCIC_TI_PCI1221: 29883db86aabSstevel case PCIC_SMC_34C90: 29893db86aabSstevel case PCIC_CL_PD6832: 29903db86aabSstevel case PCIC_RICOH_RL5C466: 29913db86aabSstevel case PCIC_TI_PCI1410: 29923db86aabSstevel case PCIC_ENE_1410: 29933db86aabSstevel case PCIC_TI_PCI1510: 29943db86aabSstevel case PCIC_TI_PCI1520: 29953db86aabSstevel case PCIC_O2_OZ6912: 29963db86aabSstevel case PCIC_TI_PCI1420: 29973db86aabSstevel case PCIC_ENE_1420: 29983db86aabSstevel case PCIC_TI_VENDOR: 29993db86aabSstevel case PCIC_TOSHIBA_TOPIC100: 30003db86aabSstevel case PCIC_TOSHIBA_TOPIC95: 30013db86aabSstevel case PCIC_TOSHIBA_VENDOR: 30023db86aabSstevel case PCIC_RICOH_VENDOR: 30033db86aabSstevel case PCIC_O2MICRO_VENDOR: 30043db86aabSstevel pcic_putb(pcic, socket, 30053db86aabSstevel PCIC_YENTA_MEM_PAGE + win, 30063db86aabSstevel SYSMEM_EXT(base)); 30073db86aabSstevel break; 30083db86aabSstevel default: 30093db86aabSstevel cmn_err(CE_NOTE, "pcic_set_window: unknown " 30103db86aabSstevel "cardbus vendor:0x%X\n", 30113db86aabSstevel pcic->pc_type); 30123db86aabSstevel pcic_putb(pcic, socket, 30133db86aabSstevel PCIC_YENTA_MEM_PAGE + win, 30143db86aabSstevel SYSMEM_EXT(base)); 30153db86aabSstevel 30163db86aabSstevel break; 30173db86aabSstevel } /* switch */ 30183db86aabSstevel 30193db86aabSstevel /* 30203db86aabSstevel * specify the length of the mapped range 30213db86aabSstevel * we convert to pages (rounding up) so that 30223db86aabSstevel * the hardware gets the right thing 30233db86aabSstevel */ 30243db86aabSstevel pages = (window->WindowSize+PCIC_PAGE-1)/PCIC_PAGE; 30253db86aabSstevel 30263db86aabSstevel /* 30273db86aabSstevel * Setup this window's timing. 30283db86aabSstevel */ 30293db86aabSstevel switch (pcic->pc_type) { 30303db86aabSstevel case PCIC_CL_PD6729: 30313db86aabSstevel case PCIC_CL_PD6730: 30323db86aabSstevel case PCIC_CL_PD6710: 30333db86aabSstevel case PCIC_CL_PD6722: 30343db86aabSstevel wspeed = SYSMEM_CLTIMER_SET_0; 30353db86aabSstevel pcic_set_cdtimers(pcic, socket, 30363db86aabSstevel window->speed, 30373db86aabSstevel wspeed); 30383db86aabSstevel break; 30393db86aabSstevel 30403db86aabSstevel case PCIC_INTEL_i82092: 30413db86aabSstevel default: 30423db86aabSstevel wspeed = pcic_calc_speed(pcic, window->speed); 30433db86aabSstevel break; 30443db86aabSstevel } /* switch */ 30453db86aabSstevel 30463db86aabSstevel #if defined(PCIC_DEBUG) 30473db86aabSstevel if (pcic_debug) 30483db86aabSstevel cmn_err(CE_CONT, 30493db86aabSstevel "\twindow %d speed bits = %x for " 30503db86aabSstevel "%dns\n", 30513db86aabSstevel win, (unsigned)wspeed, window->speed); 30523db86aabSstevel #endif 30533db86aabSstevel 30543db86aabSstevel pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPLOW + select, 30553db86aabSstevel SYSMEM_LOW(base + 30563db86aabSstevel (pages * PCIC_PAGE)-1)); 30573db86aabSstevel 30583db86aabSstevel wspeed |= SYSMEM_HIGH(base + (pages * PCIC_PAGE)-1); 30593db86aabSstevel pcic_putb(pcic, socket, PCIC_SYSMEM_0_STOPHI + select, 30603db86aabSstevel wspeed); 30613db86aabSstevel 30623db86aabSstevel /* 30633db86aabSstevel * now map the card's memory pages - we start with page 30643db86aabSstevel * 0 30653db86aabSstevel * we also default to AM -- set page might change it 30663db86aabSstevel */ 30673db86aabSstevel base = memp->pcw_base; 30683db86aabSstevel pcic_putb(pcic, socket, 30693db86aabSstevel PCIC_CARDMEM_0_LOW + select, 30703db86aabSstevel CARDMEM_LOW(0 - (uint32_t)base)); 30713db86aabSstevel 30723db86aabSstevel pcic_putb(pcic, socket, 30733db86aabSstevel PCIC_CARDMEM_0_HI + select, 30743db86aabSstevel CARDMEM_HIGH(0 - (uint32_t)base) | 30753db86aabSstevel CARDMEM_REG_ACTIVE); 30763db86aabSstevel 30773db86aabSstevel /* 30783db86aabSstevel * enable the window even though redundant 30793db86aabSstevel * and SetPage may do it again. 30803db86aabSstevel */ 30813db86aabSstevel select = pcic_getb(pcic, socket, 30823db86aabSstevel PCIC_MAPPING_ENABLE); 30833db86aabSstevel select |= SYSMEM_WINDOW(win); 30843db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select); 30853db86aabSstevel memp->pcw_offset = 0; 30863db86aabSstevel memp->pcw_status |= PCW_ENABLED; 30873db86aabSstevel } else { 30883db86aabSstevel /* 30893db86aabSstevel * not only do we unmap the memory, the 30903db86aabSstevel * window has been turned off. 30913db86aabSstevel */ 30923db86aabSstevel if (which && memp->pcw_status & PCW_MAPPED) { 30933db86aabSstevel ddi_regs_map_free(&memp->pcw_handle); 30943db86aabSstevel res.ra_addr_lo = memp->pcw_base; 30953db86aabSstevel res.ra_len = memp->pcw_len; 30968134ee03Srw148561 (void) pcmcia_free_mem(memp->res_dip, &res); 30973db86aabSstevel memp->pcw_hostmem = NULL; 30983db86aabSstevel memp->pcw_status &= ~PCW_MAPPED; 30993db86aabSstevel } 31003db86aabSstevel 31013db86aabSstevel /* disable current mapping */ 31023db86aabSstevel select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 31033db86aabSstevel select &= ~SYSMEM_WINDOW(win); 31043db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, select); 31053db86aabSstevel memp->pcw_status &= ~PCW_ENABLED; 31063db86aabSstevel } 31073db86aabSstevel memp->pcw_len = window->WindowSize; 31083db86aabSstevel window->handle = memp->pcw_handle; 31093db86aabSstevel #if defined(PCIC_DEBUG) 31103db86aabSstevel if (pcic_debug) 31113db86aabSstevel xxdmp_all_regs(pcic, window->socket, -1); 31123db86aabSstevel #endif 31133db86aabSstevel } else { 31143db86aabSstevel /* 31153db86aabSstevel * This is a request for an IO window 31163db86aabSstevel */ 31173db86aabSstevel int win, tmp; 31183db86aabSstevel pcs_iowin_t *winp; 31193db86aabSstevel /* I/O windows */ 31203db86aabSstevel #if defined(PCIC_DEBUG) 31213db86aabSstevel if (pcic_debug) 31223db86aabSstevel cmn_err(CE_CONT, "\twindow type is I/O\n"); 31233db86aabSstevel #endif 31243db86aabSstevel 31253db86aabSstevel /* only windows 0 and 1 can do I/O */ 31263db86aabSstevel win = window->window % PCIC_NUMWINSOCK; 31273db86aabSstevel tmp = window->window / PCIC_NUMWINSOCK; 31283db86aabSstevel 31293db86aabSstevel if (win >= PCIC_IOWINDOWS || tmp != window->socket) { 31303db86aabSstevel cmn_err(CE_WARN, 31313db86aabSstevel "\twindow is out of range (%d)\n", 31323db86aabSstevel window->window); 31333db86aabSstevel return (BAD_WINDOW); 31343db86aabSstevel } 31353db86aabSstevel 31363db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 31373db86aabSstevel 31383db86aabSstevel winp = &sockp->pcs_windows[win].io; 31393db86aabSstevel winp->pcw_speed = window->speed; 31403db86aabSstevel if (window->WindowSize != 1 && window->WindowSize & 1) { 31413db86aabSstevel /* we don't want an odd-size window */ 31423db86aabSstevel window->WindowSize++; 31433db86aabSstevel } 31443db86aabSstevel winp->pcw_len = window->WindowSize; 31453db86aabSstevel 31463db86aabSstevel if (window->state & WS_ENABLED) { 31473db86aabSstevel if (winp->pcw_status & PCW_MAPPED) { 31483db86aabSstevel ddi_regs_map_free(&winp->pcw_handle); 31493db86aabSstevel res.ra_addr_lo = winp->pcw_base; 31503db86aabSstevel res.ra_len = winp->pcw_len; 31518134ee03Srw148561 (void) pcmcia_free_io(winp->res_dip, &res); 31523db86aabSstevel winp->pcw_status &= ~(PCW_MAPPED|PCW_ENABLED); 31533db86aabSstevel } 31543db86aabSstevel 31553db86aabSstevel /* 31563db86aabSstevel * if the I/O address wasn't allocated, allocate 31573db86aabSstevel * it now. If it was allocated, it better 31583db86aabSstevel * be free to use. 31593db86aabSstevel * The winp->pcw_offset value is set and used 31603db86aabSstevel * later on if the particular adapter 31613db86aabSstevel * that we're running on has the ability 31623db86aabSstevel * to translate IO accesses to the card 31633db86aabSstevel * (such as some adapters in the Cirrus 31643db86aabSstevel * Logic family). 31653db86aabSstevel */ 31663db86aabSstevel winp->pcw_offset = 0; 31673db86aabSstevel 31683db86aabSstevel /* 31693db86aabSstevel * Setup the request parameters for the 31703db86aabSstevel * requested base and length. If 31713db86aabSstevel * we're on an adapter that has 31723db86aabSstevel * IO window offset registers, then 31733db86aabSstevel * we don't need a specific base 31743db86aabSstevel * address, just a length, and then 31753db86aabSstevel * we'll cause the correct IO address 31763db86aabSstevel * to be generated on the socket by 31773db86aabSstevel * setting up the IO window offset 31783db86aabSstevel * registers. 31793db86aabSstevel * For adapters that support this capability, we 31803db86aabSstevel * always use the IO window offset registers, 31813db86aabSstevel * even if the passed base/length would be in 31823db86aabSstevel * range. 31833db86aabSstevel */ 31843db86aabSstevel base = window->base; 31853db86aabSstevel bzero(&req, sizeof (req)); 31863db86aabSstevel req.ra_len = window->WindowSize; 31873db86aabSstevel 31883db86aabSstevel req.ra_addr = (uint64_t) 31893db86aabSstevel ((pcic->pc_flags & PCF_IO_REMAP) ? 0 : base); 31903db86aabSstevel req.ra_flags = (req.ra_addr) ? 31913db86aabSstevel NDI_RA_ALLOC_SPECIFIED : 0; 31923db86aabSstevel 31933db86aabSstevel req.ra_flags |= NDI_RA_ALIGN_SIZE; 31943db86aabSstevel /* need to rethink this */ 31953db86aabSstevel req.ra_boundbase = pcic->pc_iobase; 31963db86aabSstevel req.ra_boundlen = pcic->pc_iobound; 31973db86aabSstevel req.ra_flags |= NDI_RA_ALLOC_BOUNDED; 31983db86aabSstevel 31993db86aabSstevel #if defined(PCIC_DEBUG) 32003db86aabSstevel pcic_err(dip, 8, 32013db86aabSstevel "\tlen 0x%"PRIx64" addr 0x%"PRIx64 32023db86aabSstevel "bbase 0x%"PRIx64 32033db86aabSstevel "blen 0x%"PRIx64" flags 0x%x algn 0x%" 32043db86aabSstevel PRIx64"\n", 32053db86aabSstevel req.ra_len, (uint64_t)req.ra_addr, 32063db86aabSstevel req.ra_boundbase, 32073db86aabSstevel req.ra_boundlen, req.ra_flags, 32083db86aabSstevel req.ra_align_mask); 32093db86aabSstevel #endif 32103db86aabSstevel 32113db86aabSstevel /* 32123db86aabSstevel * Try to allocate the space. If we fail this, 32133db86aabSstevel * return the appropriate error depending 32143db86aabSstevel * on whether the caller specified a 32153db86aabSstevel * specific base address or not. 32163db86aabSstevel */ 32178134ee03Srw148561 if (pcmcia_alloc_io(dip, &req, &res, 32188134ee03Srw148561 &winp->res_dip) == DDI_FAILURE) { 32193db86aabSstevel winp->pcw_status &= ~PCW_ENABLED; 32203db86aabSstevel mutex_exit(&pcic->pc_lock); 32213db86aabSstevel cmn_err(CE_WARN, "Failed to alloc I/O:\n" 32223db86aabSstevel "\tlen 0x%" PRIx64 " addr 0x%" PRIx64 32233db86aabSstevel "bbase 0x%" PRIx64 32243db86aabSstevel "blen 0x%" PRIx64 "flags 0x%x" 32253db86aabSstevel "algn 0x%" PRIx64 "\n", 32263db86aabSstevel req.ra_len, req.ra_addr, 32273db86aabSstevel req.ra_boundbase, 32283db86aabSstevel req.ra_boundlen, req.ra_flags, 32293db86aabSstevel req.ra_align_mask); 32303db86aabSstevel 32313db86aabSstevel return (base?BAD_BASE:BAD_SIZE); 32323db86aabSstevel } /* pcmcia_alloc_io */ 32333db86aabSstevel 32343db86aabSstevel /* 32353db86aabSstevel * Don't change the original base. Either we use 32363db86aabSstevel * the offset registers below (PCF_IO_REMAP is set) 32373db86aabSstevel * or it was allocated correctly anyway. 32383db86aabSstevel */ 32393db86aabSstevel winp->pcw_base = res.ra_addr_lo; 32403db86aabSstevel 32413db86aabSstevel #if defined(PCIC_DEBUG) 32423db86aabSstevel pcic_err(dip, 8, 32433db86aabSstevel "\tsetwindow: new base=%x orig base 0x%x\n", 32443db86aabSstevel (unsigned)winp->pcw_base, base); 32453db86aabSstevel #endif 32463db86aabSstevel 32473db86aabSstevel if ((which = pcmcia_map_reg(pcic->dip, 32483db86aabSstevel window->child, 32493db86aabSstevel &res, 32503db86aabSstevel (uint32_t)(window->state & 32513db86aabSstevel 0xffff) | 32523db86aabSstevel (window->socket << 16), 32533db86aabSstevel (caddr_t *)&winp->pcw_hostmem, 32543db86aabSstevel &winp->pcw_handle, 32553db86aabSstevel &window->attr, 32563db86aabSstevel base)) != DDI_SUCCESS) { 32573db86aabSstevel 32583db86aabSstevel cmn_err(CE_WARN, "pcmcia_map_reg()" 32593db86aabSstevel "failed\n"); 32603db86aabSstevel 32613db86aabSstevel res.ra_addr_lo = winp->pcw_base; 32623db86aabSstevel res.ra_len = winp->pcw_len; 32638134ee03Srw148561 (void) pcmcia_free_io(winp->res_dip, &res); 32643db86aabSstevel 32653db86aabSstevel mutex_exit(&pcic->pc_lock); 32663db86aabSstevel return (BAD_WINDOW); 32673db86aabSstevel } 32683db86aabSstevel 32693db86aabSstevel window->handle = winp->pcw_handle; 32703db86aabSstevel winp->pcw_status |= PCW_MAPPED; 32713db86aabSstevel 32723db86aabSstevel /* find the register set offset */ 32733db86aabSstevel select = win * PCIC_IO_OFFSET; 32743db86aabSstevel 32753db86aabSstevel #if defined(PCIC_DEBUG) 32763db86aabSstevel if (pcic_debug) { 32773db86aabSstevel cmn_err(CE_CONT, 32783db86aabSstevel "\tenable: window=%d, select=%x, " 32793db86aabSstevel "base=%x, handle=%p\n", 32803db86aabSstevel win, select, 32813db86aabSstevel (unsigned)window->base, 32823db86aabSstevel (void *)window->handle); 32833db86aabSstevel } 32843db86aabSstevel #endif 32853db86aabSstevel /* 32863db86aabSstevel * at this point, the register window indicator has 32873db86aabSstevel * been converted to be an offset from the first 32883db86aabSstevel * set of registers that are used for programming 32893db86aabSstevel * the window mapping and the offset used to select 32903db86aabSstevel * the correct set of registers to access the 32913db86aabSstevel * specified socket. This allows basing everything 32923db86aabSstevel * off the _0 window 32933db86aabSstevel */ 32943db86aabSstevel 32953db86aabSstevel /* map the I/O base in */ 32963db86aabSstevel pcic_putb(pcic, socket, 32973db86aabSstevel PCIC_IO_ADDR_0_STARTLOW + select, 32983db86aabSstevel LOW_BYTE((uint32_t)winp->pcw_base)); 32993db86aabSstevel pcic_putb(pcic, socket, 33003db86aabSstevel PCIC_IO_ADDR_0_STARTHI + select, 33013db86aabSstevel HIGH_BYTE((uint32_t)winp->pcw_base)); 33023db86aabSstevel 33033db86aabSstevel pcic_putb(pcic, socket, 33043db86aabSstevel PCIC_IO_ADDR_0_STOPLOW + select, 33053db86aabSstevel LOW_BYTE((uint32_t)winp->pcw_base + 33063db86aabSstevel window->WindowSize - 1)); 33073db86aabSstevel pcic_putb(pcic, socket, 33083db86aabSstevel PCIC_IO_ADDR_0_STOPHI + select, 33093db86aabSstevel HIGH_BYTE((uint32_t)winp->pcw_base + 33103db86aabSstevel window->WindowSize - 1)); 33113db86aabSstevel 33123db86aabSstevel /* 33133db86aabSstevel * We've got the requested IO space, now see if we 33143db86aabSstevel * need to adjust the IO window offset registers 33153db86aabSstevel * so that the correct IO address is generated 33163db86aabSstevel * at the socket. If this window doesn't have 33173db86aabSstevel * this capability, then we're all done setting 33183db86aabSstevel * up the IO resources. 33193db86aabSstevel */ 33203db86aabSstevel if (pcic->pc_flags & PCF_IO_REMAP) { 33213db86aabSstevel 33223db86aabSstevel 33233db86aabSstevel /* 33243db86aabSstevel * Note that only 16 bits are used to program 33253db86aabSstevel * the registers but leave 32 bits on pcw_offset 33263db86aabSstevel * so that we can generate the original base 33273db86aabSstevel * in get_window() 33283db86aabSstevel */ 33293db86aabSstevel winp->pcw_offset = (base - winp->pcw_base); 33303db86aabSstevel 33313db86aabSstevel pcic_putb(pcic, socket, 33323db86aabSstevel PCIC_IO_OFFSET_LOW + 33333db86aabSstevel (win * PCIC_IO_OFFSET_OFFSET), 33343db86aabSstevel winp->pcw_offset & 0x0ff); 33353db86aabSstevel pcic_putb(pcic, socket, 33363db86aabSstevel PCIC_IO_OFFSET_HI + 33373db86aabSstevel (win * PCIC_IO_OFFSET_OFFSET), 33383db86aabSstevel (winp->pcw_offset >> 8) & 0x0ff); 33393db86aabSstevel 33403db86aabSstevel } /* PCF_IO_REMAP */ 33413db86aabSstevel 33423db86aabSstevel /* now get the other details (size, etc) right */ 33433db86aabSstevel 33443db86aabSstevel /* 33453db86aabSstevel * Set the data size control bits here. Most of the 33463db86aabSstevel * adapters will ignore IOMEM_16BIT when 33473db86aabSstevel * IOMEM_IOCS16 is set, except for the Intel 33483db86aabSstevel * 82092, which only pays attention to the 33493db86aabSstevel * IOMEM_16BIT bit. Sigh... Intel can't even 33503db86aabSstevel * make a proper clone of their own chip. 33513db86aabSstevel * The 82092 also apparently can't set the timing 33523db86aabSstevel * of I/O windows. 33533db86aabSstevel */ 33543db86aabSstevel which = (window->state & WS_16BIT) ? 33553db86aabSstevel (IOMEM_16BIT | IOMEM_IOCS16) : 0; 33563db86aabSstevel 33573db86aabSstevel switch (pcic->pc_type) { 33583db86aabSstevel case PCIC_CL_PD6729: 33593db86aabSstevel case PCIC_CL_PD6730: 33603db86aabSstevel case PCIC_CL_PD6710: 33613db86aabSstevel case PCIC_CL_PD6722: 33623db86aabSstevel case PCIC_CL_PD6832: 33633db86aabSstevel /* 33643db86aabSstevel * Select Timer Set 1 - this will take 33653db86aabSstevel * effect when the PCIC_IO_CONTROL 33663db86aabSstevel * register is written to later on; 33673db86aabSstevel * the call to pcic_set_cdtimers 33683db86aabSstevel * just sets up the timer itself. 33693db86aabSstevel */ 33703db86aabSstevel which |= IOMEM_CLTIMER_SET_1; 33713db86aabSstevel pcic_set_cdtimers(pcic, socket, 33723db86aabSstevel window->speed, 33733db86aabSstevel IOMEM_CLTIMER_SET_1); 33743db86aabSstevel which |= IOMEM_IOCS16; 33753db86aabSstevel break; 33763db86aabSstevel case PCIC_TI_PCI1031: 33773db86aabSstevel 33783db86aabSstevel if (window->state & WS_16BIT) 33793db86aabSstevel which |= IOMEM_WAIT16; 33803db86aabSstevel 33813db86aabSstevel break; 33823db86aabSstevel case PCIC_TI_PCI1130: 33833db86aabSstevel 33843db86aabSstevel if (window->state & WS_16BIT) 33853db86aabSstevel which |= IOMEM_WAIT16; 33863db86aabSstevel 33873db86aabSstevel break; 33883db86aabSstevel case PCIC_INTEL_i82092: 33893db86aabSstevel break; 33903db86aabSstevel default: 33913db86aabSstevel if (window->speed > 33923db86aabSstevel mhztons(pcic->bus_speed) * 3) 33933db86aabSstevel which |= IOMEM_WAIT16; 33943db86aabSstevel #ifdef notdef 33953db86aabSstevel if (window->speed < 33963db86aabSstevel mhztons(pcic->bus_speed) * 6) 33973db86aabSstevel which |= IOMEM_ZERO_WAIT; 33983db86aabSstevel #endif 33993db86aabSstevel break; 34003db86aabSstevel } /* switch (pc_type) */ 34013db86aabSstevel 34023db86aabSstevel /* 34033db86aabSstevel * Setup the data width and timing 34043db86aabSstevel */ 34053db86aabSstevel select = pcic_getb(pcic, socket, PCIC_IO_CONTROL); 34063db86aabSstevel select &= ~(PCIC_IO_WIN_MASK << (win * 4)); 34073db86aabSstevel select |= IOMEM_SETWIN(win, which); 34083db86aabSstevel pcic_putb(pcic, socket, PCIC_IO_CONTROL, select); 34093db86aabSstevel 34103db86aabSstevel /* 34113db86aabSstevel * Enable the IO window 34123db86aabSstevel */ 34133db86aabSstevel select = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 34143db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 34153db86aabSstevel select | IOMEM_WINDOW(win)); 34163db86aabSstevel 34173db86aabSstevel winp->pcw_status |= PCW_ENABLED; 34183db86aabSstevel 34193db86aabSstevel #if defined(PCIC_DEBUG) 34203db86aabSstevel if (pcic_debug) { 34213db86aabSstevel cmn_err(CE_CONT, 34223db86aabSstevel "\twhich = %x, select = %x (%x)\n", 34233db86aabSstevel which, select, 34243db86aabSstevel IOMEM_SETWIN(win, which)); 34253db86aabSstevel xxdmp_all_regs(pcic, window->socket * 0x40, 24); 34263db86aabSstevel } 34273db86aabSstevel #endif 34283db86aabSstevel } else { 34293db86aabSstevel /* 34303db86aabSstevel * not only do we unmap the IO space, the 34313db86aabSstevel * window has been turned off. 34323db86aabSstevel */ 34333db86aabSstevel if (winp->pcw_status & PCW_MAPPED) { 34343db86aabSstevel ddi_regs_map_free(&winp->pcw_handle); 34353db86aabSstevel res.ra_addr_lo = winp->pcw_base; 34363db86aabSstevel res.ra_len = winp->pcw_len; 34378134ee03Srw148561 (void) pcmcia_free_io(winp->res_dip, &res); 34383db86aabSstevel winp->pcw_status &= ~PCW_MAPPED; 34393db86aabSstevel } 34403db86aabSstevel 34413db86aabSstevel /* disable current mapping */ 34423db86aabSstevel select = pcic_getb(pcic, socket, 34433db86aabSstevel PCIC_MAPPING_ENABLE); 34443db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 34453db86aabSstevel select &= ~IOMEM_WINDOW(win)); 34463db86aabSstevel winp->pcw_status &= ~PCW_ENABLED; 34473db86aabSstevel 34483db86aabSstevel winp->pcw_base = 0; 34493db86aabSstevel winp->pcw_len = 0; 34503db86aabSstevel winp->pcw_offset = 0; 34513db86aabSstevel window->base = 0; 34523db86aabSstevel /* now make sure we don't accidentally re-enable */ 34533db86aabSstevel /* find the register set offset */ 34543db86aabSstevel select = win * PCIC_IO_OFFSET; 34553db86aabSstevel pcic_putb(pcic, socket, 34563db86aabSstevel PCIC_IO_ADDR_0_STARTLOW + select, 0); 34573db86aabSstevel pcic_putb(pcic, socket, 34583db86aabSstevel PCIC_IO_ADDR_0_STARTHI + select, 0); 34593db86aabSstevel pcic_putb(pcic, socket, 34603db86aabSstevel PCIC_IO_ADDR_0_STOPLOW + select, 0); 34613db86aabSstevel pcic_putb(pcic, socket, 34623db86aabSstevel PCIC_IO_ADDR_0_STOPHI + select, 0); 34633db86aabSstevel } 34643db86aabSstevel } 34653db86aabSstevel mutex_exit(&pcic->pc_lock); 34663db86aabSstevel 34673db86aabSstevel return (SUCCESS); 34683db86aabSstevel } 34693db86aabSstevel 34703db86aabSstevel /* 34713db86aabSstevel * pcic_card_state() 34723db86aabSstevel * compute the instantaneous Card State information 34733db86aabSstevel */ 34743db86aabSstevel static int 34753db86aabSstevel pcic_card_state(pcicdev_t *pcic, pcic_socket_t *sockp) 34763db86aabSstevel { 34773db86aabSstevel int value, result; 34783db86aabSstevel #if defined(PCIC_DEBUG) 34793db86aabSstevel int orig_value; 34803db86aabSstevel #endif 34813db86aabSstevel 34823db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 34833db86aabSstevel 34843db86aabSstevel value = pcic_getb(pcic, sockp->pcs_socket, PCIC_INTERFACE_STATUS); 34853db86aabSstevel 34863db86aabSstevel #if defined(PCIC_DEBUG) 34873db86aabSstevel orig_value = value; 34883db86aabSstevel if (pcic_debug >= 8) 34893db86aabSstevel cmn_err(CE_CONT, "pcic_card_state(%p) if status = %b for %d\n", 34903db86aabSstevel (void *)sockp, 34913db86aabSstevel value, 34923db86aabSstevel "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI", 34933db86aabSstevel sockp->pcs_socket); 34943db86aabSstevel #endif 34953db86aabSstevel /* 34963db86aabSstevel * Lie to socket services if we are not ready. 34973db86aabSstevel * This is when we are starting up or during debounce timeouts 34983db86aabSstevel * or if the card is a cardbus card. 34993db86aabSstevel */ 35003db86aabSstevel if (!(sockp->pcs_flags & (PCS_STARTING|PCS_CARD_ISCARDBUS)) && 35013db86aabSstevel !sockp->pcs_debounce_id && 35023db86aabSstevel (value & PCIC_ISTAT_CD_MASK) == PCIC_CD_PRESENT_OK) { 35033db86aabSstevel result = SBM_CD; 35043db86aabSstevel 35053db86aabSstevel if (value & PCIC_WRITE_PROTECT || !(value & PCIC_POWER_ON)) 35063db86aabSstevel result |= SBM_WP; 35073db86aabSstevel if (value & PCIC_POWER_ON) { 35083db86aabSstevel if (value & PCIC_READY) 35093db86aabSstevel result |= SBM_RDYBSY; 35103db86aabSstevel value = (~value) & (PCIC_BVD1 | PCIC_BVD2); 35113db86aabSstevel if (value & PCIC_BVD1) 35123db86aabSstevel result |= SBM_BVD1; 35133db86aabSstevel if (value & PCIC_BVD2) 35143db86aabSstevel result |= SBM_BVD2; 35153db86aabSstevel } 35163db86aabSstevel } else 35173db86aabSstevel result = 0; 35183db86aabSstevel 35193db86aabSstevel mutex_exit(&pcic->pc_lock); 35203db86aabSstevel 35213db86aabSstevel #if defined(PCIC_DEBUG) 35223db86aabSstevel pcic_err(pcic->dip, 8, 35233db86aabSstevel "pcic_card_state(%p) if status = %b for %d (rval=0x%x)\n", 35243db86aabSstevel (void *) sockp, orig_value, 35253db86aabSstevel "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI", 35263db86aabSstevel sockp->pcs_socket, result); 35273db86aabSstevel #endif 35283db86aabSstevel 35293db86aabSstevel return (result); 35303db86aabSstevel } 35313db86aabSstevel 35323db86aabSstevel /* 35333db86aabSstevel * pcic_set_page() 35343db86aabSstevel * SocketServices SetPage function 35353db86aabSstevel * set the page of PC Card memory that should be in the mapped 35363db86aabSstevel * window 35373db86aabSstevel */ 35383db86aabSstevel /*ARGSUSED*/ 35393db86aabSstevel static int 35403db86aabSstevel pcic_set_page(dev_info_t *dip, set_page_t *page) 35413db86aabSstevel { 35423db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 35433db86aabSstevel pcicdev_t *pcic = anp->an_private; 35443db86aabSstevel int select; 35453db86aabSstevel int which, socket, window; 35463db86aabSstevel uint32_t base; 35473db86aabSstevel pcs_memwin_t *memp; 35483db86aabSstevel 35493db86aabSstevel /* get real socket/window numbers */ 35503db86aabSstevel window = page->window % PCIC_NUMWINSOCK; 35513db86aabSstevel socket = page->window / PCIC_NUMWINSOCK; 35523db86aabSstevel 35533db86aabSstevel #if defined(PCIC_DEBUG) 35543db86aabSstevel if (pcic_debug) { 35553db86aabSstevel cmn_err(CE_CONT, 35563db86aabSstevel "pcic_set_page: window=%d, socket=%d, page=%d\n", 35573db86aabSstevel window, socket, page->page); 35583db86aabSstevel } 35593db86aabSstevel #endif 35603db86aabSstevel /* only windows 2-6 work on memory */ 35613db86aabSstevel if (window < PCIC_IOWINDOWS) 35623db86aabSstevel return (BAD_WINDOW); 35633db86aabSstevel 35643db86aabSstevel /* only one page supported (but any size) */ 35653db86aabSstevel if (page->page != 0) 35663db86aabSstevel return (BAD_PAGE); 35673db86aabSstevel 35683db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 35693db86aabSstevel 35703db86aabSstevel memp = &pcic->pc_sockets[socket].pcs_windows[window].mem; 35713db86aabSstevel window -= PCIC_IOWINDOWS; 35723db86aabSstevel 35733db86aabSstevel #if defined(PCIC_DEBUG) 35743db86aabSstevel if (pcic_debug) 35753db86aabSstevel cmn_err(CE_CONT, "\tpcw_base=%x, pcw_hostmem=%p, pcw_len=%x\n", 35763db86aabSstevel (uint32_t)memp->pcw_base, 35773db86aabSstevel (void *)memp->pcw_hostmem, memp->pcw_len); 35783db86aabSstevel #endif 35793db86aabSstevel 35803db86aabSstevel /* window must be enabled */ 35813db86aabSstevel if (!(memp->pcw_status & PCW_ENABLED)) 35823db86aabSstevel return (BAD_ATTRIBUTE); 35833db86aabSstevel 35843db86aabSstevel /* find the register set offset */ 35853db86aabSstevel select = window * PCIC_MEM_1_OFFSET; 35863db86aabSstevel #if defined(PCIC_DEBUG) 35873db86aabSstevel if (pcic_debug) 35883db86aabSstevel cmn_err(CE_CONT, "\tselect=%x\n", select); 35893db86aabSstevel #endif 35903db86aabSstevel 35913db86aabSstevel /* 35923db86aabSstevel * now map the card's memory pages - we start with page 0 35933db86aabSstevel */ 35943db86aabSstevel 35953db86aabSstevel which = 0; /* assume simple case */ 35963db86aabSstevel if (page->state & PS_ATTRIBUTE) { 35973db86aabSstevel which |= CARDMEM_REG_ACTIVE; 35983db86aabSstevel memp->pcw_status |= PCW_ATTRIBUTE; 35993db86aabSstevel } else { 36003db86aabSstevel memp->pcw_status &= ~PCW_ATTRIBUTE; 36013db86aabSstevel } 36023db86aabSstevel 36033db86aabSstevel /* 36043db86aabSstevel * if caller says Write Protect, enforce it. 36053db86aabSstevel */ 36063db86aabSstevel if (page->state & PS_WP) { 36073db86aabSstevel which |= CARDMEM_WRITE_PROTECT; 36083db86aabSstevel memp->pcw_status |= PCW_WP; 36093db86aabSstevel } else { 36103db86aabSstevel memp->pcw_status &= ~PCW_WP; 36113db86aabSstevel } 36123db86aabSstevel #if defined(PCIC_DEBUG) 36133db86aabSstevel if (pcic_debug) { 36143db86aabSstevel cmn_err(CE_CONT, "\tmemory type = %s\n", 36153db86aabSstevel (which & CARDMEM_REG_ACTIVE) ? "attribute" : "common"); 36163db86aabSstevel if (which & CARDMEM_WRITE_PROTECT) 36173db86aabSstevel cmn_err(CE_CONT, "\twrite protect\n"); 36183db86aabSstevel cmn_err(CE_CONT, "\tpage offset=%x pcw_base=%x (%x)\n", 36193db86aabSstevel (unsigned)page->offset, 36203db86aabSstevel (unsigned)memp->pcw_base, 36213db86aabSstevel (int)page->offset - (int)memp->pcw_base & 0xffffff); 36223db86aabSstevel } 36233db86aabSstevel #endif 36243db86aabSstevel /* address computation based on 64MB range and not larger */ 36253db86aabSstevel base = (uint32_t)memp->pcw_base & 0x3ffffff; 36263db86aabSstevel pcic_putb(pcic, socket, PCIC_CARDMEM_0_LOW + select, 36273db86aabSstevel CARDMEM_LOW((int)page->offset - (int)base)); 36283db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_LOW + select); 36293db86aabSstevel pcic_putb(pcic, socket, PCIC_CARDMEM_0_HI + select, 36303db86aabSstevel CARDMEM_HIGH((int)page->offset - base) | which); 36313db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_CARDMEM_0_HI + select); 36323db86aabSstevel 36333db86aabSstevel /* 36343db86aabSstevel * while not really necessary, this just makes sure 36353db86aabSstevel * nothing turned the window off behind our backs 36363db86aabSstevel */ 36373db86aabSstevel which = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 36383db86aabSstevel which |= SYSMEM_WINDOW(window); 36393db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, which); 36403db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 36413db86aabSstevel 36423db86aabSstevel memp->pcw_offset = (off_t)page->offset; 36433db86aabSstevel 36443db86aabSstevel #if defined(PCIC_DEBUG) 36453db86aabSstevel if (pcic_debug) { 36463db86aabSstevel cmn_err(CE_CONT, "\tbase=%p, *base=%x\n", 36473db86aabSstevel (void *)memp->pcw_hostmem, 36483db86aabSstevel (uint32_t)*memp->pcw_hostmem); 36493db86aabSstevel 36503db86aabSstevel xxdmp_all_regs(pcic, socket, -1); 36513db86aabSstevel 36523db86aabSstevel cmn_err(CE_CONT, "\tbase=%p, *base=%x\n", 36533db86aabSstevel (void *)memp->pcw_hostmem, 36543db86aabSstevel (uint32_t)*memp->pcw_hostmem); 36553db86aabSstevel } 36563db86aabSstevel #endif 36573db86aabSstevel 36583db86aabSstevel if (which & PCW_ATTRIBUTE) 36593db86aabSstevel pcic_mswait(pcic, socket, 2); 36603db86aabSstevel 36613db86aabSstevel mutex_exit(&pcic->pc_lock); 36623db86aabSstevel 36633db86aabSstevel return (SUCCESS); 36643db86aabSstevel } 36653db86aabSstevel 36663db86aabSstevel /* 36673db86aabSstevel * pcic_set_vcc_level() 36683db86aabSstevel * 36693db86aabSstevel * set voltage based on adapter information 36703db86aabSstevel * 36713db86aabSstevel * this routine implements a limited solution for support of 3.3v cards. 36723db86aabSstevel * the general solution, which would fully support the pcmcia spec 36733db86aabSstevel * as far as allowing client drivers to request which voltage levels 36743db86aabSstevel * to be set, requires more framework support and driver changes - ess 36753db86aabSstevel */ 36763db86aabSstevel static int 36773db86aabSstevel pcic_set_vcc_level(pcicdev_t *pcic, set_socket_t *socket) 36783db86aabSstevel { 36793db86aabSstevel uint32_t socket_present_state; 36803db86aabSstevel 36813db86aabSstevel #if defined(PCIC_DEBUG) 36823db86aabSstevel if (pcic_debug) { 36833db86aabSstevel cmn_err(CE_CONT, 36843db86aabSstevel "pcic_set_vcc_level(pcic=%p, VccLevel=%d)\n", 36853db86aabSstevel (void *)pcic, socket->VccLevel); 36863db86aabSstevel } 36873db86aabSstevel #endif 36883db86aabSstevel 36893db86aabSstevel /* 36903db86aabSstevel * check VccLevel 36913db86aabSstevel * if this is zero, power is being turned off 36923db86aabSstevel * if it is non-zero, power is being turned on. 36933db86aabSstevel */ 36943db86aabSstevel if (socket->VccLevel == 0) { 36953db86aabSstevel return (0); 36963db86aabSstevel } 36973db86aabSstevel 36983db86aabSstevel /* 36993db86aabSstevel * range checking for sanity's sake 37003db86aabSstevel */ 37013db86aabSstevel if (socket->VccLevel >= pcic->pc_numpower) { 37023db86aabSstevel return (BAD_VCC); 37033db86aabSstevel } 37043db86aabSstevel 37053db86aabSstevel switch (pcic->pc_io_type) { 37063db86aabSstevel /* 37073db86aabSstevel * Yenta-compliant adapters have vcc info in the extended registers 37083db86aabSstevel * Other adapters can be added as needed, but the 'default' case 37093db86aabSstevel * has been left as it was previously so as not to break existing 37103db86aabSstevel * adapters. 37113db86aabSstevel */ 37123db86aabSstevel case PCIC_IO_TYPE_YENTA: 37133db86aabSstevel /* 37143db86aabSstevel * Here we ignore the VccLevel passed in and read the 37153db86aabSstevel * card type from the adapter socket present state register 37163db86aabSstevel */ 37173db86aabSstevel socket_present_state = 37183db86aabSstevel ddi_get32(pcic->handle, (uint32_t *)(pcic->ioaddr + 37193db86aabSstevel PCIC_PRESENT_STATE_REG)); 37203db86aabSstevel #if defined(PCIC_DEBUG) 37213db86aabSstevel if (pcic_debug) { 37223db86aabSstevel cmn_err(CE_CONT, 37233db86aabSstevel "socket present state = 0x%x\n", 37243db86aabSstevel socket_present_state); 37253db86aabSstevel } 37263db86aabSstevel #endif 37273db86aabSstevel switch (socket_present_state & PCIC_VCC_MASK) { 37283db86aabSstevel case PCIC_VCC_3VCARD: 37293db86aabSstevel /* fall through */ 37303db86aabSstevel case PCIC_VCC_3VCARD|PCIC_VCC_5VCARD: 37313db86aabSstevel socket->VccLevel = PCIC_VCC_3VLEVEL; 37323db86aabSstevel return 37333db86aabSstevel (POWER_3VCARD_ENABLE|POWER_OUTPUT_ENABLE); 37343db86aabSstevel case PCIC_VCC_5VCARD: 37353db86aabSstevel socket->VccLevel = PCIC_VCC_5VLEVEL; 37363db86aabSstevel return 37373db86aabSstevel (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE); 37383db86aabSstevel default: 37393db86aabSstevel /* 37403db86aabSstevel * if no card is present, this can be the 37413db86aabSstevel * case of a client making a SetSocket call 37423db86aabSstevel * after card removal. In this case we return 37433db86aabSstevel * the current power level 37443db86aabSstevel */ 37453db86aabSstevel return ((unsigned)ddi_get8(pcic->handle, 37463db86aabSstevel pcic->ioaddr + CB_R2_OFFSET + 37473db86aabSstevel PCIC_POWER_CONTROL)); 37483db86aabSstevel } 37493db86aabSstevel 37503db86aabSstevel default: 37513db86aabSstevel 37523db86aabSstevel switch (socket->VccLevel) { 37533db86aabSstevel case PCIC_VCC_3VLEVEL: 37543db86aabSstevel return (BAD_VCC); 37553db86aabSstevel case PCIC_VCC_5VLEVEL: 37563db86aabSstevel /* enable Vcc */ 37573db86aabSstevel return (POWER_CARD_ENABLE|POWER_OUTPUT_ENABLE); 37583db86aabSstevel default: 37593db86aabSstevel return (BAD_VCC); 37603db86aabSstevel } 37613db86aabSstevel } 37623db86aabSstevel } 37633db86aabSstevel 37643db86aabSstevel 37653db86aabSstevel /* 37663db86aabSstevel * pcic_set_socket() 37673db86aabSstevel * Socket Services SetSocket call 37683db86aabSstevel * sets basic socket configuration 37693db86aabSstevel */ 37703db86aabSstevel static int 37713db86aabSstevel pcic_set_socket(dev_info_t *dip, set_socket_t *socket) 37723db86aabSstevel { 37733db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 37743db86aabSstevel pcicdev_t *pcic = anp->an_private; 37753db86aabSstevel pcic_socket_t *sockp = &pcic->pc_sockets[socket->socket]; 37763db86aabSstevel int irq, interrupt, mirq; 37773db86aabSstevel int powerlevel = 0; 37783db86aabSstevel int ind, value, orig_pwrctl; 37793db86aabSstevel 37803db86aabSstevel #if defined(PCIC_DEBUG) 37813db86aabSstevel if (pcic_debug) { 37823db86aabSstevel cmn_err(CE_CONT, 37833db86aabSstevel "pcic_set_socket(dip=%p, socket=%d)" 37843db86aabSstevel " Vcc=%d Vpp1=%d Vpp2=%d\n", (void *)dip, 37853db86aabSstevel socket->socket, socket->VccLevel, socket->Vpp1Level, 37863db86aabSstevel socket->Vpp2Level); 37873db86aabSstevel } 37883db86aabSstevel #endif 37893db86aabSstevel /* 37903db86aabSstevel * check VccLevel, etc. before setting mutex 37913db86aabSstevel * if this is zero, power is being turned off 37923db86aabSstevel * if it is non-zero, power is being turned on. 37933db86aabSstevel * the default case is to assume Vcc only. 37943db86aabSstevel */ 37953db86aabSstevel 37963db86aabSstevel /* this appears to be very implementation specific */ 37973db86aabSstevel 37983db86aabSstevel if (socket->Vpp1Level != socket->Vpp2Level) 37993db86aabSstevel return (BAD_VPP); 38003db86aabSstevel 38013db86aabSstevel if (socket->VccLevel == 0 || !(sockp->pcs_flags & PCS_CARD_PRESENT)) { 38023db86aabSstevel powerlevel = 0; 38033db86aabSstevel sockp->pcs_vcc = 0; 38043db86aabSstevel sockp->pcs_vpp1 = 0; 38053db86aabSstevel sockp->pcs_vpp2 = 0; 38063db86aabSstevel } else { 38073db86aabSstevel #if defined(PCIC_DEBUG) 38083db86aabSstevel pcic_err(dip, 9, "\tVcc=%d Vpp1Level=%d, Vpp2Level=%d\n", 38093db86aabSstevel socket->VccLevel, socket->Vpp1Level, socket->Vpp2Level); 38103db86aabSstevel #endif 38113db86aabSstevel /* valid Vcc power level? */ 38123db86aabSstevel if (socket->VccLevel >= pcic->pc_numpower) 38133db86aabSstevel return (BAD_VCC); 38143db86aabSstevel 38153db86aabSstevel switch (pcic_power[socket->VccLevel].PowerLevel) { 38163db86aabSstevel case 33: /* 3.3V */ 38173db86aabSstevel case 60: /* for bad CIS in Option GPRS card */ 38183db86aabSstevel if (!(pcic->pc_flags & PCF_33VCAP)) { 38193db86aabSstevel cmn_err(CE_WARN, 38203db86aabSstevel "%s%d: Bad Request for 3.3V " 38213db86aabSstevel "(Controller incapable)\n", 38223db86aabSstevel ddi_get_name(pcic->dip), 38233db86aabSstevel ddi_get_instance(pcic->dip)); 38243db86aabSstevel return (BAD_VCC); 38253db86aabSstevel } 38263db86aabSstevel /* FALLTHROUGH */ 38273db86aabSstevel case 50: /* 5V */ 38283db86aabSstevel if ((pcic->pc_io_type == PCIC_IO_TYPE_YENTA) && 38293db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE) & 38303db86aabSstevel CB_PS_33VCARD) { 38313db86aabSstevel /* 38323db86aabSstevel * This is actually a 3.3V card. 38333db86aabSstevel * Solaris Card Services 38343db86aabSstevel * doesn't understand 3.3V 38353db86aabSstevel * so we cheat and change 38363db86aabSstevel * the setting to the one appropriate to 3.3V. 38373db86aabSstevel * Note that this is the entry number 38383db86aabSstevel * in the pcic_power[] array. 38393db86aabSstevel */ 38403db86aabSstevel sockp->pcs_vcc = PCIC_VCC_3VLEVEL; 38413db86aabSstevel } else 38423db86aabSstevel sockp->pcs_vcc = socket->VccLevel; 38433db86aabSstevel break; 38443db86aabSstevel default: 38453db86aabSstevel return (BAD_VCC); 38463db86aabSstevel } 38473db86aabSstevel 38483db86aabSstevel /* enable Vcc */ 38493db86aabSstevel powerlevel = POWER_CARD_ENABLE; 38503db86aabSstevel 38513db86aabSstevel #if defined(PCIC_DEBUG) 38523db86aabSstevel if (pcic_debug) { 38533db86aabSstevel cmn_err(CE_CONT, "\tVcc=%d powerlevel=%x\n", 38543db86aabSstevel socket->VccLevel, powerlevel); 38553db86aabSstevel } 38563db86aabSstevel #endif 38573db86aabSstevel ind = 0; /* default index to 0 power */ 38583db86aabSstevel if ((int)socket->Vpp1Level >= 0 && 38593db86aabSstevel socket->Vpp1Level < pcic->pc_numpower) { 38603db86aabSstevel if (!(pcic_power[socket->Vpp1Level].ValidSignals 38613db86aabSstevel & VPP1)) { 38623db86aabSstevel return (BAD_VPP); 38633db86aabSstevel } 38643db86aabSstevel ind = pcic_power[socket->Vpp1Level].PowerLevel/10; 38653db86aabSstevel powerlevel |= pcic_vpp_levels[ind]; 38663db86aabSstevel sockp->pcs_vpp1 = socket->Vpp1Level; 38673db86aabSstevel } 38683db86aabSstevel if ((int)socket->Vpp2Level >= 0 && 38693db86aabSstevel socket->Vpp2Level < pcic->pc_numpower) { 38703db86aabSstevel if (!(pcic_power[socket->Vpp2Level].ValidSignals 38713db86aabSstevel & VPP2)) { 38723db86aabSstevel return (BAD_VPP); 38733db86aabSstevel } 38743db86aabSstevel ind = pcic_power[socket->Vpp2Level].PowerLevel/10; 38753db86aabSstevel powerlevel |= (pcic_vpp_levels[ind] << 2); 38763db86aabSstevel sockp->pcs_vpp2 = socket->Vpp2Level; 38773db86aabSstevel } 38783db86aabSstevel 38793db86aabSstevel if (pcic->pc_flags & PCF_VPPX) { 38803db86aabSstevel /* 38813db86aabSstevel * this adapter doesn't allow separate Vpp1/Vpp2 38823db86aabSstevel * if one is turned on, both are turned on and only 38833db86aabSstevel * the Vpp1 bits should be set 38843db86aabSstevel */ 38853db86aabSstevel if (sockp->pcs_vpp2 != sockp->pcs_vpp1) { 38863db86aabSstevel /* must be the same if one not zero */ 38873db86aabSstevel if (sockp->pcs_vpp1 != 0 && 38883db86aabSstevel sockp->pcs_vpp2 != 0) { 38893db86aabSstevel cmn_err(CE_WARN, 38903db86aabSstevel "%s%d: Bad Power Request " 38913db86aabSstevel "(Vpp1/2 not the same)\n", 38923db86aabSstevel ddi_get_name(pcic->dip), 38933db86aabSstevel ddi_get_instance(pcic->dip)); 38943db86aabSstevel return (BAD_VPP); 38953db86aabSstevel } 38963db86aabSstevel } 38973db86aabSstevel powerlevel &= ~(3<<2); 38983db86aabSstevel } 38993db86aabSstevel 39003db86aabSstevel #if defined(PCIC_DEBUG) 39013db86aabSstevel if (pcic_debug) { 39023db86aabSstevel cmn_err(CE_CONT, "\tpowerlevel=%x, ind=%x\n", 39033db86aabSstevel powerlevel, ind); 39043db86aabSstevel } 39053db86aabSstevel #endif 39063db86aabSstevel } 39073db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 39083db86aabSstevel 39093db86aabSstevel /* turn socket->IREQRouting off while programming */ 39103db86aabSstevel interrupt = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT); 39113db86aabSstevel interrupt &= ~PCIC_INTR_MASK; 39123db86aabSstevel if (pcic->pc_flags & PCF_USE_SMI) 39133db86aabSstevel interrupt |= PCIC_INTR_ENABLE; 39143db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, interrupt); 39153db86aabSstevel 39163db86aabSstevel switch (pcic->pc_type) { 39173db86aabSstevel case PCIC_INTEL_i82092: 39183db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket->socket, PCIC_82092_CTL_IRQ, 39193db86aabSstevel PCIC_82092_INT_DISABLE); 39203db86aabSstevel break; 39213db86aabSstevel default: 39223db86aabSstevel break; 39233db86aabSstevel } /* switch */ 39243db86aabSstevel 39253db86aabSstevel /* the SCIntMask specifies events to detect */ 39263db86aabSstevel mirq = pcic_getb(pcic, socket->socket, PCIC_MANAGEMENT_INT); 39273db86aabSstevel 39283db86aabSstevel #if defined(PCIC_DEBUG) 39293db86aabSstevel if (pcic_debug) 39303db86aabSstevel cmn_err(CE_CONT, 39313db86aabSstevel "\tSCIntMask=%x, interrupt=%x, mirq=%x\n", 39323db86aabSstevel socket->SCIntMask, interrupt, mirq); 39333db86aabSstevel #endif 39343db86aabSstevel mirq &= ~(PCIC_BD_DETECT|PCIC_BW_DETECT|PCIC_RD_DETECT); 39353db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, 39363db86aabSstevel mirq & ~PCIC_CHANGE_MASK); 39373db86aabSstevel 39383db86aabSstevel /* save the mask we want to use */ 39393db86aabSstevel sockp->pcs_intmask = socket->SCIntMask; 39403db86aabSstevel 39413db86aabSstevel /* 39423db86aabSstevel * Until there is a card present it's not worth enabling 39433db86aabSstevel * any interrupts except "Card detect". This is done 39443db86aabSstevel * elsewhere in the driver so don't change things if 39453db86aabSstevel * there is no card! 39463db86aabSstevel */ 39473db86aabSstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) { 39483db86aabSstevel 39493db86aabSstevel /* now update the hardware to reflect events desired */ 39503db86aabSstevel if (sockp->pcs_intmask & SBM_BVD1 || socket->IFType == IF_IO) 39513db86aabSstevel mirq |= PCIC_BD_DETECT; 39523db86aabSstevel 39533db86aabSstevel if (sockp->pcs_intmask & SBM_BVD2) 39543db86aabSstevel mirq |= PCIC_BW_DETECT; 39553db86aabSstevel 39563db86aabSstevel if (sockp->pcs_intmask & SBM_RDYBSY) 39573db86aabSstevel mirq |= PCIC_RD_DETECT; 39583db86aabSstevel 39593db86aabSstevel if (sockp->pcs_intmask & SBM_CD) 39603db86aabSstevel mirq |= PCIC_CD_DETECT; 39613db86aabSstevel } 39623db86aabSstevel 39633db86aabSstevel if (sockp->pcs_flags & PCS_READY) { 39643db86aabSstevel /* 39653db86aabSstevel * card just came ready. 39663db86aabSstevel * make sure enough time elapses 39673db86aabSstevel * before touching it. 39683db86aabSstevel */ 39693db86aabSstevel sockp->pcs_flags &= ~PCS_READY; 39703db86aabSstevel pcic_mswait(pcic, socket->socket, 10); 39713db86aabSstevel } 39723db86aabSstevel 39733db86aabSstevel #if defined(PCIC_DEBUG) 39743db86aabSstevel if (pcic_debug) { 39753db86aabSstevel cmn_err(CE_CONT, "\tstatus change set to %x\n", mirq); 39763db86aabSstevel } 39773db86aabSstevel #endif 39783db86aabSstevel 39793db86aabSstevel switch (pcic->pc_type) { 39803db86aabSstevel case PCIC_I82365SL: 39813db86aabSstevel case PCIC_VADEM: 39823db86aabSstevel case PCIC_VADEM_VG469: 39833db86aabSstevel /* 39843db86aabSstevel * The Intel version has different options. This is a 39853db86aabSstevel * special case of GPI which might be used for eject 39863db86aabSstevel */ 39873db86aabSstevel 39883db86aabSstevel irq = pcic_getb(pcic, socket->socket, PCIC_CARD_DETECT); 39893db86aabSstevel if (sockp->pcs_intmask & (SBM_EJECT|SBM_INSERT) && 39903db86aabSstevel pcic->pc_flags & PCF_GPI_EJECT) { 39913db86aabSstevel irq |= PCIC_GPI_ENABLE; 39923db86aabSstevel } else { 39933db86aabSstevel irq &= ~PCIC_GPI_ENABLE; 39943db86aabSstevel } 39953db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_CARD_DETECT, irq); 39963db86aabSstevel break; 39973db86aabSstevel case PCIC_CL_PD6710: 39983db86aabSstevel case PCIC_CL_PD6722: 39993db86aabSstevel if (socket->IFType == IF_IO) { 40003db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_2, 0x0); 40013db86aabSstevel value = pcic_getb(pcic, socket->socket, 40023db86aabSstevel PCIC_MISC_CTL_1); 40033db86aabSstevel if (pcic->pc_flags & PCF_AUDIO) 40043db86aabSstevel value |= PCIC_MC_SPEAKER_ENB; 40053db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, 40063db86aabSstevel value); 40073db86aabSstevel } else { 40083db86aabSstevel value = pcic_getb(pcic, socket->socket, 40093db86aabSstevel PCIC_MISC_CTL_1); 40103db86aabSstevel value &= ~PCIC_MC_SPEAKER_ENB; 40113db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, 40123db86aabSstevel value); 40133db86aabSstevel } 40143db86aabSstevel break; 40153db86aabSstevel case PCIC_CL_PD6729: 40163db86aabSstevel case PCIC_CL_PD6730: 40173db86aabSstevel case PCIC_CL_PD6832: 40183db86aabSstevel value = pcic_getb(pcic, socket->socket, PCIC_MISC_CTL_1); 40193db86aabSstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) { 40203db86aabSstevel value |= PCIC_MC_SPEAKER_ENB; 40213db86aabSstevel } else { 40223db86aabSstevel value &= ~PCIC_MC_SPEAKER_ENB; 40233db86aabSstevel } 40243db86aabSstevel 40253db86aabSstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33) 40263db86aabSstevel value |= PCIC_MC_3VCC; 40273db86aabSstevel else 40283db86aabSstevel value &= ~PCIC_MC_3VCC; 40293db86aabSstevel 40303db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MISC_CTL_1, value); 40313db86aabSstevel break; 40323db86aabSstevel 40333db86aabSstevel case PCIC_O2_OZ6912: 40343db86aabSstevel value = pcic_getcb(pcic, CB_MISCCTRL); 40353db86aabSstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) 40363db86aabSstevel value |= (1<<25); 40373db86aabSstevel else 40383db86aabSstevel value &= ~(1<<25); 40393db86aabSstevel pcic_putcb(pcic, CB_MISCCTRL, value); 40403db86aabSstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33) 40413db86aabSstevel powerlevel |= 0x08; 40423db86aabSstevel break; 40433db86aabSstevel 40443db86aabSstevel case PCIC_TI_PCI1250: 40453db86aabSstevel case PCIC_TI_PCI1221: 40463db86aabSstevel case PCIC_TI_PCI1225: 40473db86aabSstevel case PCIC_TI_PCI1410: 40483db86aabSstevel case PCIC_ENE_1410: 40493db86aabSstevel case PCIC_TI_PCI1510: 40503db86aabSstevel case PCIC_TI_PCI1520: 40513db86aabSstevel case PCIC_TI_PCI1420: 40523db86aabSstevel case PCIC_ENE_1420: 40533db86aabSstevel value = ddi_get8(pcic->cfg_handle, 40543db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG); 40553db86aabSstevel if ((socket->IFType == IF_IO) && (pcic->pc_flags & PCF_AUDIO)) { 40563db86aabSstevel value |= PCIC_CRDCTL_SPKR_ENBL; 40573db86aabSstevel } else { 40583db86aabSstevel value &= ~PCIC_CRDCTL_SPKR_ENBL; 40593db86aabSstevel } 40603db86aabSstevel ddi_put8(pcic->cfg_handle, 40613db86aabSstevel pcic->cfgaddr + PCIC_CRDCTL_REG, value); 40623db86aabSstevel if (pcic_power[sockp->pcs_vcc].PowerLevel == 33) 40633db86aabSstevel powerlevel |= 0x08; 40643db86aabSstevel break; 40653db86aabSstevel } 40663db86aabSstevel 40673db86aabSstevel /* 40683db86aabSstevel * ctlind processing -- we can ignore this 40693db86aabSstevel * there aren't any outputs on the chip for this and 40703db86aabSstevel * the GUI will display what it thinks is correct 40713db86aabSstevel */ 40723db86aabSstevel 40733db86aabSstevel /* 40743db86aabSstevel * If outputs are enabled and the power is going off 40753db86aabSstevel * turn off outputs first. 40763db86aabSstevel */ 40773db86aabSstevel 40783db86aabSstevel /* power setup -- if necessary */ 40793db86aabSstevel orig_pwrctl = pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL); 40803db86aabSstevel if ((orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc == 0) { 40813db86aabSstevel orig_pwrctl &= ~POWER_OUTPUT_ENABLE; 40823db86aabSstevel pcic_putb(pcic, socket->socket, 40833db86aabSstevel PCIC_POWER_CONTROL, orig_pwrctl); 40843db86aabSstevel (void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL); 40853db86aabSstevel } 40863db86aabSstevel 40873db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) { 40883db86aabSstevel value = pcic_cbus_powerctl(pcic, socket->socket); 40893db86aabSstevel powerlevel = 0; 40903db86aabSstevel } else 40913db86aabSstevel value = pcic_exca_powerctl(pcic, socket->socket, powerlevel); 40923db86aabSstevel 40933db86aabSstevel if (value != SUCCESS) { 40943db86aabSstevel mutex_exit(&pcic->pc_lock); 40953db86aabSstevel return (value); 40963db86aabSstevel } 40973db86aabSstevel 40983db86aabSstevel /* 40993db86aabSstevel * If outputs were disabled and the power is going on 41003db86aabSstevel * turn on outputs afterwards. 41013db86aabSstevel */ 41023db86aabSstevel if (!(orig_pwrctl & POWER_OUTPUT_ENABLE) && sockp->pcs_vcc != 0) { 41033db86aabSstevel orig_pwrctl = pcic_getb(pcic, socket->socket, 41043db86aabSstevel PCIC_POWER_CONTROL); 41053db86aabSstevel orig_pwrctl |= POWER_OUTPUT_ENABLE; 41063db86aabSstevel pcic_putb(pcic, socket->socket, 41073db86aabSstevel PCIC_POWER_CONTROL, orig_pwrctl); 41083db86aabSstevel (void) pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL); 41093db86aabSstevel } 41103db86aabSstevel 41113db86aabSstevel /* 41123db86aabSstevel * Once we have done the power stuff can re-enable management 41133db86aabSstevel * interrupts. 41143db86aabSstevel */ 41153db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_MANAGEMENT_INT, mirq); 41163db86aabSstevel 41173db86aabSstevel #if defined(PCIC_DEBUG) 41183db86aabSstevel pcic_err(dip, 8, "\tmanagement int set to %x pwrctl to 0x%x " 41193db86aabSstevel "cbctl 0x%x\n", 41203db86aabSstevel mirq, pcic_getb(pcic, socket->socket, PCIC_POWER_CONTROL), 41213db86aabSstevel pcic_getcb(pcic, CB_CONTROL)); 41223db86aabSstevel #endif 41233db86aabSstevel 41243db86aabSstevel /* irq processing */ 41253db86aabSstevel if (socket->IFType == IF_IO) { 41263db86aabSstevel /* IRQ only for I/O */ 41273db86aabSstevel irq = socket->IREQRouting & PCIC_INTR_MASK; 41283db86aabSstevel value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT); 41293db86aabSstevel value &= ~PCIC_INTR_MASK; 41303db86aabSstevel 41313db86aabSstevel /* to enable I/O operation */ 41323db86aabSstevel value |= PCIC_IO_CARD | PCIC_RESET; 41333db86aabSstevel sockp->pcs_flags |= PCS_CARD_IO; 41343db86aabSstevel if (irq != sockp->pcs_irq) { 41353db86aabSstevel if (sockp->pcs_irq != 0) 41363db86aabSstevel cmn_err(CE_CONT, 41373db86aabSstevel "SetSocket: IRQ mismatch %x != %x!\n", 41383db86aabSstevel irq, sockp->pcs_irq); 41393db86aabSstevel else 41403db86aabSstevel sockp->pcs_irq = irq; 41413db86aabSstevel } 41423db86aabSstevel irq = sockp->pcs_irq; 41433db86aabSstevel 41443db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value); 41453db86aabSstevel if (socket->IREQRouting & IRQ_ENABLE) { 41463db86aabSstevel pcic_enable_io_intr(pcic, socket->socket, irq); 41473db86aabSstevel sockp->pcs_flags |= PCS_IRQ_ENABLED; 41483db86aabSstevel } else { 41493db86aabSstevel pcic_disable_io_intr(pcic, socket->socket); 41503db86aabSstevel sockp->pcs_flags &= ~PCS_IRQ_ENABLED; 41513db86aabSstevel } 41523db86aabSstevel #if defined(PCIC_DEBUG) 41533db86aabSstevel if (pcic_debug) { 41543db86aabSstevel cmn_err(CE_CONT, 41553db86aabSstevel "\tsocket type is I/O and irq %x is %s\n", irq, 41563db86aabSstevel (socket->IREQRouting & IRQ_ENABLE) ? 41573db86aabSstevel "enabled" : "not enabled"); 41583db86aabSstevel xxdmp_all_regs(pcic, socket->socket, 20); 41593db86aabSstevel } 41603db86aabSstevel #endif 41613db86aabSstevel } else { 41623db86aabSstevel /* make sure I/O mode is off */ 41633db86aabSstevel 41643db86aabSstevel sockp->pcs_irq = 0; 41653db86aabSstevel 41663db86aabSstevel value = pcic_getb(pcic, socket->socket, PCIC_INTERRUPT); 41673db86aabSstevel value &= ~PCIC_IO_CARD; 41683db86aabSstevel pcic_putb(pcic, socket->socket, PCIC_INTERRUPT, value); 41693db86aabSstevel pcic_disable_io_intr(pcic, socket->socket); 41703db86aabSstevel sockp->pcs_flags &= ~(PCS_CARD_IO|PCS_IRQ_ENABLED); 41713db86aabSstevel } 41723db86aabSstevel 41733db86aabSstevel sockp->pcs_state &= ~socket->State; 41743db86aabSstevel 41753db86aabSstevel mutex_exit(&pcic->pc_lock); 41763db86aabSstevel return (SUCCESS); 41773db86aabSstevel } 41783db86aabSstevel 41793db86aabSstevel /* 41803db86aabSstevel * pcic_inquire_socket() 41813db86aabSstevel * SocketServices InquireSocket function 41823db86aabSstevel * returns basic characteristics of the socket 41833db86aabSstevel */ 41843db86aabSstevel /*ARGSUSED*/ 41853db86aabSstevel static int 41863db86aabSstevel pcic_inquire_socket(dev_info_t *dip, inquire_socket_t *socket) 41873db86aabSstevel { 41883db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 41893db86aabSstevel pcicdev_t *pcic = anp->an_private; 41903db86aabSstevel int value; 41913db86aabSstevel 41923db86aabSstevel socket->SCIntCaps = PCIC_DEFAULT_INT_CAPS; 41933db86aabSstevel socket->SCRptCaps = PCIC_DEFAULT_RPT_CAPS; 41943db86aabSstevel socket->CtlIndCaps = PCIC_DEFAULT_CTL_CAPS; 41953db86aabSstevel value = pcic->pc_sockets[socket->socket].pcs_flags; 41963db86aabSstevel socket->SocketCaps = (value & PCS_SOCKET_IO) ? IF_IO : IF_MEMORY; 41973db86aabSstevel socket->ActiveHigh = 0; 41983db86aabSstevel /* these are the usable IRQs */ 41993db86aabSstevel socket->ActiveLow = 0xfff0; 42003db86aabSstevel return (SUCCESS); 42013db86aabSstevel } 42023db86aabSstevel 42033db86aabSstevel /* 42043db86aabSstevel * pcic_inquire_window() 42053db86aabSstevel * SocketServices InquireWindow function 42063db86aabSstevel * returns detailed characteristics of the window 42073db86aabSstevel * this is where windows get tied to sockets 42083db86aabSstevel */ 42093db86aabSstevel /*ARGSUSED*/ 42103db86aabSstevel static int 42113db86aabSstevel pcic_inquire_window(dev_info_t *dip, inquire_window_t *window) 42123db86aabSstevel { 42133db86aabSstevel int type, socket; 42143db86aabSstevel 42153db86aabSstevel type = window->window % PCIC_NUMWINSOCK; 42163db86aabSstevel socket = window->window / PCIC_NUMWINSOCK; 42173db86aabSstevel 42183db86aabSstevel #if defined(PCIC_DEBUG) 42193db86aabSstevel if (pcic_debug >= 8) 42203db86aabSstevel cmn_err(CE_CONT, 42213db86aabSstevel "pcic_inquire_window: window = %d/%d socket=%d\n", 42223db86aabSstevel window->window, type, socket); 42233db86aabSstevel #endif 42243db86aabSstevel if (type < PCIC_IOWINDOWS) { 42253db86aabSstevel window->WndCaps = WC_IO|WC_WAIT; 42263db86aabSstevel type = IF_IO; 42273db86aabSstevel } else { 42283db86aabSstevel window->WndCaps = WC_COMMON|WC_ATTRIBUTE|WC_WAIT; 42293db86aabSstevel type = IF_MEMORY; 42303db86aabSstevel } 42313db86aabSstevel 42323db86aabSstevel /* initialize the socket map - one socket per window */ 42333db86aabSstevel PR_ZERO(window->Sockets); 42343db86aabSstevel PR_SET(window->Sockets, socket); 42353db86aabSstevel 42363db86aabSstevel if (type == IF_IO) { 42373db86aabSstevel iowin_char_t *io; 42383db86aabSstevel io = &window->iowin_char; 42393db86aabSstevel io->IOWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT| 42403db86aabSstevel WC_16BIT; 42413db86aabSstevel io->FirstByte = (baseaddr_t)IOMEM_FIRST; 42423db86aabSstevel io->LastByte = (baseaddr_t)IOMEM_LAST; 42433db86aabSstevel io->MinSize = IOMEM_MIN; 42443db86aabSstevel io->MaxSize = IOMEM_MAX; 42453db86aabSstevel io->ReqGran = IOMEM_GRAN; 42463db86aabSstevel io->AddrLines = IOMEM_DECODE; 42473db86aabSstevel io->EISASlot = 0; 42483db86aabSstevel } else { 42493db86aabSstevel mem_win_char_t *mem; 42503db86aabSstevel mem = &window->mem_win_char; 42513db86aabSstevel mem->MemWndCaps = WC_BASE|WC_SIZE|WC_WENABLE|WC_8BIT| 42523db86aabSstevel WC_16BIT|WC_WP; 42533db86aabSstevel 42543db86aabSstevel mem->FirstByte = (baseaddr_t)MEM_FIRST; 42553db86aabSstevel mem->LastByte = (baseaddr_t)MEM_LAST; 42563db86aabSstevel 42573db86aabSstevel mem->MinSize = MEM_MIN; 42583db86aabSstevel mem->MaxSize = MEM_MAX; 42593db86aabSstevel mem->ReqGran = PCIC_PAGE; 42603db86aabSstevel mem->ReqBase = 0; 42613db86aabSstevel mem->ReqOffset = PCIC_PAGE; 42623db86aabSstevel mem->Slowest = MEM_SPEED_MAX; 42633db86aabSstevel mem->Fastest = MEM_SPEED_MIN; 42643db86aabSstevel } 42653db86aabSstevel return (SUCCESS); 42663db86aabSstevel } 42673db86aabSstevel 42683db86aabSstevel /* 42693db86aabSstevel * pcic_get_adapter() 42703db86aabSstevel * SocketServices GetAdapter function 42713db86aabSstevel * this is nearly a no-op. 42723db86aabSstevel */ 42733db86aabSstevel /*ARGSUSED*/ 42743db86aabSstevel static int 42753db86aabSstevel pcic_get_adapter(dev_info_t *dip, get_adapter_t *adapt) 42763db86aabSstevel { 42773db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 42783db86aabSstevel pcicdev_t *pcic = anp->an_private; 42793db86aabSstevel 42803db86aabSstevel if (pcic->pc_flags & PCF_INTRENAB) 42813db86aabSstevel adapt->SCRouting = IRQ_ENABLE; 42823db86aabSstevel adapt->state = 0; 42833db86aabSstevel return (SUCCESS); 42843db86aabSstevel } 42853db86aabSstevel 42863db86aabSstevel /* 42873db86aabSstevel * pcic_get_page() 42883db86aabSstevel * SocketServices GetPage function 42893db86aabSstevel * returns info about the window 42903db86aabSstevel */ 42913db86aabSstevel /*ARGSUSED*/ 42923db86aabSstevel static int 42933db86aabSstevel pcic_get_page(dev_info_t *dip, get_page_t *page) 42943db86aabSstevel { 42953db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 42963db86aabSstevel pcicdev_t *pcic = anp->an_private; 42973db86aabSstevel int socket, window; 42983db86aabSstevel pcs_memwin_t *winp; 42993db86aabSstevel 43003db86aabSstevel socket = page->window / PCIC_NUMWINSOCK; 43013db86aabSstevel window = page->window % PCIC_NUMWINSOCK; 43023db86aabSstevel 43033db86aabSstevel /* I/O windows are the first two */ 43043db86aabSstevel if (window < PCIC_IOWINDOWS || socket >= pcic->pc_numsockets) { 43053db86aabSstevel return (BAD_WINDOW); 43063db86aabSstevel } 43073db86aabSstevel 43083db86aabSstevel winp = &pcic->pc_sockets[socket].pcs_windows[window].mem; 43093db86aabSstevel 43103db86aabSstevel if (page->page != 0) 43113db86aabSstevel return (BAD_PAGE); 43123db86aabSstevel 43133db86aabSstevel page->state = 0; 43143db86aabSstevel if (winp->pcw_status & PCW_ENABLED) 43153db86aabSstevel page->state |= PS_ENABLED; 43163db86aabSstevel if (winp->pcw_status & PCW_ATTRIBUTE) 43173db86aabSstevel page->state |= PS_ATTRIBUTE; 43183db86aabSstevel if (winp->pcw_status & PCW_WP) 43193db86aabSstevel page->state |= PS_WP; 43203db86aabSstevel 43213db86aabSstevel page->offset = (off_t)winp->pcw_offset; 43223db86aabSstevel 43233db86aabSstevel return (SUCCESS); 43243db86aabSstevel } 43253db86aabSstevel 43263db86aabSstevel /* 43273db86aabSstevel * pcic_get_socket() 43283db86aabSstevel * SocketServices GetSocket 43293db86aabSstevel * returns information about the current socket setting 43303db86aabSstevel */ 43313db86aabSstevel /*ARGSUSED*/ 43323db86aabSstevel static int 43333db86aabSstevel pcic_get_socket(dev_info_t *dip, get_socket_t *socket) 43343db86aabSstevel { 43353db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 43363db86aabSstevel pcicdev_t *pcic = anp->an_private; 43373db86aabSstevel int socknum, irq_enabled; 43383db86aabSstevel pcic_socket_t *sockp; 43393db86aabSstevel 43403db86aabSstevel socknum = socket->socket; 43413db86aabSstevel sockp = &pcic->pc_sockets[socknum]; 43423db86aabSstevel 43433db86aabSstevel socket->SCIntMask = sockp->pcs_intmask; 43443db86aabSstevel sockp->pcs_state = pcic_card_state(pcic, sockp); 43453db86aabSstevel 43463db86aabSstevel socket->state = sockp->pcs_state; 43473db86aabSstevel if (socket->state & SBM_CD) { 43483db86aabSstevel socket->VccLevel = sockp->pcs_vcc; 43493db86aabSstevel socket->Vpp1Level = sockp->pcs_vpp1; 43503db86aabSstevel socket->Vpp2Level = sockp->pcs_vpp2; 43513db86aabSstevel irq_enabled = (sockp->pcs_flags & PCS_IRQ_ENABLED) ? 43523db86aabSstevel IRQ_ENABLE : 0; 43533db86aabSstevel socket->IRQRouting = sockp->pcs_irq | irq_enabled; 43543db86aabSstevel socket->IFType = (sockp->pcs_flags & PCS_CARD_IO) ? 43553db86aabSstevel IF_IO : IF_MEMORY; 43563db86aabSstevel } else { 43573db86aabSstevel socket->VccLevel = 0; 43583db86aabSstevel socket->Vpp1Level = 0; 43593db86aabSstevel socket->Vpp2Level = 0; 43603db86aabSstevel socket->IRQRouting = 0; 43613db86aabSstevel socket->IFType = IF_MEMORY; 43623db86aabSstevel } 43633db86aabSstevel socket->CtlInd = 0; /* no indicators */ 43643db86aabSstevel 43653db86aabSstevel return (SUCCESS); 43663db86aabSstevel } 43673db86aabSstevel 43683db86aabSstevel /* 43693db86aabSstevel * pcic_get_status() 43703db86aabSstevel * SocketServices GetStatus 43713db86aabSstevel * returns status information about the PC Card in 43723db86aabSstevel * the selected socket 43733db86aabSstevel */ 43743db86aabSstevel /*ARGSUSED*/ 43753db86aabSstevel static int 43763db86aabSstevel pcic_get_status(dev_info_t *dip, get_ss_status_t *status) 43773db86aabSstevel { 43783db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 43793db86aabSstevel pcicdev_t *pcic = anp->an_private; 43803db86aabSstevel int socknum, irq_enabled; 43813db86aabSstevel pcic_socket_t *sockp; 43823db86aabSstevel 43833db86aabSstevel socknum = status->socket; 43843db86aabSstevel sockp = &pcic->pc_sockets[socknum]; 43853db86aabSstevel 43863db86aabSstevel status->CardState = pcic_card_state(pcic, sockp); 43873db86aabSstevel status->SocketState = sockp->pcs_state; 43883db86aabSstevel status->CtlInd = 0; /* no indicators */ 43893db86aabSstevel 43903db86aabSstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) 43913db86aabSstevel status->SocketState |= SBM_CD; 43923db86aabSstevel if (status->CardState & SBM_CD) { 43933db86aabSstevel irq_enabled = (sockp->pcs_flags & PCS_CARD_ENABLED) ? 43943db86aabSstevel IRQ_ENABLE : 0; 43953db86aabSstevel status->IRQRouting = sockp->pcs_irq | irq_enabled; 43963db86aabSstevel status->IFType = (sockp->pcs_flags & PCS_CARD_IO) ? 43973db86aabSstevel IF_IO : IF_MEMORY; 43983db86aabSstevel } else { 43993db86aabSstevel status->IRQRouting = 0; 44003db86aabSstevel status->IFType = IF_MEMORY; 44013db86aabSstevel } 44023db86aabSstevel 44033db86aabSstevel #if defined(PCIC_DEBUG) 44043db86aabSstevel if (pcic_debug >= 8) 44053db86aabSstevel cmn_err(CE_CONT, "pcic_get_status: socket=%d, CardState=%x," 44063db86aabSstevel "SocketState=%x\n", 44073db86aabSstevel socknum, status->CardState, status->SocketState); 44083db86aabSstevel #endif 44093db86aabSstevel switch (pcic->pc_type) { 44103db86aabSstevel uint32_t present_state; 44113db86aabSstevel case PCIC_TI_PCI1410: 44123db86aabSstevel case PCIC_TI_PCI1520: 44133db86aabSstevel case PCIC_TI_PCI1420: 44143db86aabSstevel case PCIC_ENE_1420: 44153db86aabSstevel case PCIC_TOSHIBA_TOPIC100: 44163db86aabSstevel case PCIC_TOSHIBA_TOPIC95: 44173db86aabSstevel case PCIC_TOSHIBA_VENDOR: 44183db86aabSstevel case PCIC_O2MICRO_VENDOR: 44193db86aabSstevel case PCIC_TI_VENDOR: 44203db86aabSstevel case PCIC_RICOH_VENDOR: 44213db86aabSstevel present_state = pcic_getcb(pcic, CB_PRESENT_STATE); 44223db86aabSstevel if (present_state & PCIC_CB_CARD) 44233db86aabSstevel status->IFType = IF_CARDBUS; 44243db86aabSstevel #if defined(PCIC_DEBUG) 44253db86aabSstevel if (pcic_debug >= 8) 44263db86aabSstevel cmn_err(CE_CONT, "pcic_get_status: present_state=0x%x\n", 44273db86aabSstevel present_state); 44283db86aabSstevel #endif 44293db86aabSstevel break; 44303db86aabSstevel default: 44313db86aabSstevel break; 44323db86aabSstevel } 44333db86aabSstevel 44343db86aabSstevel return (SUCCESS); 44353db86aabSstevel } 44363db86aabSstevel 44373db86aabSstevel /* 44383db86aabSstevel * pcic_get_window() 44393db86aabSstevel * SocketServices GetWindow function 44403db86aabSstevel * returns state information about the specified window 44413db86aabSstevel */ 44423db86aabSstevel /*ARGSUSED*/ 44433db86aabSstevel static int 44443db86aabSstevel pcic_get_window(dev_info_t *dip, get_window_t *window) 44453db86aabSstevel { 44463db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 44473db86aabSstevel pcicdev_t *pcic = anp->an_private; 44483db86aabSstevel int socket, win; 44493db86aabSstevel pcic_socket_t *sockp; 44503db86aabSstevel pcs_memwin_t *winp; 44513db86aabSstevel 44523db86aabSstevel socket = window->window / PCIC_NUMWINSOCK; 44533db86aabSstevel win = window->window % PCIC_NUMWINSOCK; 44543db86aabSstevel #if defined(PCIC_DEBUG) 44553db86aabSstevel if (pcic_debug) { 44563db86aabSstevel cmn_err(CE_CONT, "pcic_get_window(socket=%d, window=%d)\n", 44573db86aabSstevel socket, win); 44583db86aabSstevel } 44593db86aabSstevel #endif 44603db86aabSstevel 44613db86aabSstevel if (socket > pcic->pc_numsockets) 44623db86aabSstevel return (BAD_WINDOW); 44633db86aabSstevel 44643db86aabSstevel sockp = &pcic->pc_sockets[socket]; 44653db86aabSstevel winp = &sockp->pcs_windows[win].mem; 44663db86aabSstevel 44673db86aabSstevel window->socket = socket; 44683db86aabSstevel window->size = winp->pcw_len; 44693db86aabSstevel window->speed = winp->pcw_speed; 44703db86aabSstevel window->handle = (ddi_acc_handle_t)winp->pcw_handle; 44713db86aabSstevel window->base = (uint32_t)winp->pcw_base + winp->pcw_offset; 44723db86aabSstevel 44733db86aabSstevel if (win >= PCIC_IOWINDOWS) { 44743db86aabSstevel window->state = 0; 44753db86aabSstevel } else { 44763db86aabSstevel window->state = WS_IO; 44773db86aabSstevel } 44783db86aabSstevel if (winp->pcw_status & PCW_ENABLED) 44793db86aabSstevel window->state |= WS_ENABLED; 44803db86aabSstevel 44813db86aabSstevel if (winp->pcw_status & PCS_CARD_16BIT) 44823db86aabSstevel window->state |= WS_16BIT; 44833db86aabSstevel #if defined(PCIC_DEBUG) 44843db86aabSstevel if (pcic_debug) 44853db86aabSstevel cmn_err(CE_CONT, "\tsize=%d, speed=%d, base=%p, state=%x\n", 44863db86aabSstevel window->size, (unsigned)window->speed, 44873db86aabSstevel (void *)window->handle, window->state); 44883db86aabSstevel #endif 44893db86aabSstevel 44903db86aabSstevel return (SUCCESS); 44913db86aabSstevel } 44923db86aabSstevel 44933db86aabSstevel /* 44943db86aabSstevel * pcic_ll_reset 44953db86aabSstevel * low level reset 44963db86aabSstevel * separated out so it can be called when already locked 44973db86aabSstevel * 44983db86aabSstevel * There are two variables that control the RESET timing: 44993db86aabSstevel * pcic_prereset_time - time in mS before asserting RESET 45003db86aabSstevel * pcic_reset_time - time in mS to assert RESET 45013db86aabSstevel * 45023db86aabSstevel */ 45033db86aabSstevel int pcic_prereset_time = 1; 45043db86aabSstevel int pcic_reset_time = 10; 45053db86aabSstevel int pcic_postreset_time = 20; 45063db86aabSstevel int pcic_vpp_is_vcc_during_reset = 0; 45073db86aabSstevel 45083db86aabSstevel static int 45093db86aabSstevel pcic_ll_reset(pcicdev_t *pcic, int socket) 45103db86aabSstevel { 45113db86aabSstevel int windowbits, iobits; 45123db86aabSstevel uint32_t pwr; 45133db86aabSstevel 45143db86aabSstevel /* save windows that were on */ 45153db86aabSstevel windowbits = pcic_getb(pcic, socket, PCIC_MAPPING_ENABLE); 45163db86aabSstevel if (pcic_reset_time == 0) 45173db86aabSstevel return (windowbits); 45183db86aabSstevel /* turn all windows off */ 45193db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, 0); 45203db86aabSstevel 45213db86aabSstevel #if defined(PCIC_DEBUG) 45223db86aabSstevel pcic_err(pcic->dip, 6, 45233db86aabSstevel "pcic_ll_reset(socket %d) powerlevel=%x cbctl 0x%x cbps 0x%x\n", 45243db86aabSstevel socket, pcic_getb(pcic, socket, PCIC_POWER_CONTROL), 45253db86aabSstevel pcic_getcb(pcic, CB_CONTROL), 45263db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE)); 45273db86aabSstevel #endif 45283db86aabSstevel 45293db86aabSstevel if (pcic_vpp_is_vcc_during_reset) { 45303db86aabSstevel 45313db86aabSstevel /* 45323db86aabSstevel * Set VPP to VCC for the duration of the reset - for aironet 45333db86aabSstevel * card. 45343db86aabSstevel */ 45353db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) { 45363db86aabSstevel pwr = pcic_getcb(pcic, CB_CONTROL); 45373db86aabSstevel pcic_putcb(pcic, CB_CONTROL, (pwr&~CB_C_VPPMASK)|CB_C_VPPVCC); 45383db86aabSstevel (void) pcic_getcb(pcic, CB_CONTROL); 45393db86aabSstevel } else { 45403db86aabSstevel pwr = pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 45413db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, 45423db86aabSstevel pwr | 1); 45433db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 45443db86aabSstevel } 45453db86aabSstevel } 45463db86aabSstevel 45473db86aabSstevel if (pcic_prereset_time > 0) { 45483db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset pre_wait %d mS\n", 45493db86aabSstevel pcic_prereset_time); 45503db86aabSstevel pcic_mswait(pcic, socket, pcic_prereset_time); 45513db86aabSstevel } 45523db86aabSstevel 45533db86aabSstevel /* turn interrupts off and start a reset */ 45543db86aabSstevel pcic_err(pcic->dip, 8, 45553db86aabSstevel "pcic_ll_reset turn interrupts off and start a reset\n"); 45563db86aabSstevel iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT); 45573db86aabSstevel iobits &= ~(PCIC_INTR_MASK | PCIC_RESET); 45583db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits); 45593db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_INTERRUPT); 45603db86aabSstevel 45613db86aabSstevel switch (pcic->pc_type) { 45623db86aabSstevel case PCIC_INTEL_i82092: 45633db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ, 45643db86aabSstevel PCIC_82092_INT_DISABLE); 45653db86aabSstevel break; 45663db86aabSstevel default: 45673db86aabSstevel break; 45683db86aabSstevel } /* switch */ 45693db86aabSstevel 45703db86aabSstevel pcic->pc_sockets[socket].pcs_state = 0; 45713db86aabSstevel 45723db86aabSstevel if (pcic_reset_time > 0) { 45733db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset reset_wait %d mS\n", 45743db86aabSstevel pcic_reset_time); 45753db86aabSstevel pcic_mswait(pcic, socket, pcic_reset_time); 45763db86aabSstevel } 45773db86aabSstevel 45783db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset take it out of reset now\n"); 45793db86aabSstevel 45803db86aabSstevel /* take it out of RESET now */ 45813db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, PCIC_RESET | iobits); 45823db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_INTERRUPT); 45833db86aabSstevel 45843db86aabSstevel /* 45853db86aabSstevel * can't access the card for 20ms, but we really don't 45863db86aabSstevel * want to sit around that long. The pcic is still usable. 45873db86aabSstevel * memory accesses must wait for RDY to come up. 45883db86aabSstevel */ 45893db86aabSstevel if (pcic_postreset_time > 0) { 45903db86aabSstevel pcic_err(pcic->dip, 8, "pcic_ll_reset post_wait %d mS\n", 45913db86aabSstevel pcic_postreset_time); 45923db86aabSstevel pcic_mswait(pcic, socket, pcic_postreset_time); 45933db86aabSstevel } 45943db86aabSstevel 45953db86aabSstevel if (pcic_vpp_is_vcc_during_reset > 1) { 45963db86aabSstevel 45973db86aabSstevel /* 45983db86aabSstevel * Return VPP power to whatever it was before. 45993db86aabSstevel */ 46003db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) { 46013db86aabSstevel pcic_putcb(pcic, CB_CONTROL, pwr); 46023db86aabSstevel (void) pcic_getcb(pcic, CB_CONTROL); 46033db86aabSstevel } else { 46043db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, pwr); 46053db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 46063db86aabSstevel } 46073db86aabSstevel } 46083db86aabSstevel 46093db86aabSstevel pcic_err(pcic->dip, 7, "pcic_ll_reset returning 0x%x\n", windowbits); 46103db86aabSstevel 46113db86aabSstevel return (windowbits); 46123db86aabSstevel } 46133db86aabSstevel 46143db86aabSstevel /* 46153db86aabSstevel * pcic_reset_socket() 46163db86aabSstevel * SocketServices ResetSocket function 46173db86aabSstevel * puts the PC Card in the socket into the RESET state 46183db86aabSstevel * and then takes it out after the the cycle time 46193db86aabSstevel * The socket is back to initial state when done 46203db86aabSstevel */ 46213db86aabSstevel static int 46223db86aabSstevel pcic_reset_socket(dev_info_t *dip, int socket, int mode) 46233db86aabSstevel { 46243db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 46253db86aabSstevel pcicdev_t *pcic = anp->an_private; 46263db86aabSstevel int value; 46273db86aabSstevel int i, mint; 46283db86aabSstevel pcic_socket_t *sockp; 46293db86aabSstevel 46303db86aabSstevel #if defined(PCIC_DEBUG) 46313db86aabSstevel if (pcic_debug >= 8) 46323db86aabSstevel cmn_err(CE_CONT, "pcic_reset_socket(%p, %d, %d/%s)\n", 46333db86aabSstevel (void *)dip, socket, mode, 46343db86aabSstevel mode == RESET_MODE_FULL ? "full" : "partial"); 46353db86aabSstevel #endif 46363db86aabSstevel 46373db86aabSstevel mutex_enter(&pcic->pc_lock); /* protect the registers */ 46383db86aabSstevel 46393db86aabSstevel /* Turn off management interupts. */ 46403db86aabSstevel mint = pcic_getb(pcic, socket, PCIC_MANAGEMENT_INT); 46413db86aabSstevel pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint & ~PCIC_CHANGE_MASK); 46423db86aabSstevel 46433db86aabSstevel sockp = &pcic->pc_sockets[socket]; 46443db86aabSstevel 46453db86aabSstevel value = pcic_ll_reset(pcic, socket); 46463db86aabSstevel if (mode == RESET_MODE_FULL) { 46473db86aabSstevel /* disable and unmap all mapped windows */ 46483db86aabSstevel for (i = 0; i < PCIC_NUMWINSOCK; i++) { 46493db86aabSstevel if (i < PCIC_IOWINDOWS) { 46503db86aabSstevel if (sockp->pcs_windows[i].io.pcw_status & 46513db86aabSstevel PCW_MAPPED) { 46523db86aabSstevel pcs_iowin_t *io; 46533db86aabSstevel io = &sockp->pcs_windows[i].io; 46543db86aabSstevel io->pcw_status &= ~PCW_ENABLED; 46553db86aabSstevel } 46563db86aabSstevel } else { 46573db86aabSstevel if (sockp->pcs_windows[i].mem.pcw_status & 46583db86aabSstevel PCW_MAPPED) { 46593db86aabSstevel pcs_memwin_t *mem; 46603db86aabSstevel mem = &sockp->pcs_windows[i].mem; 46613db86aabSstevel mem->pcw_status &= ~PCW_ENABLED; 46623db86aabSstevel } 46633db86aabSstevel } 46643db86aabSstevel } 46653db86aabSstevel } else { 46663db86aabSstevel /* turn windows back on */ 46673db86aabSstevel pcic_putb(pcic, socket, PCIC_MAPPING_ENABLE, value); 46683db86aabSstevel /* wait the rest of the time here */ 46693db86aabSstevel pcic_mswait(pcic, socket, 10); 46703db86aabSstevel } 46713db86aabSstevel pcic_putb(pcic, socket, PCIC_MANAGEMENT_INT, mint); 46723db86aabSstevel mutex_exit(&pcic->pc_lock); 46733db86aabSstevel return (SUCCESS); 46743db86aabSstevel } 46753db86aabSstevel 46763db86aabSstevel /* 46773db86aabSstevel * pcic_set_interrupt() 46783db86aabSstevel * SocketServices SetInterrupt function 46793db86aabSstevel */ 46803db86aabSstevel static int 46813db86aabSstevel pcic_set_interrupt(dev_info_t *dip, set_irq_handler_t *handler) 46823db86aabSstevel { 46833db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 46843db86aabSstevel pcicdev_t *pcic = anp->an_private; 46853db86aabSstevel int value = DDI_SUCCESS; 46863db86aabSstevel inthandler_t *intr; 46873db86aabSstevel 46883db86aabSstevel #if defined(PCIC_DEBUG) 46893db86aabSstevel if (pcic_debug) { 46903db86aabSstevel cmn_err(CE_CONT, 46913db86aabSstevel "pcic_set_interrupt: entered pc_intr_mode=0x%x\n", 46923db86aabSstevel pcic->pc_intr_mode); 46933db86aabSstevel cmn_err(CE_CONT, 46943db86aabSstevel "\t irq_top=%p handler=%p handler_id=%x\n", 46953db86aabSstevel (void *)pcic->irq_top, (void *)handler->handler, 46963db86aabSstevel handler->handler_id); 46973db86aabSstevel } 46983db86aabSstevel #endif 46993db86aabSstevel 47003db86aabSstevel /* 47013db86aabSstevel * If we're on a PCI bus, we route all IO IRQs through a single 47023db86aabSstevel * PCI interrupt (typically INT A#) so we don't have to do 47033db86aabSstevel * much other than add the caller to general interrupt handler 47043db86aabSstevel * and set some state. 47053db86aabSstevel */ 47063db86aabSstevel 47073db86aabSstevel intr = kmem_zalloc(sizeof (inthandler_t), KM_NOSLEEP); 47083db86aabSstevel if (intr == NULL) 47093db86aabSstevel return (NO_RESOURCE); 47103db86aabSstevel 47113db86aabSstevel switch (pcic->pc_intr_mode) { 47123db86aabSstevel case PCIC_INTR_MODE_PCI_1: 47133db86aabSstevel /* 47143db86aabSstevel * We only allow above-lock-level IO IRQ handlers 47153db86aabSstevel * in the PCI bus case. 47163db86aabSstevel */ 47173db86aabSstevel 47183db86aabSstevel mutex_enter(&pcic->intr_lock); 47193db86aabSstevel 47203db86aabSstevel if (pcic->irq_top == NULL) { 47213db86aabSstevel pcic->irq_top = intr; 47223db86aabSstevel pcic->irq_current = pcic->irq_top; 47233db86aabSstevel } else { 47243db86aabSstevel while (pcic->irq_current->next != NULL) 47253db86aabSstevel pcic->irq_current = pcic->irq_current->next; 47263db86aabSstevel pcic->irq_current->next = intr; 47273db86aabSstevel pcic->irq_current = pcic->irq_current->next; 47283db86aabSstevel } 47293db86aabSstevel 47303db86aabSstevel pcic->irq_current->intr = 47313db86aabSstevel (ddi_intr_handler_t *)handler->handler; 47323db86aabSstevel pcic->irq_current->handler_id = handler->handler_id; 47333db86aabSstevel pcic->irq_current->arg1 = handler->arg1; 47343db86aabSstevel pcic->irq_current->arg2 = handler->arg2; 47353db86aabSstevel pcic->irq_current->socket = handler->socket; 47363db86aabSstevel 47373db86aabSstevel mutex_exit(&pcic->intr_lock); 47383db86aabSstevel 47393db86aabSstevel handler->iblk_cookie = &pcic->pc_pri; 47403db86aabSstevel handler->idev_cookie = &pcic->pc_dcookie; 47413db86aabSstevel break; 47423db86aabSstevel 47433db86aabSstevel default: 47443db86aabSstevel intr->intr = (ddi_intr_handler_t *)handler->handler; 47453db86aabSstevel intr->handler_id = handler->handler_id; 47463db86aabSstevel intr->arg1 = handler->arg1; 47473db86aabSstevel intr->arg2 = handler->arg2; 47483db86aabSstevel intr->socket = handler->socket; 47493db86aabSstevel intr->irq = handler->irq; 47503db86aabSstevel 47513db86aabSstevel /* 47523db86aabSstevel * need to revisit this to see if interrupts can be 47533db86aabSstevel * shared someday. Note that IRQ is set in the common 47543db86aabSstevel * code. 47553db86aabSstevel */ 47563db86aabSstevel mutex_enter(&pcic->pc_lock); 47573db86aabSstevel if (pcic->pc_handlers == NULL) { 47583db86aabSstevel pcic->pc_handlers = intr; 47593db86aabSstevel intr->next = intr->prev = intr; 47603db86aabSstevel } else { 47613db86aabSstevel insque(intr, pcic->pc_handlers); 47623db86aabSstevel } 47633db86aabSstevel mutex_exit(&pcic->pc_lock); 47643db86aabSstevel 47653db86aabSstevel break; 47663db86aabSstevel } 47673db86aabSstevel 47683db86aabSstevel /* 47693db86aabSstevel * need to fill in cookies in event of multiple high priority 47703db86aabSstevel * interrupt handlers on same IRQ 47713db86aabSstevel */ 47723db86aabSstevel 47733db86aabSstevel #if defined(PCIC_DEBUG) 47743db86aabSstevel if (pcic_debug) { 47753db86aabSstevel cmn_err(CE_CONT, 47763db86aabSstevel "pcic_set_interrupt: exit irq_top=%p value=%d\n", 47773db86aabSstevel (void *)pcic->irq_top, value); 47783db86aabSstevel } 47793db86aabSstevel #endif 47803db86aabSstevel 47813db86aabSstevel if (value == DDI_SUCCESS) { 47823db86aabSstevel return (SUCCESS); 47833db86aabSstevel } else { 47843db86aabSstevel return (BAD_IRQ); 47853db86aabSstevel } 47863db86aabSstevel } 47873db86aabSstevel 47883db86aabSstevel /* 47893db86aabSstevel * pcic_clear_interrupt() 47903db86aabSstevel * SocketServices ClearInterrupt function 47913db86aabSstevel * 47923db86aabSstevel * Interrupts for PCIC are complicated by the fact that we must 47933db86aabSstevel * follow several different models for interrupts. 47943db86aabSstevel * ISA: there is an interrupt per adapter and per socket and 47953db86aabSstevel * they can't be shared. 47963db86aabSstevel * PCI: some adapters have one PCI interrupt available while others 47973db86aabSstevel * have up to 4. Solaris may or may not allow us to use more 47983db86aabSstevel * than 1 so we essentially share them all at this point. 47993db86aabSstevel * Hybrid: PCI bridge but interrupts wired to host interrupt controller. 48003db86aabSstevel * This is like ISA but we have to fudge and create an intrspec 48013db86aabSstevel * that PCI's parent understands and bypass the PCI nexus. 48023db86aabSstevel * multifunction: this requires sharing the interrupts on a per-socket 48033db86aabSstevel * basis. 48043db86aabSstevel */ 48053db86aabSstevel static int 48063db86aabSstevel pcic_clear_interrupt(dev_info_t *dip, clear_irq_handler_t *handler) 48073db86aabSstevel { 48083db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 48093db86aabSstevel pcicdev_t *pcic = anp->an_private; 48103db86aabSstevel inthandler_t *intr, *prev, *current; 48113db86aabSstevel int i; 48123db86aabSstevel 48133db86aabSstevel /* 48143db86aabSstevel * If we're on a PCI bus, we route all IO IRQs through a single 48153db86aabSstevel * PCI interrupt (typically INT A#) so we don't have to do 48163db86aabSstevel * much other than remove the caller from the general 48173db86aabSstevel * interrupt handler callout list. 48183db86aabSstevel */ 48193db86aabSstevel 48203db86aabSstevel #if defined(PCIC_DEBUG) 48213db86aabSstevel if (pcic_debug) { 48223db86aabSstevel cmn_err(CE_CONT, 48233db86aabSstevel "pcic_clear_interrupt: entered pc_intr_mode=0x%x\n", 48243db86aabSstevel pcic->pc_intr_mode); 48253db86aabSstevel cmn_err(CE_CONT, 48263db86aabSstevel "\t irq_top=%p handler=%p handler_id=%x\n", 48273db86aabSstevel (void *)pcic->irq_top, (void *)handler->handler, 48283db86aabSstevel handler->handler_id); 48293db86aabSstevel } 48303db86aabSstevel #endif 48313db86aabSstevel 48323db86aabSstevel switch (pcic->pc_intr_mode) { 48333db86aabSstevel case PCIC_INTR_MODE_PCI_1: 48343db86aabSstevel 48353db86aabSstevel mutex_enter(&pcic->intr_lock); 48363db86aabSstevel if (pcic->irq_top == NULL) { 48373db86aabSstevel mutex_exit(&pcic->intr_lock); 48383db86aabSstevel return (BAD_IRQ); 48393db86aabSstevel } 48403db86aabSstevel 48413db86aabSstevel intr = NULL; 48423db86aabSstevel pcic->irq_current = pcic->irq_top; 48433db86aabSstevel 48443db86aabSstevel while ((pcic->irq_current != NULL) && 48453db86aabSstevel (pcic->irq_current->handler_id != 48463db86aabSstevel handler->handler_id)) { 48473db86aabSstevel intr = pcic->irq_current; 48483db86aabSstevel pcic->irq_current = pcic->irq_current->next; 48493db86aabSstevel } 48503db86aabSstevel 48513db86aabSstevel if (pcic->irq_current == NULL) { 48523db86aabSstevel mutex_exit(&pcic->intr_lock); 48533db86aabSstevel return (BAD_IRQ); 48543db86aabSstevel } 48553db86aabSstevel 48563db86aabSstevel if (intr != NULL) { 48573db86aabSstevel intr->next = pcic->irq_current->next; 48583db86aabSstevel } else { 48593db86aabSstevel pcic->irq_top = pcic->irq_current->next; 48603db86aabSstevel } 48613db86aabSstevel 48623db86aabSstevel current = pcic->irq_current; 48633db86aabSstevel pcic->irq_current = pcic->irq_top; 48643db86aabSstevel mutex_exit(&pcic->intr_lock); 48653db86aabSstevel kmem_free(current, sizeof (inthandler_t)); 48663db86aabSstevel 48673db86aabSstevel break; 48683db86aabSstevel 48693db86aabSstevel default: 48703db86aabSstevel 48713db86aabSstevel mutex_enter(&pcic->pc_lock); 48723db86aabSstevel intr = pcic_handlers; 48733db86aabSstevel prev = (inthandler_t *)&pcic_handlers; 48743db86aabSstevel 48753db86aabSstevel while (intr != NULL) { 48763db86aabSstevel if (intr->handler_id == handler->handler_id) { 48773db86aabSstevel i = intr->irq & PCIC_INTR_MASK; 48783db86aabSstevel if (--pcic_irq_map[i].count == 0) { 48793db86aabSstevel /* multi-handler form */ 48803db86aabSstevel (void) ddi_intr_disable(pcic->pc_intr_htblp[i]); 48813db86aabSstevel (void) ddi_intr_remove_handler( 48823db86aabSstevel pcic->pc_intr_htblp[i]); 48833db86aabSstevel (void) ddi_intr_free(pcic->pc_intr_htblp[i]); 48843db86aabSstevel (void) pcmcia_return_intr(pcic->dip, i); 48853db86aabSstevel #if defined(PCIC_DEBUG) 48863db86aabSstevel if (pcic_debug) { 48873db86aabSstevel cmn_err(CE_CONT, 48883db86aabSstevel "removing interrupt %d at %s " 48893db86aabSstevel "priority\n", i, "high"); 48903db86aabSstevel cmn_err(CE_CONT, 48913db86aabSstevel "ddi_remove_intr(%p, %x, %p)\n", 48923db86aabSstevel (void *)dip, 48933db86aabSstevel 0, 48943db86aabSstevel (void *)intr->iblk_cookie); 48953db86aabSstevel } 48963db86aabSstevel #endif 48973db86aabSstevel } 48983db86aabSstevel prev->next = intr->next; 48993db86aabSstevel kmem_free(intr, sizeof (inthandler_t)); 49003db86aabSstevel intr = prev->next; 49013db86aabSstevel } else { 49023db86aabSstevel prev = intr; 49033db86aabSstevel intr = intr->next; 49043db86aabSstevel } /* if (handler_id) */ 49053db86aabSstevel } /* while */ 49063db86aabSstevel 49073db86aabSstevel mutex_exit(&pcic->pc_lock); 49083db86aabSstevel } 49093db86aabSstevel 49103db86aabSstevel #if defined(PCIC_DEBUG) 49113db86aabSstevel if (pcic_debug) { 49123db86aabSstevel cmn_err(CE_CONT, 49133db86aabSstevel "pcic_clear_interrupt: exit irq_top=%p\n", 49143db86aabSstevel (void *)pcic->irq_top); 49153db86aabSstevel } 49163db86aabSstevel #endif 49173db86aabSstevel 49183db86aabSstevel 49193db86aabSstevel return (SUCCESS); 49203db86aabSstevel } 49213db86aabSstevel 49223db86aabSstevel struct intel_regs { 49233db86aabSstevel char *name; 49243db86aabSstevel int off; 49253db86aabSstevel char *fmt; 49263db86aabSstevel } iregs[] = { 49273db86aabSstevel {"ident ", 0}, 49283db86aabSstevel {"if-status ", 1, "\020\1BVD1\2BVD2\3CD1\4CD2\5WP\6RDY\7PWR\10~GPI"}, 49293db86aabSstevel {"power ", 2, "\020\1Vpp1c0\2Vpp1c1\3Vpp2c0\4Vpp2c1\5PE\6AUTO" 49303db86aabSstevel "\7DRD\10OE"}, 49313db86aabSstevel {"cardstatus", 4, "\020\1BD\2BW\3RC\4CD\5GPI\6R1\7R2\010R3"}, 49323db86aabSstevel {"enable ", 6, "\020\1MW0\2MW1\3MW2\4MW3\5MW4\6MEM16\7IO0\10IO1"}, 49333db86aabSstevel {"cd-gcr ", 0x16, "\020\1MDI16\2CRE\3GPIE\4GPIT\5CDR\6S/W"}, 49343db86aabSstevel {"GCR ", 0x1e, "\020\1PD\2LEVEL\3WCSC\4PLS14"}, 49353db86aabSstevel {"int-gcr ", 3, "\020\5INTR\6IO\7~RST\10RI"}, 49363db86aabSstevel {"management", 5, "\020\1BDE\2BWE\3RE\4CDE"}, 49373db86aabSstevel {"volt-sense", 0x1f, "\020\1A_VS1\2A_VS2\3B_VS1\4B_VS2"}, 49383db86aabSstevel {"volt-sel ", 0x2f, "\020\5EXTCONF\6BUSSELECT\7MIXEDV\10ISAV"}, 49393db86aabSstevel {"VG ext A ", 0x3c, "\20\3IVS\4CABLE\5CSTEP\6TEST\7RIO"}, 49403db86aabSstevel {"io-ctrl ", 7, "\020\1DS0\2IOCS0\3ZWS0\4WS0\5DS1\6IOS1\7ZWS1\10WS1"}, 49413db86aabSstevel {"io0-slow ", 8}, 49423db86aabSstevel {"io0-shi ", 9}, 49433db86aabSstevel {"io0-elow ", 0xa}, 49443db86aabSstevel {"io0-ehi ", 0xb}, 49453db86aabSstevel {"io1-slow ", 0xc}, 49463db86aabSstevel {"io1-shi ", 0xd}, 49473db86aabSstevel {"io1-elow ", 0xe}, 49483db86aabSstevel {"io1-ehi ", 0xf}, 49493db86aabSstevel {"mem0-slow ", 0x10}, 49503db86aabSstevel {"mem0-shi ", 0x11, "\020\7ZW\10DS"}, 49513db86aabSstevel {"mem0-elow ", 0x12}, 49523db86aabSstevel {"mem0-ehi ", 0x13, "\020\7WS0\10WS1"}, 49533db86aabSstevel {"card0-low ", 0x14}, 49543db86aabSstevel {"card0-hi ", 0x15, "\020\7AM\10WP"}, 49553db86aabSstevel {"mem1-slow ", 0x18}, 49563db86aabSstevel {"mem1-shi ", 0x19, "\020\7ZW\10DS"}, 49573db86aabSstevel {"mem1-elow ", 0x1a}, 49583db86aabSstevel {"mem1-ehi ", 0x1b, "\020\7WS0\10WS1"}, 49593db86aabSstevel {"card1-low ", 0x1c}, 49603db86aabSstevel {"card1-hi ", 0x1d, "\020\7AM\10WP"}, 49613db86aabSstevel {"mem2-slow ", 0x20}, 49623db86aabSstevel {"mem2-shi ", 0x21, "\020\7ZW\10DS"}, 49633db86aabSstevel {"mem2-elow ", 0x22}, 49643db86aabSstevel {"mem2-ehi ", 0x23, "\020\7WS0\10WS1"}, 49653db86aabSstevel {"card2-low ", 0x24}, 49663db86aabSstevel {"card2-hi ", 0x25, "\020\7AM\10WP"}, 49673db86aabSstevel {"mem3-slow ", 0x28}, 49683db86aabSstevel {"mem3-shi ", 0x29, "\020\7ZW\10DS"}, 49693db86aabSstevel {"mem3-elow ", 0x2a}, 49703db86aabSstevel {"mem3-ehi ", 0x2b, "\020\7WS0\10WS1"}, 49713db86aabSstevel {"card3-low ", 0x2c}, 49723db86aabSstevel {"card3-hi ", 0x2d, "\020\7AM\10WP"}, 49733db86aabSstevel 49743db86aabSstevel {"mem4-slow ", 0x30}, 49753db86aabSstevel {"mem4-shi ", 0x31, "\020\7ZW\10DS"}, 49763db86aabSstevel {"mem4-elow ", 0x32}, 49773db86aabSstevel {"mem4-ehi ", 0x33, "\020\7WS0\10WS1"}, 49783db86aabSstevel {"card4-low ", 0x34}, 49793db86aabSstevel {"card4-hi ", 0x35, "\020\7AM\10WP"}, 49803db86aabSstevel {"mpage0 ", 0x40}, 49813db86aabSstevel {"mpage1 ", 0x41}, 49823db86aabSstevel {"mpage2 ", 0x42}, 49833db86aabSstevel {"mpage3 ", 0x43}, 49843db86aabSstevel {"mpage4 ", 0x44}, 49853db86aabSstevel {NULL}, 49863db86aabSstevel }; 49873db86aabSstevel 49883db86aabSstevel static struct intel_regs cregs[] = { 49893db86aabSstevel {"misc-ctl1 ", 0x16, "\20\2VCC3\3PMI\4PSI\5SPKR\10INPACK"}, 49903db86aabSstevel {"fifo ", 0x17, "\20\6DIOP\7DMEMP\10EMPTY"}, 49913db86aabSstevel {"misc-ctl2 ", 0x1e, "\20\1XCLK\2LOW\3SUSP\4CORE5V\5TCD\10RIOUT"}, 49923db86aabSstevel {"chip-info ", 0x1f, "\20\6DUAL"}, 49933db86aabSstevel {"IO-offlow0", 0x36}, 49943db86aabSstevel {"IO-offhi0 ", 0x37}, 49953db86aabSstevel {"IO-offlow1", 0x38}, 49963db86aabSstevel {"IO-offhi1 ", 0x39}, 49973db86aabSstevel NULL, 49983db86aabSstevel }; 49993db86aabSstevel 50003db86aabSstevel static struct intel_regs cxregs[] = { 50013db86aabSstevel {"ext-ctl-1 ", 0x03, 50023db86aabSstevel "\20\1VCCLCK\2AUTOCLR\3LED\4INVIRQC\5INVIRQM\6PUC"}, 50033db86aabSstevel {"misc-ctl3 ", 0x25, "\20\5HWSUSP"}, 50043db86aabSstevel {"mem0-up ", 0x05}, 50053db86aabSstevel {"mem1-up ", 0x06}, 50063db86aabSstevel {"mem2-up ", 0x07}, 50073db86aabSstevel {"mem3-up ", 0x08}, 50083db86aabSstevel {"mem4-up ", 0x09}, 50093db86aabSstevel {NULL} 50103db86aabSstevel }; 50113db86aabSstevel 50123db86aabSstevel void 50133db86aabSstevel xxdmp_cl_regs(pcicdev_t *pcic, int socket, uint32_t len) 50143db86aabSstevel { 50153db86aabSstevel int i, value, j; 50163db86aabSstevel char buff[256]; 50173db86aabSstevel char *fmt; 50183db86aabSstevel 50193db86aabSstevel cmn_err(CE_CONT, "--------- Cirrus Logic Registers --------\n"); 50203db86aabSstevel for (buff[0] = '\0', i = 0; cregs[i].name != NULL && len-- != 0; i++) { 50213db86aabSstevel int sval; 50223db86aabSstevel if (cregs[i].off == PCIC_MISC_CTL_2) 50233db86aabSstevel sval = 0; 50243db86aabSstevel else 50253db86aabSstevel sval = socket; 50263db86aabSstevel value = pcic_getb(pcic, sval, cregs[i].off); 50273db86aabSstevel if (i & 1) { 50283db86aabSstevel if (cregs[i].fmt) 50293db86aabSstevel fmt = "%s\t%s\t%b\n"; 50303db86aabSstevel else 50313db86aabSstevel fmt = "%s\t%s\t%x\n"; 50323db86aabSstevel cmn_err(CE_CONT, fmt, buff, 50333db86aabSstevel cregs[i].name, value, cregs[i].fmt); 50343db86aabSstevel buff[0] = '\0'; 50353db86aabSstevel } else { 50363db86aabSstevel if (cregs[i].fmt) 50373db86aabSstevel fmt = "\t%s\t%b"; 50383db86aabSstevel else 50393db86aabSstevel fmt = "\t%s\t%x"; 50403db86aabSstevel (void) sprintf(buff, fmt, 50413db86aabSstevel cregs[i].name, value, cregs[i].fmt); 50423db86aabSstevel for (j = strlen(buff); j < 40; j++) 50433db86aabSstevel buff[j] = ' '; 50443db86aabSstevel buff[40] = '\0'; 50453db86aabSstevel } 50463db86aabSstevel } 50473db86aabSstevel cmn_err(CE_CONT, "%s\n", buff); 50483db86aabSstevel 50493db86aabSstevel i = pcic_getb(pcic, socket, PCIC_TIME_SETUP_0); 50503db86aabSstevel j = pcic_getb(pcic, socket, PCIC_TIME_SETUP_1); 50513db86aabSstevel cmn_err(CE_CONT, "\tsetup-tim0\t%x\tsetup-tim1\t%x\n", i, j); 50523db86aabSstevel 50533db86aabSstevel i = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_0); 50543db86aabSstevel j = pcic_getb(pcic, socket, PCIC_TIME_COMMAND_1); 50553db86aabSstevel cmn_err(CE_CONT, "\tcmd-tim0 \t%x\tcmd-tim1 \t%x\n", i, j); 50563db86aabSstevel 50573db86aabSstevel i = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_0); 50583db86aabSstevel j = pcic_getb(pcic, socket, PCIC_TIME_RECOVER_1); 50593db86aabSstevel cmn_err(CE_CONT, "\trcvr-tim0 \t%x\trcvr-tim1 \t%x\n", i, j); 50603db86aabSstevel 50613db86aabSstevel cmn_err(CE_CONT, "--------- Extended Registers --------\n"); 50623db86aabSstevel 50633db86aabSstevel for (buff[0] = '\0', i = 0; cxregs[i].name != NULL && len-- != 0; i++) { 50643db86aabSstevel value = clext_reg_read(pcic, socket, cxregs[i].off); 50653db86aabSstevel if (i & 1) { 50663db86aabSstevel if (cxregs[i].fmt) 50673db86aabSstevel fmt = "%s\t%s\t%b\n"; 50683db86aabSstevel else 50693db86aabSstevel fmt = "%s\t%s\t%x\n"; 50703db86aabSstevel cmn_err(CE_CONT, fmt, buff, 50713db86aabSstevel cxregs[i].name, value, cxregs[i].fmt); 50723db86aabSstevel buff[0] = '\0'; 50733db86aabSstevel } else { 50743db86aabSstevel if (cxregs[i].fmt) 50753db86aabSstevel fmt = "\t%s\t%b"; 50763db86aabSstevel else 50773db86aabSstevel fmt = "\t%s\t%x"; 50783db86aabSstevel (void) sprintf(buff, fmt, 50793db86aabSstevel cxregs[i].name, value, cxregs[i].fmt); 50803db86aabSstevel for (j = strlen(buff); j < 40; j++) 50813db86aabSstevel buff[j] = ' '; 50823db86aabSstevel buff[40] = '\0'; 50833db86aabSstevel } 50843db86aabSstevel } 50853db86aabSstevel } 50863db86aabSstevel 50873db86aabSstevel #if defined(PCIC_DEBUG) 50883db86aabSstevel static void 50893db86aabSstevel xxdmp_all_regs(pcicdev_t *pcic, int socket, uint32_t len) 50903db86aabSstevel { 50913db86aabSstevel int i, value, j; 50923db86aabSstevel char buff[256]; 50933db86aabSstevel char *fmt; 50943db86aabSstevel 50953db86aabSstevel #if defined(PCIC_DEBUG) 50963db86aabSstevel if (pcic_debug < 2) 50973db86aabSstevel return; 50983db86aabSstevel #endif 50993db86aabSstevel cmn_err(CE_CONT, 51003db86aabSstevel "----------- PCIC Registers for socket %d---------\n", 51013db86aabSstevel socket); 51023db86aabSstevel cmn_err(CE_CONT, 51033db86aabSstevel "\tname value name value\n"); 51043db86aabSstevel 51053db86aabSstevel for (buff[0] = '\0', i = 0; iregs[i].name != NULL && len-- != 0; i++) { 51063db86aabSstevel value = pcic_getb(pcic, socket, iregs[i].off); 51073db86aabSstevel if (i & 1) { 51083db86aabSstevel if (iregs[i].fmt) 51093db86aabSstevel fmt = "%s\t%s\t%b\n"; 51103db86aabSstevel else 51113db86aabSstevel fmt = "%s\t%s\t%x\n"; 51123db86aabSstevel cmn_err(CE_CONT, fmt, buff, 51133db86aabSstevel iregs[i].name, value, iregs[i].fmt); 51143db86aabSstevel buff[0] = '\0'; 51153db86aabSstevel } else { 51163db86aabSstevel if (iregs[i].fmt) 51173db86aabSstevel fmt = "\t%s\t%b"; 51183db86aabSstevel else 51193db86aabSstevel fmt = "\t%s\t%x"; 51203db86aabSstevel (void) sprintf(buff, fmt, 51213db86aabSstevel iregs[i].name, value, iregs[i].fmt); 51223db86aabSstevel for (j = strlen(buff); j < 40; j++) 51233db86aabSstevel buff[j] = ' '; 51243db86aabSstevel buff[40] = '\0'; 51253db86aabSstevel } 51263db86aabSstevel } 51273db86aabSstevel switch (pcic->pc_type) { 51283db86aabSstevel case PCIC_CL_PD6710: 51293db86aabSstevel case PCIC_CL_PD6722: 51303db86aabSstevel case PCIC_CL_PD6729: 51313db86aabSstevel case PCIC_CL_PD6832: 51323db86aabSstevel (void) xxdmp_cl_regs(pcic, socket, 0xFFFF); 51333db86aabSstevel break; 51343db86aabSstevel } 51353db86aabSstevel cmn_err(CE_CONT, "%s\n", buff); 51363db86aabSstevel } 51373db86aabSstevel #endif 51383db86aabSstevel 51393db86aabSstevel /* 51403db86aabSstevel * pcic_mswait(ms) 51413db86aabSstevel * sleep ms milliseconds 51423db86aabSstevel * call drv_usecwait once for each ms 51433db86aabSstevel */ 51443db86aabSstevel static void 51453db86aabSstevel pcic_mswait(pcicdev_t *pcic, int socket, int ms) 51463db86aabSstevel { 51473db86aabSstevel if (ms) { 51483db86aabSstevel pcic->pc_sockets[socket].pcs_flags |= PCS_WAITING; 51493db86aabSstevel pcic_mutex_exit(&pcic->pc_lock); 51503db86aabSstevel delay(drv_usectohz(ms*1000)); 51513db86aabSstevel pcic_mutex_enter(&pcic->pc_lock); 51523db86aabSstevel pcic->pc_sockets[socket].pcs_flags &= ~PCS_WAITING; 51533db86aabSstevel } 51543db86aabSstevel } 51553db86aabSstevel 51563db86aabSstevel /* 51573db86aabSstevel * pcic_check_ready(pcic, index, off) 51583db86aabSstevel * Wait for card to come ready 51593db86aabSstevel * We only wait if the card is NOT in RESET 51603db86aabSstevel * and power is on. 51613db86aabSstevel */ 51623db86aabSstevel static boolean_t 51633db86aabSstevel pcic_check_ready(pcicdev_t *pcic, int socket) 51643db86aabSstevel { 51653db86aabSstevel int ifstate, intstate; 51663db86aabSstevel 51673db86aabSstevel intstate = pcic_getb(pcic, socket, PCIC_INTERRUPT); 51683db86aabSstevel ifstate = pcic_getb(pcic, socket, PCIC_INTERFACE_STATUS); 51693db86aabSstevel 51703db86aabSstevel if ((intstate & PCIC_RESET) && 51713db86aabSstevel ((ifstate & (PCIC_READY|PCIC_POWER_ON|PCIC_ISTAT_CD_MASK)) == 51723db86aabSstevel (PCIC_READY|PCIC_POWER_ON|PCIC_CD_PRESENT_OK))) 51733db86aabSstevel return (B_TRUE); 51743db86aabSstevel 51753db86aabSstevel #ifdef PCIC_DEBUG 51763db86aabSstevel pcic_err(NULL, 5, "pcic_check_read: Card not ready, intstate = 0x%x, " 51773db86aabSstevel "ifstate = 0x%x\n", intstate, ifstate); 51783db86aabSstevel if (pcic_debug) { 51793db86aabSstevel pcic_debug += 4; 51803db86aabSstevel xxdmp_all_regs(pcic, socket, -1); 51813db86aabSstevel pcic_debug -= 4; 51823db86aabSstevel } 51833db86aabSstevel #endif 51843db86aabSstevel return (B_FALSE); 51853db86aabSstevel } 51863db86aabSstevel 51873db86aabSstevel /* 51883db86aabSstevel * Cirrus Logic extended register read/write routines 51893db86aabSstevel */ 51903db86aabSstevel static int 51913db86aabSstevel clext_reg_read(pcicdev_t *pcic, int sn, uchar_t ext_reg) 51923db86aabSstevel { 51933db86aabSstevel int val; 51943db86aabSstevel 51953db86aabSstevel switch (pcic->pc_io_type) { 51963db86aabSstevel case PCIC_IO_TYPE_YENTA: 51973db86aabSstevel val = ddi_get8(pcic->handle, 51983db86aabSstevel pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg); 51993db86aabSstevel break; 52003db86aabSstevel default: 52013db86aabSstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg); 52023db86aabSstevel val = pcic_getb(pcic, sn, PCIC_CL_EXINDEX + 1); 52033db86aabSstevel break; 52043db86aabSstevel } 52053db86aabSstevel 52063db86aabSstevel return (val); 52073db86aabSstevel } 52083db86aabSstevel 52093db86aabSstevel static void 52103db86aabSstevel clext_reg_write(pcicdev_t *pcic, int sn, uchar_t ext_reg, uchar_t value) 52113db86aabSstevel { 52123db86aabSstevel switch (pcic->pc_io_type) { 52133db86aabSstevel case PCIC_IO_TYPE_YENTA: 52143db86aabSstevel ddi_put8(pcic->handle, 52153db86aabSstevel pcic->ioaddr + CB_CLEXT_OFFSET + ext_reg, value); 52163db86aabSstevel break; 52173db86aabSstevel default: 52183db86aabSstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX, ext_reg); 52193db86aabSstevel pcic_putb(pcic, sn, PCIC_CL_EXINDEX + 1, value); 52203db86aabSstevel break; 52213db86aabSstevel } 52223db86aabSstevel } 52233db86aabSstevel 52243db86aabSstevel /* 52253db86aabSstevel * Misc PCI functions 52263db86aabSstevel */ 52273db86aabSstevel static void 52283db86aabSstevel pcic_iomem_pci_ctl(ddi_acc_handle_t handle, uchar_t *cfgaddr, unsigned flags) 52293db86aabSstevel { 52303db86aabSstevel unsigned cmd; 52313db86aabSstevel 52323db86aabSstevel if (flags & (PCIC_ENABLE_IO | PCIC_ENABLE_MEM)) { 52333db86aabSstevel cmd = ddi_get16(handle, (ushort_t *)(cfgaddr + 4)); 52343db86aabSstevel if ((cmd & (PCI_COMM_IO|PCI_COMM_MAE)) == 52353db86aabSstevel (PCI_COMM_IO|PCI_COMM_MAE)) 52363db86aabSstevel return; 52373db86aabSstevel 52383db86aabSstevel if (flags & PCIC_ENABLE_IO) 52393db86aabSstevel cmd |= PCI_COMM_IO; 52403db86aabSstevel 52413db86aabSstevel if (flags & PCIC_ENABLE_MEM) 52423db86aabSstevel cmd |= PCI_COMM_MAE; 52433db86aabSstevel 52443db86aabSstevel ddi_put16(handle, (ushort_t *)(cfgaddr + 4), cmd); 52453db86aabSstevel } /* if (PCIC_ENABLE_IO | PCIC_ENABLE_MEM) */ 52463db86aabSstevel } 52473db86aabSstevel 52483db86aabSstevel /* 52493db86aabSstevel * pcic_find_pci_type - Find and return PCI-PCMCIA adapter type 52503db86aabSstevel */ 52513db86aabSstevel static int 52523db86aabSstevel pcic_find_pci_type(pcicdev_t *pcic) 52533db86aabSstevel { 52543db86aabSstevel uint32_t vend, device; 52553db86aabSstevel 52563db86aabSstevel vend = ddi_getprop(DDI_DEV_T_ANY, pcic->dip, 52573db86aabSstevel DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 52583db86aabSstevel "vendor-id", -1); 52593db86aabSstevel device = ddi_getprop(DDI_DEV_T_ANY, pcic->dip, 52603db86aabSstevel DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS, 52613db86aabSstevel "device-id", -1); 52623db86aabSstevel 52633db86aabSstevel device = PCI_ID(vend, device); 52643db86aabSstevel pcic->pc_type = device; 52653db86aabSstevel pcic->pc_chipname = "PCI:unknown"; 52663db86aabSstevel 52673db86aabSstevel switch (device) { 52683db86aabSstevel case PCIC_INTEL_i82092: 52693db86aabSstevel pcic->pc_chipname = PCIC_TYPE_i82092; 52703db86aabSstevel break; 52713db86aabSstevel case PCIC_CL_PD6729: 52723db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6729; 52733db86aabSstevel /* 52743db86aabSstevel * Some 6730's incorrectly identify themselves 52753db86aabSstevel * as a 6729, so we need to do some more tests 52763db86aabSstevel * here to see if the device that's claiming 52773db86aabSstevel * to be a 6729 is really a 6730. 52783db86aabSstevel */ 52793db86aabSstevel if ((clext_reg_read(pcic, 0, PCIC_CLEXT_MISC_CTL_3) & 52803db86aabSstevel PCIC_CLEXT_MISC_CTL_3_REV_MASK) == 52813db86aabSstevel 0) { 52823db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6730; 52833db86aabSstevel pcic->pc_type = PCIC_CL_PD6730; 52843db86aabSstevel } 52853db86aabSstevel break; 52863db86aabSstevel case PCIC_CL_PD6730: 52873db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6730; 52883db86aabSstevel break; 52893db86aabSstevel case PCIC_CL_PD6832: 52903db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6832; 52913db86aabSstevel break; 52923db86aabSstevel case PCIC_SMC_34C90: 52933db86aabSstevel pcic->pc_chipname = PCIC_TYPE_34C90; 52943db86aabSstevel break; 52953db86aabSstevel case PCIC_TOSHIBA_TOPIC95: 52963db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TOPIC95; 52973db86aabSstevel break; 52983db86aabSstevel case PCIC_TOSHIBA_TOPIC100: 52993db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TOPIC100; 53003db86aabSstevel break; 53013db86aabSstevel case PCIC_TI_PCI1031: 53023db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1031; 53033db86aabSstevel break; 53043db86aabSstevel case PCIC_TI_PCI1130: 53053db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1130; 53063db86aabSstevel break; 53073db86aabSstevel case PCIC_TI_PCI1131: 53083db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1131; 53093db86aabSstevel break; 53103db86aabSstevel case PCIC_TI_PCI1250: 53113db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1250; 53123db86aabSstevel break; 53133db86aabSstevel case PCIC_TI_PCI1225: 53143db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1225; 53153db86aabSstevel break; 53163db86aabSstevel case PCIC_TI_PCI1410: 53173db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1410; 53183db86aabSstevel break; 53193db86aabSstevel case PCIC_TI_PCI1510: 53203db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1510; 53213db86aabSstevel break; 53223db86aabSstevel case PCIC_TI_PCI1520: 53233db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1520; 53243db86aabSstevel break; 53253db86aabSstevel case PCIC_TI_PCI1221: 53263db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1221; 53273db86aabSstevel break; 53283db86aabSstevel case PCIC_TI_PCI1050: 53293db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1050; 53303db86aabSstevel break; 53313db86aabSstevel case PCIC_ENE_1410: 53323db86aabSstevel pcic->pc_chipname = PCIC_TYPE_1410; 53333db86aabSstevel break; 53343db86aabSstevel case PCIC_O2_OZ6912: 53353db86aabSstevel pcic->pc_chipname = PCIC_TYPE_OZ6912; 53363db86aabSstevel break; 53373db86aabSstevel case PCIC_RICOH_RL5C466: 53383db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RL5C466; 53393db86aabSstevel break; 53403db86aabSstevel case PCIC_TI_PCI1420: 53413db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PCI1420; 53423db86aabSstevel break; 53433db86aabSstevel case PCIC_ENE_1420: 53443db86aabSstevel pcic->pc_chipname = PCIC_TYPE_1420; 53453db86aabSstevel break; 53463db86aabSstevel default: 53473db86aabSstevel switch (PCI_ID(vend, (uint32_t)0)) { 53483db86aabSstevel case PCIC_TOSHIBA_VENDOR: 53493db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TOSHIBA; 53503db86aabSstevel pcic->pc_type = PCIC_TOSHIBA_VENDOR; 53513db86aabSstevel break; 53523db86aabSstevel case PCIC_TI_VENDOR: 53533db86aabSstevel pcic->pc_chipname = PCIC_TYPE_TI; 53543db86aabSstevel pcic->pc_type = PCIC_TI_VENDOR; 53553db86aabSstevel break; 53563db86aabSstevel case PCIC_O2MICRO_VENDOR: 53573db86aabSstevel pcic->pc_chipname = PCIC_TYPE_O2MICRO; 53583db86aabSstevel pcic->pc_type = PCIC_O2MICRO_VENDOR; 53593db86aabSstevel break; 53603db86aabSstevel case PCIC_RICOH_VENDOR: 53613db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RICOH; 53623db86aabSstevel pcic->pc_type = PCIC_RICOH_VENDOR; 53633db86aabSstevel break; 53643db86aabSstevel default: 53653db86aabSstevel if (!(pcic->pc_flags & PCF_CARDBUS)) 53663db86aabSstevel return (DDI_FAILURE); 53673db86aabSstevel pcic->pc_chipname = PCIC_TYPE_YENTA; 53683db86aabSstevel break; 53693db86aabSstevel } 53703db86aabSstevel } 53713db86aabSstevel return (DDI_SUCCESS); 53723db86aabSstevel } 53733db86aabSstevel 53743db86aabSstevel static void 53753db86aabSstevel pcic_82092_smiirq_ctl(pcicdev_t *pcic, int socket, int intr, int state) 53763db86aabSstevel { 53773db86aabSstevel uchar_t ppirr = ddi_get8(pcic->cfg_handle, 53783db86aabSstevel pcic->cfgaddr + PCIC_82092_PPIRR); 53793db86aabSstevel uchar_t val; 53803db86aabSstevel 53813db86aabSstevel if (intr == PCIC_82092_CTL_SMI) { 53823db86aabSstevel val = PCIC_82092_SMI_CTL(socket, 53833db86aabSstevel PCIC_82092_INT_DISABLE); 53843db86aabSstevel ppirr &= ~val; 53853db86aabSstevel val = PCIC_82092_SMI_CTL(socket, state); 53863db86aabSstevel ppirr |= val; 53873db86aabSstevel } else { 53883db86aabSstevel val = PCIC_82092_IRQ_CTL(socket, 53893db86aabSstevel PCIC_82092_INT_DISABLE); 53903db86aabSstevel ppirr &= ~val; 53913db86aabSstevel val = PCIC_82092_IRQ_CTL(socket, state); 53923db86aabSstevel ppirr |= val; 53933db86aabSstevel } 53943db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_82092_PPIRR, 53953db86aabSstevel ppirr); 53963db86aabSstevel } 53973db86aabSstevel 53983db86aabSstevel static uint_t 53993db86aabSstevel pcic_cd_softint(caddr_t arg1, caddr_t arg2) 54003db86aabSstevel { 54013db86aabSstevel pcic_socket_t *sockp = (pcic_socket_t *)arg1; 54023db86aabSstevel uint_t rc = DDI_INTR_UNCLAIMED; 54033db86aabSstevel 54043db86aabSstevel _NOTE(ARGUNUSED(arg2)) 54053db86aabSstevel 54063db86aabSstevel mutex_enter(&sockp->pcs_pcic->pc_lock); 54073db86aabSstevel if (sockp->pcs_cd_softint_flg) { 54083db86aabSstevel uint8_t status; 54093db86aabSstevel sockp->pcs_cd_softint_flg = 0; 54103db86aabSstevel rc = DDI_INTR_CLAIMED; 54113db86aabSstevel status = pcic_getb(sockp->pcs_pcic, sockp->pcs_socket, 54123db86aabSstevel PCIC_INTERFACE_STATUS); 54133db86aabSstevel pcic_handle_cd_change(sockp->pcs_pcic, sockp, status); 54143db86aabSstevel } 54153db86aabSstevel mutex_exit(&sockp->pcs_pcic->pc_lock); 54163db86aabSstevel return (rc); 54173db86aabSstevel } 54183db86aabSstevel 54193db86aabSstevel int pcic_debounce_cnt = PCIC_REM_DEBOUNCE_CNT; 54203db86aabSstevel int pcic_debounce_intr_time = PCIC_REM_DEBOUNCE_TIME; 54213db86aabSstevel int pcic_debounce_cnt_ok = PCIC_DEBOUNCE_OK_CNT; 54223db86aabSstevel 54233db86aabSstevel #ifdef CARDBUS 54243db86aabSstevel static uint32_t pcic_cbps_on = 0; 54253db86aabSstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK | 54263db86aabSstevel CB_PS_XVCARD | CB_PS_YVCARD; 54273db86aabSstevel #else 54283db86aabSstevel static uint32_t pcic_cbps_on = CB_PS_16BITCARD; 54293db86aabSstevel static uint32_t pcic_cbps_off = CB_PS_NOTACARD | CB_PS_CCDMASK | 54303db86aabSstevel CB_PS_CBCARD | 54313db86aabSstevel CB_PS_XVCARD | CB_PS_YVCARD; 54323db86aabSstevel #endif 54333db86aabSstevel static void 54343db86aabSstevel pcic_handle_cd_change(pcicdev_t *pcic, pcic_socket_t *sockp, uint8_t status) 54353db86aabSstevel { 54363db86aabSstevel boolean_t do_debounce = B_FALSE; 54373db86aabSstevel int debounce_time = drv_usectohz(pcic_debounce_time); 54383db86aabSstevel uint8_t irq; 54393db86aabSstevel timeout_id_t debounce; 54403db86aabSstevel 54413db86aabSstevel /* 54423db86aabSstevel * Always reset debounce but may need to check original state later. 54433db86aabSstevel */ 54443db86aabSstevel debounce = sockp->pcs_debounce_id; 54453db86aabSstevel sockp->pcs_debounce_id = 0; 54463db86aabSstevel 54473db86aabSstevel /* 54483db86aabSstevel * Check to see whether a card is present or not. There are 54493db86aabSstevel * only two states that we are concerned with - the state 54503db86aabSstevel * where both CD pins are asserted, which means that the 54513db86aabSstevel * card is fully seated, and the state where neither CD 54523db86aabSstevel * pin is asserted, which means that the card is not 54533db86aabSstevel * present. 54543db86aabSstevel * The CD signals are generally very noisy and cause a lot of 54553db86aabSstevel * contact bounce as the card is being inserted and 54563db86aabSstevel * removed, so we need to do some software debouncing. 54573db86aabSstevel */ 54583db86aabSstevel 54593db86aabSstevel #ifdef PCIC_DEBUG 54603db86aabSstevel pcic_err(pcic->dip, 6, 54613db86aabSstevel "pcic%d handle_cd_change: socket %d card status 0x%x" 54623db86aabSstevel " deb 0x%p\n", ddi_get_instance(pcic->dip), 54633db86aabSstevel sockp->pcs_socket, status, debounce); 54643db86aabSstevel #endif 54653db86aabSstevel switch (status & PCIC_ISTAT_CD_MASK) { 54663db86aabSstevel case PCIC_CD_PRESENT_OK: 54673db86aabSstevel sockp->pcs_flags &= ~(PCS_CARD_REMOVED|PCS_CARD_CBREM); 54683db86aabSstevel if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) { 54693db86aabSstevel uint32_t cbps; 54703db86aabSstevel #ifdef PCIC_DEBUG 54713db86aabSstevel pcic_err(pcic->dip, 8, "New card (0x%x)\n", sockp->pcs_flags); 54723db86aabSstevel #endif 54733db86aabSstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE); 54743db86aabSstevel #ifdef PCIC_DEBUG 54753db86aabSstevel pcic_err(pcic->dip, 8, "CBus PS (0x%x)\n", cbps); 54763db86aabSstevel #endif 54773db86aabSstevel /* 54783db86aabSstevel * Check the CB bits are sane. 54793db86aabSstevel */ 54803db86aabSstevel if ((cbps & pcic_cbps_on) != pcic_cbps_on || 54813db86aabSstevel cbps & pcic_cbps_off) { 54823db86aabSstevel cmn_err(CE_WARN, 54833db86aabSstevel "%s%d: Odd Cardbus Present State 0x%x\n", 54843db86aabSstevel ddi_get_name(pcic->dip), 54853db86aabSstevel ddi_get_instance(pcic->dip), 54863db86aabSstevel cbps); 54873db86aabSstevel pcic_putcb(pcic, CB_EVENT_FORCE, CB_EF_CVTEST); 54883db86aabSstevel debounce = 0; 54893db86aabSstevel debounce_time = drv_usectohz(1000000); 54903db86aabSstevel } 54913db86aabSstevel if (debounce) { 54923db86aabSstevel sockp->pcs_flags |= PCS_CARD_PRESENT; 54933db86aabSstevel if (pcic_do_insertion) { 54943db86aabSstevel 54953db86aabSstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE); 54963db86aabSstevel 54973db86aabSstevel if (cbps & CB_PS_16BITCARD) { 54983db86aabSstevel pcic_err(pcic->dip, 8, "16 bit card inserted\n"); 54993db86aabSstevel sockp->pcs_flags |= PCS_CARD_IS16BIT; 55003db86aabSstevel /* calls pcm_adapter_callback() */ 55013db86aabSstevel if (pcic->pc_callback) { 55023db86aabSstevel 55033db86aabSstevel (void) ddi_prop_update_string(DDI_DEV_T_NONE, 55043db86aabSstevel pcic->dip, PCM_DEVICETYPE, 55053db86aabSstevel "pccard"); 55063db86aabSstevel PC_CALLBACK(pcic->dip, pcic->pc_cb_arg, 55073db86aabSstevel PCE_CARD_INSERT, 55083db86aabSstevel sockp->pcs_socket); 55093db86aabSstevel } 55103db86aabSstevel } else if (cbps & CB_PS_CBCARD) { 55113db86aabSstevel pcic_err(pcic->dip, 8, "32 bit card inserted\n"); 55123db86aabSstevel 55133db86aabSstevel if (pcic->pc_flags & PCF_CARDBUS) { 55143db86aabSstevel sockp->pcs_flags |= PCS_CARD_ISCARDBUS; 55153db86aabSstevel #ifdef CARDBUS 55163db86aabSstevel if (!pcic_load_cardbus(pcic, sockp)) { 55173db86aabSstevel pcic_unload_cardbus(pcic, sockp); 55183db86aabSstevel } 55193db86aabSstevel 55203db86aabSstevel #else 55213db86aabSstevel cmn_err(CE_NOTE, 55223db86aabSstevel "32 bit Cardbus not supported in" 55233db86aabSstevel " this device driver\n"); 55243db86aabSstevel #endif 55253db86aabSstevel } else { 55263db86aabSstevel /* 55273db86aabSstevel * Ignore the card 55283db86aabSstevel */ 55293db86aabSstevel cmn_err(CE_NOTE, 55303db86aabSstevel "32 bit Cardbus not supported on this" 55313db86aabSstevel " device\n"); 55323db86aabSstevel } 55333db86aabSstevel } else { 55343db86aabSstevel cmn_err(CE_NOTE, 55353db86aabSstevel "Unsupported PCMCIA card inserted\n"); 55363db86aabSstevel } 55373db86aabSstevel } 55383db86aabSstevel syshw_send_signal(sockp->pcs_syshwsig); 55393db86aabSstevel } else { 55403db86aabSstevel do_debounce = B_TRUE; 55413db86aabSstevel } 55423db86aabSstevel } else { 55433db86aabSstevel /* 55443db86aabSstevel * It is possible to come through here if the system 55453db86aabSstevel * starts up with cards already inserted. Do nothing 55463db86aabSstevel * and don't worry about it. 55473db86aabSstevel */ 55483db86aabSstevel #ifdef PCIC_DEBUG 55493db86aabSstevel pcic_err(pcic->dip, 5, 55503db86aabSstevel "pcic%d: Odd card insertion indication on socket %d\n", 55513db86aabSstevel ddi_get_instance(pcic->dip), 55523db86aabSstevel sockp->pcs_socket); 55533db86aabSstevel #endif 55543db86aabSstevel } 55553db86aabSstevel break; 55563db86aabSstevel 55573db86aabSstevel default: 55583db86aabSstevel if (!(sockp->pcs_flags & PCS_CARD_PRESENT)) { 55593db86aabSstevel /* 55603db86aabSstevel * Someone has started to insert a card so delay a while. 55613db86aabSstevel */ 55623db86aabSstevel do_debounce = B_TRUE; 55633db86aabSstevel break; 55643db86aabSstevel } 55653db86aabSstevel /* 55663db86aabSstevel * Otherwise this is basically the same as not present 55673db86aabSstevel * so fall through. 55683db86aabSstevel */ 55693db86aabSstevel 55703db86aabSstevel /* FALLTHRU */ 55713db86aabSstevel case 0: 55723db86aabSstevel if (sockp->pcs_flags & PCS_CARD_PRESENT) { 55733db86aabSstevel if (pcic->pc_flags & PCF_CBPWRCTL) { 55743db86aabSstevel pcic_putcb(pcic, CB_CONTROL, 0); 55753db86aabSstevel } else { 55763db86aabSstevel pcic_putb(pcic, sockp->pcs_socket, PCIC_POWER_CONTROL, 0); 55773db86aabSstevel (void) pcic_getb(pcic, sockp->pcs_socket, 55783db86aabSstevel PCIC_POWER_CONTROL); 55793db86aabSstevel } 55803db86aabSstevel #ifdef PCIC_DEBUG 55813db86aabSstevel pcic_err(pcic->dip, 8, "Card removed\n"); 55823db86aabSstevel #endif 55833db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_PRESENT; 55843db86aabSstevel 55853db86aabSstevel if (sockp->pcs_flags & PCS_CARD_IS16BIT) { 55863db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_IS16BIT; 55873db86aabSstevel if (pcic_do_removal && pcic->pc_callback) { 55883db86aabSstevel PC_CALLBACK(pcic->dip, pcic->pc_cb_arg, 55893db86aabSstevel PCE_CARD_REMOVAL, sockp->pcs_socket); 55903db86aabSstevel } 55913db86aabSstevel } 55923db86aabSstevel if (sockp->pcs_flags & PCS_CARD_ISCARDBUS) { 55933db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_ISCARDBUS; 55943db86aabSstevel sockp->pcs_flags |= PCS_CARD_CBREM; 55953db86aabSstevel } 55963db86aabSstevel sockp->pcs_flags |= PCS_CARD_REMOVED; 55973db86aabSstevel 55983db86aabSstevel do_debounce = B_TRUE; 55993db86aabSstevel } 56003db86aabSstevel if (debounce && (sockp->pcs_flags & PCS_CARD_REMOVED)) { 56013db86aabSstevel if (sockp->pcs_flags & PCS_CARD_CBREM) { 56023db86aabSstevel /* 56033db86aabSstevel * Ensure that we do the unloading in the 56043db86aabSstevel * debounce handler, that way we're not doing 56053db86aabSstevel * nasty things in an interrupt handler. e.g. 56063db86aabSstevel * a USB device will wait for data which will 56073db86aabSstevel * obviously never come because we've 56083db86aabSstevel * unplugged the device, but the wait will 56093db86aabSstevel * wait forever because no interrupts can 56103db86aabSstevel * come in... 56113db86aabSstevel */ 56123db86aabSstevel #ifdef CARDBUS 56133db86aabSstevel pcic_unload_cardbus(pcic, sockp); 56143db86aabSstevel /* pcic_dump_all(pcic); */ 56153db86aabSstevel #endif 56163db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_CBREM; 56173db86aabSstevel } 56183db86aabSstevel syshw_send_signal(sockp->pcs_syshwsig); 56193db86aabSstevel sockp->pcs_flags &= ~PCS_CARD_REMOVED; 56203db86aabSstevel } 56213db86aabSstevel break; 56223db86aabSstevel } /* switch */ 56233db86aabSstevel 56243db86aabSstevel if (do_debounce) { 56253db86aabSstevel /* 56263db86aabSstevel * Delay doing 56273db86aabSstevel * anything for a while so that things can settle 56283db86aabSstevel * down a little. Interrupts are already disabled. 56293db86aabSstevel * Reset the state and we'll reevaluate the 56303db86aabSstevel * whole kit 'n kaboodle when the timeout fires 56313db86aabSstevel */ 56323db86aabSstevel #ifdef PCIC_DEBUG 56333db86aabSstevel pcic_err(pcic->dip, 8, "Queueing up debounce timeout for " 56343db86aabSstevel "socket %d.%d\n", 56353db86aabSstevel ddi_get_instance(pcic->dip), 56363db86aabSstevel sockp->pcs_socket); 56373db86aabSstevel #endif 56383db86aabSstevel sockp->pcs_debounce_id = pcic_add_debqueue(sockp, debounce_time); 56393db86aabSstevel 56403db86aabSstevel /* 56413db86aabSstevel * We bug out here without re-enabling interrupts. They will 56423db86aabSstevel * be re-enabled when the debounce timeout swings through 56433db86aabSstevel * here. 56443db86aabSstevel */ 56453db86aabSstevel return; 56463db86aabSstevel } 56473db86aabSstevel 56483db86aabSstevel /* 56493db86aabSstevel * Turn on Card detect interrupts. Other interrupts will be 56503db86aabSstevel * enabled during set_socket calls. 56513db86aabSstevel * 56523db86aabSstevel * Note that set_socket only changes interrupt settings when there 56533db86aabSstevel * is a card present. 56543db86aabSstevel */ 56553db86aabSstevel irq = pcic_getb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT); 56563db86aabSstevel irq |= PCIC_CD_DETECT; 56573db86aabSstevel pcic_putb(pcic, sockp->pcs_socket, PCIC_MANAGEMENT_INT, irq); 56580e995c33Srw148561 pcic_putcb(pcic, CB_STATUS_MASK, CB_SE_CCDMASK); 56593db86aabSstevel 56600d282d13Srw148561 /* Out from debouncing state */ 56610d282d13Srw148561 sockp->pcs_flags &= ~PCS_DEBOUNCING; 56620d282d13Srw148561 56633db86aabSstevel pcic_err(pcic->dip, 7, "Leaving pcic_handle_cd_change\n"); 56643db86aabSstevel } 56653db86aabSstevel 56663db86aabSstevel /* 56673db86aabSstevel * pcic_getb() 56683db86aabSstevel * get an I/O byte based on the yardware decode method 56693db86aabSstevel */ 56703db86aabSstevel static uint8_t 56713db86aabSstevel pcic_getb(pcicdev_t *pcic, int socket, int reg) 56723db86aabSstevel { 56733db86aabSstevel int work; 56743db86aabSstevel 56753db86aabSstevel #if defined(PCIC_DEBUG) 56763db86aabSstevel if (pcic_debug == 0x7fff) { 56773db86aabSstevel cmn_err(CE_CONT, "pcic_getb0: pcic=%p socket=%d reg=%d\n", 56783db86aabSstevel (void *)pcic, socket, reg); 56793db86aabSstevel cmn_err(CE_CONT, "pcic_getb1: type=%d handle=%p ioaddr=%p \n", 56803db86aabSstevel pcic->pc_io_type, (void *)pcic->handle, 56813db86aabSstevel (void *)pcic->ioaddr); 56823db86aabSstevel } 56833db86aabSstevel #endif 56843db86aabSstevel 56853db86aabSstevel switch (pcic->pc_io_type) { 56863db86aabSstevel case PCIC_IO_TYPE_YENTA: 56873db86aabSstevel return (ddi_get8(pcic->handle, 56883db86aabSstevel pcic->ioaddr + CB_R2_OFFSET + reg)); 56893db86aabSstevel default: 56903db86aabSstevel work = (socket * PCIC_SOCKET_1) | reg; 56913db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, work); 56923db86aabSstevel return (ddi_get8(pcic->handle, pcic->ioaddr + 1)); 56933db86aabSstevel } 56943db86aabSstevel } 56953db86aabSstevel 56963db86aabSstevel static void 56973db86aabSstevel pcic_putb(pcicdev_t *pcic, int socket, int reg, int8_t value) 56983db86aabSstevel { 56993db86aabSstevel int work; 57003db86aabSstevel 57013db86aabSstevel #if defined(PCIC_DEBUG) 57023db86aabSstevel if (pcic_debug == 0x7fff) { 57033db86aabSstevel cmn_err(CE_CONT, 57043db86aabSstevel "pcic_putb0: pcic=%p socket=%d reg=%d value=%x \n", 57053db86aabSstevel (void *)pcic, socket, reg, value); 57063db86aabSstevel cmn_err(CE_CONT, 57073db86aabSstevel "pcic_putb1: type=%d handle=%p ioaddr=%p \n", 57083db86aabSstevel pcic->pc_io_type, (void *)pcic->handle, 57093db86aabSstevel (void *)pcic->ioaddr); 57103db86aabSstevel } 57113db86aabSstevel #endif 57123db86aabSstevel 57133db86aabSstevel 57143db86aabSstevel switch (pcic->pc_io_type) { 57153db86aabSstevel case PCIC_IO_TYPE_YENTA: 57163db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr + CB_R2_OFFSET + reg, 57173db86aabSstevel value); 57183db86aabSstevel break; 57193db86aabSstevel default: 57203db86aabSstevel work = (socket * PCIC_SOCKET_1) | reg; 57213db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, work); 57223db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr + 1, value); 57233db86aabSstevel break; 57243db86aabSstevel } 57253db86aabSstevel } 57263db86aabSstevel 57273db86aabSstevel /* 57283db86aabSstevel * chip identification functions 57293db86aabSstevel */ 57303db86aabSstevel 57313db86aabSstevel /* 57323db86aabSstevel * chip identification: Cirrus Logic PD6710/6720/6722 57333db86aabSstevel */ 57343db86aabSstevel static int 57353db86aabSstevel pcic_ci_cirrus(pcicdev_t *pcic) 57363db86aabSstevel { 57373db86aabSstevel int value1, value2; 57383db86aabSstevel 57393db86aabSstevel /* Init the CL id mode */ 57403db86aabSstevel value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 57413db86aabSstevel pcic_putb(pcic, 0, PCIC_CHIP_INFO, 0); 57423db86aabSstevel value1 = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 57433db86aabSstevel value2 = pcic_getb(pcic, 0, PCIC_CHIP_INFO); 57443db86aabSstevel 57453db86aabSstevel if ((value1 & PCIC_CI_ID) == PCIC_CI_ID && 57463db86aabSstevel (value2 & PCIC_CI_ID) == 0) { 57473db86aabSstevel /* chip is a Cirrus Logic and not Intel */ 57483db86aabSstevel pcic->pc_type = PCIC_CL_PD6710; 57493db86aabSstevel if (value1 & PCIC_CI_SLOTS) 57503db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6720; 57513db86aabSstevel else 57523db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6710; 57533db86aabSstevel /* now fine tune things just in case a 6722 */ 57543db86aabSstevel value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_DMASK_0); 57553db86aabSstevel if (value1 == 0) { 57563db86aabSstevel clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0x55); 57573db86aabSstevel value1 = clext_reg_read(pcic, 0, PCIC_CLEXT_SCRATCH); 57583db86aabSstevel if (value1 == 0x55) { 57593db86aabSstevel pcic->pc_chipname = PCIC_TYPE_PD6722; 57603db86aabSstevel pcic->pc_type = PCIC_CL_PD6722; 57613db86aabSstevel clext_reg_write(pcic, 0, PCIC_CLEXT_SCRATCH, 0); 57623db86aabSstevel } 57633db86aabSstevel } 57643db86aabSstevel return (1); 57653db86aabSstevel } 57663db86aabSstevel return (0); 57673db86aabSstevel } 57683db86aabSstevel 57693db86aabSstevel /* 57703db86aabSstevel * chip identification: Vadem (VG365/465/468/469) 57713db86aabSstevel */ 57723db86aabSstevel 57733db86aabSstevel static void 57743db86aabSstevel pcic_vadem_enable(pcicdev_t *pcic) 57753db86aabSstevel { 57763db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P1); 57773db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, PCIC_VADEM_P2); 57783db86aabSstevel ddi_put8(pcic->handle, pcic->ioaddr, pcic->pc_lastreg); 57793db86aabSstevel } 57803db86aabSstevel 57813db86aabSstevel static int 57823db86aabSstevel pcic_ci_vadem(pcicdev_t *pcic) 57833db86aabSstevel { 57843db86aabSstevel int value; 57853db86aabSstevel 57863db86aabSstevel pcic_vadem_enable(pcic); 57873db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION); 57883db86aabSstevel pcic_putb(pcic, 0, PCIC_CHIP_REVISION, 0xFF); 57893db86aabSstevel if (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) == 57903db86aabSstevel (value | PCIC_VADEM_D3) || 57913db86aabSstevel (pcic_getb(pcic, 0, PCIC_CHIP_REVISION) & PCIC_REV_MASK) == 57923db86aabSstevel PCIC_VADEM_469) { 57933db86aabSstevel int vadem, new; 57943db86aabSstevel pcic_vadem_enable(pcic); 57953db86aabSstevel vadem = pcic_getb(pcic, 0, PCIC_VG_DMA) & 57963db86aabSstevel ~(PCIC_V_UNLOCK | PCIC_V_VADEMREV); 57973db86aabSstevel new = vadem | (PCIC_V_VADEMREV|PCIC_V_UNLOCK); 57983db86aabSstevel pcic_putb(pcic, 0, PCIC_VG_DMA, new); 57993db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CHIP_REVISION); 58003db86aabSstevel 58013db86aabSstevel /* want to lock but leave mouse or other on */ 58023db86aabSstevel pcic_putb(pcic, 0, PCIC_VG_DMA, vadem); 58033db86aabSstevel switch (value & PCIC_REV_MASK) { 58043db86aabSstevel case PCIC_VADEM_365: 58053db86aabSstevel pcic->pc_chipname = PCIC_VG_365; 58063db86aabSstevel pcic->pc_type = PCIC_VADEM; 58073db86aabSstevel break; 58083db86aabSstevel case PCIC_VADEM_465: 58093db86aabSstevel pcic->pc_chipname = PCIC_VG_465; 58103db86aabSstevel pcic->pc_type = PCIC_VADEM; 58113db86aabSstevel pcic->pc_flags |= PCF_1SOCKET; 58123db86aabSstevel break; 58133db86aabSstevel case PCIC_VADEM_468: 58143db86aabSstevel pcic->pc_chipname = PCIC_VG_468; 58153db86aabSstevel pcic->pc_type = PCIC_VADEM; 58163db86aabSstevel break; 58173db86aabSstevel case PCIC_VADEM_469: 58183db86aabSstevel pcic->pc_chipname = PCIC_VG_469; 58193db86aabSstevel pcic->pc_type = PCIC_VADEM_VG469; 58203db86aabSstevel break; 58213db86aabSstevel } 58223db86aabSstevel return (1); 58233db86aabSstevel } 58243db86aabSstevel return (0); 58253db86aabSstevel } 58263db86aabSstevel 58273db86aabSstevel /* 58283db86aabSstevel * chip identification: Ricoh 58293db86aabSstevel */ 58303db86aabSstevel static int 58313db86aabSstevel pcic_ci_ricoh(pcicdev_t *pcic) 58323db86aabSstevel { 58333db86aabSstevel int value; 58343db86aabSstevel 58353db86aabSstevel value = pcic_getb(pcic, 0, PCIC_RF_CHIP_IDENT); 58363db86aabSstevel switch (value) { 58373db86aabSstevel case PCIC_RF_296: 58383db86aabSstevel pcic->pc_type = PCIC_RICOH; 58393db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RF5C296; 58403db86aabSstevel return (1); 58413db86aabSstevel case PCIC_RF_396: 58423db86aabSstevel pcic->pc_type = PCIC_RICOH; 58433db86aabSstevel pcic->pc_chipname = PCIC_TYPE_RF5C396; 58443db86aabSstevel return (1); 58453db86aabSstevel } 58463db86aabSstevel return (0); 58473db86aabSstevel } 58483db86aabSstevel 58493db86aabSstevel 58503db86aabSstevel /* 58513db86aabSstevel * set up available address spaces in busra 58523db86aabSstevel */ 58533db86aabSstevel static void 58543db86aabSstevel pcic_init_assigned(dev_info_t *dip) 58553db86aabSstevel { 58563db86aabSstevel pcm_regs_t *pcic_avail_p; 58573db86aabSstevel pci_regspec_t *pci_avail_p, *regs; 58583db86aabSstevel int len, entries, rlen; 58593db86aabSstevel dev_info_t *pdip; 58603db86aabSstevel 58613db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 58623db86aabSstevel "available", (caddr_t)&pcic_avail_p, &len) == DDI_PROP_SUCCESS) { 58633db86aabSstevel /* 58643db86aabSstevel * found "available" property at the cardbus/pcmcia node 58653db86aabSstevel * need to translate address space entries from pcmcia 58663db86aabSstevel * format to pci format 58673db86aabSstevel */ 58683db86aabSstevel entries = len / sizeof (pcm_regs_t); 58693db86aabSstevel pci_avail_p = kmem_alloc(sizeof (pci_regspec_t) * entries, 58703db86aabSstevel KM_SLEEP); 58713db86aabSstevel if (pcic_apply_avail_ranges(dip, pcic_avail_p, pci_avail_p, 58723db86aabSstevel entries) == DDI_SUCCESS) 58733db86aabSstevel (void) pci_resource_setup_avail(dip, pci_avail_p, 58743db86aabSstevel entries); 58753db86aabSstevel kmem_free(pcic_avail_p, len); 58763db86aabSstevel kmem_free(pci_avail_p, entries * sizeof (pci_regspec_t)); 58773db86aabSstevel return; 58783db86aabSstevel } 58793db86aabSstevel 58803db86aabSstevel /* 58813db86aabSstevel * "legacy" platforms will have "available" property in pci node 58823db86aabSstevel */ 58833db86aabSstevel for (pdip = ddi_get_parent(dip); pdip; pdip = ddi_get_parent(pdip)) { 58843db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 58853db86aabSstevel "available", (caddr_t)&pci_avail_p, &len) == 58863db86aabSstevel DDI_PROP_SUCCESS) { 58873db86aabSstevel /* (void) pci_resource_setup(pdip); */ 58883db86aabSstevel kmem_free(pci_avail_p, len); 58893db86aabSstevel break; 58903db86aabSstevel } 58913db86aabSstevel } 58923db86aabSstevel 58933db86aabSstevel if (pdip == NULL) { 58943db86aabSstevel int len; 58953db86aabSstevel char bus_type[16] = "(unknown)"; 58963db86aabSstevel dev_info_t *par; 58973db86aabSstevel 58983db86aabSstevel cmn_err(CE_CONT, 58993db86aabSstevel "?pcic_init_assigned: no available property for pcmcia\n"); 59003db86aabSstevel 59013db86aabSstevel /* 59023db86aabSstevel * This code is taken from pci_resource_setup() but does 59033db86aabSstevel * not attempt to use the "available" property to populate 59043db86aabSstevel * the ndi maps that are created. 59053db86aabSstevel * The fact that we will actually 59063db86aabSstevel * free some resource below (that was allocated by OBP) 59073db86aabSstevel * should be enough to be going on with. 59083db86aabSstevel */ 59093db86aabSstevel for (par = dip; par != NULL; par = ddi_get_parent(par)) { 59103db86aabSstevel len = sizeof (bus_type); 59113db86aabSstevel 59123db86aabSstevel if ((ddi_prop_op(DDI_DEV_T_ANY, par, 59133db86aabSstevel PROP_LEN_AND_VAL_BUF, 59143db86aabSstevel DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, 59153db86aabSstevel "device_type", 59163db86aabSstevel (caddr_t)&bus_type, &len) == DDI_SUCCESS) && 59178134ee03Srw148561 (strcmp(bus_type, DEVI_PCI_NEXNAME) == 0 || 59188134ee03Srw148561 strcmp(bus_type, DEVI_PCIEX_NEXNAME) == 0)) 59193db86aabSstevel break; 59203db86aabSstevel } 59213db86aabSstevel if (par != NULL && 59223db86aabSstevel (ndi_ra_map_setup(par, NDI_RA_TYPE_MEM) != NDI_SUCCESS || 59233db86aabSstevel ndi_ra_map_setup(par, NDI_RA_TYPE_IO) != NDI_SUCCESS)) 59243db86aabSstevel par = NULL; 59253db86aabSstevel } else { 59263db86aabSstevel #ifdef CARDBUS 59273db86aabSstevel cardbus_bus_range_t *bus_range; 59283db86aabSstevel int k; 59293db86aabSstevel 59303db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "bus-range", 59313db86aabSstevel (caddr_t)&bus_range, &k) == DDI_PROP_SUCCESS) { 59323db86aabSstevel if (bus_range->lo != bus_range->hi) 59333db86aabSstevel pcic_err(pdip, 9, "allowable bus range is " 59343db86aabSstevel "%u->%u\n", bus_range->lo, bus_range->hi); 59353db86aabSstevel else { 59363db86aabSstevel pcic_err(pdip, 0, 59373db86aabSstevel "!No spare PCI bus numbers, range is " 59383db86aabSstevel "%u->%u, cardbus isn't usable\n", 59393db86aabSstevel bus_range->lo, bus_range->hi); 59403db86aabSstevel } 59413db86aabSstevel kmem_free(bus_range, k); 59423db86aabSstevel } else 59433db86aabSstevel pcic_err(pdip, 0, "!No bus-range property seems to " 59443db86aabSstevel "have been set up\n"); 59453db86aabSstevel #endif 59463db86aabSstevel /* 59473db86aabSstevel * Have a valid parent with the "available" property 59483db86aabSstevel */ 59493db86aabSstevel (void) pci_resource_setup(pdip); 59503db86aabSstevel } 59513db86aabSstevel 59523db86aabSstevel if ((strcmp(ddi_get_name(dip), "pcma") == 0) && 59533db86aabSstevel ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 59543db86aabSstevel "assigned-addresses", 59553db86aabSstevel (caddr_t)®s, &rlen) == DDI_SUCCESS) { 59563db86aabSstevel ra_return_t ra; 59573db86aabSstevel 59583db86aabSstevel /* 59593db86aabSstevel * On the UltraBook IIi the ranges are assigned under 59603db86aabSstevel * openboot. If we don't free them here the first I/O 59613db86aabSstevel * space that can be used is up above 0x10000 which 59623db86aabSstevel * doesn't work for this driver due to restrictions 59633db86aabSstevel * on the PCI I/O addresses the controllers can cope with. 59643db86aabSstevel * They are never going to be used by anything else 59653db86aabSstevel * so free them up to the general pool. AG. 59663db86aabSstevel */ 59673db86aabSstevel pcic_err(dip, 1, "Free assigned addresses\n"); 59683db86aabSstevel 59693db86aabSstevel if ((PCI_REG_ADDR_G(regs[0].pci_phys_hi) == 59703db86aabSstevel PCI_REG_ADDR_G(PCI_ADDR_MEM32)) && 59713db86aabSstevel regs[0].pci_size_low == 0x1000000) { 59723db86aabSstevel ra.ra_addr_lo = regs[0].pci_phys_low; 59733db86aabSstevel ra.ra_len = regs[0].pci_size_low; 59743db86aabSstevel (void) pcmcia_free_mem(dip, &ra); 59753db86aabSstevel } 59763db86aabSstevel if ((PCI_REG_ADDR_G(regs[1].pci_phys_hi) == 59773db86aabSstevel PCI_REG_ADDR_G(PCI_ADDR_IO)) && 59783db86aabSstevel (regs[1].pci_size_low == 0x8000 || 59793db86aabSstevel regs[1].pci_size_low == 0x4000)) /* UB-IIi || UB-I */ 59803db86aabSstevel { 59813db86aabSstevel ra.ra_addr_lo = regs[1].pci_phys_low; 59823db86aabSstevel ra.ra_len = regs[1].pci_size_low; 59833db86aabSstevel (void) pcmcia_free_io(dip, &ra); 59843db86aabSstevel } 59853db86aabSstevel kmem_free((caddr_t)regs, rlen); 59863db86aabSstevel } 59873db86aabSstevel } 59883db86aabSstevel 59893db86aabSstevel /* 59903db86aabSstevel * translate "available" from pcmcia format to pci format 59913db86aabSstevel */ 59923db86aabSstevel static int 59933db86aabSstevel pcic_apply_avail_ranges(dev_info_t *dip, pcm_regs_t *pcic_p, 59943db86aabSstevel pci_regspec_t *pci_p, int entries) 59953db86aabSstevel { 59963db86aabSstevel int i, range_len, range_entries; 59973db86aabSstevel pcic_ranges_t *pcic_range_p; 59983db86aabSstevel 59993db86aabSstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 60003db86aabSstevel (caddr_t)&pcic_range_p, &range_len) != DDI_PROP_SUCCESS) { 60013db86aabSstevel cmn_err(CE_CONT, "?pcic_apply_avail_ranges: " 60023db86aabSstevel "no ranges property for pcmcia\n"); 60033db86aabSstevel return (DDI_FAILURE); 60043db86aabSstevel } 60053db86aabSstevel 60063db86aabSstevel range_entries = range_len / sizeof (pcic_ranges_t); 60073db86aabSstevel 60083db86aabSstevel /* for each "available" entry to be translated */ 60093db86aabSstevel for (i = 0; i < entries; i++, pcic_p++, pci_p++) { 60103db86aabSstevel int j; 60113db86aabSstevel pcic_ranges_t *range_p = pcic_range_p; 60123db86aabSstevel pci_p->pci_phys_hi = -1u; /* default invalid value */ 60133db86aabSstevel 60143db86aabSstevel /* for each "ranges" entry to be searched */ 60153db86aabSstevel for (j = 0; j < range_entries; j++, range_p++) { 60163db86aabSstevel uint64_t range_end = range_p->pcic_range_caddrlo + 60173db86aabSstevel range_p->pcic_range_size; 60183db86aabSstevel uint64_t avail_end = pcic_p->phys_lo + pcic_p->phys_len; 60193db86aabSstevel 60203db86aabSstevel if ((range_p->pcic_range_caddrhi != pcic_p->phys_hi) || 60213db86aabSstevel (range_p->pcic_range_caddrlo > pcic_p->phys_lo) || 60223db86aabSstevel (range_end < avail_end)) 60233db86aabSstevel continue; 60243db86aabSstevel 60253db86aabSstevel pci_p->pci_phys_hi = range_p->pcic_range_paddrhi; 60263db86aabSstevel pci_p->pci_phys_mid = range_p->pcic_range_paddrmid; 60273db86aabSstevel pci_p->pci_phys_low = range_p->pcic_range_paddrlo 60283db86aabSstevel + (pcic_p->phys_lo - range_p->pcic_range_caddrlo); 60293db86aabSstevel pci_p->pci_size_hi = 0; 60303db86aabSstevel pci_p->pci_size_low = pcic_p->phys_len; 60313db86aabSstevel } 60323db86aabSstevel } 60333db86aabSstevel kmem_free(pcic_range_p, range_len); 60343db86aabSstevel return (DDI_SUCCESS); 60353db86aabSstevel } 60363db86aabSstevel 60373db86aabSstevel static int 60383db86aabSstevel pcic_open(dev_t *dev, int flag, int otyp, cred_t *cred) 60393db86aabSstevel { 60403db86aabSstevel if (getminor(*dev) == SYSHW_MINOR) 60413db86aabSstevel return (syshw_open(dev, flag, otyp, cred)); 60423db86aabSstevel #ifdef CARDBUS 60433db86aabSstevel if (cardbus_is_cb_minor(*dev)) 60443db86aabSstevel return (cardbus_open(dev, flag, otyp, cred)); 60453db86aabSstevel #endif 60463db86aabSstevel return (EINVAL); 60473db86aabSstevel } 60483db86aabSstevel 60493db86aabSstevel static int 60503db86aabSstevel pcic_close(dev_t dev, int flag, int otyp, cred_t *cred) 60513db86aabSstevel { 60523db86aabSstevel if (getminor(dev) == SYSHW_MINOR) 60533db86aabSstevel return (syshw_close(dev, flag, otyp, cred)); 60543db86aabSstevel #ifdef CARDBUS 60553db86aabSstevel if (cardbus_is_cb_minor(dev)) 60563db86aabSstevel return (cardbus_close(dev, flag, otyp, cred)); 60573db86aabSstevel #endif 60583db86aabSstevel return (EINVAL); 60593db86aabSstevel } 60603db86aabSstevel 60613db86aabSstevel static int 60623db86aabSstevel pcic_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, 60633db86aabSstevel int *rval) 60643db86aabSstevel { 60653db86aabSstevel if (getminor(dev) == SYSHW_MINOR) 60663db86aabSstevel return (syshw_ioctl(dev, cmd, arg, mode, cred, rval)); 60673db86aabSstevel #ifdef CARDBUS 60683db86aabSstevel if (cardbus_is_cb_minor(dev)) 60693db86aabSstevel return (cardbus_ioctl(dev, cmd, arg, mode, cred, rval)); 60703db86aabSstevel #endif 60713db86aabSstevel return (EINVAL); 60723db86aabSstevel } 60733db86aabSstevel 60743db86aabSstevel 60753db86aabSstevel static boolean_t 60763db86aabSstevel pcic_load_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp) 60773db86aabSstevel { 60783db86aabSstevel uint32_t present_state; 60793db86aabSstevel dev_info_t *dip = pcic->dip; 60803db86aabSstevel set_socket_t s; 60813db86aabSstevel get_socket_t g; 60823db86aabSstevel boolean_t retval; 60833db86aabSstevel unsigned vccLevel; 60843db86aabSstevel 60853db86aabSstevel pcic_err(dip, 8, "entering pcic_load_cardbus\n"); 60863db86aabSstevel 60873db86aabSstevel pcic_mutex_exit(&pcic->pc_lock); 60883db86aabSstevel 60893db86aabSstevel bzero(&s, sizeof (set_socket_t)); 60903db86aabSstevel s.socket = sockp->pcs_socket; 60913db86aabSstevel s.SCIntMask = SBM_CD|SBM_RDYBSY; 60923db86aabSstevel s.IFType = IF_CARDBUS; 60933db86aabSstevel s.State = (unsigned)~0; 60943db86aabSstevel 60953db86aabSstevel present_state = pcic_getcb(pcic, CB_PRESENT_STATE); 60963db86aabSstevel if (present_state & PCIC_VCC_3VCARD) 60973db86aabSstevel s.VccLevel = PCIC_VCC_3VLEVEL; 60983db86aabSstevel else if (present_state & PCIC_VCC_5VCARD) 60993db86aabSstevel s.VccLevel = PCIC_VCC_5VLEVEL; 61003db86aabSstevel else { 61013db86aabSstevel cmn_err(CE_CONT, 61023db86aabSstevel "pcic_load_cardbus: unsupported card voltage\n"); 61033db86aabSstevel goto failure; 61043db86aabSstevel } 61053db86aabSstevel vccLevel = s.VccLevel; 61063db86aabSstevel s.Vpp1Level = s.Vpp2Level = 0; 61073db86aabSstevel 61083db86aabSstevel if (pcic_set_socket(dip, &s) != SUCCESS) 61093db86aabSstevel goto failure; 61103db86aabSstevel 61113db86aabSstevel if (pcic_reset_socket(dip, sockp->pcs_socket, 61123db86aabSstevel RESET_MODE_CARD_ONLY) != SUCCESS) 61133db86aabSstevel goto failure; 61143db86aabSstevel 61153db86aabSstevel bzero(&g, sizeof (get_socket_t)); 61163db86aabSstevel g.socket = sockp->pcs_socket; 61173db86aabSstevel if (pcic_get_socket(dip, &g) != SUCCESS) 61183db86aabSstevel goto failure; 61193db86aabSstevel 61203db86aabSstevel bzero(&s, sizeof (set_socket_t)); 61213db86aabSstevel s.socket = sockp->pcs_socket; 61223db86aabSstevel s.SCIntMask = SBM_CD; 61233db86aabSstevel s.IREQRouting = g.IRQRouting; 61243db86aabSstevel s.IFType = g.IFType; 61253db86aabSstevel s.CtlInd = g.CtlInd; 61263db86aabSstevel s.State = (unsigned)~0; 61273db86aabSstevel s.VccLevel = vccLevel; 61283db86aabSstevel s.Vpp1Level = s.Vpp2Level = 0; 61293db86aabSstevel 61303db86aabSstevel if (pcic_set_socket(dip, &s) != SUCCESS) 61313db86aabSstevel goto failure; 61323db86aabSstevel 61333db86aabSstevel retval = cardbus_load_cardbus(dip, sockp->pcs_socket, pcic->pc_base); 61343db86aabSstevel goto exit; 61353db86aabSstevel 61363db86aabSstevel failure: 61373db86aabSstevel retval = B_FALSE; 61383db86aabSstevel 61393db86aabSstevel exit: 61403db86aabSstevel pcic_mutex_enter(&pcic->pc_lock); 61413db86aabSstevel pcic_err(dip, 8, "exit pcic_load_cardbus (%s)\n", 61423db86aabSstevel retval ? "success" : "failure"); 61433db86aabSstevel return (retval); 61443db86aabSstevel } 61453db86aabSstevel 61463db86aabSstevel static void 61473db86aabSstevel pcic_unload_cardbus(pcicdev_t *pcic, const pcic_socket_t *sockp) 61483db86aabSstevel { 61493db86aabSstevel dev_info_t *dip = pcic->dip; 61503db86aabSstevel set_socket_t s; 61513db86aabSstevel 61523db86aabSstevel pcic_mutex_exit(&pcic->pc_lock); 61533db86aabSstevel 61543db86aabSstevel cardbus_unload_cardbus(dip); 61553db86aabSstevel 61563db86aabSstevel bzero(&s, sizeof (set_socket_t)); 61573db86aabSstevel s.socket = sockp->pcs_socket; 61583db86aabSstevel s.SCIntMask = SBM_CD|SBM_RDYBSY; 61593db86aabSstevel s.IREQRouting = 0; 61603db86aabSstevel s.IFType = IF_MEMORY; 61613db86aabSstevel s.CtlInd = 0; 61623db86aabSstevel s.State = 0; 61633db86aabSstevel s.VccLevel = s.Vpp1Level = s.Vpp2Level = 0; 61643db86aabSstevel 61653db86aabSstevel (void) pcic_set_socket(dip, &s); 61663db86aabSstevel 61673db86aabSstevel pcic_mutex_enter(&pcic->pc_lock); 61683db86aabSstevel } 61693db86aabSstevel 61703db86aabSstevel static uint32_t 61713db86aabSstevel pcic_getcb(pcicdev_t *pcic, int reg) 61723db86aabSstevel { 61733db86aabSstevel ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA); 61743db86aabSstevel 61753db86aabSstevel return (ddi_get32(pcic->handle, 61763db86aabSstevel (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg))); 61773db86aabSstevel } 61783db86aabSstevel 61793db86aabSstevel static void 61803db86aabSstevel pcic_putcb(pcicdev_t *pcic, int reg, uint32_t value) 61813db86aabSstevel { 61823db86aabSstevel ASSERT(pcic->pc_io_type == PCIC_IO_TYPE_YENTA); 61833db86aabSstevel 61843db86aabSstevel ddi_put32(pcic->handle, 61853db86aabSstevel (uint32_t *)(pcic->ioaddr + CB_CB_OFFSET + reg), value); 61863db86aabSstevel } 61873db86aabSstevel 61883db86aabSstevel static void 61893db86aabSstevel pcic_enable_io_intr(pcicdev_t *pcic, int socket, int irq) 61903db86aabSstevel { 61913db86aabSstevel uint8_t value; 61923db86aabSstevel uint16_t brdgctl; 61933db86aabSstevel 61943db86aabSstevel value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK; 61953db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, value | irq); 61963db86aabSstevel 61973db86aabSstevel switch (pcic->pc_type) { 61983db86aabSstevel case PCIC_INTEL_i82092: 61993db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ, 62003db86aabSstevel PCIC_82092_INT_ENABLE); 62013db86aabSstevel break; 62023db86aabSstevel case PCIC_O2_OZ6912: 62033db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CENTDMA); 62043db86aabSstevel value |= 0x8; 62053db86aabSstevel pcic_putb(pcic, 0, PCIC_CENTDMA, value); 62063db86aabSstevel break; 62073db86aabSstevel case PCIC_CL_PD6832: 62083db86aabSstevel case PCIC_TI_PCI1250: 62093db86aabSstevel case PCIC_TI_PCI1221: 62103db86aabSstevel case PCIC_TI_PCI1225: 62113db86aabSstevel case PCIC_TI_PCI1410: 62123db86aabSstevel case PCIC_ENE_1410: 62133db86aabSstevel case PCIC_TI_PCI1510: 62143db86aabSstevel case PCIC_TI_PCI1520: 62153db86aabSstevel case PCIC_TI_PCI1420: 62163db86aabSstevel case PCIC_ENE_1420: 62173db86aabSstevel /* route card functional interrupts to PCI interrupts */ 62183db86aabSstevel brdgctl = ddi_get16(pcic->cfg_handle, 62193db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 62203db86aabSstevel pcic_err(NULL, 1, 62213db86aabSstevel "pcic_enable_io_intr brdgctl(0x%x) was: 0x%x\n", 62223db86aabSstevel PCI_CBUS_BRIDGE_CTRL, brdgctl); 62233db86aabSstevel brdgctl &= ~PCIC_BRDGCTL_INTR_MASK; 62243db86aabSstevel ddi_put16(pcic->cfg_handle, 62253db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL), 62263db86aabSstevel brdgctl); 62273db86aabSstevel /* Flush the write */ 62283db86aabSstevel (void) ddi_get16(pcic->cfg_handle, 62293db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 62303db86aabSstevel break; 62313db86aabSstevel default: 62323db86aabSstevel break; 62333db86aabSstevel } 62343db86aabSstevel } 62353db86aabSstevel 62363db86aabSstevel static void 62373db86aabSstevel pcic_disable_io_intr(pcicdev_t *pcic, int socket) 62383db86aabSstevel { 62393db86aabSstevel uint8_t value; 62403db86aabSstevel uint16_t brdgctl; 62413db86aabSstevel 62423db86aabSstevel value = pcic_getb(pcic, socket, PCIC_INTERRUPT) & ~PCIC_INTR_MASK; 62433db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, value); 62443db86aabSstevel 62453db86aabSstevel switch (pcic->pc_type) { 62463db86aabSstevel case PCIC_INTEL_i82092: 62473db86aabSstevel pcic_82092_smiirq_ctl(pcic, socket, PCIC_82092_CTL_IRQ, 62483db86aabSstevel PCIC_82092_INT_DISABLE); 62493db86aabSstevel break; 62503db86aabSstevel case PCIC_O2_OZ6912: 62513db86aabSstevel value = pcic_getb(pcic, 0, PCIC_CENTDMA); 62523db86aabSstevel value &= ~0x8; 62533db86aabSstevel pcic_putb(pcic, 0, PCIC_CENTDMA, value); 62543db86aabSstevel /* Flush the write */ 62553db86aabSstevel (void) pcic_getb(pcic, 0, PCIC_CENTDMA); 62563db86aabSstevel break; 62573db86aabSstevel case PCIC_CL_PD6832: 62583db86aabSstevel case PCIC_TI_PCI1250: 62593db86aabSstevel case PCIC_TI_PCI1221: 62603db86aabSstevel case PCIC_TI_PCI1225: 62613db86aabSstevel case PCIC_TI_PCI1410: 62623db86aabSstevel case PCIC_ENE_1410: 62633db86aabSstevel case PCIC_TI_PCI1510: 62643db86aabSstevel case PCIC_TI_PCI1520: 62653db86aabSstevel case PCIC_TI_PCI1420: 62663db86aabSstevel case PCIC_ENE_1420: 62673db86aabSstevel /* 62683db86aabSstevel * This maps I/O interrupts to ExCA which 62693db86aabSstevel * have been turned off by the write to 62703db86aabSstevel * PCIC_INTERRUPT above. It would appear to 62713db86aabSstevel * be the only way to actually turn I/O Ints off 62723db86aabSstevel * while retaining CS Ints. 62733db86aabSstevel */ 62743db86aabSstevel brdgctl = ddi_get16(pcic->cfg_handle, 62753db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 62763db86aabSstevel pcic_err(NULL, 1, 62773db86aabSstevel "pcic_disable_io_intr brdgctl(0x%x) was: 0x%x\n", 62783db86aabSstevel PCI_CBUS_BRIDGE_CTRL, brdgctl); 62793db86aabSstevel brdgctl |= PCIC_BRDGCTL_INTR_MASK; 62803db86aabSstevel ddi_put16(pcic->cfg_handle, 62813db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL), 62823db86aabSstevel brdgctl); 62833db86aabSstevel /* Flush the write */ 62843db86aabSstevel (void) ddi_get16(pcic->cfg_handle, 62853db86aabSstevel (uint16_t *)(pcic->cfgaddr + PCI_CBUS_BRIDGE_CTRL)); 62863db86aabSstevel break; 62873db86aabSstevel default: 62883db86aabSstevel break; 62893db86aabSstevel } 62903db86aabSstevel } 62913db86aabSstevel 62923db86aabSstevel static void 62933db86aabSstevel pcic_cb_enable_intr(dev_info_t *dip) 62943db86aabSstevel { 62953db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 62963db86aabSstevel pcicdev_t *pcic = anp->an_private; 62973db86aabSstevel 62983db86aabSstevel mutex_enter(&pcic->pc_lock); 62993db86aabSstevel pcic_enable_io_intr(pcic, 0, pcic->pc_sockets[0].pcs_irq); 63003db86aabSstevel mutex_exit(&pcic->pc_lock); 63013db86aabSstevel } 63023db86aabSstevel 63033db86aabSstevel static void 63043db86aabSstevel pcic_cb_disable_intr(dev_info_t *dip) 63053db86aabSstevel { 63063db86aabSstevel anp_t *anp = ddi_get_driver_private(dip); 63073db86aabSstevel pcicdev_t *pcic = anp->an_private; 63083db86aabSstevel 63093db86aabSstevel mutex_enter(&pcic->pc_lock); 63103db86aabSstevel pcic_disable_io_intr(pcic, 0); 63113db86aabSstevel mutex_exit(&pcic->pc_lock); 63123db86aabSstevel } 63133db86aabSstevel 63143db86aabSstevel static int 63153db86aabSstevel log_pci_cfg_err(ushort_t e, int bridge_secondary) 63163db86aabSstevel { 63173db86aabSstevel int nerr = 0; 63183db86aabSstevel if (e & PCI_STAT_PERROR) { 63193db86aabSstevel nerr++; 63203db86aabSstevel cmn_err(CE_CONT, "detected parity error.\n"); 63213db86aabSstevel } 63223db86aabSstevel if (e & PCI_STAT_S_SYSERR) { 63233db86aabSstevel nerr++; 63243db86aabSstevel if (bridge_secondary) 63253db86aabSstevel cmn_err(CE_CONT, "received system error.\n"); 63263db86aabSstevel else 63273db86aabSstevel cmn_err(CE_CONT, "signalled system error.\n"); 63283db86aabSstevel } 63293db86aabSstevel if (e & PCI_STAT_R_MAST_AB) { 63303db86aabSstevel nerr++; 63313db86aabSstevel cmn_err(CE_CONT, "received master abort.\n"); 63323db86aabSstevel } 63333db86aabSstevel if (e & PCI_STAT_R_TARG_AB) 63343db86aabSstevel cmn_err(CE_CONT, "received target abort.\n"); 63353db86aabSstevel if (e & PCI_STAT_S_TARG_AB) 63363db86aabSstevel cmn_err(CE_CONT, "signalled target abort\n"); 63373db86aabSstevel if (e & PCI_STAT_S_PERROR) { 63383db86aabSstevel nerr++; 63393db86aabSstevel cmn_err(CE_CONT, "signalled parity error\n"); 63403db86aabSstevel } 63413db86aabSstevel return (nerr); 63423db86aabSstevel } 63433db86aabSstevel 63443db86aabSstevel #if defined(__sparc) 63453db86aabSstevel static int 63463db86aabSstevel pcic_fault(enum pci_fault_ops op, void *arg) 63473db86aabSstevel { 63483db86aabSstevel pcicdev_t *pcic = (pcicdev_t *)arg; 63493db86aabSstevel ushort_t pci_cfg_stat = 63503db86aabSstevel pci_config_get16(pcic->cfg_handle, PCI_CONF_STAT); 63513db86aabSstevel ushort_t pci_cfg_sec_stat = 63523db86aabSstevel pci_config_get16(pcic->cfg_handle, 0x16); 63533db86aabSstevel char nm[24]; 63543db86aabSstevel int nerr = 0; 63553db86aabSstevel 63563db86aabSstevel cardbus_dump_pci_config(pcic->dip); 63573db86aabSstevel 63583db86aabSstevel switch (op) { 63593db86aabSstevel case FAULT_LOG: 63603db86aabSstevel (void) sprintf(nm, "%s-%d", ddi_driver_name(pcic->dip), 63613db86aabSstevel ddi_get_instance(pcic->dip)); 63623db86aabSstevel 63633db86aabSstevel cmn_err(CE_WARN, "%s: PCIC fault log start:\n", nm); 63643db86aabSstevel cmn_err(CE_WARN, "%s: primary err (%x):\n", nm, pci_cfg_stat); 63653db86aabSstevel nerr += log_pci_cfg_err(pci_cfg_stat, 0); 63663db86aabSstevel cmn_err(CE_WARN, "%s: sec err (%x):\n", nm, pci_cfg_sec_stat); 63673db86aabSstevel nerr += log_pci_cfg_err(pci_cfg_sec_stat, 1); 63683db86aabSstevel cmn_err(CE_CONT, "%s: PCI fault log end.\n", nm); 63693db86aabSstevel return (nerr); 63703db86aabSstevel case FAULT_POKEFINI: 63713db86aabSstevel case FAULT_RESET: 63723db86aabSstevel pci_config_put16(pcic->cfg_handle, 63733db86aabSstevel PCI_CONF_STAT, pci_cfg_stat); 63743db86aabSstevel pci_config_put16(pcic->cfg_handle, 0x16, pci_cfg_sec_stat); 63753db86aabSstevel break; 63763db86aabSstevel case FAULT_POKEFLT: 63773db86aabSstevel if (!(pci_cfg_stat & PCI_STAT_S_SYSERR)) 63783db86aabSstevel return (1); 63793db86aabSstevel if (!(pci_cfg_sec_stat & PCI_STAT_R_MAST_AB)) 63803db86aabSstevel return (1); 63813db86aabSstevel break; 63823db86aabSstevel default: 63833db86aabSstevel break; 63843db86aabSstevel } 63853db86aabSstevel return (DDI_SUCCESS); 63863db86aabSstevel } 63873db86aabSstevel #endif 63883db86aabSstevel 63893db86aabSstevel static void 63903db86aabSstevel pcic_delayed_resume(void *arg) 63913db86aabSstevel { 63923db86aabSstevel int i, j, interrupt; 63933db86aabSstevel anp_t *pcic_nexus; 63943db86aabSstevel pcicdev_t *pcic; 63953db86aabSstevel 63963db86aabSstevel _NOTE(ARGUNUSED(arg)) 63973db86aabSstevel 63983db86aabSstevel #if defined(PCIC_DEBUG) 63993db86aabSstevel pcic_err(NULL, 6, "pcic_delayed_resume(): entered\n"); 64003db86aabSstevel #endif 64013db86aabSstevel for (j = 0; j <= pcic_maxinst; j++) { 64023db86aabSstevel 64033db86aabSstevel pcic_nexus = ddi_get_soft_state(pcic_soft_state_p, j); 64043db86aabSstevel if (!pcic_nexus) 64053db86aabSstevel continue; 64063db86aabSstevel pcic = (pcicdev_t *)pcic_nexus->an_private; 64073db86aabSstevel if (!pcic) 64083db86aabSstevel continue; 64093db86aabSstevel 64103db86aabSstevel pcic_mutex_enter(&pcic->pc_lock); /* protect the registers */ 64113db86aabSstevel for (i = 0; i < pcic->pc_numsockets; i++) { 64123db86aabSstevel /* Enable interrupts on PCI if needs be */ 64133db86aabSstevel interrupt = pcic_getb(pcic, i, PCIC_INTERRUPT); 64143db86aabSstevel if (pcic->pc_flags & PCF_USE_SMI) 64153db86aabSstevel interrupt |= PCIC_INTR_ENABLE; 64163db86aabSstevel pcic_putb(pcic, i, PCIC_INTERRUPT, 64173db86aabSstevel PCIC_RESET | interrupt); 64183db86aabSstevel pcic->pc_sockets[i].pcs_debounce_id = 64193db86aabSstevel pcic_add_debqueue(&pcic->pc_sockets[i], 64203db86aabSstevel drv_usectohz(pcic_debounce_time)); 64213db86aabSstevel } 64223db86aabSstevel pcic_mutex_exit(&pcic->pc_lock); /* protect the registers */ 64233db86aabSstevel if (pcic_do_pcmcia_sr) 64243db86aabSstevel (void) pcmcia_wait_insert(pcic->dip); 64253db86aabSstevel } 64263db86aabSstevel } 64273db86aabSstevel 64283db86aabSstevel static void 64293db86aabSstevel pcic_debounce(pcic_socket_t *pcs) 64303db86aabSstevel { 64313db86aabSstevel uint8_t status, stschng; 64323db86aabSstevel 64333db86aabSstevel pcic_mutex_enter(&pcs->pcs_pcic->pc_lock); 64343db86aabSstevel pcs->pcs_flags &= ~PCS_STARTING; 64353db86aabSstevel stschng = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket, 64363db86aabSstevel PCIC_CARD_STATUS_CHANGE); 64373db86aabSstevel status = pcic_getb(pcs->pcs_pcic, pcs->pcs_socket, 64383db86aabSstevel PCIC_INTERFACE_STATUS); 64393db86aabSstevel #ifdef PCIC_DEBUG 64403db86aabSstevel pcic_err(pcs->pcs_pcic->dip, 8, 64413db86aabSstevel "pcic_debounce(0x%p, dip=0x%p) socket %d st 0x%x " 64423db86aabSstevel "chg 0x%x flg 0x%x\n", 64433db86aabSstevel (void *)pcs, (void *) pcs->pcs_pcic->dip, pcs->pcs_socket, 64443db86aabSstevel status, stschng, pcs->pcs_flags); 64453db86aabSstevel #endif 64463db86aabSstevel 64473db86aabSstevel pcic_putb(pcs->pcs_pcic, pcs->pcs_socket, PCIC_CARD_STATUS_CHANGE, 64483db86aabSstevel PCIC_CD_DETECT); 64493db86aabSstevel pcic_handle_cd_change(pcs->pcs_pcic, pcs, status); 64503db86aabSstevel pcic_mutex_exit(&pcs->pcs_pcic->pc_lock); 64513db86aabSstevel } 64523db86aabSstevel 64533db86aabSstevel static void 64543db86aabSstevel pcic_deb_thread() 64553db86aabSstevel { 64563db86aabSstevel callb_cpr_t cprinfo; 64573db86aabSstevel struct debounce *debp; 64583db86aabSstevel clock_t lastt; 64593db86aabSstevel 64603db86aabSstevel CALLB_CPR_INIT(&cprinfo, &pcic_deb_mtx, 64613db86aabSstevel callb_generic_cpr, "pcic debounce thread"); 64623db86aabSstevel mutex_enter(&pcic_deb_mtx); 64633db86aabSstevel while (pcic_deb_threadid) { 64643db86aabSstevel while (pcic_deb_queue) { 64653db86aabSstevel #ifdef PCIC_DEBUG 64663db86aabSstevel pcic_dump_debqueue("Thread"); 64673db86aabSstevel #endif 64683db86aabSstevel debp = pcic_deb_queue; 64693db86aabSstevel (void) drv_getparm(LBOLT, &lastt); 64703db86aabSstevel if (lastt >= debp->expire) { 64713db86aabSstevel pcic_deb_queue = debp->next; 64723db86aabSstevel mutex_exit(&pcic_deb_mtx); 64733db86aabSstevel pcic_debounce(debp->pcs); 64743db86aabSstevel mutex_enter(&pcic_deb_mtx); 64753db86aabSstevel kmem_free(debp, sizeof (*debp)); 64763db86aabSstevel } else { 64773db86aabSstevel (void) cv_timedwait(&pcic_deb_cv, 64783db86aabSstevel &pcic_deb_mtx, debp->expire); 64793db86aabSstevel } 64803db86aabSstevel } 64813db86aabSstevel CALLB_CPR_SAFE_BEGIN(&cprinfo); 64823db86aabSstevel cv_wait(&pcic_deb_cv, &pcic_deb_mtx); 64833db86aabSstevel CALLB_CPR_SAFE_END(&cprinfo, &pcic_deb_mtx); 64843db86aabSstevel } 64853db86aabSstevel pcic_deb_threadid = (kthread_t *)1; 64863db86aabSstevel cv_signal(&pcic_deb_cv); 64873db86aabSstevel CALLB_CPR_EXIT(&cprinfo); /* Also exits the mutex */ 64883db86aabSstevel thread_exit(); 64893db86aabSstevel } 64903db86aabSstevel 64913db86aabSstevel static void * 64923db86aabSstevel pcic_add_debqueue(pcic_socket_t *pcs, int clocks) 64933db86aabSstevel { 64943db86aabSstevel clock_t lbolt; 64953db86aabSstevel struct debounce *dbp, **dbpp = &pcic_deb_queue; 64963db86aabSstevel 64973db86aabSstevel (void) drv_getparm(LBOLT, &lbolt); 64988134ee03Srw148561 dbp = kmem_alloc(sizeof (struct debounce), KM_SLEEP); 64993db86aabSstevel 65003db86aabSstevel dbp->expire = lbolt + clocks; 65013db86aabSstevel dbp->pcs = pcs; 65023db86aabSstevel mutex_enter(&pcic_deb_mtx); 65033db86aabSstevel while (*dbpp) { 65043db86aabSstevel if (dbp->expire > (*dbpp)->expire) 65053db86aabSstevel dbpp = &((*dbpp)->next); 65063db86aabSstevel else 65073db86aabSstevel break; 65083db86aabSstevel } 65093db86aabSstevel dbp->next = *dbpp; 65103db86aabSstevel *dbpp = dbp; 65113db86aabSstevel #ifdef PCIC_DEBUG 65123db86aabSstevel pcic_dump_debqueue("Add"); 65133db86aabSstevel #endif 65143db86aabSstevel cv_signal(&pcic_deb_cv); 65153db86aabSstevel mutex_exit(&pcic_deb_mtx); 65163db86aabSstevel return (dbp); 65173db86aabSstevel } 65183db86aabSstevel 65193db86aabSstevel static void 65203db86aabSstevel pcic_rm_debqueue(void *id) 65213db86aabSstevel { 65223db86aabSstevel struct debounce *dbp, **dbpp = &pcic_deb_queue; 65233db86aabSstevel 65243db86aabSstevel dbp = (struct debounce *)id; 65253db86aabSstevel mutex_enter(&pcic_deb_mtx); 65263db86aabSstevel while (*dbpp) { 65273db86aabSstevel if (*dbpp == dbp) { 65283db86aabSstevel *dbpp = dbp->next; 65293db86aabSstevel kmem_free(dbp, sizeof (*dbp)); 65303db86aabSstevel #ifdef PCIC_DEBUG 65313db86aabSstevel pcic_dump_debqueue("Remove"); 65323db86aabSstevel #endif 65333db86aabSstevel cv_signal(&pcic_deb_cv); 65343db86aabSstevel mutex_exit(&pcic_deb_mtx); 65353db86aabSstevel return; 65363db86aabSstevel } 65373db86aabSstevel dbpp = &((*dbpp)->next); 65383db86aabSstevel } 65393db86aabSstevel pcic_err(NULL, 6, "pcic: Failed to find debounce id 0x%p\n", id); 65403db86aabSstevel mutex_exit(&pcic_deb_mtx); 65413db86aabSstevel } 65423db86aabSstevel 65433db86aabSstevel 65443db86aabSstevel static int pcic_powerdelay = 0; 65453db86aabSstevel 65463db86aabSstevel static int 65473db86aabSstevel pcic_exca_powerctl(pcicdev_t *pcic, int socket, int powerlevel) 65483db86aabSstevel { 65493db86aabSstevel int ind, value, orig_pwrctl; 65503db86aabSstevel 65513db86aabSstevel /* power setup -- if necessary */ 65523db86aabSstevel orig_pwrctl = pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 65533db86aabSstevel 65543db86aabSstevel #if defined(PCIC_DEBUG) 65553db86aabSstevel pcic_err(pcic->dip, 6, 65563db86aabSstevel "pcic_exca_powerctl(socket %d) powerlevel=%x orig 0x%x\n", 65573db86aabSstevel socket, powerlevel, orig_pwrctl); 65583db86aabSstevel #endif 65593db86aabSstevel /* Preserve the PCIC_OUTPUT_ENABLE (control lines output enable) bit. */ 65603db86aabSstevel powerlevel = (powerlevel & ~POWER_OUTPUT_ENABLE) | 65613db86aabSstevel (orig_pwrctl & POWER_OUTPUT_ENABLE); 65623db86aabSstevel if (powerlevel != orig_pwrctl) { 65633db86aabSstevel if (powerlevel & ~POWER_OUTPUT_ENABLE) { 65643db86aabSstevel int ifs; 65653db86aabSstevel /* 65663db86aabSstevel * set power to socket 65673db86aabSstevel * note that the powerlevel was calculated earlier 65683db86aabSstevel */ 65693db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel); 65703db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 65713db86aabSstevel 65723db86aabSstevel /* 65733db86aabSstevel * this second write to the power control register 65743db86aabSstevel * is needed to resolve a problem on 65753db86aabSstevel * the IBM ThinkPad 750 65763db86aabSstevel * where the first write doesn't latch. 65773db86aabSstevel * The second write appears to always work and 65783db86aabSstevel * doesn't hurt the operation of other chips 65793db86aabSstevel * so we can just use it -- this is good since we can't 65803db86aabSstevel * determine what chip the 750 actually uses 65813db86aabSstevel * (I suspect an early Ricoh). 65823db86aabSstevel */ 65833db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel); 65843db86aabSstevel 65853db86aabSstevel value = pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 65863db86aabSstevel pcic_mswait(pcic, socket, pcic_powerdelay); 65873db86aabSstevel #if defined(PCIC_DEBUG) 65883db86aabSstevel pcic_err(pcic->dip, 8, 65893db86aabSstevel "\tpowerlevel reg = %x (ifs %x)\n", 65903db86aabSstevel value, pcic_getb(pcic, socket, 65913db86aabSstevel PCIC_INTERFACE_STATUS)); 65923db86aabSstevel pcic_err(pcic->dip, 8, 65933db86aabSstevel "CBus regs: PS 0x%x, Control 0x%x\n", 65943db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE), 65953db86aabSstevel pcic_getcb(pcic, CB_CONTROL)); 65963db86aabSstevel #endif 65973db86aabSstevel /* 65983db86aabSstevel * since power was touched, make sure it says it 65993db86aabSstevel * is on. This lets it become stable. 66003db86aabSstevel */ 66013db86aabSstevel for (ind = 0; ind < 20; ind++) { 66023db86aabSstevel ifs = pcic_getb(pcic, socket, 66033db86aabSstevel PCIC_INTERFACE_STATUS); 66043db86aabSstevel if (ifs & PCIC_POWER_ON) 66053db86aabSstevel break; 66063db86aabSstevel else { 66073db86aabSstevel pcic_putb(pcic, socket, 66083db86aabSstevel PCIC_POWER_CONTROL, 0); 66093db86aabSstevel (void) pcic_getb(pcic, socket, 66103db86aabSstevel PCIC_POWER_CONTROL); 66113db86aabSstevel pcic_mswait(pcic, socket, 40); 66123db86aabSstevel if (ind == 10) { 66133db86aabSstevel pcic_putcb(pcic, CB_EVENT_FORCE, 66143db86aabSstevel CB_EF_CVTEST); 66153db86aabSstevel pcic_mswait(pcic, socket, 100); 66163db86aabSstevel } 66173db86aabSstevel pcic_putb(pcic, socket, 66183db86aabSstevel PCIC_POWER_CONTROL, 66193db86aabSstevel powerlevel & ~POWER_OUTPUT_ENABLE); 66203db86aabSstevel (void) pcic_getb(pcic, socket, 66213db86aabSstevel PCIC_POWER_CONTROL); 66223db86aabSstevel pcic_mswait(pcic, socket, 66233db86aabSstevel pcic_powerdelay); 66243db86aabSstevel pcic_putb(pcic, socket, 66253db86aabSstevel PCIC_POWER_CONTROL, powerlevel); 66263db86aabSstevel (void) pcic_getb(pcic, socket, 66273db86aabSstevel PCIC_POWER_CONTROL); 66283db86aabSstevel pcic_mswait(pcic, socket, 66293db86aabSstevel pcic_powerdelay); 66303db86aabSstevel } 66313db86aabSstevel } 66323db86aabSstevel 66333db86aabSstevel if (!(ifs & PCIC_POWER_ON)) { 66343db86aabSstevel cmn_err(CE_WARN, 66353db86aabSstevel "pcic socket %d: Power didn't get turned" 66363db86aabSstevel "on!\nif status 0x%x pwrc 0x%x(x%x) " 66373db86aabSstevel "misc1 0x%x igc 0x%x ind %d\n", 66383db86aabSstevel socket, ifs, 66393db86aabSstevel pcic_getb(pcic, socket, PCIC_POWER_CONTROL), 66403db86aabSstevel orig_pwrctl, 66413db86aabSstevel pcic_getb(pcic, socket, PCIC_MISC_CTL_1), 66423db86aabSstevel pcic_getb(pcic, socket, PCIC_INTERRUPT), 66433db86aabSstevel ind); 66443db86aabSstevel return (BAD_VCC); 66453db86aabSstevel } 66463db86aabSstevel #if defined(PCIC_DEBUG) 66473db86aabSstevel pcic_err(pcic->dip, 8, 66483db86aabSstevel "\tind = %d, if status %x pwrc 0x%x " 66493db86aabSstevel "misc1 0x%x igc 0x%x\n", 66503db86aabSstevel ind, ifs, 66513db86aabSstevel pcic_getb(pcic, socket, PCIC_POWER_CONTROL), 66523db86aabSstevel pcic_getb(pcic, socket, PCIC_MISC_CTL_1), 66533db86aabSstevel pcic_getb(pcic, socket, PCIC_INTERRUPT)); 66543db86aabSstevel #endif 66553db86aabSstevel } else { 66563db86aabSstevel /* explicitly turned off the power */ 66573db86aabSstevel pcic_putb(pcic, socket, PCIC_POWER_CONTROL, powerlevel); 66583db86aabSstevel (void) pcic_getb(pcic, socket, PCIC_POWER_CONTROL); 66593db86aabSstevel } 66603db86aabSstevel } 66613db86aabSstevel return (SUCCESS); 66623db86aabSstevel } 66633db86aabSstevel 66643db86aabSstevel static int pcic_cbdoreset_during_poweron = 1; 66653db86aabSstevel static int 66663db86aabSstevel pcic_cbus_powerctl(pcicdev_t *pcic, int socket) 66673db86aabSstevel { 66683db86aabSstevel uint32_t cbctl = 0, orig_cbctl, cbstev, cbps; 66693db86aabSstevel int ind, iobits; 66703db86aabSstevel pcic_socket_t *sockp = &pcic->pc_sockets[socket]; 66713db86aabSstevel 66723db86aabSstevel pcic_putcb(pcic, CB_STATUS_EVENT, CB_SE_POWER_CYCLE); 66733db86aabSstevel 66743db86aabSstevel ind = pcic_power[sockp->pcs_vpp1].PowerLevel/10; 66753db86aabSstevel cbctl |= pcic_cbv_levels[ind]; 66763db86aabSstevel 66773db86aabSstevel ind = pcic_power[sockp->pcs_vcc].PowerLevel/10; 66783db86aabSstevel cbctl |= (pcic_cbv_levels[ind]<<4); 66793db86aabSstevel 66803db86aabSstevel orig_cbctl = pcic_getcb(pcic, CB_CONTROL); 66813db86aabSstevel 66823db86aabSstevel #if defined(PCIC_DEBUG) 66833db86aabSstevel pcic_err(pcic->dip, 6, 66843db86aabSstevel "pcic_cbus_powerctl(socket %d) vcc %d vpp1 %d " 66853db86aabSstevel "cbctl 0x%x->0x%x\n", 66863db86aabSstevel socket, sockp->pcs_vcc, sockp->pcs_vpp1, orig_cbctl, cbctl); 66873db86aabSstevel #endif 66883db86aabSstevel if (cbctl != orig_cbctl) { 66893db86aabSstevel if (pcic_cbdoreset_during_poweron && 66903db86aabSstevel (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) { 66913db86aabSstevel iobits = pcic_getb(pcic, socket, PCIC_INTERRUPT); 66923db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits & ~PCIC_RESET); 66933db86aabSstevel } 66943db86aabSstevel pcic_putcb(pcic, CB_CONTROL, cbctl); 66953db86aabSstevel 66963db86aabSstevel if ((cbctl & CB_C_VCCMASK) == (orig_cbctl & CB_C_VCCMASK)) { 66973db86aabSstevel pcic_mswait(pcic, socket, pcic_powerdelay); 66983db86aabSstevel return (SUCCESS); 66993db86aabSstevel } 67003db86aabSstevel for (ind = 0; ind < 20; ind++) { 67013db86aabSstevel cbstev = pcic_getcb(pcic, CB_STATUS_EVENT); 67023db86aabSstevel 67033db86aabSstevel if (cbstev & CB_SE_POWER_CYCLE) { 67043db86aabSstevel 67053db86aabSstevel /* 67063db86aabSstevel * delay 400 ms: though the standard defines that the Vcc 67073db86aabSstevel * set-up time is 20 ms, some PC-Card bridge requires longer 67083db86aabSstevel * duration. 67093db86aabSstevel * Note: We should check the status AFTER the delay to give time 67103db86aabSstevel * for things to stabilize. 67113db86aabSstevel */ 67123db86aabSstevel pcic_mswait(pcic, socket, 400); 67133db86aabSstevel 67143db86aabSstevel cbps = pcic_getcb(pcic, CB_PRESENT_STATE); 67153db86aabSstevel if (cbctl && !(cbps & CB_PS_POWER_CYCLE)) { 67163db86aabSstevel /* break; */ 67173db86aabSstevel cmn_err(CE_WARN, "cbus_powerctl: power off??\n"); 67183db86aabSstevel } 67193db86aabSstevel if (cbctl & CB_PS_BADVCC) { 67203db86aabSstevel cmn_err(CE_WARN, "cbus_powerctl: bad power request\n"); 67213db86aabSstevel break; 67223db86aabSstevel } 67233db86aabSstevel 67243db86aabSstevel #if defined(PCIC_DEBUG) 67253db86aabSstevel pcic_err(pcic->dip, 8, 67263db86aabSstevel "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x)", 67273db86aabSstevel cbstev, pcic_getcb(pcic, CB_PRESENT_STATE), 67283db86aabSstevel cbctl, orig_cbctl); 67293db86aabSstevel #endif 67303db86aabSstevel if (pcic_cbdoreset_during_poweron && 67313db86aabSstevel (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) { 67323db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits); 67333db86aabSstevel } 67343db86aabSstevel return (SUCCESS); 67353db86aabSstevel } 67363db86aabSstevel pcic_mswait(pcic, socket, 40); 67373db86aabSstevel } 67383db86aabSstevel if (pcic_cbdoreset_during_poweron && 67393db86aabSstevel (orig_cbctl & (CB_C_VCCMASK|CB_C_VPPMASK)) == 0) { 67403db86aabSstevel pcic_putb(pcic, socket, PCIC_INTERRUPT, iobits); 67413db86aabSstevel } 67423db86aabSstevel cmn_err(CE_WARN, 67433db86aabSstevel "pcic socket %d: Power didn't get turned on/off!\n" 67443db86aabSstevel "cbstev = 0x%x cbps = 0x%x cbctl 0x%x(0x%x) " 67453db86aabSstevel "vcc %d vpp1 %d", socket, cbstev, 67463db86aabSstevel pcic_getcb(pcic, CB_PRESENT_STATE), 67473db86aabSstevel cbctl, orig_cbctl, sockp->pcs_vcc, sockp->pcs_vpp1); 67483db86aabSstevel return (BAD_VCC); 67493db86aabSstevel } 67503db86aabSstevel return (SUCCESS); 67513db86aabSstevel } 67523db86aabSstevel 67533db86aabSstevel static int pcic_do_pprintf = 0; 67543db86aabSstevel 67553db86aabSstevel static void 67563db86aabSstevel pcic_dump_debqueue(char *msg) 67573db86aabSstevel { 67583db86aabSstevel struct debounce *debp = pcic_deb_queue; 67593db86aabSstevel clock_t lbolt; 67603db86aabSstevel 67613db86aabSstevel (void) drv_getparm(LBOLT, &lbolt); 67623db86aabSstevel pcic_err(NULL, 6, debp ? "pcic debounce list (%s) lbolt 0x%x:\n" : 67633db86aabSstevel "pcic debounce_list (%s) EMPTY lbolt 0x%x\n", msg, lbolt); 67643db86aabSstevel while (debp) { 67653db86aabSstevel pcic_err(NULL, 6, "%p: exp 0x%x next 0x%p id 0x%p\n", 67663db86aabSstevel (void *) debp, (int)debp->expire, (void *) debp->next, 67673db86aabSstevel debp->pcs->pcs_debounce_id); 67683db86aabSstevel debp = debp->next; 67693db86aabSstevel } 67703db86aabSstevel } 67713db86aabSstevel 67723db86aabSstevel 67733db86aabSstevel /* PRINTFLIKE3 */ 67743db86aabSstevel static void 67753db86aabSstevel pcic_err(dev_info_t *dip, int level, const char *fmt, ...) 67763db86aabSstevel { 67773db86aabSstevel if (pcic_debug && (level <= pcic_debug)) { 67783db86aabSstevel va_list adx; 67793db86aabSstevel int instance; 67803db86aabSstevel char buf[256]; 67813db86aabSstevel const char *name; 67823db86aabSstevel #if !defined(PCIC_DEBUG) 67833db86aabSstevel int ce; 67843db86aabSstevel char qmark = 0; 67853db86aabSstevel 67863db86aabSstevel if (level <= 3) 67873db86aabSstevel ce = CE_WARN; 67883db86aabSstevel else 67893db86aabSstevel ce = CE_CONT; 67903db86aabSstevel if (level == 4) 67913db86aabSstevel qmark = 1; 67923db86aabSstevel #endif 67933db86aabSstevel 67943db86aabSstevel if (dip) { 67953db86aabSstevel instance = ddi_get_instance(dip); 67963db86aabSstevel /* name = ddi_binding_name(dip); */ 67973db86aabSstevel name = ddi_driver_name(dip); 67983db86aabSstevel } else { 67993db86aabSstevel instance = 0; 68003db86aabSstevel name = ""; 68013db86aabSstevel } 68023db86aabSstevel 68033db86aabSstevel va_start(adx, fmt); 68043db86aabSstevel (void) vsprintf(buf, fmt, adx); 68053db86aabSstevel va_end(adx); 68063db86aabSstevel 68073db86aabSstevel #if defined(PCIC_DEBUG) 68083db86aabSstevel if (pcic_do_pprintf) { 68093db86aabSstevel if (dip) { 68103db86aabSstevel if (instance >= 0) 68113db86aabSstevel prom_printf("%s(%d),0x%p: %s", name, 68123db86aabSstevel instance, dip, buf); 68133db86aabSstevel else 68143db86aabSstevel prom_printf("%s,0x%p: %s", 68153db86aabSstevel name, dip, buf); 68163db86aabSstevel } else 68173db86aabSstevel prom_printf(buf); 68183db86aabSstevel } else { 68193db86aabSstevel if (dip) { 68203db86aabSstevel if (instance >= 0) 68213db86aabSstevel cmn_err(CE_CONT, "%s(%d),0x%p: %s", 68223db86aabSstevel name, instance, (void *) dip, buf); 68233db86aabSstevel else 68243db86aabSstevel cmn_err(CE_CONT, "%s,0x%p: %s", 68253db86aabSstevel name, (void *) dip, buf); 68263db86aabSstevel } else 68273db86aabSstevel cmn_err(CE_CONT, buf); 68283db86aabSstevel } 68293db86aabSstevel #else 68303db86aabSstevel if (dip) 68313db86aabSstevel cmn_err(ce, qmark ? "?%s%d: %s" : "%s%d: %s", name, 68323db86aabSstevel instance, buf); 68333db86aabSstevel else 68343db86aabSstevel cmn_err(ce, qmark ? "?%s" : buf, buf); 68353db86aabSstevel #endif 68363db86aabSstevel } 68373db86aabSstevel } 68383db86aabSstevel 68393db86aabSstevel 68403db86aabSstevel static void 68413db86aabSstevel pcic_syshw_cardstate(syshw_t *item, void *arg) 68423db86aabSstevel { 68433db86aabSstevel pcic_socket_t *pcs = (pcic_socket_t *)arg; 68443db86aabSstevel 68453db86aabSstevel if (pcs->pcs_flags & PCS_CARD_PRESENT) { 68463db86aabSstevel item->state = B_TRUE; 68473db86aabSstevel if (pcs->pcs_flags & PCS_CARD_IS16BIT) 68483db86aabSstevel item->values[0] = 1; 68493db86aabSstevel else if (pcs->pcs_flags & PCS_CARD_ISCARDBUS) 68503db86aabSstevel item->values[0] = 2; 68513db86aabSstevel else 68523db86aabSstevel item->values[0] = 0; 68533db86aabSstevel } else { 68543db86aabSstevel item->state = B_FALSE; 68553db86aabSstevel item->values[0] = 0; 68563db86aabSstevel } 68573db86aabSstevel } 68583db86aabSstevel 68593db86aabSstevel /* 68603db86aabSstevel * Tadpole additional for the syshw interface used to control the 68613db86aabSstevel * start/stop switch which is physically linked to the GPIO1 pin 68623db86aabSstevel * on the 1250a. 68633db86aabSstevel */ 68643db86aabSstevel 68653db86aabSstevel #define CLIENT_CALLED 0x8000000 68663db86aabSstevel #define NCE_EVENT_MASK 0xffff 68673db86aabSstevel 68683db86aabSstevel typedef struct _client { 68693db86aabSstevel pid_t pid; /* set by kernel */ 68703db86aabSstevel int flags; /* NCE_REGISTER... */ 68713db86aabSstevel int priority; /* >100 unless root */ 68723db86aabSstevel int events; /* pending event flags */ 68733db86aabSstevel int event_sig; /* SIG... etc */ 68743db86aabSstevel struct _client *next; /* set by kernel */ 68753db86aabSstevel struct _client *prev; /* set by kernel */ 68763db86aabSstevel } client_data; 68773db86aabSstevel 68783db86aabSstevel static client_data *cl_data; 68793db86aabSstevel static int n_clients; 68803db86aabSstevel static kmutex_t client_mtx, intr_mtx; 68813db86aabSstevel 68823db86aabSstevel static void delete_client(int); 68833db86aabSstevel 68843db86aabSstevel #ifdef VOYAGER 68853db86aabSstevel static uint32_t runstop_sig; 68863db86aabSstevel static ddi_softintr_t softint_id; 68873db86aabSstevel static uchar_t softint_flag; 68883db86aabSstevel static int switch_debounce_time = 100; /* in milliseconds */ 68893db86aabSstevel static timeout_id_t switch_to_id; 68903db86aabSstevel 68913db86aabSstevel static syshw_t syshw_run_stop = { 68923db86aabSstevel 0, "Run/Stop", SH_SWITCH, 68933db86aabSstevel SYSHW_CAN_SIGNAL_CHANGE|SYSHW_STATE_VALID, 68943db86aabSstevel B_FALSE, { 0 } }; 68953db86aabSstevel 68963db86aabSstevel static void 68973db86aabSstevel syshw_get_run_stop(syshw_t *item, void *arg) 68983db86aabSstevel { 68993db86aabSstevel pcicdev_t *pcic = (pcicdev_t *)arg; 69003db86aabSstevel 69013db86aabSstevel if (ddi_get8(pcic->cfg_handle, 69023db86aabSstevel pcic->cfgaddr + PCIC_GPIO1_REG) & PCIC_GPIO_DIN) 69033db86aabSstevel item->state = B_TRUE; 69043db86aabSstevel else 69053db86aabSstevel item->state = B_FALSE; 69063db86aabSstevel } 69073db86aabSstevel 69083db86aabSstevel 69093db86aabSstevel #endif 69103db86aabSstevel 69113db86aabSstevel static void 69123db86aabSstevel syshw_attach(pcicdev_t *pcic) 69133db86aabSstevel { 69143db86aabSstevel if (ddi_get_instance(pcic->dip) != 0) 69153db86aabSstevel return; 69163db86aabSstevel 69173db86aabSstevel #ifdef VOYAGER 69183db86aabSstevel if (pcic->pc_type == PCIC_TI_PCI1250) { 69193db86aabSstevel 69203db86aabSstevel /* 69213db86aabSstevel * Only setup run/stop on a Voyager. 69223db86aabSstevel * This is currently defined as 69233db86aabSstevel * a TI1250 on a SPARC architecture. May have to make this a 69243db86aabSstevel * property definition in the future. 69253db86aabSstevel */ 69263db86aabSstevel if (ddi_add_softintr(pcic->dip, 69273db86aabSstevel DDI_SOFTINT_LOW, &softint_id, 69283db86aabSstevel NULL, NULL, syshw_intr, 69293db86aabSstevel (caddr_t)pcic) == DDI_SUCCESS) { 69303db86aabSstevel runstop_sig = syshw_add2map(&syshw_run_stop, 69313db86aabSstevel syshw_get_run_stop, pcic); 69323db86aabSstevel mutex_init(&intr_mtx, NULL, MUTEX_DRIVER, 69333db86aabSstevel pcic->pc_pri); 69343db86aabSstevel ddi_put8(pcic->cfg_handle, 69353db86aabSstevel pcic->cfgaddr + PCIC_GPIO1_REG, 69363db86aabSstevel PCIC_GPIO_FINPUT | PCIC_GPIO_INTENBL | 69373db86aabSstevel PCIC_GPIO_DELTA); 69383db86aabSstevel } 69393db86aabSstevel } 69403db86aabSstevel #endif 69413db86aabSstevel mutex_init(&client_mtx, "syshw client", MUTEX_DRIVER, NULL); 69423db86aabSstevel (void) ddi_create_minor_node(pcic->dip, "syshw", S_IFCHR, 69433db86aabSstevel SYSHW_MINOR, NULL, NULL); 69443db86aabSstevel } 69453db86aabSstevel 69463db86aabSstevel static void 69473db86aabSstevel syshw_detach(pcicdev_t *pcic) 69483db86aabSstevel { 69493db86aabSstevel #ifdef VOYAGER 69503db86aabSstevel if (pcic->pc_type == PCIC_TI_PCI1250) { 69513db86aabSstevel pcic_mutex_enter(&intr_mtx); 69523db86aabSstevel 69533db86aabSstevel /* 69543db86aabSstevel * Turn off this interrupt. 69553db86aabSstevel */ 69563db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG, 69573db86aabSstevel PCIC_GPIO_FINPUT); 69583db86aabSstevel 69593db86aabSstevel if (switch_to_id) 69603db86aabSstevel (void) untimeout(switch_to_id); 69613db86aabSstevel switch_to_id = 0; 69623db86aabSstevel softint_flag = 0; 69633db86aabSstevel 69643db86aabSstevel pcic_mutex_exit(&intr_mtx); 69653db86aabSstevel ddi_remove_softintr(softint_id); 69663db86aabSstevel mutex_destroy(&intr_mtx); 69673db86aabSstevel } 69683db86aabSstevel #endif 69693db86aabSstevel 69703db86aabSstevel ddi_remove_minor_node(pcic->dip, NULL); 69713db86aabSstevel mutex_destroy(&client_mtx); 69723db86aabSstevel } 69733db86aabSstevel 69743db86aabSstevel static void 69753db86aabSstevel syshw_resume(pcicdev_t *pcic) 69763db86aabSstevel { 69773db86aabSstevel #ifdef VOYAGER 69783db86aabSstevel if (pcic->pc_type == PCIC_TI_PCI1250) { 69793db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG, 69803db86aabSstevel PCIC_GPIO_FINPUT | PCIC_GPIO_INTENBL | PCIC_GPIO_DELTA); 69813db86aabSstevel } 69823db86aabSstevel #else 69833db86aabSstevel _NOTE(ARGUNUSED(pcic)) 69843db86aabSstevel #endif 69853db86aabSstevel } 69863db86aabSstevel 69873db86aabSstevel #ifdef VOYAGER 69883db86aabSstevel static uint_t 69893db86aabSstevel syshw_intr_hi(pcicdev_t *pcic) 69903db86aabSstevel { 69913db86aabSstevel uchar_t regval; 69923db86aabSstevel 69933db86aabSstevel if (pcic->pc_type != PCIC_TI_PCI1250) 69943db86aabSstevel return (DDI_INTR_UNCLAIMED); 69953db86aabSstevel 69963db86aabSstevel regval = ddi_get8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG); 69973db86aabSstevel if (regval & PCIC_GPIO_DELTA) { 69983db86aabSstevel pcic_mutex_enter(&intr_mtx); 69993db86aabSstevel if (softint_flag == 0 && switch_to_id == 0) { 70003db86aabSstevel softint_flag = 1; 70013db86aabSstevel ddi_trigger_softintr(softint_id); 70023db86aabSstevel } 70033db86aabSstevel ddi_put8(pcic->cfg_handle, pcic->cfgaddr + PCIC_GPIO1_REG, 70043db86aabSstevel regval); 70053db86aabSstevel pcic_mutex_exit(&intr_mtx); 70063db86aabSstevel return (DDI_INTR_CLAIMED); 70073db86aabSstevel } 70083db86aabSstevel 70093db86aabSstevel return (DDI_INTR_UNCLAIMED); 70103db86aabSstevel } 70113db86aabSstevel 70123db86aabSstevel /* 70133db86aabSstevel * Don't deliver the signal until the debounce period has expired. 70143db86aabSstevel * Unfortuately this means it end up as a three tier interrupt just 70153db86aabSstevel * to indicate a bit change. 70163db86aabSstevel */ 70173db86aabSstevel static void 70183db86aabSstevel syshw_debounce_to(void *arg) 70193db86aabSstevel { 70203db86aabSstevel _NOTE(ARGUNUSED(arg)) 70213db86aabSstevel 70223db86aabSstevel if (switch_to_id) { 70233db86aabSstevel pcic_mutex_enter(&intr_mtx); 70243db86aabSstevel switch_to_id = 0; 70253db86aabSstevel pcic_mutex_exit(&intr_mtx); 70263db86aabSstevel syshw_send_signal(runstop_sig); 70273db86aabSstevel return; 70283db86aabSstevel } 70293db86aabSstevel } 70303db86aabSstevel 70313db86aabSstevel static uint_t 70323db86aabSstevel syshw_intr(caddr_t arg) 70333db86aabSstevel { 70343db86aabSstevel _NOTE(ARGUNUSED(arg)) 70353db86aabSstevel 70363db86aabSstevel if (softint_flag) { 70373db86aabSstevel pcic_mutex_enter(&intr_mtx); 70383db86aabSstevel softint_flag = 0; 70393db86aabSstevel if (!switch_to_id) 70403db86aabSstevel switch_to_id = timeout(syshw_debounce_to, arg, 70413db86aabSstevel drv_usectohz(switch_debounce_time * 1000)); 70423db86aabSstevel pcic_mutex_exit(&intr_mtx); 70433db86aabSstevel return (DDI_INTR_CLAIMED); 70443db86aabSstevel } 70453db86aabSstevel return (DDI_INTR_UNCLAIMED); 70463db86aabSstevel } 70473db86aabSstevel #endif 70483db86aabSstevel 70493db86aabSstevel /* 70503db86aabSstevel * Send signals to the registered clients 70513db86aabSstevel */ 70523db86aabSstevel static void 70533db86aabSstevel syshw_send_signal(int events) 70543db86aabSstevel { 70553db86aabSstevel client_data *ptr; 70563db86aabSstevel proc_t *pr; 70573db86aabSstevel int done_flag; 70583db86aabSstevel 70593db86aabSstevel ptr = cl_data; 70603db86aabSstevel while (ptr != NULL) { 70613db86aabSstevel done_flag = CLIENT_CALLED; 70623db86aabSstevel 70633db86aabSstevel if ((ptr->flags & events) && 70643db86aabSstevel (ptr->event_sig != 0) && 70653db86aabSstevel ((ptr->flags & done_flag) == 0)) { 70663db86aabSstevel 70673db86aabSstevel /* 70683db86aabSstevel * only call the process if: 70693db86aabSstevel * it has not already received the nce signal 70703db86aabSstevel * its signal was not zero (just in case) 70713db86aabSstevel * and it is registered to receive this signal 70723db86aabSstevel */ 70733db86aabSstevel pcic_mutex_enter(&pidlock); 70743db86aabSstevel pr = prfind(ptr->pid); 70753db86aabSstevel pcic_mutex_exit(&pidlock); 70763db86aabSstevel if (pr == NULL) { 70773db86aabSstevel /* 70783db86aabSstevel * This process has died, 70793db86aabSstevel * so we free its memory and move on 70803db86aabSstevel * start at the begining again: 70813db86aabSstevel * a waste of cycles but it makes things easy.. 70823db86aabSstevel */ 70833db86aabSstevel delete_client(ptr->pid); 70843db86aabSstevel ptr = cl_data; 70853db86aabSstevel } else { 70863db86aabSstevel ptr->events |= (events & ptr->flags & 70873db86aabSstevel NCE_EVENT_MASK); 70883db86aabSstevel psignal(pr, ptr->event_sig); 70893db86aabSstevel ptr->flags |= done_flag; 70903db86aabSstevel ptr = ptr->next; 70913db86aabSstevel } 70923db86aabSstevel } else { 70933db86aabSstevel ptr = ptr->next; 70943db86aabSstevel } 70953db86aabSstevel } 70963db86aabSstevel 70973db86aabSstevel ptr = cl_data; 70983db86aabSstevel while (ptr != NULL) { 70993db86aabSstevel ptr->flags &= ~done_flag; 71003db86aabSstevel ptr = ptr->next; 71013db86aabSstevel } 71023db86aabSstevel } 71033db86aabSstevel 71043db86aabSstevel static int 71053db86aabSstevel syshw_open(dev_t *dev, int flag, int otyp, cred_t *cred) 71063db86aabSstevel { 71073db86aabSstevel _NOTE(ARGUNUSED(dev, flag, cred)) 71083db86aabSstevel 71093db86aabSstevel if (otyp != OTYP_CHR) 71103db86aabSstevel return (EINVAL); 71113db86aabSstevel 71123db86aabSstevel return (0); 71133db86aabSstevel } 71143db86aabSstevel 71153db86aabSstevel static int 71163db86aabSstevel syshw_close(dev_t dev, int flag, int otyp, cred_t *cred) 71173db86aabSstevel { 71183db86aabSstevel _NOTE(ARGUNUSED(dev, flag, otyp, cred)) 71193db86aabSstevel 71203db86aabSstevel return (0); 71213db86aabSstevel } 71223db86aabSstevel 71233db86aabSstevel /* 71243db86aabSstevel * Add a client to the list of interested processes 71253db86aabSstevel */ 71263db86aabSstevel static void 71273db86aabSstevel add_client(client_data *new) 71283db86aabSstevel { 71293db86aabSstevel client_data * ptr; 71303db86aabSstevel 71313db86aabSstevel n_clients++; 71323db86aabSstevel if (cl_data == NULL) { 71333db86aabSstevel cl_data = new; 71343db86aabSstevel return; 71353db86aabSstevel } 71363db86aabSstevel 71373db86aabSstevel ptr = cl_data; 71383db86aabSstevel while ((ptr->next != NULL) && (ptr->priority <= new->priority)) 71393db86aabSstevel ptr = ptr->next; 71403db86aabSstevel 71413db86aabSstevel if (ptr == cl_data) { 71423db86aabSstevel /* at head of the list */ 71433db86aabSstevel cl_data = new; 71443db86aabSstevel new->next = ptr; 71453db86aabSstevel new->prev = NULL; 71463db86aabSstevel if (ptr != NULL) 71473db86aabSstevel ptr->prev = new; 71483db86aabSstevel } else { 71493db86aabSstevel /* somewhere else in the list - insert after */ 71503db86aabSstevel new->next = ptr->next; 71513db86aabSstevel ptr->next = new; 71523db86aabSstevel new->prev = ptr; 71533db86aabSstevel if (new->next != NULL) 71543db86aabSstevel (new->next)->prev = new; 71553db86aabSstevel } 71563db86aabSstevel } 71573db86aabSstevel 71583db86aabSstevel /* 71593db86aabSstevel * Locate a client data structure in the client list by looking for a PID match. 71603db86aabSstevel */ 71613db86aabSstevel static client_data * 71623db86aabSstevel locate_client(pid_t pid) 71633db86aabSstevel { 71643db86aabSstevel client_data * ptr = cl_data; 71653db86aabSstevel 71663db86aabSstevel while ((ptr != NULL) && (ptr->pid != pid)) 71673db86aabSstevel ptr = ptr->next; 71683db86aabSstevel 71693db86aabSstevel return (ptr); 71703db86aabSstevel } 71713db86aabSstevel 71723db86aabSstevel /* 71733db86aabSstevel * Remove a client record from the client list 71743db86aabSstevel */ 71753db86aabSstevel static void 71763db86aabSstevel delete_client(pid_t pid) 71773db86aabSstevel { 71783db86aabSstevel client_data * ptr; 71793db86aabSstevel 71803db86aabSstevel ptr = locate_client(pid); 71813db86aabSstevel if (ptr == NULL) 71823db86aabSstevel return; /* hmmm!! */ 71833db86aabSstevel 71843db86aabSstevel n_clients--; 71853db86aabSstevel 71863db86aabSstevel if (ptr == cl_data) { 71873db86aabSstevel /* remove the head of the list */ 71883db86aabSstevel cl_data = ptr->next; 71893db86aabSstevel } 71903db86aabSstevel if (ptr->prev != NULL) 71913db86aabSstevel (ptr->prev)->next = ptr->next; 71923db86aabSstevel if (ptr->next != NULL) 71933db86aabSstevel (ptr->next)->prev = ptr->prev; 71943db86aabSstevel 71953db86aabSstevel kmem_free(ptr, sizeof (client_data)); 71963db86aabSstevel } 71973db86aabSstevel 71983db86aabSstevel static void 71993db86aabSstevel unregister_event_client() 72003db86aabSstevel { 72013db86aabSstevel pcic_mutex_enter(&client_mtx); 72023db86aabSstevel delete_client(ddi_get_pid()); 72033db86aabSstevel pcic_mutex_exit(&client_mtx); 72043db86aabSstevel } 72053db86aabSstevel 72063db86aabSstevel static int 72073db86aabSstevel register_event_client(client_data *u_client) 72083db86aabSstevel { 72093db86aabSstevel int error; 72103db86aabSstevel client_data * client; 72113db86aabSstevel 72123db86aabSstevel pcic_mutex_enter(&client_mtx); 72133db86aabSstevel client = locate_client(ddi_get_pid()); 72143db86aabSstevel if (client) { 72153db86aabSstevel /* 72163db86aabSstevel * we are re-registering ourself 72173db86aabSstevel * so we delete the previous entry 72183db86aabSstevel */ 72193db86aabSstevel delete_client(ddi_get_pid()); 72203db86aabSstevel } 72213db86aabSstevel 72223db86aabSstevel client = (client_data *)kmem_alloc(sizeof (client_data), KM_SLEEP); 72233db86aabSstevel 72243db86aabSstevel if (client) { 72253db86aabSstevel client->pid = ddi_get_pid(); 72263db86aabSstevel client->priority = u_client->priority; 72273db86aabSstevel client->flags = u_client->flags & NCE_EVENT_MASK; 72283db86aabSstevel client->events = 0; 72293db86aabSstevel client->event_sig = u_client->event_sig; 72303db86aabSstevel client->next = NULL; 72313db86aabSstevel client->prev = NULL; 72323db86aabSstevel add_client(client); 72333db86aabSstevel error = 0; 72343db86aabSstevel } else 72353db86aabSstevel error = EIO; 72363db86aabSstevel 72373db86aabSstevel pcic_mutex_exit(&client_mtx); 72383db86aabSstevel return (error); 72393db86aabSstevel } 72403db86aabSstevel 72413db86aabSstevel /* 72423db86aabSstevel * Read the currently pending event flags for the process in question 72433db86aabSstevel */ 72443db86aabSstevel static int 72453db86aabSstevel check_events_pending(caddr_t data) 72463db86aabSstevel { 72473db86aabSstevel client_data * client; 72483db86aabSstevel int error = 0; 72493db86aabSstevel 72503db86aabSstevel pcic_mutex_enter(&client_mtx); 72513db86aabSstevel client = locate_client(ddi_get_pid()); 72523db86aabSstevel if (client) { 72533db86aabSstevel if (copyout((caddr_t)&client->events, data, sizeof (int))) 72543db86aabSstevel error = EFAULT; 72553db86aabSstevel else 72563db86aabSstevel client->events = 0; 72573db86aabSstevel } else 72583db86aabSstevel error = EINVAL; 72593db86aabSstevel 72603db86aabSstevel pcic_mutex_exit(&client_mtx); 72613db86aabSstevel return (error); 72623db86aabSstevel } 72633db86aabSstevel 72643db86aabSstevel 72653db86aabSstevel #define MAXITEMS 8 72663db86aabSstevel static syshw_t *syshw_map[MAXITEMS]; 72673db86aabSstevel static void (*syshw_getfuncs[MAXITEMS])(syshw_t *, void *); 72683db86aabSstevel static void *syshw_getfunc_args[MAXITEMS]; 72693db86aabSstevel static int nsyshw_items = 0; 72703db86aabSstevel #define NSYSHW_ITEMS nsyshw_items 72713db86aabSstevel 72723db86aabSstevel static uint32_t 72733db86aabSstevel syshw_add2map(syshw_t *item, void (*getfunc)(syshw_t *, void *), void *getarg) 72743db86aabSstevel { 72753db86aabSstevel uint32_t rval = (1 << nsyshw_items); 72763db86aabSstevel if (nsyshw_items == MAXITEMS) 72773db86aabSstevel return (0); 72783db86aabSstevel item->hw_id = nsyshw_items; 72793db86aabSstevel syshw_map[nsyshw_items] = item; 72803db86aabSstevel syshw_getfuncs[nsyshw_items] = getfunc; 72813db86aabSstevel syshw_getfunc_args[nsyshw_items] = getarg; 72823db86aabSstevel nsyshw_items++; 72833db86aabSstevel return (rval); 72843db86aabSstevel } 72853db86aabSstevel 72863db86aabSstevel static int 72873db86aabSstevel syshw_ioctl(dev_t dev, int cmd, intptr_t ioctldata, int mode, 72883db86aabSstevel cred_t *cred, int *rval) 72893db86aabSstevel { 72903db86aabSstevel caddr_t data = (caddr_t)ioctldata; 72913db86aabSstevel syshw_t sh; 72923db86aabSstevel hwev_t hwev; 72933db86aabSstevel client_data dummy_client; 72943db86aabSstevel int rc = 0, i; 72953db86aabSstevel 72963db86aabSstevel _NOTE(ARGUNUSED(dev, mode, cred, rval)) 72973db86aabSstevel 72983db86aabSstevel switch (cmd) { 72993db86aabSstevel default: 73003db86aabSstevel rc = EINVAL; 73013db86aabSstevel break; 73023db86aabSstevel 73033db86aabSstevel case SYSHW_GET_ITEM: 73043db86aabSstevel case SYSHW_GET_ITEM_MAXVALUES: 73053db86aabSstevel if (copyin(data, (caddr_t)&sh, sizeof (sh))) { 73063db86aabSstevel rc = EFAULT; 73073db86aabSstevel break; 73083db86aabSstevel } 73093db86aabSstevel 73103db86aabSstevel if (sh.hw_id >= NSYSHW_ITEMS) { 73113db86aabSstevel rc = EINVAL; 73123db86aabSstevel break; 73133db86aabSstevel } 73143db86aabSstevel 73153db86aabSstevel sh = *syshw_map[sh.hw_id]; 73163db86aabSstevel if (!sh.id_string[0]) { 73173db86aabSstevel rc = ENOTTY; 73183db86aabSstevel break; 73193db86aabSstevel } 73203db86aabSstevel if (cmd == SYSHW_GET_ITEM) { 73213db86aabSstevel if (syshw_getfuncs[sh.hw_id]) 73223db86aabSstevel syshw_getfuncs[sh.hw_id](&sh, 73233db86aabSstevel syshw_getfunc_args[sh.hw_id]); 73243db86aabSstevel else 73253db86aabSstevel rc = ENOTTY; 73263db86aabSstevel } 73273db86aabSstevel 73283db86aabSstevel if (copyout((caddr_t)&sh, data, sizeof (sh))) { 73293db86aabSstevel rc = EFAULT; 73303db86aabSstevel break; 73313db86aabSstevel } 73323db86aabSstevel break; 73333db86aabSstevel 73343db86aabSstevel case SYSHW_SET_ITEM: 73353db86aabSstevel if (copyin(data, (caddr_t)&sh, sizeof (sh))) { 73363db86aabSstevel rc = EFAULT; 73373db86aabSstevel break; 73383db86aabSstevel } 73393db86aabSstevel 73403db86aabSstevel if (sh.hw_id >= NSYSHW_ITEMS || 73413db86aabSstevel !syshw_map[sh.hw_id]->id_string[0] || 73423db86aabSstevel !(syshw_map[sh.hw_id]->capabilities & 73433db86aabSstevel (SYSHW_STATE_MODIFY | SYSHW_VAL0_MODIFY | 73443db86aabSstevel SYSHW_VAL1_MODIFY | SYSHW_VAL2_MODIFY | 73453db86aabSstevel SYSHW_VAL3_MODIFY))) { 73463db86aabSstevel rc = EINVAL; 73473db86aabSstevel break; 73483db86aabSstevel } 73493db86aabSstevel 73503db86aabSstevel switch (sh.hw_id) { 73513db86aabSstevel default: 73523db86aabSstevel rc = EINVAL; 73533db86aabSstevel break; 73543db86aabSstevel } 73553db86aabSstevel break; 73563db86aabSstevel 73573db86aabSstevel case SYSHW_EVREG: 73583db86aabSstevel if (copyin(data, (caddr_t)&hwev, sizeof (hwev))) { 73593db86aabSstevel rc = EFAULT; 73603db86aabSstevel break; 73613db86aabSstevel } 73623db86aabSstevel 73633db86aabSstevel for (i = 0; i < NSYSHW_ITEMS; i++) { 73643db86aabSstevel if (hwev.events & (1 << i) && 73653db86aabSstevel !(syshw_map[i]->capabilities & 73663db86aabSstevel SYSHW_CAN_SIGNAL_CHANGE)) { 73673db86aabSstevel rc = EINVAL; 73683db86aabSstevel break; 73693db86aabSstevel } 73703db86aabSstevel } 73713db86aabSstevel if (hwev.event_sig != SIGUSR1 && hwev.event_sig != SIGUSR2) 73723db86aabSstevel rc = EINVAL; 73733db86aabSstevel 73743db86aabSstevel if (!rc) { 73753db86aabSstevel dummy_client.priority = 100; 73763db86aabSstevel dummy_client.flags = hwev.events; 73773db86aabSstevel dummy_client.event_sig = hwev.event_sig; 73783db86aabSstevel rc = register_event_client(&dummy_client); 73793db86aabSstevel } 73803db86aabSstevel break; 73813db86aabSstevel 73823db86aabSstevel case SYSHW_EVUNREG: 73833db86aabSstevel unregister_event_client(); 73843db86aabSstevel break; 73853db86aabSstevel 73863db86aabSstevel case SYSHW_CHKEV: 73873db86aabSstevel rc = check_events_pending(data); 73883db86aabSstevel break; 73893db86aabSstevel } 73903db86aabSstevel return (rc); 73913db86aabSstevel } 7392