10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51458Syq193411 * Common Development and Distribution License (the "License").
61458Syq193411 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
2112733SRaymond.Chen@Sun.COM
220Sstevel@tonic-gate /*
2312733SRaymond.Chen@Sun.COM * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * EHCI Host Controller Driver (EHCI)
280Sstevel@tonic-gate *
290Sstevel@tonic-gate * The EHCI driver is a software driver which interfaces to the Universal
300Sstevel@tonic-gate * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
310Sstevel@tonic-gate * the Host Controller is defined by the EHCI Host Controller Interface.
320Sstevel@tonic-gate *
330Sstevel@tonic-gate * This module contains the main EHCI driver code which handles all USB
340Sstevel@tonic-gate * transfers, bandwidth allocations and other general functionalities.
350Sstevel@tonic-gate */
360Sstevel@tonic-gate
370Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehcid.h>
380Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_isoch.h>
390Sstevel@tonic-gate #include <sys/usb/hcd/ehci/ehci_xfer.h>
400Sstevel@tonic-gate
41965Sgovinda /*
42965Sgovinda * EHCI MSI tunable:
43965Sgovinda *
44965Sgovinda * By default MSI is enabled on all supported platforms except for the
45965Sgovinda * EHCI controller of ULI1575 South bridge.
46965Sgovinda */
47965Sgovinda boolean_t ehci_enable_msi = B_TRUE;
48965Sgovinda
490Sstevel@tonic-gate /* Pointer to the state structure */
500Sstevel@tonic-gate extern void *ehci_statep;
510Sstevel@tonic-gate
520Sstevel@tonic-gate extern void ehci_handle_endpoint_reclaimation(ehci_state_t *);
530Sstevel@tonic-gate
540Sstevel@tonic-gate extern uint_t ehci_vt62x2_workaround;
555295Srandyf extern int force_ehci_off;
560Sstevel@tonic-gate
570Sstevel@tonic-gate /* Adjustable variables for the size of the pools */
580Sstevel@tonic-gate int ehci_qh_pool_size = EHCI_QH_POOL_SIZE;
590Sstevel@tonic-gate int ehci_qtd_pool_size = EHCI_QTD_POOL_SIZE;
600Sstevel@tonic-gate
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate * Initialize the values which the order of 32ms intr qh are executed
630Sstevel@tonic-gate * by the host controller in the lattice tree.
640Sstevel@tonic-gate */
650Sstevel@tonic-gate static uchar_t ehci_index[EHCI_NUM_INTR_QH_LISTS] =
660Sstevel@tonic-gate {0x00, 0x10, 0x08, 0x18,
670Sstevel@tonic-gate 0x04, 0x14, 0x0c, 0x1c,
680Sstevel@tonic-gate 0x02, 0x12, 0x0a, 0x1a,
690Sstevel@tonic-gate 0x06, 0x16, 0x0e, 0x1e,
700Sstevel@tonic-gate 0x01, 0x11, 0x09, 0x19,
710Sstevel@tonic-gate 0x05, 0x15, 0x0d, 0x1d,
720Sstevel@tonic-gate 0x03, 0x13, 0x0b, 0x1b,
730Sstevel@tonic-gate 0x07, 0x17, 0x0f, 0x1f};
740Sstevel@tonic-gate
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate * Initialize the values which are used to calculate start split mask
770Sstevel@tonic-gate * for the low/full/high speed interrupt and isochronous endpoints.
780Sstevel@tonic-gate */
790Sstevel@tonic-gate static uint_t ehci_start_split_mask[15] = {
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate * For high/full/low speed usb devices. For high speed
820Sstevel@tonic-gate * device with polling interval greater than or equal
830Sstevel@tonic-gate * to 8us (125us).
840Sstevel@tonic-gate */
850Sstevel@tonic-gate 0x01, /* 00000001 */
860Sstevel@tonic-gate 0x02, /* 00000010 */
870Sstevel@tonic-gate 0x04, /* 00000100 */
880Sstevel@tonic-gate 0x08, /* 00001000 */
890Sstevel@tonic-gate 0x10, /* 00010000 */
900Sstevel@tonic-gate 0x20, /* 00100000 */
910Sstevel@tonic-gate 0x40, /* 01000000 */
920Sstevel@tonic-gate 0x80, /* 10000000 */
930Sstevel@tonic-gate
940Sstevel@tonic-gate /* Only for high speed devices with polling interval 4us */
950Sstevel@tonic-gate 0x11, /* 00010001 */
960Sstevel@tonic-gate 0x22, /* 00100010 */
970Sstevel@tonic-gate 0x44, /* 01000100 */
980Sstevel@tonic-gate 0x88, /* 10001000 */
990Sstevel@tonic-gate
1000Sstevel@tonic-gate /* Only for high speed devices with polling interval 2us */
1010Sstevel@tonic-gate 0x55, /* 01010101 */
1020Sstevel@tonic-gate 0xaa, /* 10101010 */
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate /* Only for high speed devices with polling interval 1us */
1050Sstevel@tonic-gate 0xff /* 11111111 */
1060Sstevel@tonic-gate };
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate * Initialize the values which are used to calculate complete split mask
1100Sstevel@tonic-gate * for the low/full speed interrupt and isochronous endpoints.
1110Sstevel@tonic-gate */
1120Sstevel@tonic-gate static uint_t ehci_intr_complete_split_mask[7] = {
1130Sstevel@tonic-gate /* Only full/low speed devices */
1140Sstevel@tonic-gate 0x1c, /* 00011100 */
1150Sstevel@tonic-gate 0x38, /* 00111000 */
1160Sstevel@tonic-gate 0x70, /* 01110000 */
1170Sstevel@tonic-gate 0xe0, /* 11100000 */
1180Sstevel@tonic-gate 0x00, /* Need FSTN feature */
1190Sstevel@tonic-gate 0x00, /* Need FSTN feature */
1200Sstevel@tonic-gate 0x00 /* Need FSTN feature */
1210Sstevel@tonic-gate };
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate * EHCI Internal Function Prototypes
1260Sstevel@tonic-gate */
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate /* Host Controller Driver (HCD) initialization functions */
1290Sstevel@tonic-gate void ehci_set_dma_attributes(ehci_state_t *ehcip);
1300Sstevel@tonic-gate int ehci_allocate_pools(ehci_state_t *ehcip);
1310Sstevel@tonic-gate void ehci_decode_ddi_dma_addr_bind_handle_result(
1320Sstevel@tonic-gate ehci_state_t *ehcip,
1330Sstevel@tonic-gate int result);
1340Sstevel@tonic-gate int ehci_map_regs(ehci_state_t *ehcip);
1350Sstevel@tonic-gate int ehci_register_intrs_and_init_mutex(
1360Sstevel@tonic-gate ehci_state_t *ehcip);
137965Sgovinda static int ehci_add_intrs(ehci_state_t *ehcip,
138965Sgovinda int intr_type);
1391458Syq193411 int ehci_init_ctlr(ehci_state_t *ehcip,
1401458Syq193411 int init_type);
1410Sstevel@tonic-gate static int ehci_take_control(ehci_state_t *ehcip);
1420Sstevel@tonic-gate static int ehci_init_periodic_frame_lst_table(
1430Sstevel@tonic-gate ehci_state_t *ehcip);
1440Sstevel@tonic-gate static void ehci_build_interrupt_lattice(
1450Sstevel@tonic-gate ehci_state_t *ehcip);
1460Sstevel@tonic-gate usba_hcdi_ops_t *ehci_alloc_hcdi_ops(ehci_state_t *ehcip);
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate /* Host Controller Driver (HCD) deinitialization functions */
1490Sstevel@tonic-gate int ehci_cleanup(ehci_state_t *ehcip);
150965Sgovinda static void ehci_rem_intrs(ehci_state_t *ehcip);
1510Sstevel@tonic-gate int ehci_cpr_suspend(ehci_state_t *ehcip);
1520Sstevel@tonic-gate int ehci_cpr_resume(ehci_state_t *ehcip);
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate /* Bandwidth Allocation functions */
1550Sstevel@tonic-gate int ehci_allocate_bandwidth(ehci_state_t *ehcip,
1560Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1570Sstevel@tonic-gate uint_t *pnode,
1580Sstevel@tonic-gate uchar_t *smask,
1590Sstevel@tonic-gate uchar_t *cmask);
1600Sstevel@tonic-gate static int ehci_allocate_high_speed_bandwidth(
1610Sstevel@tonic-gate ehci_state_t *ehcip,
1620Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1630Sstevel@tonic-gate uint_t *hnode,
1640Sstevel@tonic-gate uchar_t *smask,
1650Sstevel@tonic-gate uchar_t *cmask);
1660Sstevel@tonic-gate static int ehci_allocate_classic_tt_bandwidth(
1670Sstevel@tonic-gate ehci_state_t *ehcip,
1680Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1690Sstevel@tonic-gate uint_t pnode);
1700Sstevel@tonic-gate void ehci_deallocate_bandwidth(ehci_state_t *ehcip,
1710Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1720Sstevel@tonic-gate uint_t pnode,
1730Sstevel@tonic-gate uchar_t smask,
1740Sstevel@tonic-gate uchar_t cmask);
1750Sstevel@tonic-gate static void ehci_deallocate_high_speed_bandwidth(
1760Sstevel@tonic-gate ehci_state_t *ehcip,
1770Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1780Sstevel@tonic-gate uint_t hnode,
1790Sstevel@tonic-gate uchar_t smask,
1800Sstevel@tonic-gate uchar_t cmask);
1810Sstevel@tonic-gate static void ehci_deallocate_classic_tt_bandwidth(
1820Sstevel@tonic-gate ehci_state_t *ehcip,
1830Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
1840Sstevel@tonic-gate uint_t pnode);
1850Sstevel@tonic-gate static int ehci_compute_high_speed_bandwidth(
1860Sstevel@tonic-gate ehci_state_t *ehcip,
1870Sstevel@tonic-gate usb_ep_descr_t *endpoint,
1880Sstevel@tonic-gate usb_port_status_t port_status,
1890Sstevel@tonic-gate uint_t *sbandwidth,
1900Sstevel@tonic-gate uint_t *cbandwidth);
1910Sstevel@tonic-gate static int ehci_compute_classic_bandwidth(
1920Sstevel@tonic-gate usb_ep_descr_t *endpoint,
1930Sstevel@tonic-gate usb_port_status_t port_status,
1940Sstevel@tonic-gate uint_t *bandwidth);
1950Sstevel@tonic-gate int ehci_adjust_polling_interval(
1960Sstevel@tonic-gate ehci_state_t *ehcip,
1970Sstevel@tonic-gate usb_ep_descr_t *endpoint,
1980Sstevel@tonic-gate usb_port_status_t port_status);
1990Sstevel@tonic-gate static int ehci_adjust_high_speed_polling_interval(
2000Sstevel@tonic-gate ehci_state_t *ehcip,
2010Sstevel@tonic-gate usb_ep_descr_t *endpoint);
2020Sstevel@tonic-gate static uint_t ehci_lattice_height(uint_t interval);
2030Sstevel@tonic-gate static uint_t ehci_lattice_parent(uint_t node);
2040Sstevel@tonic-gate static uint_t ehci_find_periodic_node(
2050Sstevel@tonic-gate uint_t leaf,
2060Sstevel@tonic-gate int interval);
2070Sstevel@tonic-gate static uint_t ehci_leftmost_leaf(uint_t node,
2080Sstevel@tonic-gate uint_t height);
2090Sstevel@tonic-gate static uint_t ehci_pow_2(uint_t x);
2100Sstevel@tonic-gate static uint_t ehci_log_2(uint_t x);
2110Sstevel@tonic-gate static int ehci_find_bestfit_hs_mask(
2120Sstevel@tonic-gate ehci_state_t *ehcip,
2130Sstevel@tonic-gate uchar_t *smask,
2140Sstevel@tonic-gate uint_t *pnode,
2150Sstevel@tonic-gate usb_ep_descr_t *endpoint,
2160Sstevel@tonic-gate uint_t bandwidth,
2170Sstevel@tonic-gate int interval);
2180Sstevel@tonic-gate static int ehci_find_bestfit_ls_intr_mask(
2190Sstevel@tonic-gate ehci_state_t *ehcip,
2200Sstevel@tonic-gate uchar_t *smask,
2210Sstevel@tonic-gate uchar_t *cmask,
2220Sstevel@tonic-gate uint_t *pnode,
2230Sstevel@tonic-gate uint_t sbandwidth,
2240Sstevel@tonic-gate uint_t cbandwidth,
2250Sstevel@tonic-gate int interval);
2260Sstevel@tonic-gate static int ehci_find_bestfit_sitd_in_mask(
2270Sstevel@tonic-gate ehci_state_t *ehcip,
2280Sstevel@tonic-gate uchar_t *smask,
2290Sstevel@tonic-gate uchar_t *cmask,
2300Sstevel@tonic-gate uint_t *pnode,
2310Sstevel@tonic-gate uint_t sbandwidth,
2320Sstevel@tonic-gate uint_t cbandwidth,
2330Sstevel@tonic-gate int interval);
2340Sstevel@tonic-gate static int ehci_find_bestfit_sitd_out_mask(
2350Sstevel@tonic-gate ehci_state_t *ehcip,
2360Sstevel@tonic-gate uchar_t *smask,
2370Sstevel@tonic-gate uint_t *pnode,
2380Sstevel@tonic-gate uint_t sbandwidth,
2390Sstevel@tonic-gate int interval);
2400Sstevel@tonic-gate static uint_t ehci_calculate_bw_availability_mask(
2410Sstevel@tonic-gate ehci_state_t *ehcip,
2420Sstevel@tonic-gate uint_t bandwidth,
2430Sstevel@tonic-gate int leaf,
2440Sstevel@tonic-gate int leaf_count,
2450Sstevel@tonic-gate uchar_t *bw_mask);
2460Sstevel@tonic-gate static void ehci_update_bw_availability(
2470Sstevel@tonic-gate ehci_state_t *ehcip,
2480Sstevel@tonic-gate int bandwidth,
2490Sstevel@tonic-gate int leftmost_leaf,
2500Sstevel@tonic-gate int leaf_count,
2510Sstevel@tonic-gate uchar_t mask);
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate /* Miscellaneous functions */
2540Sstevel@tonic-gate ehci_state_t *ehci_obtain_state(
2550Sstevel@tonic-gate dev_info_t *dip);
2560Sstevel@tonic-gate int ehci_state_is_operational(
2570Sstevel@tonic-gate ehci_state_t *ehcip);
2580Sstevel@tonic-gate int ehci_do_soft_reset(
2590Sstevel@tonic-gate ehci_state_t *ehcip);
2600Sstevel@tonic-gate usb_req_attrs_t ehci_get_xfer_attrs(ehci_state_t *ehcip,
2610Sstevel@tonic-gate ehci_pipe_private_t *pp,
2620Sstevel@tonic-gate ehci_trans_wrapper_t *tw);
2630Sstevel@tonic-gate usb_frame_number_t ehci_get_current_frame_number(
2640Sstevel@tonic-gate ehci_state_t *ehcip);
2650Sstevel@tonic-gate static void ehci_cpr_cleanup(
2660Sstevel@tonic-gate ehci_state_t *ehcip);
2670Sstevel@tonic-gate int ehci_wait_for_sof(
2680Sstevel@tonic-gate ehci_state_t *ehcip);
2690Sstevel@tonic-gate void ehci_toggle_scheduler(
2700Sstevel@tonic-gate ehci_state_t *ehcip);
2710Sstevel@tonic-gate void ehci_print_caps(ehci_state_t *ehcip);
2720Sstevel@tonic-gate void ehci_print_regs(ehci_state_t *ehcip);
2730Sstevel@tonic-gate void ehci_print_qh(ehci_state_t *ehcip,
2740Sstevel@tonic-gate ehci_qh_t *qh);
2750Sstevel@tonic-gate void ehci_print_qtd(ehci_state_t *ehcip,
2760Sstevel@tonic-gate ehci_qtd_t *qtd);
2770Sstevel@tonic-gate void ehci_create_stats(ehci_state_t *ehcip);
2780Sstevel@tonic-gate void ehci_destroy_stats(ehci_state_t *ehcip);
2790Sstevel@tonic-gate void ehci_do_intrs_stats(ehci_state_t *ehcip,
2800Sstevel@tonic-gate int val);
2810Sstevel@tonic-gate void ehci_do_byte_stats(ehci_state_t *ehcip,
2820Sstevel@tonic-gate size_t len,
2830Sstevel@tonic-gate uint8_t attr,
2840Sstevel@tonic-gate uint8_t addr);
2850Sstevel@tonic-gate
2860Sstevel@tonic-gate /*
287880Sfrits * check if this ehci controller can support PM
288880Sfrits */
289880Sfrits int
ehci_hcdi_pm_support(dev_info_t * dip)290880Sfrits ehci_hcdi_pm_support(dev_info_t *dip)
291880Sfrits {
292880Sfrits ehci_state_t *ehcip = ddi_get_soft_state(ehci_statep,
2935767Slc152243 ddi_get_instance(dip));
294880Sfrits
295880Sfrits if (((ehcip->ehci_vendor_id == PCI_VENDOR_NEC_COMBO) &&
296880Sfrits (ehcip->ehci_device_id == PCI_DEVICE_NEC_COMBO)) ||
297880Sfrits
298880Sfrits ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
299880Sfrits (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) ||
300880Sfrits
301880Sfrits (ehcip->ehci_vendor_id == PCI_VENDOR_VIA)) {
302880Sfrits
303880Sfrits return (USB_SUCCESS);
304880Sfrits }
305880Sfrits
306880Sfrits return (USB_FAILURE);
307880Sfrits }
308880Sfrits
3097293Sbc224572 void
ehci_dma_attr_workaround(ehci_state_t * ehcip)3107293Sbc224572 ehci_dma_attr_workaround(ehci_state_t *ehcip)
3117293Sbc224572 {
3127293Sbc224572 /*
3137293Sbc224572 * Some Nvidia chips can not handle qh dma address above 2G.
3147293Sbc224572 * The bit 31 of the dma address might be omitted and it will
3157293Sbc224572 * cause system crash or other unpredicable result. So force
3167293Sbc224572 * the dma address allocated below 2G to make ehci work.
3177293Sbc224572 */
3187293Sbc224572 if (PCI_VENDOR_NVIDIA == ehcip->ehci_vendor_id) {
3197293Sbc224572 switch (ehcip->ehci_device_id) {
3207293Sbc224572 case PCI_DEVICE_NVIDIA_CK804:
3217669SBinzi.Cao@Sun.COM case PCI_DEVICE_NVIDIA_MCP04:
3227293Sbc224572 USB_DPRINTF_L2(PRINT_MASK_ATTA,
3237293Sbc224572 ehcip->ehci_log_hdl,
3247293Sbc224572 "ehci_dma_attr_workaround: NVIDIA dma "
3257293Sbc224572 "workaround enabled, force dma address "
3267293Sbc224572 "to be allocated below 2G");
3277293Sbc224572 ehcip->ehci_dma_attr.dma_attr_addr_hi =
3287293Sbc224572 0x7fffffffull;
3297293Sbc224572 break;
3307293Sbc224572 default:
3317293Sbc224572 break;
3327293Sbc224572
3337293Sbc224572 }
3347293Sbc224572 }
3357293Sbc224572 }
336880Sfrits
337880Sfrits /*
3380Sstevel@tonic-gate * Host Controller Driver (HCD) initialization functions
3390Sstevel@tonic-gate */
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate /*
3420Sstevel@tonic-gate * ehci_set_dma_attributes:
3430Sstevel@tonic-gate *
3440Sstevel@tonic-gate * Set the limits in the DMA attributes structure. Most of the values used
3450Sstevel@tonic-gate * in the DMA limit structures are the default values as specified by the
3460Sstevel@tonic-gate * Writing PCI device drivers document.
3470Sstevel@tonic-gate */
3480Sstevel@tonic-gate void
ehci_set_dma_attributes(ehci_state_t * ehcip)3490Sstevel@tonic-gate ehci_set_dma_attributes(ehci_state_t *ehcip)
3500Sstevel@tonic-gate {
3510Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3520Sstevel@tonic-gate "ehci_set_dma_attributes:");
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /* Initialize the DMA attributes */
3550Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_version = DMA_ATTR_V0;
3560Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_addr_lo = 0x00000000ull;
3570Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_addr_hi = 0xfffffffeull;
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate /* 32 bit addressing */
3600Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_count_max = EHCI_DMA_ATTR_COUNT_MAX;
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate /* Byte alignment */
3630Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate * Since PCI specification is byte alignment, the
3670Sstevel@tonic-gate * burst size field should be set to 1 for PCI devices.
3680Sstevel@tonic-gate */
3690Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_burstsizes = 0x1;
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_minxfer = 0x1;
3720Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_maxxfer = EHCI_DMA_ATTR_MAX_XFER;
3730Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_seg = 0xffffffffull;
3740Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_sgllen = 1;
3750Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_granular = EHCI_DMA_ATTR_GRANULAR;
3760Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_flags = 0;
3777293Sbc224572 ehci_dma_attr_workaround(ehcip);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate * ehci_allocate_pools:
3830Sstevel@tonic-gate *
3840Sstevel@tonic-gate * Allocate the system memory for the Endpoint Descriptor (QH) and for the
3850Sstevel@tonic-gate * Transfer Descriptor (QTD) pools. Both QH and QTD structures must be aligned
3860Sstevel@tonic-gate * to a 16 byte boundary.
3870Sstevel@tonic-gate */
3880Sstevel@tonic-gate int
ehci_allocate_pools(ehci_state_t * ehcip)3890Sstevel@tonic-gate ehci_allocate_pools(ehci_state_t *ehcip)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr;
3920Sstevel@tonic-gate size_t real_length;
3930Sstevel@tonic-gate int result;
3940Sstevel@tonic-gate uint_t ccount;
3950Sstevel@tonic-gate int i;
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
3980Sstevel@tonic-gate "ehci_allocate_pools:");
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate /* The host controller will be little endian */
4010Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4020Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
4030Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4040Sstevel@tonic-gate
4050Sstevel@tonic-gate /* Byte alignment */
4060Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_TD_QH_ALIGNMENT;
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate /* Allocate the QTD pool DMA handle */
4090Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr,
4105767Slc152243 DDI_DMA_SLEEP, 0,
4115767Slc152243 &ehcip->ehci_qtd_pool_dma_handle) != DDI_SUCCESS) {
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate goto failure;
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate /* Allocate the memory for the QTD pool */
4170Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_qtd_pool_dma_handle,
4185767Slc152243 ehci_qtd_pool_size * sizeof (ehci_qtd_t),
4195767Slc152243 &dev_attr,
4205767Slc152243 DDI_DMA_CONSISTENT,
4215767Slc152243 DDI_DMA_SLEEP,
4225767Slc152243 0,
4235767Slc152243 (caddr_t *)&ehcip->ehci_qtd_pool_addr,
4245767Slc152243 &real_length,
4255767Slc152243 &ehcip->ehci_qtd_pool_mem_handle)) {
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate goto failure;
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate /* Map the QTD pool into the I/O address space */
4310Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(
4325767Slc152243 ehcip->ehci_qtd_pool_dma_handle,
4335767Slc152243 NULL,
4345767Slc152243 (caddr_t)ehcip->ehci_qtd_pool_addr,
4355767Slc152243 real_length,
4365767Slc152243 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
4375767Slc152243 DDI_DMA_SLEEP,
4385767Slc152243 NULL,
4395767Slc152243 &ehcip->ehci_qtd_pool_cookie,
4405767Slc152243 &ccount);
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate bzero((void *)ehcip->ehci_qtd_pool_addr,
4435767Slc152243 ehci_qtd_pool_size * sizeof (ehci_qtd_t));
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate /* Process the result */
4460Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) {
4470Sstevel@tonic-gate /* The cookie count should be 1 */
4480Sstevel@tonic-gate if (ccount != 1) {
4490Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4500Sstevel@tonic-gate "ehci_allocate_pools: More than 1 cookie");
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate goto failure;
4530Sstevel@tonic-gate }
4540Sstevel@tonic-gate } else {
4550Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4560Sstevel@tonic-gate "ehci_allocate_pools: Result = %d", result);
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate goto failure;
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate /*
4640Sstevel@tonic-gate * DMA addresses for QTD pools are bound
4650Sstevel@tonic-gate */
4660Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_QTD_POOL_BOUND;
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate /* Initialize the QTD pool */
4690Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) {
4700Sstevel@tonic-gate Set_QTD(ehcip->ehci_qtd_pool_addr[i].
4710Sstevel@tonic-gate qtd_state, EHCI_QTD_FREE);
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate /* Allocate the QTD pool DMA handle */
4750Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip,
4765767Slc152243 &ehcip->ehci_dma_attr,
4775767Slc152243 DDI_DMA_SLEEP,
4785767Slc152243 0,
4795767Slc152243 &ehcip->ehci_qh_pool_dma_handle) != DDI_SUCCESS) {
4807293Sbc224572 USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4817293Sbc224572 "ehci_allocate_pools: ddi_dma_alloc_handle failed");
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate goto failure;
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate /* Allocate the memory for the QH pool */
4870Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_qh_pool_dma_handle,
4885767Slc152243 ehci_qh_pool_size * sizeof (ehci_qh_t),
4895767Slc152243 &dev_attr,
4905767Slc152243 DDI_DMA_CONSISTENT,
4915767Slc152243 DDI_DMA_SLEEP,
4925767Slc152243 0,
4935767Slc152243 (caddr_t *)&ehcip->ehci_qh_pool_addr,
4945767Slc152243 &real_length,
4955767Slc152243 &ehcip->ehci_qh_pool_mem_handle) != DDI_SUCCESS) {
4967293Sbc224572 USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
4977293Sbc224572 "ehci_allocate_pools: ddi_dma_mem_alloc failed");
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate goto failure;
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_qh_pool_dma_handle,
5035767Slc152243 NULL,
5045767Slc152243 (caddr_t)ehcip->ehci_qh_pool_addr,
5055767Slc152243 real_length,
5065767Slc152243 DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
5075767Slc152243 DDI_DMA_SLEEP,
5085767Slc152243 NULL,
5095767Slc152243 &ehcip->ehci_qh_pool_cookie,
5105767Slc152243 &ccount);
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate bzero((void *)ehcip->ehci_qh_pool_addr,
5135767Slc152243 ehci_qh_pool_size * sizeof (ehci_qh_t));
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate /* Process the result */
5160Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) {
5170Sstevel@tonic-gate /* The cookie count should be 1 */
5180Sstevel@tonic-gate if (ccount != 1) {
5190Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
5200Sstevel@tonic-gate "ehci_allocate_pools: More than 1 cookie");
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate goto failure;
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate } else {
5250Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate goto failure;
5280Sstevel@tonic-gate }
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate /*
5310Sstevel@tonic-gate * DMA addresses for QH pools are bound
5320Sstevel@tonic-gate */
5330Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_QH_POOL_BOUND;
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate /* Initialize the QH pool */
5360Sstevel@tonic-gate for (i = 0; i < ehci_qh_pool_size; i ++) {
5370Sstevel@tonic-gate Set_QH(ehcip->ehci_qh_pool_addr[i].qh_state, EHCI_QH_FREE);
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate /* Byte alignment */
5410Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
5420Sstevel@tonic-gate
5430Sstevel@tonic-gate return (DDI_SUCCESS);
5440Sstevel@tonic-gate
5450Sstevel@tonic-gate failure:
5460Sstevel@tonic-gate /* Byte alignment */
5470Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate return (DDI_FAILURE);
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate /*
5540Sstevel@tonic-gate * ehci_decode_ddi_dma_addr_bind_handle_result:
5550Sstevel@tonic-gate *
5560Sstevel@tonic-gate * Process the return values of ddi_dma_addr_bind_handle()
5570Sstevel@tonic-gate */
5580Sstevel@tonic-gate void
ehci_decode_ddi_dma_addr_bind_handle_result(ehci_state_t * ehcip,int result)5590Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(
5600Sstevel@tonic-gate ehci_state_t *ehcip,
5610Sstevel@tonic-gate int result)
5620Sstevel@tonic-gate {
5630Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALLOC, ehcip->ehci_log_hdl,
5640Sstevel@tonic-gate "ehci_decode_ddi_dma_addr_bind_handle_result:");
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate switch (result) {
5670Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP:
5680Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl,
5690Sstevel@tonic-gate "Partial transfers not allowed");
5700Sstevel@tonic-gate break;
5710Sstevel@tonic-gate case DDI_DMA_INUSE:
5720Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl,
5730Sstevel@tonic-gate "Handle is in use");
5740Sstevel@tonic-gate break;
5750Sstevel@tonic-gate case DDI_DMA_NORESOURCES:
5760Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl,
5770Sstevel@tonic-gate "No resources");
5780Sstevel@tonic-gate break;
5790Sstevel@tonic-gate case DDI_DMA_NOMAPPING:
5800Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl,
5810Sstevel@tonic-gate "No mapping");
5820Sstevel@tonic-gate break;
5830Sstevel@tonic-gate case DDI_DMA_TOOBIG:
5840Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl,
5850Sstevel@tonic-gate "Object is too big");
5860Sstevel@tonic-gate break;
5870Sstevel@tonic-gate default:
5880Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ALL, ehcip->ehci_log_hdl,
5890Sstevel@tonic-gate "Unknown dma error");
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate /*
5950Sstevel@tonic-gate * ehci_map_regs:
5960Sstevel@tonic-gate *
5970Sstevel@tonic-gate * The Host Controller (HC) contains a set of on-chip operational registers
5980Sstevel@tonic-gate * and which should be mapped into a non-cacheable portion of the system
5990Sstevel@tonic-gate * addressable space.
6000Sstevel@tonic-gate */
6010Sstevel@tonic-gate int
ehci_map_regs(ehci_state_t * ehcip)6020Sstevel@tonic-gate ehci_map_regs(ehci_state_t *ehcip)
6030Sstevel@tonic-gate {
6040Sstevel@tonic-gate ddi_device_acc_attr_t attr;
6050Sstevel@tonic-gate uint16_t cmd_reg;
6060Sstevel@tonic-gate uint_t length;
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_map_regs:");
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate /* Check to make sure we have memory access */
6110Sstevel@tonic-gate if (pci_config_setup(ehcip->ehci_dip,
6125767Slc152243 &ehcip->ehci_config_handle) != DDI_SUCCESS) {
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6150Sstevel@tonic-gate "ehci_map_regs: Config error");
6160Sstevel@tonic-gate
6170Sstevel@tonic-gate return (DDI_FAILURE);
6180Sstevel@tonic-gate }
6190Sstevel@tonic-gate
6200Sstevel@tonic-gate /* Make sure Memory Access Enable is set */
6210Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM);
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate if (!(cmd_reg & PCI_COMM_MAE)) {
6240Sstevel@tonic-gate
6250Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6260Sstevel@tonic-gate "ehci_map_regs: Memory base address access disabled");
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate return (DDI_FAILURE);
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate /* The host controller will be little endian */
6320Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
6330Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
6340Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate /* Map in EHCI Capability registers */
6370Sstevel@tonic-gate if (ddi_regs_map_setup(ehcip->ehci_dip, 1,
6380Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_capsp, 0,
6390Sstevel@tonic-gate sizeof (ehci_caps_t), &attr,
6400Sstevel@tonic-gate &ehcip->ehci_caps_handle) != DDI_SUCCESS) {
6410Sstevel@tonic-gate
6420Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6430Sstevel@tonic-gate "ehci_map_regs: Map setup error");
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate return (DDI_FAILURE);
6460Sstevel@tonic-gate }
6470Sstevel@tonic-gate
6480Sstevel@tonic-gate length = ddi_get8(ehcip->ehci_caps_handle,
6490Sstevel@tonic-gate (uint8_t *)&ehcip->ehci_capsp->ehci_caps_length);
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate /* Free the original mapping */
6520Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle);
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate /* Re-map in EHCI Capability and Operational registers */
6550Sstevel@tonic-gate if (ddi_regs_map_setup(ehcip->ehci_dip, 1,
6560Sstevel@tonic-gate (caddr_t *)&ehcip->ehci_capsp, 0,
6570Sstevel@tonic-gate length + sizeof (ehci_regs_t), &attr,
6580Sstevel@tonic-gate &ehcip->ehci_caps_handle) != DDI_SUCCESS) {
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6610Sstevel@tonic-gate "ehci_map_regs: Map setup error");
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate return (DDI_FAILURE);
6640Sstevel@tonic-gate }
6650Sstevel@tonic-gate
6660Sstevel@tonic-gate /* Get the pointer to EHCI Operational Register */
6670Sstevel@tonic-gate ehcip->ehci_regsp = (ehci_regs_t *)
6680Sstevel@tonic-gate ((uintptr_t)ehcip->ehci_capsp + length);
6690Sstevel@tonic-gate
6700Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
6710Sstevel@tonic-gate "ehci_map_regs: Capsp 0x%p Regsp 0x%p\n",
6726898Sfb209375 (void *)ehcip->ehci_capsp, (void *)ehcip->ehci_regsp);
6730Sstevel@tonic-gate
6740Sstevel@tonic-gate return (DDI_SUCCESS);
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate
6772191Sszhou /*
6782191Sszhou * The following simulated polling is for debugging purposes only.
6792191Sszhou * It is activated on x86 by setting usb-polling=true in GRUB or ehci.conf.
6802191Sszhou */
6812191Sszhou static int
ehci_is_polled(dev_info_t * dip)6822191Sszhou ehci_is_polled(dev_info_t *dip)
6832191Sszhou {
6842191Sszhou int ret;
6852191Sszhou char *propval;
6862191Sszhou
6872191Sszhou if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
6882191Sszhou "usb-polling", &propval) != DDI_SUCCESS)
6892191Sszhou
6902191Sszhou return (0);
6912191Sszhou
6922191Sszhou ret = (strcmp(propval, "true") == 0);
6932191Sszhou ddi_prop_free(propval);
6942191Sszhou
6952191Sszhou return (ret);
6962191Sszhou }
6972191Sszhou
6982191Sszhou static void
ehci_poll_intr(void * arg)6992191Sszhou ehci_poll_intr(void *arg)
7002191Sszhou {
7012191Sszhou /* poll every msec */
7022191Sszhou for (;;) {
7032191Sszhou (void) ehci_intr(arg, NULL);
7042191Sszhou delay(drv_usectohz(1000));
7052191Sszhou }
7062191Sszhou }
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate /*
7090Sstevel@tonic-gate * ehci_register_intrs_and_init_mutex:
7100Sstevel@tonic-gate *
7110Sstevel@tonic-gate * Register interrupts and initialize each mutex and condition variables
7120Sstevel@tonic-gate */
7130Sstevel@tonic-gate int
ehci_register_intrs_and_init_mutex(ehci_state_t * ehcip)7140Sstevel@tonic-gate ehci_register_intrs_and_init_mutex(ehci_state_t *ehcip)
7150Sstevel@tonic-gate {
716965Sgovinda int intr_types;
7170Sstevel@tonic-gate
7180Sstevel@tonic-gate #if defined(__x86)
7190Sstevel@tonic-gate uint8_t iline;
7200Sstevel@tonic-gate #endif
7210Sstevel@tonic-gate
7220Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7230Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex:");
7240Sstevel@tonic-gate
725965Sgovinda /*
726965Sgovinda * There is a known MSI hardware bug with the EHCI controller
727965Sgovinda * of ULI1575 southbridge. Hence MSI is disabled for this chip.
728965Sgovinda */
729965Sgovinda if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
730965Sgovinda (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) {
731965Sgovinda ehcip->ehci_msi_enabled = B_FALSE;
732965Sgovinda } else {
733965Sgovinda /* Set the MSI enable flag from the global EHCI MSI tunable */
734965Sgovinda ehcip->ehci_msi_enabled = ehci_enable_msi;
735965Sgovinda }
736965Sgovinda
7372191Sszhou /* launch polling thread instead of enabling pci interrupt */
7382191Sszhou if (ehci_is_polled(ehcip->ehci_dip)) {
7392191Sszhou extern pri_t maxclsyspri;
7402191Sszhou
7413435Slg150142 USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7422191Sszhou "ehci_register_intrs_and_init_mutex: "
7432191Sszhou "running in simulated polled mode");
7442191Sszhou
7452191Sszhou (void) thread_create(NULL, 0, ehci_poll_intr, ehcip, 0, &p0,
7462191Sszhou TS_RUN, maxclsyspri);
7472191Sszhou
7482191Sszhou goto skip_intr;
7492191Sszhou }
7502191Sszhou
7510Sstevel@tonic-gate #if defined(__x86)
7520Sstevel@tonic-gate /*
7530Sstevel@tonic-gate * Make sure that the interrupt pin is connected to the
7540Sstevel@tonic-gate * interrupt controller on x86. Interrupt line 255 means
7550Sstevel@tonic-gate * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43).
756880Sfrits * If we would return failure when interrupt line equals 255, then
757828Syq193411 * high speed devices will be routed to companion host controllers.
758880Sfrits * However, it is not necessary to return failure here, and
759880Sfrits * o/uhci codes don't check the interrupt line either.
760880Sfrits * But it's good to log a message here for debug purposes.
7610Sstevel@tonic-gate */
7620Sstevel@tonic-gate iline = pci_config_get8(ehcip->ehci_config_handle,
7630Sstevel@tonic-gate PCI_CONF_ILINE);
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate if (iline == 255) {
7660Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7670Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: "
7680Sstevel@tonic-gate "interrupt line value out of range (%d)",
7690Sstevel@tonic-gate iline);
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate #endif /* __x86 */
7720Sstevel@tonic-gate
773965Sgovinda /* Get supported interrupt types */
774965Sgovinda if (ddi_intr_get_supported_types(ehcip->ehci_dip,
775965Sgovinda &intr_types) != DDI_SUCCESS) {
7760Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
7770Sstevel@tonic-gate "ehci_register_intrs_and_init_mutex: "
778965Sgovinda "ddi_intr_get_supported_types failed");
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate return (DDI_FAILURE);
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate
783965Sgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
784965Sgovinda "ehci_register_intrs_and_init_mutex: "
785965Sgovinda "supported interrupt types 0x%x", intr_types);
786965Sgovinda
787965Sgovinda if ((intr_types & DDI_INTR_TYPE_MSI) && ehcip->ehci_msi_enabled) {
788965Sgovinda if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_MSI)
789965Sgovinda != DDI_SUCCESS) {
790965Sgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
791965Sgovinda "ehci_register_intrs_and_init_mutex: MSI "
792965Sgovinda "registration failed, trying FIXED interrupt \n");
793965Sgovinda } else {
794965Sgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
795965Sgovinda "ehci_register_intrs_and_init_mutex: "
796965Sgovinda "Using MSI interrupt type\n");
797965Sgovinda
798965Sgovinda ehcip->ehci_intr_type = DDI_INTR_TYPE_MSI;
799965Sgovinda ehcip->ehci_flags |= EHCI_INTR;
800965Sgovinda }
801965Sgovinda }
802965Sgovinda
803965Sgovinda if ((!(ehcip->ehci_flags & EHCI_INTR)) &&
804965Sgovinda (intr_types & DDI_INTR_TYPE_FIXED)) {
805965Sgovinda if (ehci_add_intrs(ehcip, DDI_INTR_TYPE_FIXED)
806965Sgovinda != DDI_SUCCESS) {
807965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
808965Sgovinda "ehci_register_intrs_and_init_mutex: "
809965Sgovinda "FIXED interrupt registration failed\n");
810965Sgovinda
811965Sgovinda return (DDI_FAILURE);
812965Sgovinda }
813965Sgovinda
814965Sgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
815965Sgovinda "ehci_register_intrs_and_init_mutex: "
816965Sgovinda "Using FIXED interrupt type\n");
817965Sgovinda
818965Sgovinda ehcip->ehci_intr_type = DDI_INTR_TYPE_FIXED;
819965Sgovinda ehcip->ehci_flags |= EHCI_INTR;
820965Sgovinda }
821965Sgovinda
8222191Sszhou skip_intr:
823965Sgovinda /* Create prototype for advance on async schedule */
824965Sgovinda cv_init(&ehcip->ehci_async_schedule_advance_cv,
825965Sgovinda NULL, CV_DRIVER, NULL);
826965Sgovinda
827965Sgovinda return (DDI_SUCCESS);
828965Sgovinda }
829965Sgovinda
830965Sgovinda
831965Sgovinda /*
832965Sgovinda * ehci_add_intrs:
833965Sgovinda *
834965Sgovinda * Register FIXED or MSI interrupts.
835965Sgovinda */
836965Sgovinda static int
ehci_add_intrs(ehci_state_t * ehcip,int intr_type)837965Sgovinda ehci_add_intrs(ehci_state_t *ehcip,
838965Sgovinda int intr_type)
839965Sgovinda {
840965Sgovinda int actual, avail, intr_size, count = 0;
8415767Slc152243 int i, flag, ret;
842965Sgovinda
843965Sgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
844965Sgovinda "ehci_add_intrs: interrupt type 0x%x", intr_type);
845965Sgovinda
846965Sgovinda /* Get number of interrupts */
847965Sgovinda ret = ddi_intr_get_nintrs(ehcip->ehci_dip, intr_type, &count);
848965Sgovinda if ((ret != DDI_SUCCESS) || (count == 0)) {
8490Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
850965Sgovinda "ehci_add_intrs: ddi_intr_get_nintrs() failure, "
851965Sgovinda "ret: %d, count: %d", ret, count);
8520Sstevel@tonic-gate
8530Sstevel@tonic-gate return (DDI_FAILURE);
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate
856965Sgovinda /* Get number of available interrupts */
857965Sgovinda ret = ddi_intr_get_navail(ehcip->ehci_dip, intr_type, &avail);
858965Sgovinda if ((ret != DDI_SUCCESS) || (avail == 0)) {
8590Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
860965Sgovinda "ehci_add_intrs: ddi_intr_get_navail() failure, "
861965Sgovinda "ret: %d, count: %d", ret, count);
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate return (DDI_FAILURE);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate
866965Sgovinda if (avail < count) {
867965Sgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
868965Sgovinda "ehci_add_intrs: ehci_add_intrs: nintrs () "
869965Sgovinda "returned %d, navail returned %d\n", count, avail);
870965Sgovinda }
871965Sgovinda
872965Sgovinda /* Allocate an array of interrupt handles */
873965Sgovinda intr_size = count * sizeof (ddi_intr_handle_t);
874965Sgovinda ehcip->ehci_htable = kmem_zalloc(intr_size, KM_SLEEP);
875965Sgovinda
876965Sgovinda flag = (intr_type == DDI_INTR_TYPE_MSI) ?
877965Sgovinda DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
878965Sgovinda
879965Sgovinda /* call ddi_intr_alloc() */
880965Sgovinda ret = ddi_intr_alloc(ehcip->ehci_dip, ehcip->ehci_htable,
881965Sgovinda intr_type, 0, count, &actual, flag);
882965Sgovinda
883965Sgovinda if ((ret != DDI_SUCCESS) || (actual == 0)) {
884965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
885965Sgovinda "ehci_add_intrs: ddi_intr_alloc() failed %d", ret);
886965Sgovinda
887965Sgovinda kmem_free(ehcip->ehci_htable, intr_size);
888965Sgovinda
889965Sgovinda return (DDI_FAILURE);
890965Sgovinda }
891965Sgovinda
892965Sgovinda if (actual < count) {
893965Sgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
894965Sgovinda "ehci_add_intrs: Requested: %d, Received: %d\n",
895965Sgovinda count, actual);
896965Sgovinda
897965Sgovinda for (i = 0; i < actual; i++)
898965Sgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]);
899965Sgovinda
900965Sgovinda kmem_free(ehcip->ehci_htable, intr_size);
901965Sgovinda
902965Sgovinda return (DDI_FAILURE);
903965Sgovinda }
904965Sgovinda
905965Sgovinda ehcip->ehci_intr_cnt = actual;
906965Sgovinda
907965Sgovinda if ((ret = ddi_intr_get_pri(ehcip->ehci_htable[0],
908965Sgovinda &ehcip->ehci_intr_pri)) != DDI_SUCCESS) {
909965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
910965Sgovinda "ehci_add_intrs: ddi_intr_get_pri() failed %d", ret);
911965Sgovinda
912965Sgovinda for (i = 0; i < actual; i++)
913965Sgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]);
914965Sgovinda
915965Sgovinda kmem_free(ehcip->ehci_htable, intr_size);
916965Sgovinda
917965Sgovinda return (DDI_FAILURE);
918965Sgovinda }
919965Sgovinda
920965Sgovinda USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
921965Sgovinda "ehci_add_intrs: Supported Interrupt priority 0x%x",
922965Sgovinda ehcip->ehci_intr_pri);
9230Sstevel@tonic-gate
9240Sstevel@tonic-gate /* Test for high level mutex */
9250Sstevel@tonic-gate if (ehcip->ehci_intr_pri >= ddi_intr_get_hilevel_pri()) {
9260Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
927965Sgovinda "ehci_add_intrs: Hi level interrupt not supported");
928965Sgovinda
929965Sgovinda for (i = 0; i < actual; i++)
930965Sgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]);
931965Sgovinda
932965Sgovinda kmem_free(ehcip->ehci_htable, intr_size);
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate return (DDI_FAILURE);
9350Sstevel@tonic-gate }
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate /* Initialize the mutex */
9380Sstevel@tonic-gate mutex_init(&ehcip->ehci_int_mutex, NULL, MUTEX_DRIVER,
939693Sgovinda DDI_INTR_PRI(ehcip->ehci_intr_pri));
9400Sstevel@tonic-gate
941965Sgovinda /* Call ddi_intr_add_handler() */
942965Sgovinda for (i = 0; i < actual; i++) {
943965Sgovinda if ((ret = ddi_intr_add_handler(ehcip->ehci_htable[i],
944965Sgovinda ehci_intr, (caddr_t)ehcip,
945965Sgovinda (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
946965Sgovinda USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
947965Sgovinda "ehci_add_intrs:ddi_intr_add_handler() "
948965Sgovinda "failed %d", ret);
949965Sgovinda
950965Sgovinda for (i = 0; i < actual; i++)
951965Sgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]);
952965Sgovinda
953965Sgovinda mutex_destroy(&ehcip->ehci_int_mutex);
954965Sgovinda kmem_free(ehcip->ehci_htable, intr_size);
955965Sgovinda
956965Sgovinda return (DDI_FAILURE);
957965Sgovinda }
958965Sgovinda }
959965Sgovinda
960965Sgovinda if ((ret = ddi_intr_get_cap(ehcip->ehci_htable[0],
961965Sgovinda &ehcip->ehci_intr_cap)) != DDI_SUCCESS) {
9620Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
963965Sgovinda "ehci_add_intrs: ddi_intr_get_cap() failed %d", ret);
964965Sgovinda
965965Sgovinda for (i = 0; i < actual; i++) {
966965Sgovinda (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]);
967965Sgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]);
968965Sgovinda }
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex);
971965Sgovinda kmem_free(ehcip->ehci_htable, intr_size);
9720Sstevel@tonic-gate
9730Sstevel@tonic-gate return (DDI_FAILURE);
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate
976965Sgovinda /* Enable all interrupts */
977965Sgovinda if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) {
978965Sgovinda /* Call ddi_intr_block_enable() for MSI interrupts */
979965Sgovinda (void) ddi_intr_block_enable(ehcip->ehci_htable,
980965Sgovinda ehcip->ehci_intr_cnt);
981965Sgovinda } else {
982965Sgovinda /* Call ddi_intr_enable for MSI or FIXED interrupts */
983965Sgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++)
984965Sgovinda (void) ddi_intr_enable(ehcip->ehci_htable[i]);
9850Sstevel@tonic-gate }
9860Sstevel@tonic-gate
9870Sstevel@tonic-gate return (DDI_SUCCESS);
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate
9900Sstevel@tonic-gate
9910Sstevel@tonic-gate /*
9921458Syq193411 * ehci_init_hardware
9930Sstevel@tonic-gate *
9941458Syq193411 * take control from BIOS, reset EHCI host controller, and check version, etc.
9950Sstevel@tonic-gate */
9960Sstevel@tonic-gate int
ehci_init_hardware(ehci_state_t * ehcip)9971458Syq193411 ehci_init_hardware(ehci_state_t *ehcip)
9980Sstevel@tonic-gate {
9990Sstevel@tonic-gate int revision;
10000Sstevel@tonic-gate uint16_t cmd_reg;
10010Sstevel@tonic-gate int abort_on_BIOS_take_over_failure;
10020Sstevel@tonic-gate
10030Sstevel@tonic-gate /* Take control from the BIOS */
10040Sstevel@tonic-gate if (ehci_take_control(ehcip) != USB_SUCCESS) {
10050Sstevel@tonic-gate
10060Sstevel@tonic-gate /* read .conf file properties */
10070Sstevel@tonic-gate abort_on_BIOS_take_over_failure =
10085767Slc152243 ddi_prop_get_int(DDI_DEV_T_ANY,
10095767Slc152243 ehcip->ehci_dip, DDI_PROP_DONTPASS,
10105767Slc152243 "abort-on-BIOS-take-over-failure", 0);
10110Sstevel@tonic-gate
10120Sstevel@tonic-gate if (abort_on_BIOS_take_over_failure) {
10130Sstevel@tonic-gate
10140Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10150Sstevel@tonic-gate "Unable to take control from BIOS.");
10160Sstevel@tonic-gate
10170Sstevel@tonic-gate return (DDI_FAILURE);
10180Sstevel@tonic-gate }
10190Sstevel@tonic-gate
10200Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10210Sstevel@tonic-gate "Unable to take control from BIOS. Failure is ignored.");
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate
10240Sstevel@tonic-gate /* set Memory Master Enable */
10250Sstevel@tonic-gate cmd_reg = pci_config_get16(ehcip->ehci_config_handle, PCI_CONF_COMM);
10260Sstevel@tonic-gate cmd_reg |= (PCI_COMM_MAE | PCI_COMM_ME);
10270Sstevel@tonic-gate pci_config_put16(ehcip->ehci_config_handle, PCI_CONF_COMM, cmd_reg);
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate /* Reset the EHCI host controller */
10300Sstevel@tonic-gate Set_OpReg(ehci_command,
10310Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_HOST_CTRL_RESET);
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate /* Wait 10ms for reset to complete */
10340Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT);
10350Sstevel@tonic-gate
10360Sstevel@tonic-gate ASSERT(Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED);
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate /* Verify the version number */
10390Sstevel@tonic-gate revision = Get_16Cap(ehci_version);
10400Sstevel@tonic-gate
10411458Syq193411 USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10421458Syq193411 "ehci_init_hardware: Revision 0x%x", revision);
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate /*
10450Sstevel@tonic-gate * EHCI driver supports EHCI host controllers compliant to
10460Sstevel@tonic-gate * 0.95 and higher revisions of EHCI specifications.
10470Sstevel@tonic-gate */
10480Sstevel@tonic-gate if (revision < EHCI_REVISION_0_95) {
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
10510Sstevel@tonic-gate "Revision 0x%x is not supported", revision);
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate return (DDI_FAILURE);
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate if (ehcip->ehci_hc_soft_state == EHCI_CTLR_INIT_STATE) {
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate /* Initialize the Frame list base address area */
10590Sstevel@tonic-gate if (ehci_init_periodic_frame_lst_table(ehcip) != DDI_SUCCESS) {
10600Sstevel@tonic-gate
10610Sstevel@tonic-gate return (DDI_FAILURE);
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate
10640Sstevel@tonic-gate /*
10650Sstevel@tonic-gate * For performance reasons, do not insert anything into the
10660Sstevel@tonic-gate * asynchronous list or activate the asynch list schedule until
10670Sstevel@tonic-gate * there is a valid QH.
10680Sstevel@tonic-gate */
10690Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = NULL;
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate if ((ehcip->ehci_vendor_id == PCI_VENDOR_VIA) &&
10720Sstevel@tonic-gate (ehci_vt62x2_workaround & EHCI_VIA_ASYNC_SCHEDULE)) {
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate * The driver is unable to reliably stop the asynch
10750Sstevel@tonic-gate * list schedule on VIA VT6202 controllers, so we
10760Sstevel@tonic-gate * always keep a dummy QH on the list.
10770Sstevel@tonic-gate */
10780Sstevel@tonic-gate ehci_qh_t *dummy_async_qh =
10790Sstevel@tonic-gate ehci_alloc_qh(ehcip, NULL, NULL);
10800Sstevel@tonic-gate
10810Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_link_ptr,
10820Sstevel@tonic-gate ((ehci_qh_cpu_to_iommu(ehcip, dummy_async_qh) &
10830Sstevel@tonic-gate EHCI_QH_LINK_PTR) | EHCI_QH_LINK_REF_QH));
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate /* Set this QH to be the "head" of the circular list */
10860Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_ctrl,
10870Sstevel@tonic-gate Get_QH(dummy_async_qh->qh_ctrl) |
10880Sstevel@tonic-gate EHCI_QH_CTRL_RECLAIM_HEAD);
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_next_qtd,
10910Sstevel@tonic-gate EHCI_QH_NEXT_QTD_PTR_VALID);
10920Sstevel@tonic-gate Set_QH(dummy_async_qh->qh_alt_next_qtd,
10930Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID);
10940Sstevel@tonic-gate
10950Sstevel@tonic-gate ehcip->ehci_head_of_async_sched_list = dummy_async_qh;
10960Sstevel@tonic-gate ehcip->ehci_open_async_count++;
109712733SRaymond.Chen@Sun.COM ehcip->ehci_async_req_count++;
10980Sstevel@tonic-gate }
10990Sstevel@tonic-gate }
11000Sstevel@tonic-gate
11011458Syq193411 return (DDI_SUCCESS);
11021458Syq193411 }
11031458Syq193411
11041458Syq193411
11051458Syq193411 /*
11061458Syq193411 * ehci_init_workaround
11071458Syq193411 *
11081458Syq193411 * some workarounds during initializing ehci
11091458Syq193411 */
11101458Syq193411 int
ehci_init_workaround(ehci_state_t * ehcip)11111458Syq193411 ehci_init_workaround(ehci_state_t *ehcip)
11121458Syq193411 {
11130Sstevel@tonic-gate /*
11140Sstevel@tonic-gate * Acer Labs Inc. M5273 EHCI controller does not send
11150Sstevel@tonic-gate * interrupts unless the Root hub ports are routed to the EHCI
11160Sstevel@tonic-gate * host controller; so route the ports now, before we test for
11170Sstevel@tonic-gate * the presence of SOFs interrupts.
11180Sstevel@tonic-gate */
11190Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) {
11205767Slc152243 /* Route all Root hub ports to EHCI host controller */
11215767Slc152243 Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI);
11220Sstevel@tonic-gate }
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate /*
11250Sstevel@tonic-gate * VIA chips have some issues and may not work reliably.
1126122Shx149380 * Revisions >= 0x80 are part of a southbridge and appear
1127122Shx149380 * to be reliable with the workaround.
1128880Sfrits * For revisions < 0x80, if we were bound using class
1129122Shx149380 * complain, else proceed. This will allow the user to
1130122Shx149380 * bind ehci specifically to this chip and not have the
1131122Shx149380 * warnings
11320Sstevel@tonic-gate */
1133122Shx149380 if (ehcip->ehci_vendor_id == PCI_VENDOR_VIA) {
1134122Shx149380
11355767Slc152243 if (ehcip->ehci_rev_id >= PCI_VIA_REVISION_6212) {
1136122Shx149380
11375773Sqz150045 USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11385773Sqz150045 "ehci_init_workaround: Applying VIA workarounds "
11395773Sqz150045 "for the 6212 chip.");
1140122Shx149380
11415767Slc152243 } else if (strcmp(DEVI(ehcip->ehci_dip)->devi_binding_name,
11425773Sqz150045 "pciclass,0c0320") == 0) {
11435773Sqz150045
11445773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11455773Sqz150045 "Due to recently discovered incompatibilities");
11465773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11475773Sqz150045 "with this USB controller, USB2.x transfer");
11485773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11495773Sqz150045 "support has been disabled. This device will");
11505773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11515773Sqz150045 "continue to function as a USB1.x controller.");
11525773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11535773Sqz150045 "If you are interested in enabling USB2.x");
11545773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11555773Sqz150045 "support please, refer to the ehci(7D) man page.");
11565773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11575773Sqz150045 "Please also refer to www.sun.com/io for");
11585773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11595773Sqz150045 "Solaris Ready products and to");
11605773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11615773Sqz150045 "www.sun.com/bigadmin/hcl for additional");
11625773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11635773Sqz150045 "compatible USB products.");
11645773Sqz150045
11655773Sqz150045 return (DDI_FAILURE);
11665773Sqz150045
11675773Sqz150045 } else if (ehci_vt62x2_workaround) {
11685773Sqz150045
11695773Sqz150045 USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
11705773Sqz150045 "Applying VIA workarounds");
11715767Slc152243 }
11720Sstevel@tonic-gate }
11730Sstevel@tonic-gate
11741458Syq193411 return (DDI_SUCCESS);
11751458Syq193411 }
11761458Syq193411
11771458Syq193411
11781458Syq193411 /*
11791458Syq193411 * ehci_init_check_status
11801458Syq193411 *
11811458Syq193411 * Check if EHCI host controller is running
11821458Syq193411 */
11831458Syq193411 int
ehci_init_check_status(ehci_state_t * ehcip)11841458Syq193411 ehci_init_check_status(ehci_state_t *ehcip)
11851458Syq193411 {
11861458Syq193411 clock_t sof_time_wait;
11871458Syq193411
11880Sstevel@tonic-gate /*
11890Sstevel@tonic-gate * Get the number of clock ticks to wait.
11900Sstevel@tonic-gate * This is based on the maximum time it takes for a frame list rollover
11910Sstevel@tonic-gate * and maximum time wait for SOFs to begin.
11920Sstevel@tonic-gate */
11930Sstevel@tonic-gate sof_time_wait = drv_usectohz((EHCI_NUM_PERIODIC_FRAME_LISTS * 1000) +
11940Sstevel@tonic-gate EHCI_SOF_TIMEWAIT);
11950Sstevel@tonic-gate
11960Sstevel@tonic-gate /* Tell the ISR to broadcast ehci_async_schedule_advance_cv */
11970Sstevel@tonic-gate ehcip->ehci_flags |= EHCI_CV_INTR;
11980Sstevel@tonic-gate
11990Sstevel@tonic-gate /* We need to add a delay to allow the chip time to start running */
120011066Srafael.vanoni@sun.com (void) cv_reltimedwait(&ehcip->ehci_async_schedule_advance_cv,
120111066Srafael.vanoni@sun.com &ehcip->ehci_int_mutex, sof_time_wait, TR_CLOCK_TICK);
12020Sstevel@tonic-gate
12030Sstevel@tonic-gate /*
12040Sstevel@tonic-gate * Check EHCI host controller is running, otherwise return failure.
12050Sstevel@tonic-gate */
12060Sstevel@tonic-gate if ((ehcip->ehci_flags & EHCI_CV_INTR) ||
12070Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12100Sstevel@tonic-gate "No SOF interrupts have been received, this USB EHCI host"
12110Sstevel@tonic-gate "controller is unusable");
12120Sstevel@tonic-gate
12130Sstevel@tonic-gate /*
12140Sstevel@tonic-gate * Route all Root hub ports to Classic host
12150Sstevel@tonic-gate * controller, in case this is an unusable ALI M5273
12160Sstevel@tonic-gate * EHCI controller.
12170Sstevel@tonic-gate */
12180Sstevel@tonic-gate if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) {
12190Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate return (DDI_FAILURE);
12230Sstevel@tonic-gate }
12240Sstevel@tonic-gate
12251458Syq193411 return (DDI_SUCCESS);
12261458Syq193411 }
12271458Syq193411
12281458Syq193411
12291458Syq193411 /*
12301458Syq193411 * ehci_init_ctlr:
12311458Syq193411 *
12321458Syq193411 * Initialize the Host Controller (HC).
12331458Syq193411 */
12341458Syq193411 int
ehci_init_ctlr(ehci_state_t * ehcip,int init_type)12351458Syq193411 ehci_init_ctlr(ehci_state_t *ehcip,
12361458Syq193411 int init_type)
12371458Syq193411 {
12381458Syq193411 USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_init_ctlr:");
12391458Syq193411
12401458Syq193411 if (init_type == EHCI_NORMAL_INITIALIZATION) {
12411458Syq193411
12421458Syq193411 if (ehci_init_hardware(ehcip) != DDI_SUCCESS) {
12431458Syq193411
12441458Syq193411 return (DDI_FAILURE);
12451458Syq193411 }
12461458Syq193411 }
12471458Syq193411
12481458Syq193411 /*
12491458Syq193411 * Check for Asynchronous schedule park capability feature. If this
12501458Syq193411 * feature is supported, then, program ehci command register with
12511458Syq193411 * appropriate values..
12521458Syq193411 */
12531458Syq193411 if (Get_Cap(ehci_hcc_params) & EHCI_HCC_ASYNC_SCHED_PARK_CAP) {
12541458Syq193411
12551458Syq193411 USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12561458Syq193411 "ehci_init_ctlr: Async park mode is supported");
12571458Syq193411
12581458Syq193411 Set_OpReg(ehci_command, (Get_OpReg(ehci_command) |
12591458Syq193411 (EHCI_CMD_ASYNC_PARK_ENABLE |
12601458Syq193411 EHCI_CMD_ASYNC_PARK_COUNT_3)));
12611458Syq193411 }
12621458Syq193411
12631458Syq193411 /*
12641458Syq193411 * Check for programmable periodic frame list feature. If this
12651458Syq193411 * feature is supported, then, program ehci command register with
12661458Syq193411 * 1024 frame list value.
12671458Syq193411 */
12681458Syq193411 if (Get_Cap(ehci_hcc_params) & EHCI_HCC_PROG_FRAME_LIST_FLAG) {
12691458Syq193411
12701458Syq193411 USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12711458Syq193411 "ehci_init_ctlr: Variable programmable periodic "
12721458Syq193411 "frame list is supported");
12731458Syq193411
12741458Syq193411 Set_OpReg(ehci_command, (Get_OpReg(ehci_command) |
12751458Syq193411 EHCI_CMD_FRAME_1024_SIZE));
12761458Syq193411 }
12771458Syq193411
12781458Syq193411 /*
12791458Syq193411 * Currently EHCI driver doesn't support 64 bit addressing.
12801458Syq193411 *
12811458Syq193411 * If we are using 64 bit addressing capability, then, program
12821458Syq193411 * ehci_ctrl_segment register with 4 Gigabyte segment where all
12831458Syq193411 * of the interface data structures are allocated.
12841458Syq193411 */
12851458Syq193411 if (Get_Cap(ehci_hcc_params) & EHCI_HCC_64BIT_ADDR_CAP) {
12861458Syq193411
12871458Syq193411 USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
12881458Syq193411 "ehci_init_ctlr: EHCI driver doesn't support "
12891458Syq193411 "64 bit addressing");
12901458Syq193411 }
12911458Syq193411
12921458Syq193411 /* 64 bit addressing is not support */
12931458Syq193411 Set_OpReg(ehci_ctrl_segment, 0x00000000);
12941458Syq193411
12951458Syq193411 /* Turn on/off the schedulers */
12961458Syq193411 ehci_toggle_scheduler(ehcip);
12971458Syq193411
12985773Sqz150045 /* Set host controller soft state to operational */
12995773Sqz150045 ehcip->ehci_hc_soft_state = EHCI_CTLR_OPERATIONAL_STATE;
13005773Sqz150045
13011458Syq193411 /*
13021458Syq193411 * Set the Periodic Frame List Base Address register with the
13031458Syq193411 * starting physical address of the Periodic Frame List.
13041458Syq193411 */
13051458Syq193411 Set_OpReg(ehci_periodic_list_base,
13061458Syq193411 (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address &
13075767Slc152243 EHCI_PERIODIC_LIST_BASE));
13081458Syq193411
13091458Syq193411 /*
13101458Syq193411 * Set ehci_interrupt to enable all interrupts except Root
13111458Syq193411 * Hub Status change interrupt.
13121458Syq193411 */
13131458Syq193411 Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR |
13141458Syq193411 EHCI_INTR_FRAME_LIST_ROLLOVER | EHCI_INTR_USB_ERROR |
13151458Syq193411 EHCI_INTR_USB);
13161458Syq193411
13171458Syq193411 /*
13181458Syq193411 * Set the desired interrupt threshold and turn on EHCI host controller.
13191458Syq193411 */
13201458Syq193411 Set_OpReg(ehci_command,
13211458Syq193411 ((Get_OpReg(ehci_command) & ~EHCI_CMD_INTR_THRESHOLD) |
13225767Slc152243 (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN)));
13231458Syq193411
13241458Syq193411 ASSERT(Get_OpReg(ehci_command) & EHCI_CMD_HOST_CTRL_RUN);
13251458Syq193411
13261458Syq193411 if (init_type == EHCI_NORMAL_INITIALIZATION) {
13271458Syq193411
13281458Syq193411 if (ehci_init_workaround(ehcip) != DDI_SUCCESS) {
13291458Syq193411
13305773Sqz150045 /* Set host controller soft state to error */
13315773Sqz150045 ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
13325773Sqz150045
13331458Syq193411 return (DDI_FAILURE);
13341458Syq193411 }
13351458Syq193411
13361458Syq193411 if (ehci_init_check_status(ehcip) != DDI_SUCCESS) {
13371458Syq193411
13385773Sqz150045 /* Set host controller soft state to error */
13395773Sqz150045 ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
13405773Sqz150045
13411458Syq193411 return (DDI_FAILURE);
13421458Syq193411 }
13431458Syq193411
13441458Syq193411 USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
13451458Syq193411 "ehci_init_ctlr: SOF's have started");
13461458Syq193411 }
13470Sstevel@tonic-gate
13480Sstevel@tonic-gate /* Route all Root hub ports to EHCI host controller */
13490Sstevel@tonic-gate Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI);
13500Sstevel@tonic-gate
13510Sstevel@tonic-gate return (DDI_SUCCESS);
13520Sstevel@tonic-gate }
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate /*
13550Sstevel@tonic-gate * ehci_take_control:
13560Sstevel@tonic-gate *
13570Sstevel@tonic-gate * Handshake to take EHCI control from BIOS if necessary. Its only valid for
13580Sstevel@tonic-gate * x86 machines, because sparc doesn't have a BIOS.
13590Sstevel@tonic-gate * On x86 machine, the take control process includes
13600Sstevel@tonic-gate * o get the base address of the extended capability list
13610Sstevel@tonic-gate * o find out the capability for handoff synchronization in the list.
13620Sstevel@tonic-gate * o check if BIOS has owned the host controller.
13630Sstevel@tonic-gate * o set the OS Owned semaphore bit, ask the BIOS to release the ownership.
13640Sstevel@tonic-gate * o wait for a constant time and check if BIOS has relinquished control.
13650Sstevel@tonic-gate */
13660Sstevel@tonic-gate /* ARGSUSED */
13670Sstevel@tonic-gate static int
ehci_take_control(ehci_state_t * ehcip)13680Sstevel@tonic-gate ehci_take_control(ehci_state_t *ehcip)
13690Sstevel@tonic-gate {
13700Sstevel@tonic-gate #if defined(__x86)
13710Sstevel@tonic-gate uint32_t extended_cap;
13720Sstevel@tonic-gate uint32_t extended_cap_offset;
13730Sstevel@tonic-gate uint32_t extended_cap_id;
13740Sstevel@tonic-gate uint_t retry;
13750Sstevel@tonic-gate
13760Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
13770Sstevel@tonic-gate "ehci_take_control:");
13780Sstevel@tonic-gate
13790Sstevel@tonic-gate /*
13800Sstevel@tonic-gate * According EHCI Spec 2.2.4, get EECP base address from HCCPARAMS
13810Sstevel@tonic-gate * register.
13820Sstevel@tonic-gate */
13830Sstevel@tonic-gate extended_cap_offset = (Get_Cap(ehci_hcc_params) & EHCI_HCC_EECP) >>
13840Sstevel@tonic-gate EHCI_HCC_EECP_SHIFT;
13850Sstevel@tonic-gate
13860Sstevel@tonic-gate /*
13870Sstevel@tonic-gate * According EHCI Spec 2.2.4, if the extended capability offset is
13880Sstevel@tonic-gate * less than 40h then its not valid. This means we don't need to
13890Sstevel@tonic-gate * worry about BIOS handoff.
13900Sstevel@tonic-gate */
13910Sstevel@tonic-gate if (extended_cap_offset < EHCI_HCC_EECP_MIN_OFFSET) {
13920Sstevel@tonic-gate
13930Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
13940Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy.");
13950Sstevel@tonic-gate
13960Sstevel@tonic-gate goto success;
13970Sstevel@tonic-gate }
13980Sstevel@tonic-gate
13990Sstevel@tonic-gate /*
14000Sstevel@tonic-gate * According EHCI Spec 2.1.7, A zero offset indicates the
14010Sstevel@tonic-gate * end of the extended capability list.
14020Sstevel@tonic-gate */
14030Sstevel@tonic-gate while (extended_cap_offset) {
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate /* Get the extended capability value. */
14060Sstevel@tonic-gate extended_cap = pci_config_get32(ehcip->ehci_config_handle,
14070Sstevel@tonic-gate extended_cap_offset);
14080Sstevel@tonic-gate
14090Sstevel@tonic-gate /* Get the capability ID */
14100Sstevel@tonic-gate extended_cap_id = (extended_cap & EHCI_EX_CAP_ID) >>
14110Sstevel@tonic-gate EHCI_EX_CAP_ID_SHIFT;
14120Sstevel@tonic-gate
14130Sstevel@tonic-gate /* Check if the card support legacy */
14140Sstevel@tonic-gate if (extended_cap_id == EHCI_EX_CAP_ID_BIOS_HANDOFF) {
14150Sstevel@tonic-gate break;
14160Sstevel@tonic-gate }
14170Sstevel@tonic-gate
14180Sstevel@tonic-gate /* Get the offset of the next capability */
14190Sstevel@tonic-gate extended_cap_offset = (extended_cap & EHCI_EX_CAP_NEXT_PTR) >>
14200Sstevel@tonic-gate EHCI_EX_CAP_NEXT_PTR_SHIFT;
14210Sstevel@tonic-gate }
14220Sstevel@tonic-gate
14230Sstevel@tonic-gate /*
14240Sstevel@tonic-gate * Unable to find legacy support in hardware's extended capability list.
14250Sstevel@tonic-gate * This means we don't need to worry about BIOS handoff.
14260Sstevel@tonic-gate */
14270Sstevel@tonic-gate if (extended_cap_id != EHCI_EX_CAP_ID_BIOS_HANDOFF) {
14280Sstevel@tonic-gate
14290Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
14300Sstevel@tonic-gate "ehci_take_control: Hardware doesn't support legacy");
14310Sstevel@tonic-gate
14320Sstevel@tonic-gate goto success;
14330Sstevel@tonic-gate }
14340Sstevel@tonic-gate
14350Sstevel@tonic-gate /* Check if BIOS has owned it. */
14360Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) {
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
14390Sstevel@tonic-gate "ehci_take_control: BIOS does not own EHCI");
14400Sstevel@tonic-gate
14410Sstevel@tonic-gate goto success;
14420Sstevel@tonic-gate }
14430Sstevel@tonic-gate
14440Sstevel@tonic-gate /*
14450Sstevel@tonic-gate * According EHCI Spec 5.1, The OS driver initiates an ownership
14460Sstevel@tonic-gate * request by setting the OS Owned semaphore to a one. The OS
14470Sstevel@tonic-gate * waits for the BIOS Owned bit to go to a zero before attempting
14480Sstevel@tonic-gate * to use the EHCI controller. The time that OS must wait for BIOS
14490Sstevel@tonic-gate * to respond to the request for ownership is beyond the scope of
14500Sstevel@tonic-gate * this specification.
14510Sstevel@tonic-gate * It waits up to EHCI_TAKEOVER_WAIT_COUNT*EHCI_TAKEOVER_DELAY ms
14520Sstevel@tonic-gate * for BIOS to release the ownership.
14530Sstevel@tonic-gate */
14540Sstevel@tonic-gate extended_cap |= EHCI_LEGSUP_OS_OWNED_SEM;
14550Sstevel@tonic-gate pci_config_put32(ehcip->ehci_config_handle, extended_cap_offset,
14560Sstevel@tonic-gate extended_cap);
14570Sstevel@tonic-gate
14580Sstevel@tonic-gate for (retry = 0; retry < EHCI_TAKEOVER_WAIT_COUNT; retry++) {
14590Sstevel@tonic-gate
14600Sstevel@tonic-gate /* wait a special interval */
14613138Sfrits #ifndef __lock_lint
14620Sstevel@tonic-gate delay(drv_usectohz(EHCI_TAKEOVER_DELAY));
14633138Sfrits #endif
14640Sstevel@tonic-gate /* Check to see if the BIOS has released the ownership */
14650Sstevel@tonic-gate extended_cap = pci_config_get32(
14660Sstevel@tonic-gate ehcip->ehci_config_handle, extended_cap_offset);
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate if (!(extended_cap & EHCI_LEGSUP_BIOS_OWNED_SEM)) {
14690Sstevel@tonic-gate
14700Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA,
14710Sstevel@tonic-gate ehcip->ehci_log_hdl,
14720Sstevel@tonic-gate "ehci_take_control: BIOS has released "
14730Sstevel@tonic-gate "the ownership. retry = %d", retry);
14740Sstevel@tonic-gate
14750Sstevel@tonic-gate goto success;
14760Sstevel@tonic-gate }
14770Sstevel@tonic-gate
14780Sstevel@tonic-gate }
14790Sstevel@tonic-gate
14800Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
14810Sstevel@tonic-gate "ehci_take_control: take control from BIOS failed.");
14820Sstevel@tonic-gate
14830Sstevel@tonic-gate return (USB_FAILURE);
14840Sstevel@tonic-gate
14850Sstevel@tonic-gate success:
14860Sstevel@tonic-gate
14870Sstevel@tonic-gate #endif /* __x86 */
14880Sstevel@tonic-gate return (USB_SUCCESS);
14890Sstevel@tonic-gate }
14900Sstevel@tonic-gate
14910Sstevel@tonic-gate
14920Sstevel@tonic-gate /*
14930Sstevel@tonic-gate * ehci_init_periodic_frame_list_table :
14940Sstevel@tonic-gate *
14950Sstevel@tonic-gate * Allocate the system memory and initialize Host Controller
14960Sstevel@tonic-gate * Periodic Frame List table area. The starting of the Periodic
14970Sstevel@tonic-gate * Frame List Table area must be 4096 byte aligned.
14980Sstevel@tonic-gate */
14990Sstevel@tonic-gate static int
ehci_init_periodic_frame_lst_table(ehci_state_t * ehcip)15000Sstevel@tonic-gate ehci_init_periodic_frame_lst_table(ehci_state_t *ehcip)
15010Sstevel@tonic-gate {
15020Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr;
15030Sstevel@tonic-gate size_t real_length;
15040Sstevel@tonic-gate uint_t ccount;
15050Sstevel@tonic-gate int result;
15060Sstevel@tonic-gate
15070Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
15080Sstevel@tonic-gate
15090Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15100Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table:");
15110Sstevel@tonic-gate
15120Sstevel@tonic-gate /* The host controller will be little endian */
15130Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
15140Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
15150Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15160Sstevel@tonic-gate
15170Sstevel@tonic-gate /* Force the required 4K restrictive alignment */
15180Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_PFL_ALIGNMENT;
15190Sstevel@tonic-gate
15200Sstevel@tonic-gate /* Create space for the Periodic Frame List */
15210Sstevel@tonic-gate if (ddi_dma_alloc_handle(ehcip->ehci_dip, &ehcip->ehci_dma_attr,
15220Sstevel@tonic-gate DDI_DMA_SLEEP, 0, &ehcip->ehci_pflt_dma_handle) != DDI_SUCCESS) {
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate goto failure;
15250Sstevel@tonic-gate }
15260Sstevel@tonic-gate
15270Sstevel@tonic-gate if (ddi_dma_mem_alloc(ehcip->ehci_pflt_dma_handle,
15280Sstevel@tonic-gate sizeof (ehci_periodic_frame_list_t),
15290Sstevel@tonic-gate &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
15300Sstevel@tonic-gate 0, (caddr_t *)&ehcip->ehci_periodic_frame_list_tablep,
15310Sstevel@tonic-gate &real_length, &ehcip->ehci_pflt_mem_handle)) {
15320Sstevel@tonic-gate
15330Sstevel@tonic-gate goto failure;
15340Sstevel@tonic-gate }
15350Sstevel@tonic-gate
15361458Syq193411 USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15370Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: "
15380Sstevel@tonic-gate "Real length %lu", real_length);
15390Sstevel@tonic-gate
15400Sstevel@tonic-gate /* Map the whole Periodic Frame List into the I/O address space */
15410Sstevel@tonic-gate result = ddi_dma_addr_bind_handle(ehcip->ehci_pflt_dma_handle,
15420Sstevel@tonic-gate NULL, (caddr_t)ehcip->ehci_periodic_frame_list_tablep,
15430Sstevel@tonic-gate real_length, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
15440Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, &ehcip->ehci_pflt_cookie, &ccount);
15450Sstevel@tonic-gate
15460Sstevel@tonic-gate if (result == DDI_DMA_MAPPED) {
15470Sstevel@tonic-gate /* The cookie count should be 1 */
15480Sstevel@tonic-gate if (ccount != 1) {
15490Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15500Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: "
15510Sstevel@tonic-gate "More than 1 cookie");
15520Sstevel@tonic-gate
15530Sstevel@tonic-gate goto failure;
15540Sstevel@tonic-gate }
15550Sstevel@tonic-gate } else {
15560Sstevel@tonic-gate ehci_decode_ddi_dma_addr_bind_handle_result(ehcip, result);
15570Sstevel@tonic-gate
15580Sstevel@tonic-gate goto failure;
15590Sstevel@tonic-gate }
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
15620Sstevel@tonic-gate "ehci_init_periodic_frame_lst_table: virtual 0x%p physical 0x%x",
15630Sstevel@tonic-gate (void *)ehcip->ehci_periodic_frame_list_tablep,
15640Sstevel@tonic-gate ehcip->ehci_pflt_cookie.dmac_address);
15650Sstevel@tonic-gate
15660Sstevel@tonic-gate /*
15670Sstevel@tonic-gate * DMA addresses for Periodic Frame List are bound.
15680Sstevel@tonic-gate */
15690Sstevel@tonic-gate ehcip->ehci_dma_addr_bind_flag |= EHCI_PFLT_DMA_BOUND;
15700Sstevel@tonic-gate
15710Sstevel@tonic-gate bzero((void *)ehcip->ehci_periodic_frame_list_tablep, real_length);
15720Sstevel@tonic-gate
15730Sstevel@tonic-gate /* Initialize the Periodic Frame List */
15740Sstevel@tonic-gate ehci_build_interrupt_lattice(ehcip);
15750Sstevel@tonic-gate
15760Sstevel@tonic-gate /* Reset Byte Alignment to Default */
15770Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
15780Sstevel@tonic-gate
15790Sstevel@tonic-gate return (DDI_SUCCESS);
15800Sstevel@tonic-gate failure:
15810Sstevel@tonic-gate /* Byte alignment */
15820Sstevel@tonic-gate ehcip->ehci_dma_attr.dma_attr_align = EHCI_DMA_ATTR_ALIGNMENT;
15830Sstevel@tonic-gate
15840Sstevel@tonic-gate return (DDI_FAILURE);
15850Sstevel@tonic-gate }
15860Sstevel@tonic-gate
15870Sstevel@tonic-gate
15880Sstevel@tonic-gate /*
15890Sstevel@tonic-gate * ehci_build_interrupt_lattice:
15900Sstevel@tonic-gate *
15910Sstevel@tonic-gate * Construct the interrupt lattice tree using static Endpoint Descriptors
15920Sstevel@tonic-gate * (QH). This interrupt lattice tree will have total of 32 interrupt QH
15930Sstevel@tonic-gate * lists and the Host Controller (HC) processes one interrupt QH list in
15940Sstevel@tonic-gate * every frame. The Host Controller traverses the periodic schedule by
15950Sstevel@tonic-gate * constructing an array offset reference from the Periodic List Base Address
15960Sstevel@tonic-gate * register and bits 12 to 3 of Frame Index register. It fetches the element
15970Sstevel@tonic-gate * and begins traversing the graph of linked schedule data structures.
15980Sstevel@tonic-gate */
15990Sstevel@tonic-gate static void
ehci_build_interrupt_lattice(ehci_state_t * ehcip)16000Sstevel@tonic-gate ehci_build_interrupt_lattice(ehci_state_t *ehcip)
16010Sstevel@tonic-gate {
16020Sstevel@tonic-gate ehci_qh_t *list_array = ehcip->ehci_qh_pool_addr;
16030Sstevel@tonic-gate ushort_t ehci_index[EHCI_NUM_PERIODIC_FRAME_LISTS];
16040Sstevel@tonic-gate ehci_periodic_frame_list_t *periodic_frame_list =
16055767Slc152243 ehcip->ehci_periodic_frame_list_tablep;
16060Sstevel@tonic-gate ushort_t *temp, num_of_nodes;
16070Sstevel@tonic-gate uintptr_t addr;
16080Sstevel@tonic-gate int i, j, k;
16090Sstevel@tonic-gate
16100Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
16110Sstevel@tonic-gate "ehci_build_interrupt_lattice:");
16120Sstevel@tonic-gate
16130Sstevel@tonic-gate /*
16140Sstevel@tonic-gate * Reserve the first 63 Endpoint Descriptor (QH) structures
16150Sstevel@tonic-gate * in the pool as static endpoints & these are required for
16160Sstevel@tonic-gate * constructing interrupt lattice tree.
16170Sstevel@tonic-gate */
16180Sstevel@tonic-gate for (i = 0; i < EHCI_NUM_STATIC_NODES; i++) {
16190Sstevel@tonic-gate Set_QH(list_array[i].qh_state, EHCI_QH_STATIC);
16200Sstevel@tonic-gate Set_QH(list_array[i].qh_status, EHCI_QH_STS_HALTED);
16210Sstevel@tonic-gate Set_QH(list_array[i].qh_next_qtd, EHCI_QH_NEXT_QTD_PTR_VALID);
16220Sstevel@tonic-gate Set_QH(list_array[i].qh_alt_next_qtd,
16230Sstevel@tonic-gate EHCI_QH_ALT_NEXT_QTD_PTR_VALID);
16240Sstevel@tonic-gate }
16250Sstevel@tonic-gate
16260Sstevel@tonic-gate /*
16270Sstevel@tonic-gate * Make sure that last Endpoint on the periodic frame list terminates
16280Sstevel@tonic-gate * periodic schedule.
16290Sstevel@tonic-gate */
16300Sstevel@tonic-gate Set_QH(list_array[0].qh_link_ptr, EHCI_QH_LINK_PTR_VALID);
16310Sstevel@tonic-gate
16320Sstevel@tonic-gate /* Build the interrupt lattice tree */
16330Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_STATIC_NODES / 2); i++) {
16340Sstevel@tonic-gate /*
16350Sstevel@tonic-gate * The next pointer in the host controller endpoint
16360Sstevel@tonic-gate * descriptor must contain an iommu address. Calculate
16370Sstevel@tonic-gate * the offset into the cpu address and add this to the
16380Sstevel@tonic-gate * starting iommu address.
16390Sstevel@tonic-gate */
16400Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)&list_array[i]);
16410Sstevel@tonic-gate
16420Sstevel@tonic-gate Set_QH(list_array[2*i + 1].qh_link_ptr,
16430Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH);
16440Sstevel@tonic-gate Set_QH(list_array[2*i + 2].qh_link_ptr,
16450Sstevel@tonic-gate addr | EHCI_QH_LINK_REF_QH);
16460Sstevel@tonic-gate }
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate /* Build the tree bottom */
16490Sstevel@tonic-gate temp = (unsigned short *)
16500Sstevel@tonic-gate kmem_zalloc(EHCI_NUM_PERIODIC_FRAME_LISTS * 2, KM_SLEEP);
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate num_of_nodes = 1;
16530Sstevel@tonic-gate
16540Sstevel@tonic-gate /*
16550Sstevel@tonic-gate * Initialize the values which are used for setting up head pointers
16560Sstevel@tonic-gate * for the 32ms scheduling lists which starts from the Periodic Frame
16570Sstevel@tonic-gate * List.
16580Sstevel@tonic-gate */
16590Sstevel@tonic-gate for (i = 0; i < ehci_log_2(EHCI_NUM_PERIODIC_FRAME_LISTS); i++) {
16600Sstevel@tonic-gate for (j = 0, k = 0; k < num_of_nodes; k++, j++) {
16610Sstevel@tonic-gate ehci_index[j++] = temp[k];
16620Sstevel@tonic-gate ehci_index[j] = temp[k] + ehci_pow_2(i);
16630Sstevel@tonic-gate }
16640Sstevel@tonic-gate
16650Sstevel@tonic-gate num_of_nodes *= 2;
16660Sstevel@tonic-gate for (k = 0; k < num_of_nodes; k++)
16670Sstevel@tonic-gate temp[k] = ehci_index[k];
16680Sstevel@tonic-gate }
16690Sstevel@tonic-gate
16700Sstevel@tonic-gate kmem_free((void *)temp, (EHCI_NUM_PERIODIC_FRAME_LISTS * 2));
16710Sstevel@tonic-gate
16720Sstevel@tonic-gate /*
16730Sstevel@tonic-gate * Initialize the interrupt list in the Periodic Frame List Table
16740Sstevel@tonic-gate * so that it points to the bottom of the tree.
16750Sstevel@tonic-gate */
16760Sstevel@tonic-gate for (i = 0, j = 0; i < ehci_pow_2(TREE_HEIGHT); i++) {
16770Sstevel@tonic-gate addr = ehci_qh_cpu_to_iommu(ehcip, (ehci_qh_t *)
16780Sstevel@tonic-gate (&list_array[((EHCI_NUM_STATIC_NODES + 1) / 2) + i - 1]));
16790Sstevel@tonic-gate
16800Sstevel@tonic-gate ASSERT(addr);
16810Sstevel@tonic-gate
16820Sstevel@tonic-gate for (k = 0; k < ehci_pow_2(TREE_HEIGHT); k++) {
16830Sstevel@tonic-gate Set_PFLT(periodic_frame_list->
16840Sstevel@tonic-gate ehci_periodic_frame_list_table[ehci_index[j++]],
16850Sstevel@tonic-gate (uint32_t)(addr | EHCI_QH_LINK_REF_QH));
16860Sstevel@tonic-gate }
16870Sstevel@tonic-gate }
16880Sstevel@tonic-gate }
16890Sstevel@tonic-gate
16900Sstevel@tonic-gate
16910Sstevel@tonic-gate /*
16920Sstevel@tonic-gate * ehci_alloc_hcdi_ops:
16930Sstevel@tonic-gate *
16940Sstevel@tonic-gate * The HCDI interfaces or entry points are the software interfaces used by
16950Sstevel@tonic-gate * the Universal Serial Bus Driver (USBA) to access the services of the
16960Sstevel@tonic-gate * Host Controller Driver (HCD). During HCD initialization, inform USBA
16970Sstevel@tonic-gate * about all available HCDI interfaces or entry points.
16980Sstevel@tonic-gate */
16990Sstevel@tonic-gate usba_hcdi_ops_t *
ehci_alloc_hcdi_ops(ehci_state_t * ehcip)17000Sstevel@tonic-gate ehci_alloc_hcdi_ops(ehci_state_t *ehcip)
17010Sstevel@tonic-gate {
17020Sstevel@tonic-gate usba_hcdi_ops_t *usba_hcdi_ops;
17030Sstevel@tonic-gate
17040Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
17050Sstevel@tonic-gate "ehci_alloc_hcdi_ops:");
17060Sstevel@tonic-gate
17070Sstevel@tonic-gate usba_hcdi_ops = usba_alloc_hcdi_ops();
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_ops_version = HCDI_OPS_VERSION;
17100Sstevel@tonic-gate
1711880Sfrits usba_hcdi_ops->usba_hcdi_pm_support = ehci_hcdi_pm_support;
17120Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_open = ehci_hcdi_pipe_open;
17130Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_close = ehci_hcdi_pipe_close;
17140Sstevel@tonic-gate
17150Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_reset = ehci_hcdi_pipe_reset;
17168945SGuoqing.Zhu@Sun.COM usba_hcdi_ops->usba_hcdi_pipe_reset_data_toggle =
17178945SGuoqing.Zhu@Sun.COM ehci_hcdi_pipe_reset_data_toggle;
17180Sstevel@tonic-gate
17190Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_ctrl_xfer = ehci_hcdi_pipe_ctrl_xfer;
17200Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_bulk_xfer = ehci_hcdi_pipe_bulk_xfer;
17210Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_intr_xfer = ehci_hcdi_pipe_intr_xfer;
17220Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_isoc_xfer = ehci_hcdi_pipe_isoc_xfer;
17230Sstevel@tonic-gate
17240Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_bulk_transfer_size =
17255767Slc152243 ehci_hcdi_bulk_transfer_size;
17260Sstevel@tonic-gate
17270Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_intr_polling =
17285767Slc152243 ehci_hcdi_pipe_stop_intr_polling;
17290Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_pipe_stop_isoc_polling =
17305767Slc152243 ehci_hcdi_pipe_stop_isoc_polling;
17310Sstevel@tonic-gate
17320Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_current_frame_number =
17335767Slc152243 ehci_hcdi_get_current_frame_number;
17340Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_get_max_isoc_pkts =
17355767Slc152243 ehci_hcdi_get_max_isoc_pkts;
17360Sstevel@tonic-gate
17370Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_init =
17385767Slc152243 ehci_hcdi_polled_input_init;
17390Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_enter =
17405767Slc152243 ehci_hcdi_polled_input_enter;
17410Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_read =
17425767Slc152243 ehci_hcdi_polled_read;
17430Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_exit =
17445767Slc152243 ehci_hcdi_polled_input_exit;
17450Sstevel@tonic-gate usba_hcdi_ops->usba_hcdi_console_input_fini =
17465767Slc152243 ehci_hcdi_polled_input_fini;
17479095SZhigang.Lu@Sun.COM
17489095SZhigang.Lu@Sun.COM usba_hcdi_ops->usba_hcdi_console_output_init =
17499095SZhigang.Lu@Sun.COM ehci_hcdi_polled_output_init;
17509095SZhigang.Lu@Sun.COM usba_hcdi_ops->usba_hcdi_console_output_enter =
17519095SZhigang.Lu@Sun.COM ehci_hcdi_polled_output_enter;
17529095SZhigang.Lu@Sun.COM usba_hcdi_ops->usba_hcdi_console_write =
17539095SZhigang.Lu@Sun.COM ehci_hcdi_polled_write;
17549095SZhigang.Lu@Sun.COM usba_hcdi_ops->usba_hcdi_console_output_exit =
17559095SZhigang.Lu@Sun.COM ehci_hcdi_polled_output_exit;
17569095SZhigang.Lu@Sun.COM usba_hcdi_ops->usba_hcdi_console_output_fini =
17579095SZhigang.Lu@Sun.COM ehci_hcdi_polled_output_fini;
17580Sstevel@tonic-gate return (usba_hcdi_ops);
17590Sstevel@tonic-gate }
17600Sstevel@tonic-gate
17610Sstevel@tonic-gate
17620Sstevel@tonic-gate /*
17630Sstevel@tonic-gate * Host Controller Driver (HCD) deinitialization functions
17640Sstevel@tonic-gate */
17650Sstevel@tonic-gate
17660Sstevel@tonic-gate /*
17670Sstevel@tonic-gate * ehci_cleanup:
17680Sstevel@tonic-gate *
17690Sstevel@tonic-gate * Cleanup on attach failure or detach
17700Sstevel@tonic-gate */
17710Sstevel@tonic-gate int
ehci_cleanup(ehci_state_t * ehcip)17720Sstevel@tonic-gate ehci_cleanup(ehci_state_t *ehcip)
17730Sstevel@tonic-gate {
17740Sstevel@tonic-gate ehci_trans_wrapper_t *tw;
17750Sstevel@tonic-gate ehci_pipe_private_t *pp;
17760Sstevel@tonic-gate ehci_qtd_t *qtd;
17770Sstevel@tonic-gate int i, ctrl, rval;
17780Sstevel@tonic-gate int flags = ehcip->ehci_flags;
17790Sstevel@tonic-gate
17800Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_cleanup:");
17810Sstevel@tonic-gate
17820Sstevel@tonic-gate if (flags & EHCI_RHREG) {
17830Sstevel@tonic-gate /* Unload the root hub driver */
17840Sstevel@tonic-gate if (ehci_unload_root_hub_driver(ehcip) != USB_SUCCESS) {
17850Sstevel@tonic-gate
17860Sstevel@tonic-gate return (DDI_FAILURE);
17870Sstevel@tonic-gate }
17880Sstevel@tonic-gate }
17890Sstevel@tonic-gate
17900Sstevel@tonic-gate if (flags & EHCI_USBAREG) {
17910Sstevel@tonic-gate /* Unregister this HCD instance with USBA */
17920Sstevel@tonic-gate usba_hcdi_unregister(ehcip->ehci_dip);
17930Sstevel@tonic-gate }
17940Sstevel@tonic-gate
17950Sstevel@tonic-gate if (flags & EHCI_INTR) {
17960Sstevel@tonic-gate
17970Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate /* Disable all EHCI QH list processing */
18000Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
18010Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE |
18020Sstevel@tonic-gate EHCI_CMD_PERIODIC_SCHED_ENABLE)));
18030Sstevel@tonic-gate
18040Sstevel@tonic-gate /* Disable all EHCI interrupts */
18050Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0);
18060Sstevel@tonic-gate
18070Sstevel@tonic-gate /* wait for the next SOF */
18080Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip);
18090Sstevel@tonic-gate
1810880Sfrits /* Route all Root hub ports to Classic host controller */
1811880Sfrits Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
1812880Sfrits
18130Sstevel@tonic-gate /* Stop the EHCI host controller */
18140Sstevel@tonic-gate Set_OpReg(ehci_command,
18150Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
18160Sstevel@tonic-gate
18175767Slc152243 mutex_exit(&ehcip->ehci_int_mutex);
18185767Slc152243
18190Sstevel@tonic-gate /* Wait for sometime */
18205767Slc152243 delay(drv_usectohz(EHCI_TIMEWAIT));
18210Sstevel@tonic-gate
1822965Sgovinda ehci_rem_intrs(ehcip);
18230Sstevel@tonic-gate }
18240Sstevel@tonic-gate
18250Sstevel@tonic-gate /* Unmap the EHCI registers */
18260Sstevel@tonic-gate if (ehcip->ehci_caps_handle) {
18270Sstevel@tonic-gate ddi_regs_map_free(&ehcip->ehci_caps_handle);
18280Sstevel@tonic-gate }
18290Sstevel@tonic-gate
18300Sstevel@tonic-gate if (ehcip->ehci_config_handle) {
18310Sstevel@tonic-gate pci_config_teardown(&ehcip->ehci_config_handle);
18320Sstevel@tonic-gate }
18330Sstevel@tonic-gate
18340Sstevel@tonic-gate /* Free all the buffers */
18350Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_addr && ehcip->ehci_qtd_pool_mem_handle) {
18360Sstevel@tonic-gate for (i = 0; i < ehci_qtd_pool_size; i ++) {
18370Sstevel@tonic-gate qtd = &ehcip->ehci_qtd_pool_addr[i];
18380Sstevel@tonic-gate ctrl = Get_QTD(ehcip->
18390Sstevel@tonic-gate ehci_qtd_pool_addr[i].qtd_state);
18400Sstevel@tonic-gate
18410Sstevel@tonic-gate if ((ctrl != EHCI_QTD_FREE) &&
18420Sstevel@tonic-gate (ctrl != EHCI_QTD_DUMMY) &&
18430Sstevel@tonic-gate (qtd->qtd_trans_wrapper)) {
18440Sstevel@tonic-gate
18450Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
18460Sstevel@tonic-gate
18470Sstevel@tonic-gate tw = (ehci_trans_wrapper_t *)
18485767Slc152243 EHCI_LOOKUP_ID((uint32_t)
18495767Slc152243 Get_QTD(qtd->qtd_trans_wrapper));
18500Sstevel@tonic-gate
18510Sstevel@tonic-gate /* Obtain the pipe private structure */
18520Sstevel@tonic-gate pp = tw->tw_pipe_private;
18530Sstevel@tonic-gate
18540Sstevel@tonic-gate /* Stop the the transfer timer */
18550Sstevel@tonic-gate ehci_stop_xfer_timer(ehcip, tw,
18565767Slc152243 EHCI_REMOVE_XFER_ALWAYS);
18570Sstevel@tonic-gate
18580Sstevel@tonic-gate ehci_deallocate_tw(ehcip, pp, tw);
18590Sstevel@tonic-gate
18600Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
18610Sstevel@tonic-gate }
18620Sstevel@tonic-gate }
18630Sstevel@tonic-gate
18640Sstevel@tonic-gate /*
18650Sstevel@tonic-gate * If EHCI_QTD_POOL_BOUND flag is set, then unbind
18660Sstevel@tonic-gate * the handle for QTD pools.
18670Sstevel@tonic-gate */
18680Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag &
18690Sstevel@tonic-gate EHCI_QTD_POOL_BOUND) == EHCI_QTD_POOL_BOUND) {
18700Sstevel@tonic-gate
18710Sstevel@tonic-gate rval = ddi_dma_unbind_handle(
18720Sstevel@tonic-gate ehcip->ehci_qtd_pool_dma_handle);
18730Sstevel@tonic-gate
18740Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS);
18750Sstevel@tonic-gate }
18760Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qtd_pool_mem_handle);
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate
18790Sstevel@tonic-gate /* Free the QTD pool */
18800Sstevel@tonic-gate if (ehcip->ehci_qtd_pool_dma_handle) {
18810Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qtd_pool_dma_handle);
18820Sstevel@tonic-gate }
18830Sstevel@tonic-gate
18840Sstevel@tonic-gate if (ehcip->ehci_qh_pool_addr && ehcip->ehci_qh_pool_mem_handle) {
18850Sstevel@tonic-gate /*
18860Sstevel@tonic-gate * If EHCI_QH_POOL_BOUND flag is set, then unbind
18870Sstevel@tonic-gate * the handle for QH pools.
18880Sstevel@tonic-gate */
18890Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag &
18900Sstevel@tonic-gate EHCI_QH_POOL_BOUND) == EHCI_QH_POOL_BOUND) {
18910Sstevel@tonic-gate
18920Sstevel@tonic-gate rval = ddi_dma_unbind_handle(
18930Sstevel@tonic-gate ehcip->ehci_qh_pool_dma_handle);
18940Sstevel@tonic-gate
18950Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS);
18960Sstevel@tonic-gate }
18970Sstevel@tonic-gate
18980Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_qh_pool_mem_handle);
18990Sstevel@tonic-gate }
19000Sstevel@tonic-gate
19010Sstevel@tonic-gate /* Free the QH pool */
19020Sstevel@tonic-gate if (ehcip->ehci_qh_pool_dma_handle) {
19030Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_qh_pool_dma_handle);
19040Sstevel@tonic-gate }
19050Sstevel@tonic-gate
19060Sstevel@tonic-gate /* Free the Periodic frame list table (PFLT) area */
19070Sstevel@tonic-gate if (ehcip->ehci_periodic_frame_list_tablep &&
19080Sstevel@tonic-gate ehcip->ehci_pflt_mem_handle) {
19090Sstevel@tonic-gate /*
19100Sstevel@tonic-gate * If EHCI_PFLT_DMA_BOUND flag is set, then unbind
19110Sstevel@tonic-gate * the handle for PFLT.
19120Sstevel@tonic-gate */
19130Sstevel@tonic-gate if ((ehcip->ehci_dma_addr_bind_flag &
19140Sstevel@tonic-gate EHCI_PFLT_DMA_BOUND) == EHCI_PFLT_DMA_BOUND) {
19150Sstevel@tonic-gate
19160Sstevel@tonic-gate rval = ddi_dma_unbind_handle(
19170Sstevel@tonic-gate ehcip->ehci_pflt_dma_handle);
19180Sstevel@tonic-gate
19190Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS);
19200Sstevel@tonic-gate }
19210Sstevel@tonic-gate
19220Sstevel@tonic-gate ddi_dma_mem_free(&ehcip->ehci_pflt_mem_handle);
19230Sstevel@tonic-gate }
19240Sstevel@tonic-gate
19250Sstevel@tonic-gate (void) ehci_isoc_cleanup(ehcip);
19260Sstevel@tonic-gate
19270Sstevel@tonic-gate if (ehcip->ehci_pflt_dma_handle) {
19280Sstevel@tonic-gate ddi_dma_free_handle(&ehcip->ehci_pflt_dma_handle);
19290Sstevel@tonic-gate }
19300Sstevel@tonic-gate
19310Sstevel@tonic-gate if (flags & EHCI_INTR) {
19320Sstevel@tonic-gate /* Destroy the mutex */
19330Sstevel@tonic-gate mutex_destroy(&ehcip->ehci_int_mutex);
19340Sstevel@tonic-gate
19350Sstevel@tonic-gate /* Destroy the async schedule advance condition variable */
19360Sstevel@tonic-gate cv_destroy(&ehcip->ehci_async_schedule_advance_cv);
19370Sstevel@tonic-gate }
19380Sstevel@tonic-gate
19390Sstevel@tonic-gate /* clean up kstat structs */
19400Sstevel@tonic-gate ehci_destroy_stats(ehcip);
19410Sstevel@tonic-gate
19420Sstevel@tonic-gate /* Free ehci hcdi ops */
19430Sstevel@tonic-gate if (ehcip->ehci_hcdi_ops) {
19440Sstevel@tonic-gate usba_free_hcdi_ops(ehcip->ehci_hcdi_ops);
19450Sstevel@tonic-gate }
19460Sstevel@tonic-gate
19470Sstevel@tonic-gate if (flags & EHCI_ZALLOC) {
19480Sstevel@tonic-gate
19490Sstevel@tonic-gate usb_free_log_hdl(ehcip->ehci_log_hdl);
19500Sstevel@tonic-gate
19510Sstevel@tonic-gate /* Remove all properties that might have been created */
19520Sstevel@tonic-gate ddi_prop_remove_all(ehcip->ehci_dip);
19530Sstevel@tonic-gate
19540Sstevel@tonic-gate /* Free the soft state */
19550Sstevel@tonic-gate ddi_soft_state_free(ehci_statep,
19565767Slc152243 ddi_get_instance(ehcip->ehci_dip));
19570Sstevel@tonic-gate }
19580Sstevel@tonic-gate
19590Sstevel@tonic-gate return (DDI_SUCCESS);
19600Sstevel@tonic-gate }
19610Sstevel@tonic-gate
19620Sstevel@tonic-gate
19630Sstevel@tonic-gate /*
1964965Sgovinda * ehci_rem_intrs:
1965965Sgovinda *
1966965Sgovinda * Unregister FIXED or MSI interrupts
1967965Sgovinda */
1968965Sgovinda static void
ehci_rem_intrs(ehci_state_t * ehcip)1969965Sgovinda ehci_rem_intrs(ehci_state_t *ehcip)
1970965Sgovinda {
1971965Sgovinda int i;
1972965Sgovinda
1973965Sgovinda USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1974965Sgovinda "ehci_rem_intrs: interrupt type 0x%x", ehcip->ehci_intr_type);
1975965Sgovinda
1976965Sgovinda /* Disable all interrupts */
1977965Sgovinda if (ehcip->ehci_intr_cap & DDI_INTR_FLAG_BLOCK) {
1978965Sgovinda (void) ddi_intr_block_disable(ehcip->ehci_htable,
1979965Sgovinda ehcip->ehci_intr_cnt);
1980965Sgovinda } else {
1981965Sgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) {
1982965Sgovinda (void) ddi_intr_disable(ehcip->ehci_htable[i]);
1983965Sgovinda }
1984965Sgovinda }
1985965Sgovinda
1986965Sgovinda /* Call ddi_intr_remove_handler() */
1987965Sgovinda for (i = 0; i < ehcip->ehci_intr_cnt; i++) {
1988965Sgovinda (void) ddi_intr_remove_handler(ehcip->ehci_htable[i]);
1989965Sgovinda (void) ddi_intr_free(ehcip->ehci_htable[i]);
1990965Sgovinda }
1991965Sgovinda
1992965Sgovinda kmem_free(ehcip->ehci_htable,
1993965Sgovinda ehcip->ehci_intr_cnt * sizeof (ddi_intr_handle_t));
1994965Sgovinda }
1995965Sgovinda
1996965Sgovinda
1997965Sgovinda /*
19980Sstevel@tonic-gate * ehci_cpr_suspend
19990Sstevel@tonic-gate */
20000Sstevel@tonic-gate int
ehci_cpr_suspend(ehci_state_t * ehcip)20010Sstevel@tonic-gate ehci_cpr_suspend(ehci_state_t *ehcip)
20020Sstevel@tonic-gate {
20030Sstevel@tonic-gate int i;
20040Sstevel@tonic-gate
20050Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20060Sstevel@tonic-gate "ehci_cpr_suspend:");
20070Sstevel@tonic-gate
20080Sstevel@tonic-gate /* Call into the root hub and suspend it */
20090Sstevel@tonic-gate if (usba_hubdi_detach(ehcip->ehci_dip, DDI_SUSPEND) != DDI_SUCCESS) {
20100Sstevel@tonic-gate
20110Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20125767Slc152243 "ehci_cpr_suspend: root hub fails to suspend");
20130Sstevel@tonic-gate
20140Sstevel@tonic-gate return (DDI_FAILURE);
20150Sstevel@tonic-gate }
20160Sstevel@tonic-gate
20170Sstevel@tonic-gate /* Only root hub's intr pipe should be open at this time */
20180Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
20190Sstevel@tonic-gate
20200Sstevel@tonic-gate ASSERT(ehcip->ehci_open_pipe_count == 0);
20210Sstevel@tonic-gate
20220Sstevel@tonic-gate /* Just wait till all resources are reclaimed */
20230Sstevel@tonic-gate i = 0;
20240Sstevel@tonic-gate while ((ehcip->ehci_reclaim_list != NULL) && (i++ < 3)) {
20250Sstevel@tonic-gate ehci_handle_endpoint_reclaimation(ehcip);
20260Sstevel@tonic-gate (void) ehci_wait_for_sof(ehcip);
20270Sstevel@tonic-gate }
20280Sstevel@tonic-gate ASSERT(ehcip->ehci_reclaim_list == NULL);
20290Sstevel@tonic-gate
20301458Syq193411 USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20310Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC QH list processing");
20320Sstevel@tonic-gate
20330Sstevel@tonic-gate /* Disable all EHCI QH list processing */
20340Sstevel@tonic-gate Set_OpReg(ehci_command, (Get_OpReg(ehci_command) &
20350Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE)));
20360Sstevel@tonic-gate
20371458Syq193411 USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20380Sstevel@tonic-gate "ehci_cpr_suspend: Disable HC interrupts");
20390Sstevel@tonic-gate
20400Sstevel@tonic-gate /* Disable all EHCI interrupts */
20410Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0);
20420Sstevel@tonic-gate
20431458Syq193411 USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20440Sstevel@tonic-gate "ehci_cpr_suspend: Wait for the next SOF");
20450Sstevel@tonic-gate
20460Sstevel@tonic-gate /* Wait for the next SOF */
20470Sstevel@tonic-gate if (ehci_wait_for_sof(ehcip) != USB_SUCCESS) {
20480Sstevel@tonic-gate
20490Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20500Sstevel@tonic-gate "ehci_cpr_suspend: ehci host controller suspend failed");
20510Sstevel@tonic-gate
20520Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
20530Sstevel@tonic-gate return (DDI_FAILURE);
20540Sstevel@tonic-gate }
20550Sstevel@tonic-gate
20560Sstevel@tonic-gate /*
20570Sstevel@tonic-gate * Stop the ehci host controller
20580Sstevel@tonic-gate * if usb keyboard is not connected.
20590Sstevel@tonic-gate */
20605295Srandyf if (ehcip->ehci_polled_kbd_count == 0 || force_ehci_off != 0) {
20610Sstevel@tonic-gate Set_OpReg(ehci_command,
20620Sstevel@tonic-gate Get_OpReg(ehci_command) & ~EHCI_CMD_HOST_CTRL_RUN);
20639827SVincent.Wang@Sun.COM
20640Sstevel@tonic-gate }
20650Sstevel@tonic-gate
20660Sstevel@tonic-gate /* Set host controller soft state to suspend */
20670Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_SUSPEND_STATE;
20680Sstevel@tonic-gate
20690Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
20700Sstevel@tonic-gate
20710Sstevel@tonic-gate return (DDI_SUCCESS);
20720Sstevel@tonic-gate }
20730Sstevel@tonic-gate
20740Sstevel@tonic-gate
20750Sstevel@tonic-gate /*
20760Sstevel@tonic-gate * ehci_cpr_resume
20770Sstevel@tonic-gate */
20780Sstevel@tonic-gate int
ehci_cpr_resume(ehci_state_t * ehcip)20790Sstevel@tonic-gate ehci_cpr_resume(ehci_state_t *ehcip)
20800Sstevel@tonic-gate {
20810Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
20820Sstevel@tonic-gate
20830Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20840Sstevel@tonic-gate "ehci_cpr_resume: Restart the controller");
20850Sstevel@tonic-gate
20860Sstevel@tonic-gate /* Cleanup ehci specific information across cpr */
20870Sstevel@tonic-gate ehci_cpr_cleanup(ehcip);
20880Sstevel@tonic-gate
20890Sstevel@tonic-gate /* Restart the controller */
20901458Syq193411 if (ehci_init_ctlr(ehcip, EHCI_NORMAL_INITIALIZATION) != DDI_SUCCESS) {
20910Sstevel@tonic-gate
20920Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
20930Sstevel@tonic-gate "ehci_cpr_resume: ehci host controller resume failed ");
20940Sstevel@tonic-gate
20950Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
20960Sstevel@tonic-gate
20970Sstevel@tonic-gate return (DDI_FAILURE);
20980Sstevel@tonic-gate }
20990Sstevel@tonic-gate
21000Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
21010Sstevel@tonic-gate
21020Sstevel@tonic-gate /* Now resume the root hub */
21030Sstevel@tonic-gate if (usba_hubdi_attach(ehcip->ehci_dip, DDI_RESUME) != DDI_SUCCESS) {
21040Sstevel@tonic-gate
21050Sstevel@tonic-gate return (DDI_FAILURE);
21060Sstevel@tonic-gate }
21070Sstevel@tonic-gate
21080Sstevel@tonic-gate return (DDI_SUCCESS);
21090Sstevel@tonic-gate }
21100Sstevel@tonic-gate
21110Sstevel@tonic-gate
21120Sstevel@tonic-gate /*
21130Sstevel@tonic-gate * Bandwidth Allocation functions
21140Sstevel@tonic-gate */
21150Sstevel@tonic-gate
21160Sstevel@tonic-gate /*
21170Sstevel@tonic-gate * ehci_allocate_bandwidth:
21180Sstevel@tonic-gate *
21190Sstevel@tonic-gate * Figure out whether or not this interval may be supported. Return the index
21200Sstevel@tonic-gate * into the lattice if it can be supported. Return allocation failure if it
21210Sstevel@tonic-gate * can not be supported.
21220Sstevel@tonic-gate */
21230Sstevel@tonic-gate int
ehci_allocate_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t * pnode,uchar_t * smask,uchar_t * cmask)21240Sstevel@tonic-gate ehci_allocate_bandwidth(
21250Sstevel@tonic-gate ehci_state_t *ehcip,
21260Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
21270Sstevel@tonic-gate uint_t *pnode,
21280Sstevel@tonic-gate uchar_t *smask,
21290Sstevel@tonic-gate uchar_t *cmask)
21300Sstevel@tonic-gate {
21310Sstevel@tonic-gate int error = USB_SUCCESS;
21320Sstevel@tonic-gate
21330Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */
21340Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
21350Sstevel@tonic-gate
21360Sstevel@tonic-gate /* Reset the pnode to the last checked pnode */
21370Sstevel@tonic-gate *pnode = 0;
21380Sstevel@tonic-gate
21390Sstevel@tonic-gate /* Allocate high speed bandwidth */
21400Sstevel@tonic-gate if ((error = ehci_allocate_high_speed_bandwidth(ehcip,
21410Sstevel@tonic-gate ph, pnode, smask, cmask)) != USB_SUCCESS) {
21420Sstevel@tonic-gate
21430Sstevel@tonic-gate return (error);
21440Sstevel@tonic-gate }
21450Sstevel@tonic-gate
21460Sstevel@tonic-gate /*
21470Sstevel@tonic-gate * For low/full speed usb devices, allocate classic TT bandwidth
21480Sstevel@tonic-gate * in additional to high speed bandwidth.
21490Sstevel@tonic-gate */
21500Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) {
21510Sstevel@tonic-gate
21520Sstevel@tonic-gate /* Allocate classic TT bandwidth */
21530Sstevel@tonic-gate if ((error = ehci_allocate_classic_tt_bandwidth(
21540Sstevel@tonic-gate ehcip, ph, *pnode)) != USB_SUCCESS) {
21550Sstevel@tonic-gate
21560Sstevel@tonic-gate /* Deallocate high speed bandwidth */
21570Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(
21580Sstevel@tonic-gate ehcip, ph, *pnode, *smask, *cmask);
21590Sstevel@tonic-gate }
21600Sstevel@tonic-gate }
21610Sstevel@tonic-gate
21620Sstevel@tonic-gate return (error);
21630Sstevel@tonic-gate }
21640Sstevel@tonic-gate
21650Sstevel@tonic-gate
21660Sstevel@tonic-gate /*
21670Sstevel@tonic-gate * ehci_allocate_high_speed_bandwidth:
21680Sstevel@tonic-gate *
21690Sstevel@tonic-gate * Allocate high speed bandwidth for the low/full/high speed interrupt and
21700Sstevel@tonic-gate * isochronous endpoints.
21710Sstevel@tonic-gate */
21720Sstevel@tonic-gate static int
ehci_allocate_high_speed_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t * pnode,uchar_t * smask,uchar_t * cmask)21730Sstevel@tonic-gate ehci_allocate_high_speed_bandwidth(
21740Sstevel@tonic-gate ehci_state_t *ehcip,
21750Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
21760Sstevel@tonic-gate uint_t *pnode,
21770Sstevel@tonic-gate uchar_t *smask,
21780Sstevel@tonic-gate uchar_t *cmask)
21790Sstevel@tonic-gate {
21800Sstevel@tonic-gate uint_t sbandwidth, cbandwidth;
21810Sstevel@tonic-gate int interval;
21820Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep;
21830Sstevel@tonic-gate usba_device_t *child_ud;
21840Sstevel@tonic-gate usb_port_status_t port_status;
21850Sstevel@tonic-gate int error;
21860Sstevel@tonic-gate
21870Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */
21880Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
21890Sstevel@tonic-gate
21900Sstevel@tonic-gate /* Get child's usba device structure */
21910Sstevel@tonic-gate child_ud = ph->p_usba_device;
21920Sstevel@tonic-gate
21930Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex);
21940Sstevel@tonic-gate
21950Sstevel@tonic-gate /* Get the current usb device's port status */
21960Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status;
21970Sstevel@tonic-gate
21980Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex);
21990Sstevel@tonic-gate
22000Sstevel@tonic-gate /*
22010Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this
22020Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is
22030Sstevel@tonic-gate * zero.
22040Sstevel@tonic-gate */
22050Sstevel@tonic-gate error = ehci_compute_high_speed_bandwidth(ehcip, endpoint,
22060Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth);
22070Sstevel@tonic-gate if (error != USB_SUCCESS) {
22080Sstevel@tonic-gate
22090Sstevel@tonic-gate return (error);
22100Sstevel@tonic-gate }
22110Sstevel@tonic-gate
22120Sstevel@tonic-gate /*
22130Sstevel@tonic-gate * Adjust polling interval to be a power of 2.
22140Sstevel@tonic-gate * If this interval can't be supported, return
22150Sstevel@tonic-gate * allocation failure.
22160Sstevel@tonic-gate */
22170Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
22180Sstevel@tonic-gate if (interval == USB_FAILURE) {
22190Sstevel@tonic-gate
22200Sstevel@tonic-gate return (USB_FAILURE);
22210Sstevel@tonic-gate }
22220Sstevel@tonic-gate
22230Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) {
22243255Slg150142 /* Allocate bandwidth for high speed devices */
22253255Slg150142 if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
22263255Slg150142 USB_EP_ATTR_ISOCH) {
22273255Slg150142 error = USB_SUCCESS;
22283255Slg150142 } else {
22293255Slg150142
22303255Slg150142 error = ehci_find_bestfit_hs_mask(ehcip, smask, pnode,
22313255Slg150142 endpoint, sbandwidth, interval);
22323255Slg150142 }
22333255Slg150142
22340Sstevel@tonic-gate *cmask = 0x00;
22350Sstevel@tonic-gate
22360Sstevel@tonic-gate } else {
22370Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
22380Sstevel@tonic-gate USB_EP_ATTR_INTR) {
22390Sstevel@tonic-gate
22400Sstevel@tonic-gate /* Allocate bandwidth for low speed interrupt */
22410Sstevel@tonic-gate error = ehci_find_bestfit_ls_intr_mask(ehcip,
22420Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth,
22430Sstevel@tonic-gate interval);
22440Sstevel@tonic-gate } else {
22450Sstevel@tonic-gate if ((endpoint->bEndpointAddress &
22460Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
22470Sstevel@tonic-gate
22480Sstevel@tonic-gate /* Allocate bandwidth for sitd in */
22490Sstevel@tonic-gate error = ehci_find_bestfit_sitd_in_mask(ehcip,
22500Sstevel@tonic-gate smask, cmask, pnode, sbandwidth, cbandwidth,
22510Sstevel@tonic-gate interval);
22520Sstevel@tonic-gate } else {
22530Sstevel@tonic-gate
22540Sstevel@tonic-gate /* Allocate bandwidth for sitd out */
22550Sstevel@tonic-gate error = ehci_find_bestfit_sitd_out_mask(ehcip,
22560Sstevel@tonic-gate smask, pnode, sbandwidth, interval);
22570Sstevel@tonic-gate *cmask = 0x00;
22580Sstevel@tonic-gate }
22590Sstevel@tonic-gate }
22600Sstevel@tonic-gate }
22610Sstevel@tonic-gate
22620Sstevel@tonic-gate if (error != USB_SUCCESS) {
22630Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
22640Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Reached maximum "
22650Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a "
22660Sstevel@tonic-gate "given high-speed periodic endpoint");
22670Sstevel@tonic-gate
22680Sstevel@tonic-gate return (USB_NO_BANDWIDTH);
22690Sstevel@tonic-gate }
22700Sstevel@tonic-gate
22710Sstevel@tonic-gate return (error);
22720Sstevel@tonic-gate }
22730Sstevel@tonic-gate
22740Sstevel@tonic-gate
22750Sstevel@tonic-gate /*
22760Sstevel@tonic-gate * ehci_allocate_classic_tt_speed_bandwidth:
22770Sstevel@tonic-gate *
22780Sstevel@tonic-gate * Allocate classic TT bandwidth for the low/full speed interrupt and
22790Sstevel@tonic-gate * isochronous endpoints.
22800Sstevel@tonic-gate */
22810Sstevel@tonic-gate static int
ehci_allocate_classic_tt_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t pnode)22820Sstevel@tonic-gate ehci_allocate_classic_tt_bandwidth(
22830Sstevel@tonic-gate ehci_state_t *ehcip,
22840Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
22850Sstevel@tonic-gate uint_t pnode)
22860Sstevel@tonic-gate {
22870Sstevel@tonic-gate uint_t bandwidth, min;
22880Sstevel@tonic-gate uint_t height, leftmost, list;
22890Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep;
22900Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud;
22910Sstevel@tonic-gate usb_port_status_t port_status;
22920Sstevel@tonic-gate int i, interval;
22930Sstevel@tonic-gate
22940Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */
22950Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
22960Sstevel@tonic-gate
22970Sstevel@tonic-gate /* Get child's usba device structure */
22980Sstevel@tonic-gate child_ud = ph->p_usba_device;
22990Sstevel@tonic-gate
23000Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex);
23010Sstevel@tonic-gate
23020Sstevel@tonic-gate /* Get the current usb device's port status */
23030Sstevel@tonic-gate port_status = child_ud->usb_port_status;
23040Sstevel@tonic-gate
23050Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */
23060Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev;
23070Sstevel@tonic-gate
23080Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex);
23090Sstevel@tonic-gate
23101458Syq193411 USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23110Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: "
23126898Sfb209375 "child_ud 0x%p parent_ud 0x%p",
23136898Sfb209375 (void *)child_ud, (void *)parent_ud);
23140Sstevel@tonic-gate
23150Sstevel@tonic-gate /*
23160Sstevel@tonic-gate * Calculate the length in bytes of a transaction on this
23170Sstevel@tonic-gate * periodic endpoint. Return failure if maximum packet is
23180Sstevel@tonic-gate * zero.
23190Sstevel@tonic-gate */
23200Sstevel@tonic-gate if (ehci_compute_classic_bandwidth(endpoint,
23210Sstevel@tonic-gate port_status, &bandwidth) != USB_SUCCESS) {
23220Sstevel@tonic-gate
23230Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23240Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Periodic endpoint "
23250Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported");
23260Sstevel@tonic-gate
23270Sstevel@tonic-gate return (USB_NOT_SUPPORTED);
23280Sstevel@tonic-gate }
23290Sstevel@tonic-gate
23301458Syq193411 USB_DPRINTF_L3(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23310Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: bandwidth %d", bandwidth);
23320Sstevel@tonic-gate
23330Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex);
23340Sstevel@tonic-gate
23350Sstevel@tonic-gate /*
23360Sstevel@tonic-gate * If the length in bytes plus the allocated bandwidth exceeds
23370Sstevel@tonic-gate * the maximum, return bandwidth allocation failure.
23380Sstevel@tonic-gate */
23390Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_min_bandwidth + bandwidth) >
23400Sstevel@tonic-gate FS_PERIODIC_BANDWIDTH) {
23410Sstevel@tonic-gate
23420Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex);
23430Sstevel@tonic-gate
23440Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23450Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached maximum "
23460Sstevel@tonic-gate "bandwidth value and cannot allocate bandwidth for a "
23470Sstevel@tonic-gate "given low/full speed periodic endpoint");
23480Sstevel@tonic-gate
23490Sstevel@tonic-gate return (USB_NO_BANDWIDTH);
23500Sstevel@tonic-gate }
23510Sstevel@tonic-gate
23520Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex);
23530Sstevel@tonic-gate
23540Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */
23550Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
23560Sstevel@tonic-gate
23570Sstevel@tonic-gate /* Find the height in the tree */
23580Sstevel@tonic-gate height = ehci_lattice_height(interval);
23590Sstevel@tonic-gate
23600Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node. */
23610Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height);
23620Sstevel@tonic-gate
23630Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex);
23640Sstevel@tonic-gate
23650Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
23660Sstevel@tonic-gate list = ehci_index[leftmost + i];
23670Sstevel@tonic-gate
23680Sstevel@tonic-gate if ((parent_ud->usb_hs_hub_bandwidth[list] +
23690Sstevel@tonic-gate bandwidth) > FS_PERIODIC_BANDWIDTH) {
23700Sstevel@tonic-gate
23710Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex);
23720Sstevel@tonic-gate
23730Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
23740Sstevel@tonic-gate "ehci_allocate_classic_tt_bandwidth: Reached "
23750Sstevel@tonic-gate "maximum bandwidth value and cannot allocate "
23760Sstevel@tonic-gate "bandwidth for low/full periodic endpoint");
23770Sstevel@tonic-gate
23780Sstevel@tonic-gate return (USB_NO_BANDWIDTH);
23790Sstevel@tonic-gate }
23800Sstevel@tonic-gate }
23810Sstevel@tonic-gate
23820Sstevel@tonic-gate /*
23830Sstevel@tonic-gate * All the leaves for this node must be updated with the bandwidth.
23840Sstevel@tonic-gate */
23850Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
23860Sstevel@tonic-gate list = ehci_index[leftmost + i];
23870Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] += bandwidth;
23880Sstevel@tonic-gate }
23890Sstevel@tonic-gate
23900Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */
23910Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0];
23920Sstevel@tonic-gate
23930Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) {
23940Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) {
23950Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i];
23960Sstevel@tonic-gate }
23970Sstevel@tonic-gate }
23980Sstevel@tonic-gate
23990Sstevel@tonic-gate /* Save the minimum for later use */
24000Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min;
24010Sstevel@tonic-gate
24020Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex);
24030Sstevel@tonic-gate
24040Sstevel@tonic-gate return (USB_SUCCESS);
24050Sstevel@tonic-gate }
24060Sstevel@tonic-gate
24070Sstevel@tonic-gate
24080Sstevel@tonic-gate /*
24090Sstevel@tonic-gate * ehci_deallocate_bandwidth:
24100Sstevel@tonic-gate *
24110Sstevel@tonic-gate * Deallocate bandwidth for the given node in the lattice and the length
24120Sstevel@tonic-gate * of transfer.
24130Sstevel@tonic-gate */
24140Sstevel@tonic-gate void
ehci_deallocate_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t pnode,uchar_t smask,uchar_t cmask)24150Sstevel@tonic-gate ehci_deallocate_bandwidth(
24160Sstevel@tonic-gate ehci_state_t *ehcip,
24170Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
24180Sstevel@tonic-gate uint_t pnode,
24190Sstevel@tonic-gate uchar_t smask,
24200Sstevel@tonic-gate uchar_t cmask)
24210Sstevel@tonic-gate {
24220Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */
24230Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
24240Sstevel@tonic-gate
24250Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(ehcip, ph, pnode, smask, cmask);
24260Sstevel@tonic-gate
24270Sstevel@tonic-gate /*
24280Sstevel@tonic-gate * For low/full speed usb devices, deallocate classic TT bandwidth
24290Sstevel@tonic-gate * in additional to high speed bandwidth.
24300Sstevel@tonic-gate */
24310Sstevel@tonic-gate if (ph->p_usba_device->usb_port_status != USBA_HIGH_SPEED_DEV) {
24320Sstevel@tonic-gate
24330Sstevel@tonic-gate /* Deallocate classic TT bandwidth */
24340Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth(ehcip, ph, pnode);
24350Sstevel@tonic-gate }
24360Sstevel@tonic-gate }
24370Sstevel@tonic-gate
24380Sstevel@tonic-gate
24390Sstevel@tonic-gate /*
24400Sstevel@tonic-gate * ehci_deallocate_high_speed_bandwidth:
24410Sstevel@tonic-gate *
24420Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint.
24430Sstevel@tonic-gate */
24440Sstevel@tonic-gate static void
ehci_deallocate_high_speed_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t pnode,uchar_t smask,uchar_t cmask)24450Sstevel@tonic-gate ehci_deallocate_high_speed_bandwidth(
24460Sstevel@tonic-gate ehci_state_t *ehcip,
24470Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
24480Sstevel@tonic-gate uint_t pnode,
24490Sstevel@tonic-gate uchar_t smask,
24500Sstevel@tonic-gate uchar_t cmask)
24510Sstevel@tonic-gate {
24520Sstevel@tonic-gate uint_t height, leftmost;
24530Sstevel@tonic-gate uint_t list_count;
24540Sstevel@tonic-gate uint_t sbandwidth, cbandwidth;
24550Sstevel@tonic-gate int interval;
24560Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep;
24570Sstevel@tonic-gate usba_device_t *child_ud;
24580Sstevel@tonic-gate usb_port_status_t port_status;
24590Sstevel@tonic-gate
24600Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */
24610Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
24620Sstevel@tonic-gate
24630Sstevel@tonic-gate /* Get child's usba device structure */
24640Sstevel@tonic-gate child_ud = ph->p_usba_device;
24650Sstevel@tonic-gate
24660Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex);
24670Sstevel@tonic-gate
24680Sstevel@tonic-gate /* Get the current usb device's port status */
24690Sstevel@tonic-gate port_status = ph->p_usba_device->usb_port_status;
24700Sstevel@tonic-gate
24710Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex);
24720Sstevel@tonic-gate
24730Sstevel@tonic-gate (void) ehci_compute_high_speed_bandwidth(ehcip, endpoint,
24740Sstevel@tonic-gate port_status, &sbandwidth, &cbandwidth);
24750Sstevel@tonic-gate
24760Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */
24770Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
24780Sstevel@tonic-gate
24790Sstevel@tonic-gate /* Find the height in the tree */
24800Sstevel@tonic-gate height = ehci_lattice_height(interval);
24810Sstevel@tonic-gate
24820Sstevel@tonic-gate /*
24830Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node
24840Sstevel@tonic-gate */
24850Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height);
24860Sstevel@tonic-gate
24870Sstevel@tonic-gate list_count = EHCI_NUM_INTR_QH_LISTS/interval;
24880Sstevel@tonic-gate
24890Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */
24900Sstevel@tonic-gate if (port_status == USBA_HIGH_SPEED_DEV) {
24910Sstevel@tonic-gate
24920Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth,
24930Sstevel@tonic-gate leftmost, list_count, smask);
24940Sstevel@tonic-gate } else {
24950Sstevel@tonic-gate if ((endpoint->bmAttributes & USB_EP_ATTR_MASK) ==
24960Sstevel@tonic-gate USB_EP_ATTR_INTR) {
24970Sstevel@tonic-gate
24980Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth,
24990Sstevel@tonic-gate leftmost, list_count, smask);
25000Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -cbandwidth,
25010Sstevel@tonic-gate leftmost, list_count, cmask);
25020Sstevel@tonic-gate } else {
25030Sstevel@tonic-gate if ((endpoint->bEndpointAddress &
25040Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
25050Sstevel@tonic-gate
25060Sstevel@tonic-gate ehci_update_bw_availability(ehcip, -sbandwidth,
25070Sstevel@tonic-gate leftmost, list_count, smask);
25080Sstevel@tonic-gate ehci_update_bw_availability(ehcip,
25090Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost,
25100Sstevel@tonic-gate list_count, cmask);
25110Sstevel@tonic-gate } else {
25120Sstevel@tonic-gate
25130Sstevel@tonic-gate ehci_update_bw_availability(ehcip,
25140Sstevel@tonic-gate -MAX_UFRAME_SITD_XFER, leftmost,
25150Sstevel@tonic-gate list_count, smask);
25160Sstevel@tonic-gate }
25170Sstevel@tonic-gate }
25180Sstevel@tonic-gate }
25190Sstevel@tonic-gate }
25200Sstevel@tonic-gate
25210Sstevel@tonic-gate /*
25220Sstevel@tonic-gate * ehci_deallocate_classic_tt_bandwidth:
25230Sstevel@tonic-gate *
25240Sstevel@tonic-gate * Deallocate high speed bandwidth of a interrupt or isochronous endpoint.
25250Sstevel@tonic-gate */
25260Sstevel@tonic-gate static void
ehci_deallocate_classic_tt_bandwidth(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,uint_t pnode)25270Sstevel@tonic-gate ehci_deallocate_classic_tt_bandwidth(
25280Sstevel@tonic-gate ehci_state_t *ehcip,
25290Sstevel@tonic-gate usba_pipe_handle_data_t *ph,
25300Sstevel@tonic-gate uint_t pnode)
25310Sstevel@tonic-gate {
25320Sstevel@tonic-gate uint_t bandwidth, height, leftmost, list, min;
25330Sstevel@tonic-gate int i, interval;
25340Sstevel@tonic-gate usb_ep_descr_t *endpoint = &ph->p_ep;
25350Sstevel@tonic-gate usba_device_t *child_ud, *parent_ud;
25360Sstevel@tonic-gate usb_port_status_t port_status;
25370Sstevel@tonic-gate
25380Sstevel@tonic-gate /* This routine is protected by the ehci_int_mutex */
25390Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
25400Sstevel@tonic-gate
25410Sstevel@tonic-gate /* Get child's usba device structure */
25420Sstevel@tonic-gate child_ud = ph->p_usba_device;
25430Sstevel@tonic-gate
25440Sstevel@tonic-gate mutex_enter(&child_ud->usb_mutex);
25450Sstevel@tonic-gate
25460Sstevel@tonic-gate /* Get the current usb device's port status */
25470Sstevel@tonic-gate port_status = child_ud->usb_port_status;
25480Sstevel@tonic-gate
25490Sstevel@tonic-gate /* Get the parent high speed hub's usba device structure */
25500Sstevel@tonic-gate parent_ud = child_ud->usb_hs_hub_usba_dev;
25510Sstevel@tonic-gate
25520Sstevel@tonic-gate mutex_exit(&child_ud->usb_mutex);
25530Sstevel@tonic-gate
25540Sstevel@tonic-gate /* Obtain the bandwidth */
25550Sstevel@tonic-gate (void) ehci_compute_classic_bandwidth(endpoint,
25560Sstevel@tonic-gate port_status, &bandwidth);
25570Sstevel@tonic-gate
25580Sstevel@tonic-gate /* Adjust polling interval to be a power of 2 */
25590Sstevel@tonic-gate interval = ehci_adjust_polling_interval(ehcip, endpoint, port_status);
25600Sstevel@tonic-gate
25610Sstevel@tonic-gate /* Find the height in the tree */
25620Sstevel@tonic-gate height = ehci_lattice_height(interval);
25630Sstevel@tonic-gate
25640Sstevel@tonic-gate /* Find the leftmost leaf in the subtree specified by the node */
25650Sstevel@tonic-gate leftmost = ehci_leftmost_leaf(pnode, height);
25660Sstevel@tonic-gate
25670Sstevel@tonic-gate mutex_enter(&parent_ud->usb_mutex);
25680Sstevel@tonic-gate
25690Sstevel@tonic-gate /* Delete the bandwidth from the appropriate lists */
25700Sstevel@tonic-gate for (i = 0; i < (EHCI_NUM_INTR_QH_LISTS/interval); i++) {
25710Sstevel@tonic-gate list = ehci_index[leftmost + i];
25720Sstevel@tonic-gate parent_ud->usb_hs_hub_bandwidth[list] -= bandwidth;
25730Sstevel@tonic-gate }
25740Sstevel@tonic-gate
25750Sstevel@tonic-gate /* Find the leaf with the smallest allocated bandwidth */
25760Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[0];
25770Sstevel@tonic-gate
25780Sstevel@tonic-gate for (i = 1; i < EHCI_NUM_INTR_QH_LISTS; i++) {
25790Sstevel@tonic-gate if (parent_ud->usb_hs_hub_bandwidth[i] < min) {
25800Sstevel@tonic-gate min = parent_ud->usb_hs_hub_bandwidth[i];
25810Sstevel@tonic-gate }
25820Sstevel@tonic-gate }
25830Sstevel@tonic-gate
25840Sstevel@tonic-gate /* Save the minimum for later use */
25850Sstevel@tonic-gate parent_ud->usb_hs_hub_min_bandwidth = min;
25860Sstevel@tonic-gate
25870Sstevel@tonic-gate mutex_exit(&parent_ud->usb_mutex);
25880Sstevel@tonic-gate }
25890Sstevel@tonic-gate
25900Sstevel@tonic-gate
25910Sstevel@tonic-gate /*
25920Sstevel@tonic-gate * ehci_compute_high_speed_bandwidth:
25930Sstevel@tonic-gate *
25940Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total
25950Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the
25960Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC
25970Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC
25980Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt
25990Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a
26000Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the
26010Sstevel@tonic-gate * number of bytes for one transaction.
26020Sstevel@tonic-gate *
26030Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms
26040Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol
26050Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these
26060Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the
26070Sstevel@tonic-gate * USB 2.0 Specification.
26080Sstevel@tonic-gate *
26090Sstevel@tonic-gate * High-Speed:
26100Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + Host_Delay
26110Sstevel@tonic-gate *
26120Sstevel@tonic-gate * Split Transaction: (Low/Full speed devices connected behind usb2.0 hub)
26130Sstevel@tonic-gate *
26140Sstevel@tonic-gate * Protocol overhead + Split transaction overhead +
26150Sstevel@tonic-gate * ((MaxPktSz * 7)/6) + Host_Delay;
26160Sstevel@tonic-gate */
26170Sstevel@tonic-gate /* ARGSUSED */
26180Sstevel@tonic-gate static int
ehci_compute_high_speed_bandwidth(ehci_state_t * ehcip,usb_ep_descr_t * endpoint,usb_port_status_t port_status,uint_t * sbandwidth,uint_t * cbandwidth)26190Sstevel@tonic-gate ehci_compute_high_speed_bandwidth(
26200Sstevel@tonic-gate ehci_state_t *ehcip,
26210Sstevel@tonic-gate usb_ep_descr_t *endpoint,
26220Sstevel@tonic-gate usb_port_status_t port_status,
26230Sstevel@tonic-gate uint_t *sbandwidth,
26240Sstevel@tonic-gate uint_t *cbandwidth)
26250Sstevel@tonic-gate {
26260Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize;
26270Sstevel@tonic-gate
26280Sstevel@tonic-gate /* Return failure if endpoint maximum packet is zero */
26290Sstevel@tonic-gate if (maxpacketsize == 0) {
26300Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_BW, ehcip->ehci_log_hdl,
26310Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: Periodic endpoint "
26320Sstevel@tonic-gate "with zero endpoint maximum packet size is not supported");
26330Sstevel@tonic-gate
26340Sstevel@tonic-gate return (USB_NOT_SUPPORTED);
26350Sstevel@tonic-gate }
26360Sstevel@tonic-gate
26370Sstevel@tonic-gate /* Add bit-stuffing overhead */
26380Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6);
26390Sstevel@tonic-gate
26400Sstevel@tonic-gate /* Add Host Controller specific delay to required bandwidth */
26410Sstevel@tonic-gate *sbandwidth = EHCI_HOST_CONTROLLER_DELAY;
26420Sstevel@tonic-gate
26430Sstevel@tonic-gate /* Add xfer specific protocol overheads */
26440Sstevel@tonic-gate if ((endpoint->bmAttributes &
26450Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) {
26460Sstevel@tonic-gate /* High speed interrupt transaction */
26470Sstevel@tonic-gate *sbandwidth += HS_NON_ISOC_PROTO_OVERHEAD;
26480Sstevel@tonic-gate } else {
26490Sstevel@tonic-gate /* Isochronous transaction */
26500Sstevel@tonic-gate *sbandwidth += HS_ISOC_PROTO_OVERHEAD;
26510Sstevel@tonic-gate }
26520Sstevel@tonic-gate
26530Sstevel@tonic-gate /*
26540Sstevel@tonic-gate * For low/full speed devices, add split transaction specific
26550Sstevel@tonic-gate * overheads.
26560Sstevel@tonic-gate */
26570Sstevel@tonic-gate if (port_status != USBA_HIGH_SPEED_DEV) {
26580Sstevel@tonic-gate /*
26590Sstevel@tonic-gate * Add start and complete split transaction
26600Sstevel@tonic-gate * tokens overheads.
26610Sstevel@tonic-gate */
26620Sstevel@tonic-gate *cbandwidth = *sbandwidth + COMPLETE_SPLIT_OVERHEAD;
26630Sstevel@tonic-gate *sbandwidth += START_SPLIT_OVERHEAD;
26640Sstevel@tonic-gate
26650Sstevel@tonic-gate /* Add data overhead depending on data direction */
26660Sstevel@tonic-gate if ((endpoint->bEndpointAddress &
26670Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
26680Sstevel@tonic-gate *cbandwidth += maxpacketsize;
26690Sstevel@tonic-gate } else {
26700Sstevel@tonic-gate if ((endpoint->bmAttributes &
26710Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_ISOCH) {
26720Sstevel@tonic-gate /* There is no compete splits for out */
26730Sstevel@tonic-gate *cbandwidth = 0;
26740Sstevel@tonic-gate }
26750Sstevel@tonic-gate *sbandwidth += maxpacketsize;
26760Sstevel@tonic-gate }
26770Sstevel@tonic-gate } else {
26780Sstevel@tonic-gate uint_t xactions;
26790Sstevel@tonic-gate
26800Sstevel@tonic-gate /* Get the max transactions per microframe */
26810Sstevel@tonic-gate xactions = ((maxpacketsize & USB_EP_MAX_XACTS_MASK) >>
26820Sstevel@tonic-gate USB_EP_MAX_XACTS_SHIFT) + 1;
26830Sstevel@tonic-gate
26840Sstevel@tonic-gate /* High speed transaction */
26850Sstevel@tonic-gate *sbandwidth += maxpacketsize;
26860Sstevel@tonic-gate
26870Sstevel@tonic-gate /* Calculate bandwidth per micro-frame */
26880Sstevel@tonic-gate *sbandwidth *= xactions;
26890Sstevel@tonic-gate
26900Sstevel@tonic-gate *cbandwidth = 0;
26910Sstevel@tonic-gate }
26920Sstevel@tonic-gate
26930Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
26940Sstevel@tonic-gate "ehci_allocate_high_speed_bandwidth: "
26950Sstevel@tonic-gate "Start split bandwidth %d Complete split bandwidth %d",
26960Sstevel@tonic-gate *sbandwidth, *cbandwidth);
26970Sstevel@tonic-gate
26980Sstevel@tonic-gate return (USB_SUCCESS);
26990Sstevel@tonic-gate }
27000Sstevel@tonic-gate
27010Sstevel@tonic-gate
27020Sstevel@tonic-gate /*
27030Sstevel@tonic-gate * ehci_compute_classic_bandwidth:
27040Sstevel@tonic-gate *
27050Sstevel@tonic-gate * Given a periodic endpoint (interrupt or isochronous) determine the total
27060Sstevel@tonic-gate * bandwidth for one transaction. The EHCI host controller traverses the
27070Sstevel@tonic-gate * endpoint descriptor lists on a first-come-first-serve basis. When the HC
27080Sstevel@tonic-gate * services an endpoint, only a single transaction attempt is made. The HC
27090Sstevel@tonic-gate * moves to the next Endpoint Descriptor after the first transaction attempt
27100Sstevel@tonic-gate * rather than finishing the entire Transfer Descriptor. Therefore, when a
27110Sstevel@tonic-gate * Transfer Descriptor is inserted into the lattice, we will only count the
27120Sstevel@tonic-gate * number of bytes for one transaction.
27130Sstevel@tonic-gate *
27140Sstevel@tonic-gate * The following are the formulas used for calculating bandwidth in terms
27150Sstevel@tonic-gate * bytes and it is for the single USB high speed transaction. The protocol
27160Sstevel@tonic-gate * overheads will be different for each of type of USB transfer & all these
27170Sstevel@tonic-gate * formulas & protocol overheads are derived from the 5.11.3 section of the
27180Sstevel@tonic-gate * USB 2.0 Specification.
27190Sstevel@tonic-gate *
27200Sstevel@tonic-gate * Low-Speed:
27210Sstevel@tonic-gate * Protocol overhead + Hub LS overhead +
27220Sstevel@tonic-gate * (Low Speed clock * ((MaxPktSz * 7)/6)) + TT_Delay
27230Sstevel@tonic-gate *
27240Sstevel@tonic-gate * Full-Speed:
27250Sstevel@tonic-gate * Protocol overhead + ((MaxPktSz * 7)/6) + TT_Delay
27260Sstevel@tonic-gate */
27270Sstevel@tonic-gate /* ARGSUSED */
27280Sstevel@tonic-gate static int
ehci_compute_classic_bandwidth(usb_ep_descr_t * endpoint,usb_port_status_t port_status,uint_t * bandwidth)27290Sstevel@tonic-gate ehci_compute_classic_bandwidth(
27300Sstevel@tonic-gate usb_ep_descr_t *endpoint,
27310Sstevel@tonic-gate usb_port_status_t port_status,
27320Sstevel@tonic-gate uint_t *bandwidth)
27330Sstevel@tonic-gate {
27340Sstevel@tonic-gate ushort_t maxpacketsize = endpoint->wMaxPacketSize;
27350Sstevel@tonic-gate
27360Sstevel@tonic-gate /*
27370Sstevel@tonic-gate * If endpoint maximum packet is zero, then return immediately.
27380Sstevel@tonic-gate */
27390Sstevel@tonic-gate if (maxpacketsize == 0) {
27400Sstevel@tonic-gate
27410Sstevel@tonic-gate return (USB_NOT_SUPPORTED);
27420Sstevel@tonic-gate }
27430Sstevel@tonic-gate
27440Sstevel@tonic-gate /* Add TT delay to required bandwidth */
27450Sstevel@tonic-gate *bandwidth = TT_DELAY;
27460Sstevel@tonic-gate
27470Sstevel@tonic-gate /* Add bit-stuffing overhead */
27480Sstevel@tonic-gate maxpacketsize = (ushort_t)((maxpacketsize * 7) / 6);
27490Sstevel@tonic-gate
27500Sstevel@tonic-gate switch (port_status) {
27510Sstevel@tonic-gate case USBA_LOW_SPEED_DEV:
27520Sstevel@tonic-gate /* Low speed interrupt transaction */
27530Sstevel@tonic-gate *bandwidth += (LOW_SPEED_PROTO_OVERHEAD +
27540Sstevel@tonic-gate HUB_LOW_SPEED_PROTO_OVERHEAD +
27550Sstevel@tonic-gate (LOW_SPEED_CLOCK * maxpacketsize));
27560Sstevel@tonic-gate break;
27570Sstevel@tonic-gate case USBA_FULL_SPEED_DEV:
27580Sstevel@tonic-gate /* Full speed transaction */
27590Sstevel@tonic-gate *bandwidth += maxpacketsize;
27600Sstevel@tonic-gate
27610Sstevel@tonic-gate /* Add xfer specific protocol overheads */
27620Sstevel@tonic-gate if ((endpoint->bmAttributes &
27630Sstevel@tonic-gate USB_EP_ATTR_MASK) == USB_EP_ATTR_INTR) {
27640Sstevel@tonic-gate /* Full speed interrupt transaction */
27650Sstevel@tonic-gate *bandwidth += FS_NON_ISOC_PROTO_OVERHEAD;
27660Sstevel@tonic-gate } else {
27670Sstevel@tonic-gate /* Isochronous and input transaction */
27680Sstevel@tonic-gate if ((endpoint->bEndpointAddress &
27690Sstevel@tonic-gate USB_EP_DIR_MASK) == USB_EP_DIR_IN) {
27700Sstevel@tonic-gate *bandwidth += FS_ISOC_INPUT_PROTO_OVERHEAD;
27710Sstevel@tonic-gate } else {
27720Sstevel@tonic-gate /* Isochronous and output transaction */
27730Sstevel@tonic-gate *bandwidth += FS_ISOC_OUTPUT_PROTO_OVERHEAD;
27740Sstevel@tonic-gate }
27750Sstevel@tonic-gate }
27760Sstevel@tonic-gate break;
27770Sstevel@tonic-gate }
27780Sstevel@tonic-gate
27790Sstevel@tonic-gate return (USB_SUCCESS);
27800Sstevel@tonic-gate }
27810Sstevel@tonic-gate
27820Sstevel@tonic-gate
27830Sstevel@tonic-gate /*
27840Sstevel@tonic-gate * ehci_adjust_polling_interval:
27850Sstevel@tonic-gate *
27860Sstevel@tonic-gate * Adjust bandwidth according usb device speed.
27870Sstevel@tonic-gate */
27880Sstevel@tonic-gate /* ARGSUSED */
27890Sstevel@tonic-gate int
ehci_adjust_polling_interval(ehci_state_t * ehcip,usb_ep_descr_t * endpoint,usb_port_status_t port_status)27900Sstevel@tonic-gate ehci_adjust_polling_interval(
27910Sstevel@tonic-gate ehci_state_t *ehcip,
27920Sstevel@tonic-gate usb_ep_descr_t *endpoint,
27930Sstevel@tonic-gate usb_port_status_t port_status)
27940Sstevel@tonic-gate {
27950Sstevel@tonic-gate uint_t interval;
27960Sstevel@tonic-gate int i = 0;
27970Sstevel@tonic-gate
27980Sstevel@tonic-gate /* Get the polling interval */
27990Sstevel@tonic-gate interval = endpoint->bInterval;
28000Sstevel@tonic-gate
28010Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28020Sstevel@tonic-gate "ehci_adjust_polling_interval: Polling interval 0x%x", interval);
28030Sstevel@tonic-gate
28040Sstevel@tonic-gate /*
28050Sstevel@tonic-gate * According USB 2.0 Specifications, a high-speed endpoint's
28060Sstevel@tonic-gate * polling intervals are specified interms of 125us or micro
28070Sstevel@tonic-gate * frame, where as full/low endpoint's polling intervals are
28080Sstevel@tonic-gate * specified in milliseconds.
28090Sstevel@tonic-gate *
28100Sstevel@tonic-gate * A high speed interrupt/isochronous endpoints can specify
28110Sstevel@tonic-gate * desired polling interval between 1 to 16 micro-frames,
28120Sstevel@tonic-gate * where as full/low endpoints can specify between 1 to 255
28130Sstevel@tonic-gate * milliseconds.
28140Sstevel@tonic-gate */
28150Sstevel@tonic-gate switch (port_status) {
28160Sstevel@tonic-gate case USBA_LOW_SPEED_DEV:
28170Sstevel@tonic-gate /*
28180Sstevel@tonic-gate * Low speed endpoints are limited to specifying
28190Sstevel@tonic-gate * only 8ms to 255ms in this driver. If a device
28200Sstevel@tonic-gate * reports a polling interval that is less than 8ms,
28210Sstevel@tonic-gate * it will use 8 ms instead.
28220Sstevel@tonic-gate */
28230Sstevel@tonic-gate if (interval < LS_MIN_POLL_INTERVAL) {
28240Sstevel@tonic-gate
28250Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28260Sstevel@tonic-gate "Low speed endpoint's poll interval of %d ms "
28270Sstevel@tonic-gate "is below threshold. Rounding up to %d ms",
28280Sstevel@tonic-gate interval, LS_MIN_POLL_INTERVAL);
28290Sstevel@tonic-gate
28300Sstevel@tonic-gate interval = LS_MIN_POLL_INTERVAL;
28310Sstevel@tonic-gate }
28320Sstevel@tonic-gate
28330Sstevel@tonic-gate /*
28340Sstevel@tonic-gate * Return an error if the polling interval is greater
28350Sstevel@tonic-gate * than 255ms.
28360Sstevel@tonic-gate */
28370Sstevel@tonic-gate if (interval > LS_MAX_POLL_INTERVAL) {
28380Sstevel@tonic-gate
28390Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28400Sstevel@tonic-gate "Low speed endpoint's poll interval is "
28410Sstevel@tonic-gate "greater than %d ms", LS_MAX_POLL_INTERVAL);
28420Sstevel@tonic-gate
28430Sstevel@tonic-gate return (USB_FAILURE);
28440Sstevel@tonic-gate }
28450Sstevel@tonic-gate break;
28460Sstevel@tonic-gate
28470Sstevel@tonic-gate case USBA_FULL_SPEED_DEV:
28480Sstevel@tonic-gate /*
28490Sstevel@tonic-gate * Return an error if the polling interval is less
28500Sstevel@tonic-gate * than 1ms and greater than 255ms.
28510Sstevel@tonic-gate */
28520Sstevel@tonic-gate if ((interval < FS_MIN_POLL_INTERVAL) &&
28530Sstevel@tonic-gate (interval > FS_MAX_POLL_INTERVAL)) {
28540Sstevel@tonic-gate
28550Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28560Sstevel@tonic-gate "Full speed endpoint's poll interval must "
28570Sstevel@tonic-gate "be between %d and %d ms", FS_MIN_POLL_INTERVAL,
28580Sstevel@tonic-gate FS_MAX_POLL_INTERVAL);
28590Sstevel@tonic-gate
28600Sstevel@tonic-gate return (USB_FAILURE);
28610Sstevel@tonic-gate }
28620Sstevel@tonic-gate break;
28630Sstevel@tonic-gate case USBA_HIGH_SPEED_DEV:
28640Sstevel@tonic-gate /*
28650Sstevel@tonic-gate * Return an error if the polling interval is less 1
28660Sstevel@tonic-gate * and greater than 16. Convert this value to 125us
28670Sstevel@tonic-gate * units using 2^(bInterval -1). refer usb 2.0 spec
28680Sstevel@tonic-gate * page 51 for details.
28690Sstevel@tonic-gate */
28700Sstevel@tonic-gate if ((interval < HS_MIN_POLL_INTERVAL) &&
28710Sstevel@tonic-gate (interval > HS_MAX_POLL_INTERVAL)) {
28720Sstevel@tonic-gate
28730Sstevel@tonic-gate USB_DPRINTF_L1(PRINT_MASK_BW, ehcip->ehci_log_hdl,
28740Sstevel@tonic-gate "High speed endpoint's poll interval "
28750Sstevel@tonic-gate "must be between %d and %d units",
28760Sstevel@tonic-gate HS_MIN_POLL_INTERVAL, HS_MAX_POLL_INTERVAL);
28770Sstevel@tonic-gate
28780Sstevel@tonic-gate return (USB_FAILURE);
28790Sstevel@tonic-gate }
28800Sstevel@tonic-gate
28810Sstevel@tonic-gate /* Adjust high speed device polling interval */
28820Sstevel@tonic-gate interval =
28830Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval(ehcip, endpoint);
28840Sstevel@tonic-gate
28850Sstevel@tonic-gate break;
28860Sstevel@tonic-gate }
28870Sstevel@tonic-gate
28880Sstevel@tonic-gate /*
28890Sstevel@tonic-gate * If polling interval is greater than 32ms,
28900Sstevel@tonic-gate * adjust polling interval equal to 32ms.
28910Sstevel@tonic-gate */
28920Sstevel@tonic-gate if (interval > EHCI_NUM_INTR_QH_LISTS) {
28930Sstevel@tonic-gate interval = EHCI_NUM_INTR_QH_LISTS;
28940Sstevel@tonic-gate }
28950Sstevel@tonic-gate
28960Sstevel@tonic-gate /*
28970Sstevel@tonic-gate * Find the nearest power of 2 that's less
28980Sstevel@tonic-gate * than interval.
28990Sstevel@tonic-gate */
29000Sstevel@tonic-gate while ((ehci_pow_2(i)) <= interval) {
29010Sstevel@tonic-gate i++;
29020Sstevel@tonic-gate }
29030Sstevel@tonic-gate
29040Sstevel@tonic-gate return (ehci_pow_2((i - 1)));
29050Sstevel@tonic-gate }
29060Sstevel@tonic-gate
29070Sstevel@tonic-gate
29080Sstevel@tonic-gate /*
29090Sstevel@tonic-gate * ehci_adjust_high_speed_polling_interval:
29100Sstevel@tonic-gate */
29110Sstevel@tonic-gate /* ARGSUSED */
29120Sstevel@tonic-gate static int
ehci_adjust_high_speed_polling_interval(ehci_state_t * ehcip,usb_ep_descr_t * endpoint)29130Sstevel@tonic-gate ehci_adjust_high_speed_polling_interval(
29140Sstevel@tonic-gate ehci_state_t *ehcip,
29150Sstevel@tonic-gate usb_ep_descr_t *endpoint)
29160Sstevel@tonic-gate {
29170Sstevel@tonic-gate uint_t interval;
29180Sstevel@tonic-gate
29190Sstevel@tonic-gate /* Get the polling interval */
29200Sstevel@tonic-gate interval = ehci_pow_2(endpoint->bInterval - 1);
29210Sstevel@tonic-gate
29220Sstevel@tonic-gate /*
29230Sstevel@tonic-gate * Convert polling interval from micro seconds
29240Sstevel@tonic-gate * to milli seconds.
29250Sstevel@tonic-gate */
29260Sstevel@tonic-gate if (interval <= EHCI_MAX_UFRAMES) {
29270Sstevel@tonic-gate interval = 1;
29280Sstevel@tonic-gate } else {
29290Sstevel@tonic-gate interval = interval/EHCI_MAX_UFRAMES;
29300Sstevel@tonic-gate }
29310Sstevel@tonic-gate
29320Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
29330Sstevel@tonic-gate "ehci_adjust_high_speed_polling_interval: "
29340Sstevel@tonic-gate "High speed adjusted interval 0x%x", interval);
29350Sstevel@tonic-gate
29360Sstevel@tonic-gate return (interval);
29370Sstevel@tonic-gate }
29380Sstevel@tonic-gate
29390Sstevel@tonic-gate
29400Sstevel@tonic-gate /*
29410Sstevel@tonic-gate * ehci_lattice_height:
29420Sstevel@tonic-gate *
29430Sstevel@tonic-gate * Given the requested bandwidth, find the height in the tree at which the
29440Sstevel@tonic-gate * nodes for this bandwidth fall. The height is measured as the number of
29450Sstevel@tonic-gate * nodes from the leaf to the level specified by bandwidth The root of the
29460Sstevel@tonic-gate * tree is at height TREE_HEIGHT.
29470Sstevel@tonic-gate */
29480Sstevel@tonic-gate static uint_t
ehci_lattice_height(uint_t interval)29490Sstevel@tonic-gate ehci_lattice_height(uint_t interval)
29500Sstevel@tonic-gate {
29510Sstevel@tonic-gate return (TREE_HEIGHT - (ehci_log_2(interval)));
29520Sstevel@tonic-gate }
29530Sstevel@tonic-gate
29540Sstevel@tonic-gate
29550Sstevel@tonic-gate /*
29560Sstevel@tonic-gate * ehci_lattice_parent:
29570Sstevel@tonic-gate *
29580Sstevel@tonic-gate * Given a node in the lattice, find the index of the parent node
29590Sstevel@tonic-gate */
29600Sstevel@tonic-gate static uint_t
ehci_lattice_parent(uint_t node)29610Sstevel@tonic-gate ehci_lattice_parent(uint_t node)
29620Sstevel@tonic-gate {
29630Sstevel@tonic-gate if ((node % 2) == 0) {
29640Sstevel@tonic-gate
29650Sstevel@tonic-gate return ((node/2) - 1);
29660Sstevel@tonic-gate } else {
29670Sstevel@tonic-gate
29680Sstevel@tonic-gate return ((node + 1)/2 - 1);
29690Sstevel@tonic-gate }
29700Sstevel@tonic-gate }
29710Sstevel@tonic-gate
29720Sstevel@tonic-gate
29730Sstevel@tonic-gate /*
29740Sstevel@tonic-gate * ehci_find_periodic_node:
29750Sstevel@tonic-gate *
29760Sstevel@tonic-gate * Based on the "real" array leaf node and interval, get the periodic node.
29770Sstevel@tonic-gate */
29780Sstevel@tonic-gate static uint_t
ehci_find_periodic_node(uint_t leaf,int interval)29790Sstevel@tonic-gate ehci_find_periodic_node(uint_t leaf, int interval) {
29800Sstevel@tonic-gate uint_t lattice_leaf;
29810Sstevel@tonic-gate uint_t height = ehci_lattice_height(interval);
29820Sstevel@tonic-gate uint_t pnode;
29830Sstevel@tonic-gate int i;
29840Sstevel@tonic-gate
29850Sstevel@tonic-gate /* Get the leaf number in the lattice */
29860Sstevel@tonic-gate lattice_leaf = leaf + EHCI_NUM_INTR_QH_LISTS - 1;
29870Sstevel@tonic-gate
29880Sstevel@tonic-gate /* Get the node in the lattice based on the height and leaf */
29890Sstevel@tonic-gate pnode = lattice_leaf;
29900Sstevel@tonic-gate for (i = 0; i < height; i++) {
29910Sstevel@tonic-gate pnode = ehci_lattice_parent(pnode);
29920Sstevel@tonic-gate }
29930Sstevel@tonic-gate
29940Sstevel@tonic-gate return (pnode);
29950Sstevel@tonic-gate }
29960Sstevel@tonic-gate
29970Sstevel@tonic-gate
29980Sstevel@tonic-gate /*
29990Sstevel@tonic-gate * ehci_leftmost_leaf:
30000Sstevel@tonic-gate *
30010Sstevel@tonic-gate * Find the leftmost leaf in the subtree specified by the node. Height refers
30020Sstevel@tonic-gate * to number of nodes from the bottom of the tree to the node, including the
30030Sstevel@tonic-gate * node.
30040Sstevel@tonic-gate *
30050Sstevel@tonic-gate * The formula for a zero based tree is:
30060Sstevel@tonic-gate * 2^H * Node + 2^H - 1
30070Sstevel@tonic-gate * The leaf of the tree is an array, convert the number for the array.
30080Sstevel@tonic-gate * Subtract the size of nodes not in the array
30090Sstevel@tonic-gate * 2^H * Node + 2^H - 1 - (EHCI_NUM_INTR_QH_LISTS - 1) =
30100Sstevel@tonic-gate * 2^H * Node + 2^H - EHCI_NUM_INTR_QH_LISTS =
30110Sstevel@tonic-gate * 2^H * (Node + 1) - EHCI_NUM_INTR_QH_LISTS
30120Sstevel@tonic-gate * 0
30130Sstevel@tonic-gate * 1 2
30140Sstevel@tonic-gate * 0 1 2 3
30150Sstevel@tonic-gate */
30160Sstevel@tonic-gate static uint_t
ehci_leftmost_leaf(uint_t node,uint_t height)30170Sstevel@tonic-gate ehci_leftmost_leaf(
30180Sstevel@tonic-gate uint_t node,
30190Sstevel@tonic-gate uint_t height)
30200Sstevel@tonic-gate {
30210Sstevel@tonic-gate return ((ehci_pow_2(height) * (node + 1)) - EHCI_NUM_INTR_QH_LISTS);
30220Sstevel@tonic-gate }
30230Sstevel@tonic-gate
30240Sstevel@tonic-gate
30250Sstevel@tonic-gate /*
30260Sstevel@tonic-gate * ehci_pow_2:
30270Sstevel@tonic-gate *
30280Sstevel@tonic-gate * Compute 2 to the power
30290Sstevel@tonic-gate */
30300Sstevel@tonic-gate static uint_t
ehci_pow_2(uint_t x)30310Sstevel@tonic-gate ehci_pow_2(uint_t x)
30320Sstevel@tonic-gate {
30330Sstevel@tonic-gate if (x == 0) {
30340Sstevel@tonic-gate
30350Sstevel@tonic-gate return (1);
30360Sstevel@tonic-gate } else {
30370Sstevel@tonic-gate
30380Sstevel@tonic-gate return (2 << (x - 1));
30390Sstevel@tonic-gate }
30400Sstevel@tonic-gate }
30410Sstevel@tonic-gate
30420Sstevel@tonic-gate
30430Sstevel@tonic-gate /*
30440Sstevel@tonic-gate * ehci_log_2:
30450Sstevel@tonic-gate *
30460Sstevel@tonic-gate * Compute log base 2 of x
30470Sstevel@tonic-gate */
30480Sstevel@tonic-gate static uint_t
ehci_log_2(uint_t x)30490Sstevel@tonic-gate ehci_log_2(uint_t x)
30500Sstevel@tonic-gate {
30510Sstevel@tonic-gate int i = 0;
30520Sstevel@tonic-gate
30530Sstevel@tonic-gate while (x != 1) {
30540Sstevel@tonic-gate x = x >> 1;
30550Sstevel@tonic-gate i++;
30560Sstevel@tonic-gate }
30570Sstevel@tonic-gate
30580Sstevel@tonic-gate return (i);
30590Sstevel@tonic-gate }
30600Sstevel@tonic-gate
30610Sstevel@tonic-gate
30620Sstevel@tonic-gate /*
30630Sstevel@tonic-gate * ehci_find_bestfit_hs_mask:
30640Sstevel@tonic-gate *
30650Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation, and update the
30660Sstevel@tonic-gate * bandwidth allocation.
30670Sstevel@tonic-gate */
30680Sstevel@tonic-gate static int
ehci_find_bestfit_hs_mask(ehci_state_t * ehcip,uchar_t * smask,uint_t * pnode,usb_ep_descr_t * endpoint,uint_t bandwidth,int interval)30690Sstevel@tonic-gate ehci_find_bestfit_hs_mask(
30700Sstevel@tonic-gate ehci_state_t *ehcip,
30710Sstevel@tonic-gate uchar_t *smask,
30720Sstevel@tonic-gate uint_t *pnode,
30730Sstevel@tonic-gate usb_ep_descr_t *endpoint,
30740Sstevel@tonic-gate uint_t bandwidth,
30750Sstevel@tonic-gate int interval)
30760Sstevel@tonic-gate {
30770Sstevel@tonic-gate int i;
30780Sstevel@tonic-gate uint_t elements, index;
30790Sstevel@tonic-gate int array_leaf, best_array_leaf;
30800Sstevel@tonic-gate uint_t node_bandwidth, best_node_bandwidth;
30810Sstevel@tonic-gate uint_t leaf_count;
30820Sstevel@tonic-gate uchar_t bw_mask;
30830Sstevel@tonic-gate uchar_t best_smask;
30840Sstevel@tonic-gate
30850Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
30860Sstevel@tonic-gate "ehci_find_bestfit_hs_mask: ");
30870Sstevel@tonic-gate
30880Sstevel@tonic-gate /* Get all the valid smasks */
30890Sstevel@tonic-gate switch (ehci_pow_2(endpoint->bInterval - 1)) {
30900Sstevel@tonic-gate case EHCI_INTR_1US_POLL:
30910Sstevel@tonic-gate index = EHCI_1US_MASK_INDEX;
30920Sstevel@tonic-gate elements = EHCI_INTR_1US_POLL;
30930Sstevel@tonic-gate break;
30940Sstevel@tonic-gate case EHCI_INTR_2US_POLL:
30950Sstevel@tonic-gate index = EHCI_2US_MASK_INDEX;
30960Sstevel@tonic-gate elements = EHCI_INTR_2US_POLL;
30970Sstevel@tonic-gate break;
30980Sstevel@tonic-gate case EHCI_INTR_4US_POLL:
30990Sstevel@tonic-gate index = EHCI_4US_MASK_INDEX;
31000Sstevel@tonic-gate elements = EHCI_INTR_4US_POLL;
31010Sstevel@tonic-gate break;
31020Sstevel@tonic-gate case EHCI_INTR_XUS_POLL:
31030Sstevel@tonic-gate default:
31040Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX;
31050Sstevel@tonic-gate elements = EHCI_INTR_XUS_POLL;
31060Sstevel@tonic-gate break;
31070Sstevel@tonic-gate }
31080Sstevel@tonic-gate
31090Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
31100Sstevel@tonic-gate
31110Sstevel@tonic-gate /*
31120Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically
31130Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval.
31140Sstevel@tonic-gate */
31150Sstevel@tonic-gate best_smask = 0x00;
31160Sstevel@tonic-gate best_node_bandwidth = 0;
31170Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) {
31180Sstevel@tonic-gate /* Find the bandwidth mask */
31190Sstevel@tonic-gate node_bandwidth = ehci_calculate_bw_availability_mask(ehcip,
31200Sstevel@tonic-gate bandwidth, ehci_index[array_leaf], leaf_count, &bw_mask);
31210Sstevel@tonic-gate
31220Sstevel@tonic-gate /*
31230Sstevel@tonic-gate * If this node cannot support our requirements skip to the
31240Sstevel@tonic-gate * next leaf.
31250Sstevel@tonic-gate */
31260Sstevel@tonic-gate if (bw_mask == 0x00) {
31270Sstevel@tonic-gate continue;
31280Sstevel@tonic-gate }
31290Sstevel@tonic-gate
31300Sstevel@tonic-gate /*
31310Sstevel@tonic-gate * Now make sure our bandwidth requirements can be
31320Sstevel@tonic-gate * satisfied with one of smasks in this node.
31330Sstevel@tonic-gate */
31340Sstevel@tonic-gate *smask = 0x00;
31350Sstevel@tonic-gate for (i = index; i < (index + elements); i++) {
31360Sstevel@tonic-gate /* Check the start split mask value */
31370Sstevel@tonic-gate if (ehci_start_split_mask[index] & bw_mask) {
31380Sstevel@tonic-gate *smask = ehci_start_split_mask[index];
31390Sstevel@tonic-gate break;
31400Sstevel@tonic-gate }
31410Sstevel@tonic-gate }
31420Sstevel@tonic-gate
31430Sstevel@tonic-gate /*
31440Sstevel@tonic-gate * If an appropriate smask is found save the information if:
31450Sstevel@tonic-gate * o best_smask has not been found yet.
31460Sstevel@tonic-gate * - or -
31470Sstevel@tonic-gate * o This is the node with the least amount of bandwidth
31480Sstevel@tonic-gate */
31490Sstevel@tonic-gate if ((*smask != 0x00) &&
31500Sstevel@tonic-gate ((best_smask == 0x00) ||
31515767Slc152243 (best_node_bandwidth > node_bandwidth))) {
31520Sstevel@tonic-gate
31530Sstevel@tonic-gate best_node_bandwidth = node_bandwidth;
31540Sstevel@tonic-gate best_array_leaf = array_leaf;
31550Sstevel@tonic-gate best_smask = *smask;
31560Sstevel@tonic-gate }
31570Sstevel@tonic-gate }
31580Sstevel@tonic-gate
31590Sstevel@tonic-gate /*
31600Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the
31610Sstevel@tonic-gate * appropriate variables and return success.
31620Sstevel@tonic-gate */
31630Sstevel@tonic-gate if (best_smask) {
31640Sstevel@tonic-gate *smask = best_smask;
31650Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
31660Sstevel@tonic-gate interval);
31670Sstevel@tonic-gate ehci_update_bw_availability(ehcip, bandwidth,
31680Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask);
31690Sstevel@tonic-gate
31700Sstevel@tonic-gate return (USB_SUCCESS);
31710Sstevel@tonic-gate }
31720Sstevel@tonic-gate
31730Sstevel@tonic-gate return (USB_FAILURE);
31740Sstevel@tonic-gate }
31750Sstevel@tonic-gate
31760Sstevel@tonic-gate
31770Sstevel@tonic-gate /*
31780Sstevel@tonic-gate * ehci_find_bestfit_ls_intr_mask:
31790Sstevel@tonic-gate *
31800Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation.
31810Sstevel@tonic-gate */
31820Sstevel@tonic-gate static int
ehci_find_bestfit_ls_intr_mask(ehci_state_t * ehcip,uchar_t * smask,uchar_t * cmask,uint_t * pnode,uint_t sbandwidth,uint_t cbandwidth,int interval)31830Sstevel@tonic-gate ehci_find_bestfit_ls_intr_mask(
31840Sstevel@tonic-gate ehci_state_t *ehcip,
31850Sstevel@tonic-gate uchar_t *smask,
31860Sstevel@tonic-gate uchar_t *cmask,
31870Sstevel@tonic-gate uint_t *pnode,
31880Sstevel@tonic-gate uint_t sbandwidth,
31890Sstevel@tonic-gate uint_t cbandwidth,
31900Sstevel@tonic-gate int interval)
31910Sstevel@tonic-gate {
31920Sstevel@tonic-gate int i;
31930Sstevel@tonic-gate uint_t elements, index;
31940Sstevel@tonic-gate int array_leaf, best_array_leaf;
31950Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth;
31960Sstevel@tonic-gate uint_t best_node_bandwidth;
31970Sstevel@tonic-gate uint_t leaf_count;
31980Sstevel@tonic-gate uchar_t bw_smask, bw_cmask;
31990Sstevel@tonic-gate uchar_t best_smask, best_cmask;
32000Sstevel@tonic-gate
32010Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
32020Sstevel@tonic-gate "ehci_find_bestfit_ls_intr_mask: ");
32030Sstevel@tonic-gate
32040Sstevel@tonic-gate /* For low and full speed devices */
32050Sstevel@tonic-gate index = EHCI_XUS_MASK_INDEX;
32060Sstevel@tonic-gate elements = EHCI_INTR_4MS_POLL;
32070Sstevel@tonic-gate
32080Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
32090Sstevel@tonic-gate
32100Sstevel@tonic-gate /*
32110Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically
32120Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval.
32130Sstevel@tonic-gate */
32140Sstevel@tonic-gate best_smask = 0x00;
32150Sstevel@tonic-gate best_node_bandwidth = 0;
32160Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) {
32170Sstevel@tonic-gate /* Find the bandwidth mask */
32180Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
32190Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask);
32200Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip,
32210Sstevel@tonic-gate cbandwidth, ehci_index[array_leaf], leaf_count, &bw_cmask);
32220Sstevel@tonic-gate
32230Sstevel@tonic-gate /*
32240Sstevel@tonic-gate * If this node cannot support our requirements skip to the
32250Sstevel@tonic-gate * next leaf.
32260Sstevel@tonic-gate */
32270Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) {
32280Sstevel@tonic-gate continue;
32290Sstevel@tonic-gate }
32300Sstevel@tonic-gate
32310Sstevel@tonic-gate /*
32320Sstevel@tonic-gate * Now make sure our bandwidth requirements can be
32330Sstevel@tonic-gate * satisfied with one of smasks in this node.
32340Sstevel@tonic-gate */
32350Sstevel@tonic-gate *smask = 0x00;
32360Sstevel@tonic-gate *cmask = 0x00;
32370Sstevel@tonic-gate for (i = index; i < (index + elements); i++) {
32380Sstevel@tonic-gate /* Check the start split mask value */
32390Sstevel@tonic-gate if ((ehci_start_split_mask[index] & bw_smask) &&
32400Sstevel@tonic-gate (ehci_intr_complete_split_mask[index] & bw_cmask)) {
32410Sstevel@tonic-gate *smask = ehci_start_split_mask[index];
32420Sstevel@tonic-gate *cmask = ehci_intr_complete_split_mask[index];
32430Sstevel@tonic-gate break;
32440Sstevel@tonic-gate }
32450Sstevel@tonic-gate }
32460Sstevel@tonic-gate
32470Sstevel@tonic-gate /*
32480Sstevel@tonic-gate * If an appropriate smask is found save the information if:
32490Sstevel@tonic-gate * o best_smask has not been found yet.
32500Sstevel@tonic-gate * - or -
32510Sstevel@tonic-gate * o This is the node with the least amount of bandwidth
32520Sstevel@tonic-gate */
32530Sstevel@tonic-gate if ((*smask != 0x00) &&
32540Sstevel@tonic-gate ((best_smask == 0x00) ||
32555767Slc152243 (best_node_bandwidth >
32565767Slc152243 (node_sbandwidth + node_cbandwidth)))) {
32570Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth;
32580Sstevel@tonic-gate best_array_leaf = array_leaf;
32590Sstevel@tonic-gate best_smask = *smask;
32600Sstevel@tonic-gate best_cmask = *cmask;
32610Sstevel@tonic-gate }
32620Sstevel@tonic-gate }
32630Sstevel@tonic-gate
32640Sstevel@tonic-gate /*
32650Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the
32660Sstevel@tonic-gate * appropriate variables and return success.
32670Sstevel@tonic-gate */
32680Sstevel@tonic-gate if (best_smask) {
32690Sstevel@tonic-gate *smask = best_smask;
32700Sstevel@tonic-gate *cmask = best_cmask;
32710Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
32720Sstevel@tonic-gate interval);
32730Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth,
32740Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask);
32750Sstevel@tonic-gate ehci_update_bw_availability(ehcip, cbandwidth,
32760Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask);
32770Sstevel@tonic-gate
32780Sstevel@tonic-gate return (USB_SUCCESS);
32790Sstevel@tonic-gate }
32800Sstevel@tonic-gate
32810Sstevel@tonic-gate return (USB_FAILURE);
32820Sstevel@tonic-gate }
32830Sstevel@tonic-gate
32840Sstevel@tonic-gate
32850Sstevel@tonic-gate /*
32860Sstevel@tonic-gate * ehci_find_bestfit_sitd_in_mask:
32870Sstevel@tonic-gate *
32880Sstevel@tonic-gate * Find the smask and cmask in the bandwidth allocation.
32890Sstevel@tonic-gate */
32900Sstevel@tonic-gate static int
ehci_find_bestfit_sitd_in_mask(ehci_state_t * ehcip,uchar_t * smask,uchar_t * cmask,uint_t * pnode,uint_t sbandwidth,uint_t cbandwidth,int interval)32910Sstevel@tonic-gate ehci_find_bestfit_sitd_in_mask(
32920Sstevel@tonic-gate ehci_state_t *ehcip,
32930Sstevel@tonic-gate uchar_t *smask,
32940Sstevel@tonic-gate uchar_t *cmask,
32950Sstevel@tonic-gate uint_t *pnode,
32960Sstevel@tonic-gate uint_t sbandwidth,
32970Sstevel@tonic-gate uint_t cbandwidth,
32980Sstevel@tonic-gate int interval)
32990Sstevel@tonic-gate {
33000Sstevel@tonic-gate int i, uFrames, found;
33010Sstevel@tonic-gate int array_leaf, best_array_leaf;
33020Sstevel@tonic-gate uint_t node_sbandwidth, node_cbandwidth;
33030Sstevel@tonic-gate uint_t best_node_bandwidth;
33040Sstevel@tonic-gate uint_t leaf_count;
33050Sstevel@tonic-gate uchar_t bw_smask, bw_cmask;
33060Sstevel@tonic-gate uchar_t best_smask, best_cmask;
33070Sstevel@tonic-gate
33080Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
33090Sstevel@tonic-gate "ehci_find_bestfit_sitd_in_mask: ");
33100Sstevel@tonic-gate
33110Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
33120Sstevel@tonic-gate
33130Sstevel@tonic-gate /*
33140Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically
33150Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval.
33160Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame.
33170Sstevel@tonic-gate */
33180Sstevel@tonic-gate /*
33190Sstevel@tonic-gate * Need to add an additional 2 uFrames, if the "L"ast
33200Sstevel@tonic-gate * complete split is before uFrame 6. See section
33210Sstevel@tonic-gate * 11.8.4 in USB 2.0 Spec. Currently we do not support
33220Sstevel@tonic-gate * the "Back Ptr" which means we support on IN of
33230Sstevel@tonic-gate * ~4*MAX_UFRAME_SITD_XFER bandwidth/
33240Sstevel@tonic-gate */
33250Sstevel@tonic-gate uFrames = (cbandwidth / MAX_UFRAME_SITD_XFER) + 2;
33260Sstevel@tonic-gate if (cbandwidth % MAX_UFRAME_SITD_XFER) {
33270Sstevel@tonic-gate uFrames++;
33280Sstevel@tonic-gate }
33290Sstevel@tonic-gate if (uFrames > 6) {
33300Sstevel@tonic-gate
33310Sstevel@tonic-gate return (USB_FAILURE);
33320Sstevel@tonic-gate }
33330Sstevel@tonic-gate *smask = 0x1;
33340Sstevel@tonic-gate *cmask = 0x00;
33350Sstevel@tonic-gate for (i = 0; i < uFrames; i++) {
33360Sstevel@tonic-gate *cmask = *cmask << 1;
33370Sstevel@tonic-gate *cmask |= 0x1;
33380Sstevel@tonic-gate }
33390Sstevel@tonic-gate /* cmask must start 2 frames after the smask */
33400Sstevel@tonic-gate *cmask = *cmask << 2;
33410Sstevel@tonic-gate
33420Sstevel@tonic-gate found = 0;
33430Sstevel@tonic-gate best_smask = 0x00;
33440Sstevel@tonic-gate best_node_bandwidth = 0;
33450Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) {
33460Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
33470Sstevel@tonic-gate sbandwidth, ehci_index[array_leaf], leaf_count, &bw_smask);
33480Sstevel@tonic-gate node_cbandwidth = ehci_calculate_bw_availability_mask(ehcip,
33490Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count,
33500Sstevel@tonic-gate &bw_cmask);
33510Sstevel@tonic-gate
33520Sstevel@tonic-gate /*
33530Sstevel@tonic-gate * If this node cannot support our requirements skip to the
33540Sstevel@tonic-gate * next leaf.
33550Sstevel@tonic-gate */
33560Sstevel@tonic-gate if ((bw_smask == 0x00) || (bw_cmask == 0x00)) {
33570Sstevel@tonic-gate continue;
33580Sstevel@tonic-gate }
33590Sstevel@tonic-gate
33600Sstevel@tonic-gate for (i = 0; i < (EHCI_MAX_UFRAMES - uFrames - 2); i++) {
33610Sstevel@tonic-gate if ((*smask & bw_smask) && (*cmask & bw_cmask)) {
33620Sstevel@tonic-gate found = 1;
33630Sstevel@tonic-gate break;
33640Sstevel@tonic-gate }
33650Sstevel@tonic-gate *smask = *smask << 1;
33660Sstevel@tonic-gate *cmask = *cmask << 1;
33670Sstevel@tonic-gate }
33680Sstevel@tonic-gate
33690Sstevel@tonic-gate /*
33700Sstevel@tonic-gate * If an appropriate smask is found save the information if:
33710Sstevel@tonic-gate * o best_smask has not been found yet.
33720Sstevel@tonic-gate * - or -
33730Sstevel@tonic-gate * o This is the node with the least amount of bandwidth
33740Sstevel@tonic-gate */
33750Sstevel@tonic-gate if (found &&
33760Sstevel@tonic-gate ((best_smask == 0x00) ||
33775767Slc152243 (best_node_bandwidth >
33785767Slc152243 (node_sbandwidth + node_cbandwidth)))) {
33790Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth + node_cbandwidth;
33800Sstevel@tonic-gate best_array_leaf = array_leaf;
33810Sstevel@tonic-gate best_smask = *smask;
33820Sstevel@tonic-gate best_cmask = *cmask;
33830Sstevel@tonic-gate }
33840Sstevel@tonic-gate }
33850Sstevel@tonic-gate
33860Sstevel@tonic-gate /*
33870Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the
33880Sstevel@tonic-gate * appropriate variables and return success.
33890Sstevel@tonic-gate */
33900Sstevel@tonic-gate if (best_smask) {
33910Sstevel@tonic-gate *smask = best_smask;
33920Sstevel@tonic-gate *cmask = best_cmask;
33930Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
33940Sstevel@tonic-gate interval);
33950Sstevel@tonic-gate ehci_update_bw_availability(ehcip, sbandwidth,
33960Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask);
33970Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER,
33980Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_cmask);
33990Sstevel@tonic-gate
34000Sstevel@tonic-gate return (USB_SUCCESS);
34010Sstevel@tonic-gate }
34020Sstevel@tonic-gate
34030Sstevel@tonic-gate return (USB_FAILURE);
34040Sstevel@tonic-gate }
34050Sstevel@tonic-gate
34060Sstevel@tonic-gate
34070Sstevel@tonic-gate /*
34080Sstevel@tonic-gate * ehci_find_bestfit_sitd_out_mask:
34090Sstevel@tonic-gate *
34100Sstevel@tonic-gate * Find the smask in the bandwidth allocation.
34110Sstevel@tonic-gate */
34120Sstevel@tonic-gate static int
ehci_find_bestfit_sitd_out_mask(ehci_state_t * ehcip,uchar_t * smask,uint_t * pnode,uint_t sbandwidth,int interval)34130Sstevel@tonic-gate ehci_find_bestfit_sitd_out_mask(
34140Sstevel@tonic-gate ehci_state_t *ehcip,
34150Sstevel@tonic-gate uchar_t *smask,
34160Sstevel@tonic-gate uint_t *pnode,
34170Sstevel@tonic-gate uint_t sbandwidth,
34180Sstevel@tonic-gate int interval)
34190Sstevel@tonic-gate {
34200Sstevel@tonic-gate int i, uFrames, found;
34210Sstevel@tonic-gate int array_leaf, best_array_leaf;
34220Sstevel@tonic-gate uint_t node_sbandwidth;
34230Sstevel@tonic-gate uint_t best_node_bandwidth;
34240Sstevel@tonic-gate uint_t leaf_count;
34250Sstevel@tonic-gate uchar_t bw_smask;
34260Sstevel@tonic-gate uchar_t best_smask;
34270Sstevel@tonic-gate
34280Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
34290Sstevel@tonic-gate "ehci_find_bestfit_sitd_out_mask: ");
34300Sstevel@tonic-gate
34310Sstevel@tonic-gate leaf_count = EHCI_NUM_INTR_QH_LISTS/interval;
34320Sstevel@tonic-gate
34330Sstevel@tonic-gate /*
34340Sstevel@tonic-gate * Because of the way the leaves are setup, we will automatically
34350Sstevel@tonic-gate * hit the leftmost leaf of every possible node with this interval.
34360Sstevel@tonic-gate * You may only send MAX_UFRAME_SITD_XFER raw bits per uFrame.
34370Sstevel@tonic-gate */
34380Sstevel@tonic-gate *smask = 0x00;
34390Sstevel@tonic-gate uFrames = sbandwidth / MAX_UFRAME_SITD_XFER;
34400Sstevel@tonic-gate if (sbandwidth % MAX_UFRAME_SITD_XFER) {
34410Sstevel@tonic-gate uFrames++;
34420Sstevel@tonic-gate }
34430Sstevel@tonic-gate for (i = 0; i < uFrames; i++) {
34440Sstevel@tonic-gate *smask = *smask << 1;
34450Sstevel@tonic-gate *smask |= 0x1;
34460Sstevel@tonic-gate }
34470Sstevel@tonic-gate
34480Sstevel@tonic-gate found = 0;
34490Sstevel@tonic-gate best_smask = 0x00;
34500Sstevel@tonic-gate best_node_bandwidth = 0;
34510Sstevel@tonic-gate for (array_leaf = 0; array_leaf < interval; array_leaf++) {
34520Sstevel@tonic-gate node_sbandwidth = ehci_calculate_bw_availability_mask(ehcip,
34530Sstevel@tonic-gate MAX_UFRAME_SITD_XFER, ehci_index[array_leaf], leaf_count,
34540Sstevel@tonic-gate &bw_smask);
34550Sstevel@tonic-gate
34560Sstevel@tonic-gate /*
34570Sstevel@tonic-gate * If this node cannot support our requirements skip to the
34580Sstevel@tonic-gate * next leaf.
34590Sstevel@tonic-gate */
34600Sstevel@tonic-gate if (bw_smask == 0x00) {
34610Sstevel@tonic-gate continue;
34620Sstevel@tonic-gate }
34630Sstevel@tonic-gate
34640Sstevel@tonic-gate /* You cannot have a start split on the 8th uFrame */
34650Sstevel@tonic-gate for (i = 0; (*smask & 0x80) == 0; i++) {
34660Sstevel@tonic-gate if (*smask & bw_smask) {
34670Sstevel@tonic-gate found = 1;
34680Sstevel@tonic-gate break;
34690Sstevel@tonic-gate }
34700Sstevel@tonic-gate *smask = *smask << 1;
34710Sstevel@tonic-gate }
34720Sstevel@tonic-gate
34730Sstevel@tonic-gate /*
34740Sstevel@tonic-gate * If an appropriate smask is found save the information if:
34750Sstevel@tonic-gate * o best_smask has not been found yet.
34760Sstevel@tonic-gate * - or -
34770Sstevel@tonic-gate * o This is the node with the least amount of bandwidth
34780Sstevel@tonic-gate */
34790Sstevel@tonic-gate if (found &&
34800Sstevel@tonic-gate ((best_smask == 0x00) ||
34815767Slc152243 (best_node_bandwidth > node_sbandwidth))) {
34820Sstevel@tonic-gate best_node_bandwidth = node_sbandwidth;
34830Sstevel@tonic-gate best_array_leaf = array_leaf;
34840Sstevel@tonic-gate best_smask = *smask;
34850Sstevel@tonic-gate }
34860Sstevel@tonic-gate }
34870Sstevel@tonic-gate
34880Sstevel@tonic-gate /*
34890Sstevel@tonic-gate * If we find node that can handle the bandwidth populate the
34900Sstevel@tonic-gate * appropriate variables and return success.
34910Sstevel@tonic-gate */
34920Sstevel@tonic-gate if (best_smask) {
34930Sstevel@tonic-gate *smask = best_smask;
34940Sstevel@tonic-gate *pnode = ehci_find_periodic_node(ehci_index[best_array_leaf],
34950Sstevel@tonic-gate interval);
34960Sstevel@tonic-gate ehci_update_bw_availability(ehcip, MAX_UFRAME_SITD_XFER,
34970Sstevel@tonic-gate ehci_index[best_array_leaf], leaf_count, best_smask);
34980Sstevel@tonic-gate
34990Sstevel@tonic-gate return (USB_SUCCESS);
35000Sstevel@tonic-gate }
35010Sstevel@tonic-gate
35020Sstevel@tonic-gate return (USB_FAILURE);
35030Sstevel@tonic-gate }
35040Sstevel@tonic-gate
35050Sstevel@tonic-gate
35060Sstevel@tonic-gate /*
35070Sstevel@tonic-gate * ehci_calculate_bw_availability_mask:
35080Sstevel@tonic-gate *
35090Sstevel@tonic-gate * Returns the "total bandwidth used" in this node.
35100Sstevel@tonic-gate * Populates bw_mask with the uFrames that can support the bandwidth.
35110Sstevel@tonic-gate *
35120Sstevel@tonic-gate * If all the Frames cannot support this bandwidth, then bw_mask
35130Sstevel@tonic-gate * will return 0x00 and the "total bandwidth used" will be invalid.
35140Sstevel@tonic-gate */
35150Sstevel@tonic-gate static uint_t
ehci_calculate_bw_availability_mask(ehci_state_t * ehcip,uint_t bandwidth,int leaf,int leaf_count,uchar_t * bw_mask)35160Sstevel@tonic-gate ehci_calculate_bw_availability_mask(
35170Sstevel@tonic-gate ehci_state_t *ehcip,
35180Sstevel@tonic-gate uint_t bandwidth,
35190Sstevel@tonic-gate int leaf,
35200Sstevel@tonic-gate int leaf_count,
35210Sstevel@tonic-gate uchar_t *bw_mask)
35220Sstevel@tonic-gate {
35230Sstevel@tonic-gate int i, j;
35240Sstevel@tonic-gate uchar_t bw_uframe;
35250Sstevel@tonic-gate int uframe_total;
35260Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp;
35270Sstevel@tonic-gate uint_t total_bandwidth = 0;
35280Sstevel@tonic-gate
35290Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
35300Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: leaf %d leaf count %d",
35310Sstevel@tonic-gate leaf, leaf_count);
35320Sstevel@tonic-gate
35330Sstevel@tonic-gate /* Start by saying all uFrames are available */
35340Sstevel@tonic-gate *bw_mask = 0xFF;
35350Sstevel@tonic-gate
35360Sstevel@tonic-gate for (i = 0; (i < leaf_count) || (*bw_mask == 0x00); i++) {
35370Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leaf + i];
35380Sstevel@tonic-gate
35390Sstevel@tonic-gate total_bandwidth += fbp->ehci_allocated_frame_bandwidth;
35400Sstevel@tonic-gate
35410Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
35420Sstevel@tonic-gate /*
35430Sstevel@tonic-gate * If the uFrame in bw_mask is available check to see if
35440Sstevel@tonic-gate * it can support the additional bandwidth.
35450Sstevel@tonic-gate */
35460Sstevel@tonic-gate bw_uframe = (*bw_mask & (0x1 << j));
35470Sstevel@tonic-gate uframe_total =
35480Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] +
35490Sstevel@tonic-gate bandwidth;
35500Sstevel@tonic-gate if ((bw_uframe) &&
35510Sstevel@tonic-gate (uframe_total > HS_PERIODIC_BANDWIDTH)) {
35520Sstevel@tonic-gate *bw_mask = *bw_mask & ~bw_uframe;
35530Sstevel@tonic-gate }
35540Sstevel@tonic-gate }
35550Sstevel@tonic-gate }
35560Sstevel@tonic-gate
35570Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_BW, ehcip->ehci_log_hdl,
35580Sstevel@tonic-gate "ehci_calculate_bw_availability_mask: bandwidth mask 0x%x",
35590Sstevel@tonic-gate *bw_mask);
35600Sstevel@tonic-gate
35610Sstevel@tonic-gate return (total_bandwidth);
35620Sstevel@tonic-gate }
35630Sstevel@tonic-gate
35640Sstevel@tonic-gate
35650Sstevel@tonic-gate /*
35660Sstevel@tonic-gate * ehci_update_bw_availability:
35670Sstevel@tonic-gate *
35680Sstevel@tonic-gate * The leftmost leaf needs to be in terms of array position and
35690Sstevel@tonic-gate * not the actual lattice position.
35700Sstevel@tonic-gate */
35710Sstevel@tonic-gate static void
ehci_update_bw_availability(ehci_state_t * ehcip,int bandwidth,int leftmost_leaf,int leaf_count,uchar_t mask)35720Sstevel@tonic-gate ehci_update_bw_availability(
35730Sstevel@tonic-gate ehci_state_t *ehcip,
35740Sstevel@tonic-gate int bandwidth,
35750Sstevel@tonic-gate int leftmost_leaf,
35760Sstevel@tonic-gate int leaf_count,
35770Sstevel@tonic-gate uchar_t mask)
35780Sstevel@tonic-gate {
35790Sstevel@tonic-gate int i, j;
35800Sstevel@tonic-gate ehci_frame_bandwidth_t *fbp;
35810Sstevel@tonic-gate int uFrame_bandwidth[8];
35820Sstevel@tonic-gate
35830Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
35840Sstevel@tonic-gate "ehci_update_bw_availability: "
35850Sstevel@tonic-gate "leaf %d count %d bandwidth 0x%x mask 0x%x",
35860Sstevel@tonic-gate leftmost_leaf, leaf_count, bandwidth, mask);
35870Sstevel@tonic-gate
35880Sstevel@tonic-gate ASSERT(leftmost_leaf < 32);
35890Sstevel@tonic-gate ASSERT(leftmost_leaf >= 0);
35900Sstevel@tonic-gate
35910Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
35920Sstevel@tonic-gate if (mask & 0x1) {
35930Sstevel@tonic-gate uFrame_bandwidth[j] = bandwidth;
35940Sstevel@tonic-gate } else {
35950Sstevel@tonic-gate uFrame_bandwidth[j] = 0;
35960Sstevel@tonic-gate }
35970Sstevel@tonic-gate
35980Sstevel@tonic-gate mask = mask >> 1;
35990Sstevel@tonic-gate }
36000Sstevel@tonic-gate
36010Sstevel@tonic-gate /* Updated all the effected leafs with the bandwidth */
36020Sstevel@tonic-gate for (i = 0; i < leaf_count; i++) {
36030Sstevel@tonic-gate fbp = &ehcip->ehci_frame_bandwidth[leftmost_leaf + i];
36040Sstevel@tonic-gate
36050Sstevel@tonic-gate for (j = 0; j < EHCI_MAX_UFRAMES; j++) {
36060Sstevel@tonic-gate fbp->ehci_micro_frame_bandwidth[j] +=
36070Sstevel@tonic-gate uFrame_bandwidth[j];
36080Sstevel@tonic-gate fbp->ehci_allocated_frame_bandwidth +=
36090Sstevel@tonic-gate uFrame_bandwidth[j];
36100Sstevel@tonic-gate }
36110Sstevel@tonic-gate }
36120Sstevel@tonic-gate }
36130Sstevel@tonic-gate
36140Sstevel@tonic-gate /*
36150Sstevel@tonic-gate * Miscellaneous functions
36160Sstevel@tonic-gate */
36170Sstevel@tonic-gate
36180Sstevel@tonic-gate /*
36190Sstevel@tonic-gate * ehci_obtain_state:
36200Sstevel@tonic-gate *
36210Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
36220Sstevel@tonic-gate */
36230Sstevel@tonic-gate ehci_state_t *
ehci_obtain_state(dev_info_t * dip)36240Sstevel@tonic-gate ehci_obtain_state(dev_info_t *dip)
36250Sstevel@tonic-gate {
36260Sstevel@tonic-gate int instance = ddi_get_instance(dip);
36270Sstevel@tonic-gate
36280Sstevel@tonic-gate ehci_state_t *state = ddi_get_soft_state(ehci_statep, instance);
36290Sstevel@tonic-gate
36300Sstevel@tonic-gate ASSERT(state != NULL);
36310Sstevel@tonic-gate
36320Sstevel@tonic-gate return (state);
36330Sstevel@tonic-gate }
36340Sstevel@tonic-gate
36350Sstevel@tonic-gate
36360Sstevel@tonic-gate /*
36370Sstevel@tonic-gate * ehci_state_is_operational:
36380Sstevel@tonic-gate *
36390Sstevel@tonic-gate * Check the Host controller state and return proper values.
36400Sstevel@tonic-gate */
36410Sstevel@tonic-gate int
ehci_state_is_operational(ehci_state_t * ehcip)36420Sstevel@tonic-gate ehci_state_is_operational(ehci_state_t *ehcip)
36430Sstevel@tonic-gate {
36440Sstevel@tonic-gate int val;
36450Sstevel@tonic-gate
36460Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
36470Sstevel@tonic-gate
36480Sstevel@tonic-gate switch (ehcip->ehci_hc_soft_state) {
36490Sstevel@tonic-gate case EHCI_CTLR_INIT_STATE:
36500Sstevel@tonic-gate case EHCI_CTLR_SUSPEND_STATE:
36510Sstevel@tonic-gate val = USB_FAILURE;
36520Sstevel@tonic-gate break;
36530Sstevel@tonic-gate case EHCI_CTLR_OPERATIONAL_STATE:
36540Sstevel@tonic-gate val = USB_SUCCESS;
36550Sstevel@tonic-gate break;
36560Sstevel@tonic-gate case EHCI_CTLR_ERROR_STATE:
36570Sstevel@tonic-gate val = USB_HC_HARDWARE_ERROR;
36580Sstevel@tonic-gate break;
36590Sstevel@tonic-gate default:
36600Sstevel@tonic-gate val = USB_FAILURE;
36610Sstevel@tonic-gate break;
36620Sstevel@tonic-gate }
36630Sstevel@tonic-gate
36640Sstevel@tonic-gate return (val);
36650Sstevel@tonic-gate }
36660Sstevel@tonic-gate
36670Sstevel@tonic-gate
36680Sstevel@tonic-gate /*
36690Sstevel@tonic-gate * ehci_do_soft_reset
36700Sstevel@tonic-gate *
36710Sstevel@tonic-gate * Do soft reset of ehci host controller.
36720Sstevel@tonic-gate */
36730Sstevel@tonic-gate int
ehci_do_soft_reset(ehci_state_t * ehcip)36740Sstevel@tonic-gate ehci_do_soft_reset(ehci_state_t *ehcip)
36750Sstevel@tonic-gate {
36760Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number;
36770Sstevel@tonic-gate ehci_regs_t *ehci_save_regs;
36780Sstevel@tonic-gate
36790Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
36800Sstevel@tonic-gate
36810Sstevel@tonic-gate /* Increment host controller error count */
36820Sstevel@tonic-gate ehcip->ehci_hc_error++;
36830Sstevel@tonic-gate
36840Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
36850Sstevel@tonic-gate "ehci_do_soft_reset:"
36860Sstevel@tonic-gate "Reset ehci host controller 0x%x", ehcip->ehci_hc_error);
36870Sstevel@tonic-gate
36880Sstevel@tonic-gate /*
36890Sstevel@tonic-gate * Allocate space for saving current Host Controller
36900Sstevel@tonic-gate * registers. Don't do any recovery if allocation
36910Sstevel@tonic-gate * fails.
36920Sstevel@tonic-gate */
36930Sstevel@tonic-gate ehci_save_regs = (ehci_regs_t *)
36940Sstevel@tonic-gate kmem_zalloc(sizeof (ehci_regs_t), KM_NOSLEEP);
36950Sstevel@tonic-gate
36960Sstevel@tonic-gate if (ehci_save_regs == NULL) {
36970Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
36980Sstevel@tonic-gate "ehci_do_soft_reset: kmem_zalloc failed");
36990Sstevel@tonic-gate
37000Sstevel@tonic-gate return (USB_FAILURE);
37010Sstevel@tonic-gate }
37020Sstevel@tonic-gate
37030Sstevel@tonic-gate /* Save current ehci registers */
37040Sstevel@tonic-gate ehci_save_regs->ehci_command = Get_OpReg(ehci_command);
37050Sstevel@tonic-gate ehci_save_regs->ehci_interrupt = Get_OpReg(ehci_interrupt);
37060Sstevel@tonic-gate ehci_save_regs->ehci_ctrl_segment = Get_OpReg(ehci_ctrl_segment);
37070Sstevel@tonic-gate ehci_save_regs->ehci_async_list_addr = Get_OpReg(ehci_async_list_addr);
37080Sstevel@tonic-gate ehci_save_regs->ehci_config_flag = Get_OpReg(ehci_config_flag);
37090Sstevel@tonic-gate ehci_save_regs->ehci_periodic_list_base =
37100Sstevel@tonic-gate Get_OpReg(ehci_periodic_list_base);
37110Sstevel@tonic-gate
37121458Syq193411 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
37136898Sfb209375 "ehci_do_soft_reset: Save reg = 0x%p", (void *)ehci_save_regs);
37140Sstevel@tonic-gate
37150Sstevel@tonic-gate /* Disable all list processing and interrupts */
37160Sstevel@tonic-gate Set_OpReg(ehci_command, Get_OpReg(ehci_command) &
37170Sstevel@tonic-gate ~(EHCI_CMD_ASYNC_SCHED_ENABLE | EHCI_CMD_PERIODIC_SCHED_ENABLE));
37180Sstevel@tonic-gate
37190Sstevel@tonic-gate /* Disable all EHCI interrupts */
37200Sstevel@tonic-gate Set_OpReg(ehci_interrupt, 0);
37210Sstevel@tonic-gate
37220Sstevel@tonic-gate /* Wait for few milliseconds */
37230Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT);
37240Sstevel@tonic-gate
37250Sstevel@tonic-gate /* Do light soft reset of ehci host controller */
37260Sstevel@tonic-gate Set_OpReg(ehci_command,
37270Sstevel@tonic-gate Get_OpReg(ehci_command) | EHCI_CMD_LIGHT_HC_RESET);
37280Sstevel@tonic-gate
37291458Syq193411 USB_DPRINTF_L3(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
37300Sstevel@tonic-gate "ehci_do_soft_reset: Reset in progress");
37310Sstevel@tonic-gate
37320Sstevel@tonic-gate /* Wait for reset to complete */
37330Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT);
37340Sstevel@tonic-gate
37350Sstevel@tonic-gate /*
37360Sstevel@tonic-gate * Restore previous saved EHCI register value
37370Sstevel@tonic-gate * into the current EHCI registers.
37380Sstevel@tonic-gate */
37390Sstevel@tonic-gate Set_OpReg(ehci_ctrl_segment, (uint32_t)
37405767Slc152243 ehci_save_regs->ehci_ctrl_segment);
37410Sstevel@tonic-gate
37420Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base, (uint32_t)
37435767Slc152243 ehci_save_regs->ehci_periodic_list_base);
37440Sstevel@tonic-gate
37450Sstevel@tonic-gate Set_OpReg(ehci_async_list_addr, (uint32_t)
37465767Slc152243 ehci_save_regs->ehci_async_list_addr);
37470Sstevel@tonic-gate
37482225Sgk73471 /*
37492225Sgk73471 * For some reason this register might get nulled out by
37502225Sgk73471 * the Uli M1575 South Bridge. To workaround the hardware
37512225Sgk73471 * problem, check the value after write and retry if the
37522225Sgk73471 * last write fails.
37532225Sgk73471 */
37542225Sgk73471 if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
37552225Sgk73471 (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) &&
37562225Sgk73471 (ehci_save_regs->ehci_async_list_addr !=
37572225Sgk73471 Get_OpReg(ehci_async_list_addr))) {
37582225Sgk73471 int retry = 0;
37592225Sgk73471
37602225Sgk73471 Set_OpRegRetry(ehci_async_list_addr, (uint32_t)
37615767Slc152243 ehci_save_regs->ehci_async_list_addr, retry);
37622225Sgk73471 if (retry >= EHCI_MAX_RETRY) {
37633435Slg150142 USB_DPRINTF_L2(PRINT_MASK_ATTA,
37642225Sgk73471 ehcip->ehci_log_hdl, "ehci_do_soft_reset:"
37652225Sgk73471 " ASYNCLISTADDR write failed.");
37662225Sgk73471
37672225Sgk73471 return (USB_FAILURE);
37682225Sgk73471 }
37692225Sgk73471 USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
37702225Sgk73471 "ehci_do_soft_reset: ASYNCLISTADDR "
37715767Slc152243 "write failed, retry=%d", retry);
37722225Sgk73471 }
37732225Sgk73471
37740Sstevel@tonic-gate Set_OpReg(ehci_config_flag, (uint32_t)
37755767Slc152243 ehci_save_regs->ehci_config_flag);
37760Sstevel@tonic-gate
37770Sstevel@tonic-gate /* Enable both Asynchronous and Periodic Schedule if necessary */
37780Sstevel@tonic-gate ehci_toggle_scheduler(ehcip);
37790Sstevel@tonic-gate
37800Sstevel@tonic-gate /*
37810Sstevel@tonic-gate * Set ehci_interrupt to enable all interrupts except Root
37820Sstevel@tonic-gate * Hub Status change and frame list rollover interrupts.
37830Sstevel@tonic-gate */
37840Sstevel@tonic-gate Set_OpReg(ehci_interrupt, EHCI_INTR_HOST_SYSTEM_ERROR |
37850Sstevel@tonic-gate EHCI_INTR_FRAME_LIST_ROLLOVER |
37860Sstevel@tonic-gate EHCI_INTR_USB_ERROR |
37870Sstevel@tonic-gate EHCI_INTR_USB);
37880Sstevel@tonic-gate
37890Sstevel@tonic-gate /*
37900Sstevel@tonic-gate * Deallocate the space that allocated for saving
37910Sstevel@tonic-gate * HC registers.
37920Sstevel@tonic-gate */
37930Sstevel@tonic-gate kmem_free((void *) ehci_save_regs, sizeof (ehci_regs_t));
37940Sstevel@tonic-gate
37950Sstevel@tonic-gate /*
37960Sstevel@tonic-gate * Set the desired interrupt threshold, frame list size (if
37970Sstevel@tonic-gate * applicable) and turn EHCI host controller.
37980Sstevel@tonic-gate */
37990Sstevel@tonic-gate Set_OpReg(ehci_command, ((Get_OpReg(ehci_command) &
38000Sstevel@tonic-gate ~EHCI_CMD_INTR_THRESHOLD) |
38010Sstevel@tonic-gate (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN)));
38020Sstevel@tonic-gate
38030Sstevel@tonic-gate /* Wait 10ms for EHCI to start sending SOF */
38040Sstevel@tonic-gate drv_usecwait(EHCI_RESET_TIMEWAIT);
38050Sstevel@tonic-gate
38060Sstevel@tonic-gate /*
38070Sstevel@tonic-gate * Get the current usb frame number before waiting for
38080Sstevel@tonic-gate * few milliseconds.
38090Sstevel@tonic-gate */
38100Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip);
38110Sstevel@tonic-gate
38120Sstevel@tonic-gate /* Wait for few milliseconds */
38130Sstevel@tonic-gate drv_usecwait(EHCI_SOF_TIMEWAIT);
38140Sstevel@tonic-gate
38150Sstevel@tonic-gate /*
38160Sstevel@tonic-gate * Get the current usb frame number after waiting for
38170Sstevel@tonic-gate * few milliseconds.
38180Sstevel@tonic-gate */
38190Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip);
38200Sstevel@tonic-gate
38210Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
38220Sstevel@tonic-gate "ehci_do_soft_reset: Before Frame Number 0x%llx "
38230Sstevel@tonic-gate "After Frame Number 0x%llx",
38246898Sfb209375 (unsigned long long)before_frame_number,
38256898Sfb209375 (unsigned long long)after_frame_number);
38260Sstevel@tonic-gate
38270Sstevel@tonic-gate if ((after_frame_number <= before_frame_number) &&
38280Sstevel@tonic-gate (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
38290Sstevel@tonic-gate
38300Sstevel@tonic-gate USB_DPRINTF_L2(PRINT_MASK_INTR, ehcip->ehci_log_hdl,
38310Sstevel@tonic-gate "ehci_do_soft_reset: Soft reset failed");
38320Sstevel@tonic-gate
38330Sstevel@tonic-gate return (USB_FAILURE);
38340Sstevel@tonic-gate }
38350Sstevel@tonic-gate
38360Sstevel@tonic-gate return (USB_SUCCESS);
38370Sstevel@tonic-gate }
38380Sstevel@tonic-gate
38390Sstevel@tonic-gate
38400Sstevel@tonic-gate /*
38410Sstevel@tonic-gate * ehci_get_xfer_attrs:
38420Sstevel@tonic-gate *
38430Sstevel@tonic-gate * Get the attributes of a particular xfer.
38440Sstevel@tonic-gate *
38450Sstevel@tonic-gate * NOTE: This function is also called from POLLED MODE.
38460Sstevel@tonic-gate */
38470Sstevel@tonic-gate usb_req_attrs_t
ehci_get_xfer_attrs(ehci_state_t * ehcip,ehci_pipe_private_t * pp,ehci_trans_wrapper_t * tw)38480Sstevel@tonic-gate ehci_get_xfer_attrs(
38490Sstevel@tonic-gate ehci_state_t *ehcip,
38500Sstevel@tonic-gate ehci_pipe_private_t *pp,
38510Sstevel@tonic-gate ehci_trans_wrapper_t *tw)
38520Sstevel@tonic-gate {
38530Sstevel@tonic-gate usb_ep_descr_t *eptd = &pp->pp_pipe_handle->p_ep;
38540Sstevel@tonic-gate usb_req_attrs_t attrs = USB_ATTRS_NONE;
38550Sstevel@tonic-gate
38560Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
38570Sstevel@tonic-gate "ehci_get_xfer_attrs:");
38580Sstevel@tonic-gate
38590Sstevel@tonic-gate switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
38600Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
38610Sstevel@tonic-gate attrs = ((usb_ctrl_req_t *)
38620Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->ctrl_attributes;
38630Sstevel@tonic-gate break;
38640Sstevel@tonic-gate case USB_EP_ATTR_BULK:
38650Sstevel@tonic-gate attrs = ((usb_bulk_req_t *)
38660Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->bulk_attributes;
38670Sstevel@tonic-gate break;
38680Sstevel@tonic-gate case USB_EP_ATTR_INTR:
38690Sstevel@tonic-gate attrs = ((usb_intr_req_t *)
38700Sstevel@tonic-gate tw->tw_curr_xfer_reqp)->intr_attributes;
38710Sstevel@tonic-gate break;
38720Sstevel@tonic-gate }
38730Sstevel@tonic-gate
38740Sstevel@tonic-gate return (attrs);
38750Sstevel@tonic-gate }
38760Sstevel@tonic-gate
38770Sstevel@tonic-gate
38780Sstevel@tonic-gate /*
38790Sstevel@tonic-gate * ehci_get_current_frame_number:
38800Sstevel@tonic-gate *
38810Sstevel@tonic-gate * Get the current software based usb frame number.
38820Sstevel@tonic-gate */
38830Sstevel@tonic-gate usb_frame_number_t
ehci_get_current_frame_number(ehci_state_t * ehcip)38840Sstevel@tonic-gate ehci_get_current_frame_number(ehci_state_t *ehcip)
38850Sstevel@tonic-gate {
38860Sstevel@tonic-gate usb_frame_number_t usb_frame_number;
38870Sstevel@tonic-gate usb_frame_number_t ehci_fno, micro_frame_number;
38880Sstevel@tonic-gate
38890Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
38900Sstevel@tonic-gate
38910Sstevel@tonic-gate ehci_fno = ehcip->ehci_fno;
38920Sstevel@tonic-gate micro_frame_number = Get_OpReg(ehci_frame_index) & 0x3FFF;
38930Sstevel@tonic-gate
38940Sstevel@tonic-gate /*
38950Sstevel@tonic-gate * Calculate current software based usb frame number.
38960Sstevel@tonic-gate *
38970Sstevel@tonic-gate * This code accounts for the fact that frame number is
38980Sstevel@tonic-gate * updated by the Host Controller before the ehci driver
38990Sstevel@tonic-gate * gets an FrameListRollover interrupt that will adjust
39000Sstevel@tonic-gate * Frame higher part.
39010Sstevel@tonic-gate *
39020Sstevel@tonic-gate * Refer ehci specification 1.0, section 2.3.2, page 21.
39030Sstevel@tonic-gate */
39040Sstevel@tonic-gate micro_frame_number = ((micro_frame_number & 0x1FFF) |
39050Sstevel@tonic-gate ehci_fno) + (((micro_frame_number & 0x3FFF) ^
39060Sstevel@tonic-gate ehci_fno) & 0x2000);
39070Sstevel@tonic-gate
39080Sstevel@tonic-gate /*
39090Sstevel@tonic-gate * Micro Frame number is equivalent to 125 usec. Eight
39100Sstevel@tonic-gate * Micro Frame numbers are equivalent to one millsecond
39110Sstevel@tonic-gate * or one usb frame number.
39120Sstevel@tonic-gate */
39130Sstevel@tonic-gate usb_frame_number = micro_frame_number >>
39140Sstevel@tonic-gate EHCI_uFRAMES_PER_USB_FRAME_SHIFT;
39150Sstevel@tonic-gate
39160Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
39170Sstevel@tonic-gate "ehci_get_current_frame_number: "
39180Sstevel@tonic-gate "Current usb uframe number = 0x%llx "
39190Sstevel@tonic-gate "Current usb frame number = 0x%llx",
39206898Sfb209375 (unsigned long long)micro_frame_number,
39216898Sfb209375 (unsigned long long)usb_frame_number);
39220Sstevel@tonic-gate
39230Sstevel@tonic-gate return (usb_frame_number);
39240Sstevel@tonic-gate }
39250Sstevel@tonic-gate
39260Sstevel@tonic-gate
39270Sstevel@tonic-gate /*
39280Sstevel@tonic-gate * ehci_cpr_cleanup:
39290Sstevel@tonic-gate *
39300Sstevel@tonic-gate * Cleanup ehci state and other ehci specific informations across
39310Sstevel@tonic-gate * Check Point Resume (CPR).
39320Sstevel@tonic-gate */
39330Sstevel@tonic-gate static void
ehci_cpr_cleanup(ehci_state_t * ehcip)39340Sstevel@tonic-gate ehci_cpr_cleanup(ehci_state_t *ehcip)
39350Sstevel@tonic-gate {
39360Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
39370Sstevel@tonic-gate
39380Sstevel@tonic-gate /* Reset software part of usb frame number */
39390Sstevel@tonic-gate ehcip->ehci_fno = 0;
39400Sstevel@tonic-gate }
39410Sstevel@tonic-gate
39420Sstevel@tonic-gate
39430Sstevel@tonic-gate /*
39440Sstevel@tonic-gate * ehci_wait_for_sof:
39450Sstevel@tonic-gate *
39460Sstevel@tonic-gate * Wait for couple of SOF interrupts
39470Sstevel@tonic-gate */
39480Sstevel@tonic-gate int
ehci_wait_for_sof(ehci_state_t * ehcip)39490Sstevel@tonic-gate ehci_wait_for_sof(ehci_state_t *ehcip)
39500Sstevel@tonic-gate {
39510Sstevel@tonic-gate usb_frame_number_t before_frame_number, after_frame_number;
39520Sstevel@tonic-gate int error = USB_SUCCESS;
39530Sstevel@tonic-gate
39540Sstevel@tonic-gate USB_DPRINTF_L4(PRINT_MASK_LISTS,
39550Sstevel@tonic-gate ehcip->ehci_log_hdl, "ehci_wait_for_sof");
39560Sstevel@tonic-gate
39570Sstevel@tonic-gate ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
39580Sstevel@tonic-gate
39590Sstevel@tonic-gate error = ehci_state_is_operational(ehcip);
39600Sstevel@tonic-gate
39610Sstevel@tonic-gate if (error != USB_SUCCESS) {
39620Sstevel@tonic-gate
39630Sstevel@tonic-gate return (error);
39640Sstevel@tonic-gate }
39650Sstevel@tonic-gate
39660Sstevel@tonic-gate /* Get the current usb frame number before waiting for two SOFs */
39670Sstevel@tonic-gate before_frame_number = ehci_get_current_frame_number(ehcip);
39680Sstevel@tonic-gate
39690Sstevel@tonic-gate mutex_exit(&ehcip->ehci_int_mutex);
39700Sstevel@tonic-gate
39710Sstevel@tonic-gate /* Wait for few milliseconds */
39720Sstevel@tonic-gate delay(drv_usectohz(EHCI_SOF_TIMEWAIT));
39730Sstevel@tonic-gate
39740Sstevel@tonic-gate mutex_enter(&ehcip->ehci_int_mutex);
39750Sstevel@tonic-gate
39760Sstevel@tonic-gate /* Get the current usb frame number after woken up */
39770Sstevel@tonic-gate after_frame_number = ehci_get_current_frame_number(ehcip);
39780Sstevel@tonic-gate
39790Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
39800Sstevel@tonic-gate "ehci_wait_for_sof: framenumber: before 0x%llx "
39816898Sfb209375 "after 0x%llx",
39826898Sfb209375 (unsigned long long)before_frame_number,
39836898Sfb209375 (unsigned long long)after_frame_number);
39840Sstevel@tonic-gate
39850Sstevel@tonic-gate /* Return failure, if usb frame number has not been changed */
39860Sstevel@tonic-gate if (after_frame_number <= before_frame_number) {
39870Sstevel@tonic-gate
39880Sstevel@tonic-gate if ((ehci_do_soft_reset(ehcip)) != USB_SUCCESS) {
39890Sstevel@tonic-gate
39900Sstevel@tonic-gate USB_DPRINTF_L0(PRINT_MASK_LISTS,
39910Sstevel@tonic-gate ehcip->ehci_log_hdl, "No SOF interrupts");
39920Sstevel@tonic-gate
39930Sstevel@tonic-gate /* Set host controller soft state to error */
39940Sstevel@tonic-gate ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
39950Sstevel@tonic-gate
39960Sstevel@tonic-gate return (USB_FAILURE);
39970Sstevel@tonic-gate }
39980Sstevel@tonic-gate
39990Sstevel@tonic-gate }
40000Sstevel@tonic-gate
40010Sstevel@tonic-gate return (USB_SUCCESS);
40020Sstevel@tonic-gate }
40030Sstevel@tonic-gate
4004*12886SRaymond.Chen@Sun.COM /*
4005*12886SRaymond.Chen@Sun.COM * Toggle the async/periodic schedule based on opened pipe count.
4006*12886SRaymond.Chen@Sun.COM * During pipe cleanup(in pipe reset case), the pipe's QH is temporarily
4007*12886SRaymond.Chen@Sun.COM * disabled. But the TW on the pipe is not freed. In this case, we need
4008*12886SRaymond.Chen@Sun.COM * to disable async/periodic schedule for some non-compatible hardware.
4009*12886SRaymond.Chen@Sun.COM * Otherwise, the hardware will overwrite software's configuration of
4010*12886SRaymond.Chen@Sun.COM * the QH.
4011*12886SRaymond.Chen@Sun.COM */
4012*12886SRaymond.Chen@Sun.COM void
ehci_toggle_scheduler_on_pipe(ehci_state_t * ehcip)4013*12886SRaymond.Chen@Sun.COM ehci_toggle_scheduler_on_pipe(ehci_state_t *ehcip)
4014*12886SRaymond.Chen@Sun.COM {
4015*12886SRaymond.Chen@Sun.COM uint_t temp_reg, cmd_reg;
4016*12886SRaymond.Chen@Sun.COM
4017*12886SRaymond.Chen@Sun.COM cmd_reg = Get_OpReg(ehci_command);
4018*12886SRaymond.Chen@Sun.COM temp_reg = cmd_reg;
4019*12886SRaymond.Chen@Sun.COM
4020*12886SRaymond.Chen@Sun.COM /*
4021*12886SRaymond.Chen@Sun.COM * Enable/Disable asynchronous scheduler, and
4022*12886SRaymond.Chen@Sun.COM * turn on/off async list door bell
4023*12886SRaymond.Chen@Sun.COM */
4024*12886SRaymond.Chen@Sun.COM if (ehcip->ehci_open_async_count) {
4025*12886SRaymond.Chen@Sun.COM if ((ehcip->ehci_async_req_count > 0) &&
4026*12886SRaymond.Chen@Sun.COM ((cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE) == 0)) {
4027*12886SRaymond.Chen@Sun.COM /*
4028*12886SRaymond.Chen@Sun.COM * For some reason this address might get nulled out by
4029*12886SRaymond.Chen@Sun.COM * the ehci chip. Set it here just in case it is null.
4030*12886SRaymond.Chen@Sun.COM */
4031*12886SRaymond.Chen@Sun.COM Set_OpReg(ehci_async_list_addr,
4032*12886SRaymond.Chen@Sun.COM ehci_qh_cpu_to_iommu(ehcip,
4033*12886SRaymond.Chen@Sun.COM ehcip->ehci_head_of_async_sched_list));
4034*12886SRaymond.Chen@Sun.COM
4035*12886SRaymond.Chen@Sun.COM /*
4036*12886SRaymond.Chen@Sun.COM * For some reason this register might get nulled out by
4037*12886SRaymond.Chen@Sun.COM * the Uli M1575 Southbridge. To workaround the HW
4038*12886SRaymond.Chen@Sun.COM * problem, check the value after write and retry if the
4039*12886SRaymond.Chen@Sun.COM * last write fails.
4040*12886SRaymond.Chen@Sun.COM *
4041*12886SRaymond.Chen@Sun.COM * If the ASYNCLISTADDR remains "stuck" after
4042*12886SRaymond.Chen@Sun.COM * EHCI_MAX_RETRY retries, then the M1575 is broken
4043*12886SRaymond.Chen@Sun.COM * and is stuck in an inconsistent state and is about
4044*12886SRaymond.Chen@Sun.COM * to crash the machine with a trn_oor panic when it
4045*12886SRaymond.Chen@Sun.COM * does a DMA read from 0x0. It is better to panic
4046*12886SRaymond.Chen@Sun.COM * now rather than wait for the trn_oor crash; this
4047*12886SRaymond.Chen@Sun.COM * way Customer Service will have a clean signature
4048*12886SRaymond.Chen@Sun.COM * that indicts the M1575 chip rather than a
4049*12886SRaymond.Chen@Sun.COM * mysterious and hard-to-diagnose trn_oor panic.
4050*12886SRaymond.Chen@Sun.COM */
4051*12886SRaymond.Chen@Sun.COM if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
4052*12886SRaymond.Chen@Sun.COM (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) &&
4053*12886SRaymond.Chen@Sun.COM (ehci_qh_cpu_to_iommu(ehcip,
4054*12886SRaymond.Chen@Sun.COM ehcip->ehci_head_of_async_sched_list) !=
4055*12886SRaymond.Chen@Sun.COM Get_OpReg(ehci_async_list_addr))) {
4056*12886SRaymond.Chen@Sun.COM int retry = 0;
4057*12886SRaymond.Chen@Sun.COM
4058*12886SRaymond.Chen@Sun.COM Set_OpRegRetry(ehci_async_list_addr,
4059*12886SRaymond.Chen@Sun.COM ehci_qh_cpu_to_iommu(ehcip,
4060*12886SRaymond.Chen@Sun.COM ehcip->ehci_head_of_async_sched_list),
4061*12886SRaymond.Chen@Sun.COM retry);
4062*12886SRaymond.Chen@Sun.COM if (retry >= EHCI_MAX_RETRY)
4063*12886SRaymond.Chen@Sun.COM cmn_err(CE_PANIC,
4064*12886SRaymond.Chen@Sun.COM "ehci_toggle_scheduler_on_pipe: "
4065*12886SRaymond.Chen@Sun.COM "ASYNCLISTADDR write failed.");
4066*12886SRaymond.Chen@Sun.COM
4067*12886SRaymond.Chen@Sun.COM USB_DPRINTF_L2(PRINT_MASK_ATTA,
4068*12886SRaymond.Chen@Sun.COM ehcip->ehci_log_hdl,
4069*12886SRaymond.Chen@Sun.COM "ehci_toggle_scheduler_on_pipe:"
4070*12886SRaymond.Chen@Sun.COM " ASYNCLISTADDR write failed, retry=%d",
4071*12886SRaymond.Chen@Sun.COM retry);
4072*12886SRaymond.Chen@Sun.COM }
4073*12886SRaymond.Chen@Sun.COM
4074*12886SRaymond.Chen@Sun.COM cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE;
4075*12886SRaymond.Chen@Sun.COM }
4076*12886SRaymond.Chen@Sun.COM } else {
4077*12886SRaymond.Chen@Sun.COM cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE;
4078*12886SRaymond.Chen@Sun.COM }
4079*12886SRaymond.Chen@Sun.COM
4080*12886SRaymond.Chen@Sun.COM if (ehcip->ehci_open_periodic_count) {
4081*12886SRaymond.Chen@Sun.COM if ((ehcip->ehci_periodic_req_count > 0) &&
4082*12886SRaymond.Chen@Sun.COM ((cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE) == 0)) {
4083*12886SRaymond.Chen@Sun.COM /*
4084*12886SRaymond.Chen@Sun.COM * For some reason this address get's nulled out by
4085*12886SRaymond.Chen@Sun.COM * the ehci chip. Set it here just in case it is null.
4086*12886SRaymond.Chen@Sun.COM */
4087*12886SRaymond.Chen@Sun.COM Set_OpReg(ehci_periodic_list_base,
4088*12886SRaymond.Chen@Sun.COM (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address &
4089*12886SRaymond.Chen@Sun.COM 0xFFFFF000));
4090*12886SRaymond.Chen@Sun.COM cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE;
4091*12886SRaymond.Chen@Sun.COM }
4092*12886SRaymond.Chen@Sun.COM } else {
4093*12886SRaymond.Chen@Sun.COM cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE;
4094*12886SRaymond.Chen@Sun.COM }
4095*12886SRaymond.Chen@Sun.COM
4096*12886SRaymond.Chen@Sun.COM /* Just an optimization */
4097*12886SRaymond.Chen@Sun.COM if (temp_reg != cmd_reg) {
4098*12886SRaymond.Chen@Sun.COM Set_OpReg(ehci_command, cmd_reg);
4099*12886SRaymond.Chen@Sun.COM }
4100*12886SRaymond.Chen@Sun.COM }
4101*12886SRaymond.Chen@Sun.COM
41020Sstevel@tonic-gate
41030Sstevel@tonic-gate /*
41040Sstevel@tonic-gate * ehci_toggle_scheduler:
41050Sstevel@tonic-gate *
41060Sstevel@tonic-gate * Turn scheduler based on pipe open count.
41070Sstevel@tonic-gate */
41080Sstevel@tonic-gate void
ehci_toggle_scheduler(ehci_state_t * ehcip)410912733SRaymond.Chen@Sun.COM ehci_toggle_scheduler(ehci_state_t *ehcip)
411012733SRaymond.Chen@Sun.COM {
41110Sstevel@tonic-gate uint_t temp_reg, cmd_reg;
41120Sstevel@tonic-gate
411312733SRaymond.Chen@Sun.COM /*
411412733SRaymond.Chen@Sun.COM * For performance optimization, we need to change the bits
411512733SRaymond.Chen@Sun.COM * if (async == 1||async == 0) OR (periodic == 1||periodic == 0)
411612733SRaymond.Chen@Sun.COM *
411712733SRaymond.Chen@Sun.COM * Related bits already enabled if
411812733SRaymond.Chen@Sun.COM * async and periodic req counts are > 1
411912733SRaymond.Chen@Sun.COM * OR async req count > 1 & no periodic pipe
412012733SRaymond.Chen@Sun.COM * OR periodic req count > 1 & no async pipe
412112733SRaymond.Chen@Sun.COM */
412212733SRaymond.Chen@Sun.COM if (((ehcip->ehci_async_req_count > 1) &&
412312733SRaymond.Chen@Sun.COM (ehcip->ehci_periodic_req_count > 1)) ||
412412733SRaymond.Chen@Sun.COM ((ehcip->ehci_async_req_count > 1) &&
412512733SRaymond.Chen@Sun.COM (ehcip->ehci_open_periodic_count == 0)) ||
412612733SRaymond.Chen@Sun.COM ((ehcip->ehci_periodic_req_count > 1) &&
412712733SRaymond.Chen@Sun.COM (ehcip->ehci_open_async_count == 0))) {
412812733SRaymond.Chen@Sun.COM USB_DPRINTF_L4(PRINT_MASK_ATTA,
412912733SRaymond.Chen@Sun.COM ehcip->ehci_log_hdl, "ehci_toggle_scheduler:"
413012733SRaymond.Chen@Sun.COM "async/periodic bits no need to change");
413112733SRaymond.Chen@Sun.COM
413212733SRaymond.Chen@Sun.COM return;
413312733SRaymond.Chen@Sun.COM }
413412733SRaymond.Chen@Sun.COM
41350Sstevel@tonic-gate cmd_reg = Get_OpReg(ehci_command);
41360Sstevel@tonic-gate temp_reg = cmd_reg;
41370Sstevel@tonic-gate
41380Sstevel@tonic-gate /*
41390Sstevel@tonic-gate * Enable/Disable asynchronous scheduler, and
41400Sstevel@tonic-gate * turn on/off async list door bell
41410Sstevel@tonic-gate */
414212733SRaymond.Chen@Sun.COM if (ehcip->ehci_async_req_count > 1) {
414312733SRaymond.Chen@Sun.COM /* we already enable the async bit */
414412733SRaymond.Chen@Sun.COM USB_DPRINTF_L4(PRINT_MASK_ATTA,
414512733SRaymond.Chen@Sun.COM ehcip->ehci_log_hdl, "ehci_toggle_scheduler:"
414612733SRaymond.Chen@Sun.COM "async bit already enabled: cmd_reg=0x%x", cmd_reg);
414712733SRaymond.Chen@Sun.COM } else if (ehcip->ehci_async_req_count == 1) {
41480Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_ASYNC_SCHED_ENABLE)) {
41490Sstevel@tonic-gate /*
41500Sstevel@tonic-gate * For some reason this address might get nulled out by
41510Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null.
415212733SRaymond.Chen@Sun.COM * If it's not null, we should not reset the
415312733SRaymond.Chen@Sun.COM * ASYNCLISTADDR, because it's updated by hardware to
415412733SRaymond.Chen@Sun.COM * point to the next queue head to be executed.
41550Sstevel@tonic-gate */
415612733SRaymond.Chen@Sun.COM if (!Get_OpReg(ehci_async_list_addr)) {
415712733SRaymond.Chen@Sun.COM Set_OpReg(ehci_async_list_addr,
415812733SRaymond.Chen@Sun.COM ehci_qh_cpu_to_iommu(ehcip,
415912733SRaymond.Chen@Sun.COM ehcip->ehci_head_of_async_sched_list));
416012733SRaymond.Chen@Sun.COM }
41612225Sgk73471
41622225Sgk73471 /*
41632225Sgk73471 * For some reason this register might get nulled out by
41642225Sgk73471 * the Uli M1575 Southbridge. To workaround the HW
41652225Sgk73471 * problem, check the value after write and retry if the
41662225Sgk73471 * last write fails.
41672225Sgk73471 *
41682225Sgk73471 * If the ASYNCLISTADDR remains "stuck" after
41692225Sgk73471 * EHCI_MAX_RETRY retries, then the M1575 is broken
41702225Sgk73471 * and is stuck in an inconsistent state and is about
41712225Sgk73471 * to crash the machine with a trn_oor panic when it
41722225Sgk73471 * does a DMA read from 0x0. It is better to panic
41732225Sgk73471 * now rather than wait for the trn_oor crash; this
41742225Sgk73471 * way Customer Service will have a clean signature
41752225Sgk73471 * that indicts the M1575 chip rather than a
41762225Sgk73471 * mysterious and hard-to-diagnose trn_oor panic.
41772225Sgk73471 */
41782225Sgk73471 if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
41792225Sgk73471 (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575) &&
41802225Sgk73471 (ehci_qh_cpu_to_iommu(ehcip,
41812225Sgk73471 ehcip->ehci_head_of_async_sched_list) !=
41822225Sgk73471 Get_OpReg(ehci_async_list_addr))) {
41832225Sgk73471 int retry = 0;
41842225Sgk73471
41852225Sgk73471 Set_OpRegRetry(ehci_async_list_addr,
41862225Sgk73471 ehci_qh_cpu_to_iommu(ehcip,
41872225Sgk73471 ehcip->ehci_head_of_async_sched_list),
41882225Sgk73471 retry);
41892225Sgk73471 if (retry >= EHCI_MAX_RETRY)
41902225Sgk73471 cmn_err(CE_PANIC,
41912225Sgk73471 "ehci_toggle_scheduler: "
41922225Sgk73471 "ASYNCLISTADDR write failed.");
41932225Sgk73471
419412733SRaymond.Chen@Sun.COM USB_DPRINTF_L3(PRINT_MASK_ATTA,
41952225Sgk73471 ehcip->ehci_log_hdl,
41962225Sgk73471 "ehci_toggle_scheduler: ASYNCLISTADDR "
419712733SRaymond.Chen@Sun.COM "write failed, retry=%d", retry);
41982225Sgk73471 }
41990Sstevel@tonic-gate }
42000Sstevel@tonic-gate cmd_reg |= EHCI_CMD_ASYNC_SCHED_ENABLE;
42010Sstevel@tonic-gate } else {
42020Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_ASYNC_SCHED_ENABLE;
42030Sstevel@tonic-gate }
42040Sstevel@tonic-gate
420512733SRaymond.Chen@Sun.COM if (ehcip->ehci_periodic_req_count > 1) {
420612733SRaymond.Chen@Sun.COM /* we already enable the periodic bit. */
420712733SRaymond.Chen@Sun.COM USB_DPRINTF_L4(PRINT_MASK_ATTA,
420812733SRaymond.Chen@Sun.COM ehcip->ehci_log_hdl, "ehci_toggle_scheduler:"
420912733SRaymond.Chen@Sun.COM "periodic bit already enabled: cmd_reg=0x%x", cmd_reg);
421012733SRaymond.Chen@Sun.COM } else if (ehcip->ehci_periodic_req_count == 1) {
42110Sstevel@tonic-gate if (!(cmd_reg & EHCI_CMD_PERIODIC_SCHED_ENABLE)) {
42120Sstevel@tonic-gate /*
42130Sstevel@tonic-gate * For some reason this address get's nulled out by
42140Sstevel@tonic-gate * the ehci chip. Set it here just in case it is null.
42150Sstevel@tonic-gate */
42160Sstevel@tonic-gate Set_OpReg(ehci_periodic_list_base,
42170Sstevel@tonic-gate (uint32_t)(ehcip->ehci_pflt_cookie.dmac_address &
421812733SRaymond.Chen@Sun.COM 0xFFFFF000));
42190Sstevel@tonic-gate }
42200Sstevel@tonic-gate cmd_reg |= EHCI_CMD_PERIODIC_SCHED_ENABLE;
42210Sstevel@tonic-gate } else {
42220Sstevel@tonic-gate cmd_reg &= ~EHCI_CMD_PERIODIC_SCHED_ENABLE;
42230Sstevel@tonic-gate }
42240Sstevel@tonic-gate
42250Sstevel@tonic-gate /* Just an optimization */
42260Sstevel@tonic-gate if (temp_reg != cmd_reg) {
42270Sstevel@tonic-gate Set_OpReg(ehci_command, cmd_reg);
422812733SRaymond.Chen@Sun.COM
422912733SRaymond.Chen@Sun.COM /* To make sure the command register is updated correctly */
423012733SRaymond.Chen@Sun.COM if ((ehcip->ehci_vendor_id == PCI_VENDOR_ULi_M1575) &&
423112733SRaymond.Chen@Sun.COM (ehcip->ehci_device_id == PCI_DEVICE_ULi_M1575)) {
423212733SRaymond.Chen@Sun.COM int retry = 0;
423312733SRaymond.Chen@Sun.COM
423412733SRaymond.Chen@Sun.COM Set_OpRegRetry(ehci_command, cmd_reg, retry);
423512733SRaymond.Chen@Sun.COM USB_DPRINTF_L3(PRINT_MASK_ATTA,
423612733SRaymond.Chen@Sun.COM ehcip->ehci_log_hdl,
423712733SRaymond.Chen@Sun.COM "ehci_toggle_scheduler: CMD write failed, retry=%d",
423812733SRaymond.Chen@Sun.COM retry);
423912733SRaymond.Chen@Sun.COM }
424012733SRaymond.Chen@Sun.COM
42410Sstevel@tonic-gate }
42420Sstevel@tonic-gate }
42430Sstevel@tonic-gate
42440Sstevel@tonic-gate /*
42450Sstevel@tonic-gate * ehci print functions
42460Sstevel@tonic-gate */
42470Sstevel@tonic-gate
42480Sstevel@tonic-gate /*
42490Sstevel@tonic-gate * ehci_print_caps:
42500Sstevel@tonic-gate */
42510Sstevel@tonic-gate void
ehci_print_caps(ehci_state_t * ehcip)42520Sstevel@tonic-gate ehci_print_caps(ehci_state_t *ehcip)
42530Sstevel@tonic-gate {
42540Sstevel@tonic-gate uint_t i;
42550Sstevel@tonic-gate
42560Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42570Sstevel@tonic-gate "\n\tUSB 2.0 Host Controller Characteristics\n");
42580Sstevel@tonic-gate
42590Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42600Sstevel@tonic-gate "Caps Length: 0x%x Version: 0x%x\n",
42610Sstevel@tonic-gate Get_8Cap(ehci_caps_length), Get_16Cap(ehci_version));
42620Sstevel@tonic-gate
42630Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42640Sstevel@tonic-gate "Structural Parameters\n");
42650Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42660Sstevel@tonic-gate "Port indicators: %s", (Get_Cap(ehci_hcs_params) &
42670Sstevel@tonic-gate EHCI_HCS_PORT_INDICATOR) ? "Yes" : "No");
42680Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42690Sstevel@tonic-gate "No of Classic host controllers: 0x%x",
42700Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_COMP_CTRLS)
42710Sstevel@tonic-gate >> EHCI_HCS_NUM_COMP_CTRL_SHIFT);
42720Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42730Sstevel@tonic-gate "No of ports per Classic host controller: 0x%x",
42740Sstevel@tonic-gate (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS_CC)
42750Sstevel@tonic-gate >> EHCI_HCS_NUM_PORTS_CC_SHIFT);
42760Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42770Sstevel@tonic-gate "Port routing rules: %s", (Get_Cap(ehci_hcs_params) &
42780Sstevel@tonic-gate EHCI_HCS_PORT_ROUTING_RULES) ? "Yes" : "No");
42790Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42800Sstevel@tonic-gate "Port power control: %s", (Get_Cap(ehci_hcs_params) &
42810Sstevel@tonic-gate EHCI_HCS_PORT_POWER_CONTROL) ? "Yes" : "No");
42820Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42830Sstevel@tonic-gate "No of root hub ports: 0x%x\n",
42840Sstevel@tonic-gate Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS);
42850Sstevel@tonic-gate
42860Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42870Sstevel@tonic-gate "Capability Parameters\n");
42880Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42890Sstevel@tonic-gate "EHCI extended capability: %s", (Get_Cap(ehci_hcc_params) &
42900Sstevel@tonic-gate EHCI_HCC_EECP) ? "Yes" : "No");
42910Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42920Sstevel@tonic-gate "Isoch schedule threshold: 0x%x",
42930Sstevel@tonic-gate Get_Cap(ehci_hcc_params) & EHCI_HCC_ISOCH_SCHED_THRESHOLD);
42940Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42950Sstevel@tonic-gate "Async schedule park capability: %s", (Get_Cap(ehci_hcc_params) &
42960Sstevel@tonic-gate EHCI_HCC_ASYNC_SCHED_PARK_CAP) ? "Yes" : "No");
42970Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
42980Sstevel@tonic-gate "Programmable frame list flag: %s", (Get_Cap(ehci_hcc_params) &
42990Sstevel@tonic-gate EHCI_HCC_PROG_FRAME_LIST_FLAG) ? "256/512/1024" : "1024");
43000Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43010Sstevel@tonic-gate "64bit addressing capability: %s\n", (Get_Cap(ehci_hcc_params) &
43020Sstevel@tonic-gate EHCI_HCC_64BIT_ADDR_CAP) ? "Yes" : "No");
43030Sstevel@tonic-gate
43040Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43050Sstevel@tonic-gate "Classic Port Route Description");
43060Sstevel@tonic-gate
43070Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) {
43080Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43090Sstevel@tonic-gate "\tPort Route 0x%x: 0x%x", i, Get_8Cap(ehci_port_route[i]));
43100Sstevel@tonic-gate }
43110Sstevel@tonic-gate }
43120Sstevel@tonic-gate
43130Sstevel@tonic-gate
43140Sstevel@tonic-gate /*
43150Sstevel@tonic-gate * ehci_print_regs:
43160Sstevel@tonic-gate */
43170Sstevel@tonic-gate void
ehci_print_regs(ehci_state_t * ehcip)43180Sstevel@tonic-gate ehci_print_regs(ehci_state_t *ehcip)
43190Sstevel@tonic-gate {
43200Sstevel@tonic-gate uint_t i;
43210Sstevel@tonic-gate
43220Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43230Sstevel@tonic-gate "\n\tEHCI%d Operational Registers\n",
43240Sstevel@tonic-gate ddi_get_instance(ehcip->ehci_dip));
43250Sstevel@tonic-gate
43260Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43270Sstevel@tonic-gate "Command: 0x%x Status: 0x%x",
43280Sstevel@tonic-gate Get_OpReg(ehci_command), Get_OpReg(ehci_status));
43290Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43300Sstevel@tonic-gate "Interrupt: 0x%x Frame Index: 0x%x",
43310Sstevel@tonic-gate Get_OpReg(ehci_interrupt), Get_OpReg(ehci_frame_index));
43320Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43330Sstevel@tonic-gate "Control Segment: 0x%x Periodic List Base: 0x%x",
43340Sstevel@tonic-gate Get_OpReg(ehci_ctrl_segment), Get_OpReg(ehci_periodic_list_base));
43350Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43360Sstevel@tonic-gate "Async List Addr: 0x%x Config Flag: 0x%x",
43370Sstevel@tonic-gate Get_OpReg(ehci_async_list_addr), Get_OpReg(ehci_config_flag));
43380Sstevel@tonic-gate
43390Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43400Sstevel@tonic-gate "Root Hub Port Status");
43410Sstevel@tonic-gate
43420Sstevel@tonic-gate for (i = 0; i < (Get_Cap(ehci_hcs_params) & EHCI_HCS_NUM_PORTS); i++) {
43430Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
43440Sstevel@tonic-gate "\tPort Status 0x%x: 0x%x ", i,
43450Sstevel@tonic-gate Get_OpReg(ehci_rh_port_status[i]));
43460Sstevel@tonic-gate }
43470Sstevel@tonic-gate }
43480Sstevel@tonic-gate
43490Sstevel@tonic-gate
43500Sstevel@tonic-gate /*
43510Sstevel@tonic-gate * ehci_print_qh:
43520Sstevel@tonic-gate */
43530Sstevel@tonic-gate void
ehci_print_qh(ehci_state_t * ehcip,ehci_qh_t * qh)43540Sstevel@tonic-gate ehci_print_qh(
43550Sstevel@tonic-gate ehci_state_t *ehcip,
43560Sstevel@tonic-gate ehci_qh_t *qh)
43570Sstevel@tonic-gate {
43580Sstevel@tonic-gate uint_t i;
43590Sstevel@tonic-gate
43600Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43610Sstevel@tonic-gate "ehci_print_qh: qh = 0x%p", (void *)qh);
43620Sstevel@tonic-gate
43630Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43640Sstevel@tonic-gate "\tqh_link_ptr: 0x%x ", Get_QH(qh->qh_link_ptr));
43650Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43660Sstevel@tonic-gate "\tqh_ctrl: 0x%x ", Get_QH(qh->qh_ctrl));
43670Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43680Sstevel@tonic-gate "\tqh_split_ctrl: 0x%x ", Get_QH(qh->qh_split_ctrl));
43690Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43700Sstevel@tonic-gate "\tqh_curr_qtd: 0x%x ", Get_QH(qh->qh_curr_qtd));
43710Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43720Sstevel@tonic-gate "\tqh_next_qtd: 0x%x ", Get_QH(qh->qh_next_qtd));
43730Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43740Sstevel@tonic-gate "\tqh_alt_next_qtd: 0x%x ", Get_QH(qh->qh_alt_next_qtd));
43750Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43760Sstevel@tonic-gate "\tqh_status: 0x%x ", Get_QH(qh->qh_status));
43770Sstevel@tonic-gate
43780Sstevel@tonic-gate for (i = 0; i < 5; i++) {
43790Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43800Sstevel@tonic-gate "\tqh_buf[%d]: 0x%x ", i, Get_QH(qh->qh_buf[i]));
43810Sstevel@tonic-gate }
43820Sstevel@tonic-gate
43830Sstevel@tonic-gate for (i = 0; i < 5; i++) {
43840Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43850Sstevel@tonic-gate "\tqh_buf_high[%d]: 0x%x ",
43860Sstevel@tonic-gate i, Get_QH(qh->qh_buf_high[i]));
43870Sstevel@tonic-gate }
43880Sstevel@tonic-gate
43890Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43900Sstevel@tonic-gate "\tqh_dummy_qtd: 0x%x ", Get_QH(qh->qh_dummy_qtd));
43910Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43920Sstevel@tonic-gate "\tqh_prev: 0x%x ", Get_QH(qh->qh_prev));
43930Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43940Sstevel@tonic-gate "\tqh_state: 0x%x ", Get_QH(qh->qh_state));
43950Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43960Sstevel@tonic-gate "\tqh_reclaim_next: 0x%x ", Get_QH(qh->qh_reclaim_next));
43970Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
43980Sstevel@tonic-gate "\tqh_reclaim_frame: 0x%x ", Get_QH(qh->qh_reclaim_frame));
43990Sstevel@tonic-gate }
44000Sstevel@tonic-gate
44010Sstevel@tonic-gate
44020Sstevel@tonic-gate /*
44030Sstevel@tonic-gate * ehci_print_qtd:
44040Sstevel@tonic-gate */
44050Sstevel@tonic-gate void
ehci_print_qtd(ehci_state_t * ehcip,ehci_qtd_t * qtd)44060Sstevel@tonic-gate ehci_print_qtd(
44070Sstevel@tonic-gate ehci_state_t *ehcip,
44080Sstevel@tonic-gate ehci_qtd_t *qtd)
44090Sstevel@tonic-gate {
44100Sstevel@tonic-gate uint_t i;
44110Sstevel@tonic-gate
44120Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44130Sstevel@tonic-gate "ehci_print_qtd: qtd = 0x%p", (void *)qtd);
44140Sstevel@tonic-gate
44150Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44160Sstevel@tonic-gate "\tqtd_next_qtd: 0x%x ", Get_QTD(qtd->qtd_next_qtd));
44170Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44180Sstevel@tonic-gate "\tqtd_alt_next_qtd: 0x%x ", Get_QTD(qtd->qtd_alt_next_qtd));
44190Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44200Sstevel@tonic-gate "\tqtd_ctrl: 0x%x ", Get_QTD(qtd->qtd_ctrl));
44210Sstevel@tonic-gate
44220Sstevel@tonic-gate for (i = 0; i < 5; i++) {
44230Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44240Sstevel@tonic-gate "\tqtd_buf[%d]: 0x%x ", i, Get_QTD(qtd->qtd_buf[i]));
44250Sstevel@tonic-gate }
44260Sstevel@tonic-gate
44270Sstevel@tonic-gate for (i = 0; i < 5; i++) {
44280Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44290Sstevel@tonic-gate "\tqtd_buf_high[%d]: 0x%x ",
44300Sstevel@tonic-gate i, Get_QTD(qtd->qtd_buf_high[i]));
44310Sstevel@tonic-gate }
44320Sstevel@tonic-gate
44330Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44340Sstevel@tonic-gate "\tqtd_trans_wrapper: 0x%x ", Get_QTD(qtd->qtd_trans_wrapper));
44350Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44360Sstevel@tonic-gate "\tqtd_tw_next_qtd: 0x%x ", Get_QTD(qtd->qtd_tw_next_qtd));
44370Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44380Sstevel@tonic-gate "\tqtd_active_qtd_next: 0x%x ", Get_QTD(qtd->qtd_active_qtd_next));
44390Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44400Sstevel@tonic-gate "\tqtd_active_qtd_prev: 0x%x ", Get_QTD(qtd->qtd_active_qtd_prev));
44410Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44420Sstevel@tonic-gate "\tqtd_state: 0x%x ", Get_QTD(qtd->qtd_state));
44430Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44440Sstevel@tonic-gate "\tqtd_ctrl_phase: 0x%x ", Get_QTD(qtd->qtd_ctrl_phase));
44450Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44461500Ssl147100 "\tqtd_xfer_offs: 0x%x ", Get_QTD(qtd->qtd_xfer_offs));
44470Sstevel@tonic-gate USB_DPRINTF_L3(PRINT_MASK_LISTS, ehcip->ehci_log_hdl,
44480Sstevel@tonic-gate "\tqtd_xfer_len: 0x%x ", Get_QTD(qtd->qtd_xfer_len));
44490Sstevel@tonic-gate }
44500Sstevel@tonic-gate
44510Sstevel@tonic-gate /*
44520Sstevel@tonic-gate * ehci kstat functions
44530Sstevel@tonic-gate */
44540Sstevel@tonic-gate
44550Sstevel@tonic-gate /*
44560Sstevel@tonic-gate * ehci_create_stats:
44570Sstevel@tonic-gate *
44580Sstevel@tonic-gate * Allocate and initialize the ehci kstat structures
44590Sstevel@tonic-gate */
44600Sstevel@tonic-gate void
ehci_create_stats(ehci_state_t * ehcip)44610Sstevel@tonic-gate ehci_create_stats(ehci_state_t *ehcip)
44620Sstevel@tonic-gate {
44630Sstevel@tonic-gate char kstatname[KSTAT_STRLEN];
44640Sstevel@tonic-gate const char *dname = ddi_driver_name(ehcip->ehci_dip);
44650Sstevel@tonic-gate char *usbtypes[USB_N_COUNT_KSTATS] =
44665767Slc152243 {"ctrl", "isoch", "bulk", "intr"};
44670Sstevel@tonic-gate uint_t instance = ehcip->ehci_instance;
44680Sstevel@tonic-gate ehci_intrs_stats_t *isp;
44690Sstevel@tonic-gate int i;
44700Sstevel@tonic-gate
44710Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip) == NULL) {
44720Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,intrs",
44730Sstevel@tonic-gate dname, instance);
44740Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = kstat_create("usba", instance,
44750Sstevel@tonic-gate kstatname, "usb_interrupts", KSTAT_TYPE_NAMED,
44760Sstevel@tonic-gate sizeof (ehci_intrs_stats_t) / sizeof (kstat_named_t),
44770Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT);
44780Sstevel@tonic-gate
44790Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) {
44800Sstevel@tonic-gate isp = EHCI_INTRS_STATS_DATA(ehcip);
44810Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_total,
44820Sstevel@tonic-gate "Interrupts Total", KSTAT_DATA_UINT64);
44830Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_not_claimed,
44840Sstevel@tonic-gate "Not Claimed", KSTAT_DATA_UINT64);
44850Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_sched_status,
44860Sstevel@tonic-gate "Async schedule status", KSTAT_DATA_UINT64);
44870Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_periodic_sched_status,
44880Sstevel@tonic-gate "Periodic sched status", KSTAT_DATA_UINT64);
44890Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_empty_async_schedule,
44900Sstevel@tonic-gate "Empty async schedule", KSTAT_DATA_UINT64);
44910Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_ctrl_halted,
44920Sstevel@tonic-gate "Host controller Halted", KSTAT_DATA_UINT64);
44930Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_async_advance_intr,
44940Sstevel@tonic-gate "Intr on async advance", KSTAT_DATA_UINT64);
44950Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_host_system_error_intr,
44960Sstevel@tonic-gate "Host system error", KSTAT_DATA_UINT64);
44970Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_frm_list_rollover_intr,
44980Sstevel@tonic-gate "Frame list rollover", KSTAT_DATA_UINT64);
44990Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_rh_port_change_intr,
45000Sstevel@tonic-gate "Port change detect", KSTAT_DATA_UINT64);
45010Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_error_intr,
45020Sstevel@tonic-gate "USB error interrupt", KSTAT_DATA_UINT64);
45030Sstevel@tonic-gate kstat_named_init(&isp->ehci_sts_usb_intr,
45040Sstevel@tonic-gate "USB interrupt", KSTAT_DATA_UINT64);
45050Sstevel@tonic-gate
45060Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_private = ehcip;
45070Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip)->ks_update = nulldev;
45080Sstevel@tonic-gate kstat_install(EHCI_INTRS_STATS(ehcip));
45090Sstevel@tonic-gate }
45100Sstevel@tonic-gate }
45110Sstevel@tonic-gate
45120Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip) == NULL) {
45130Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,total",
45140Sstevel@tonic-gate dname, instance);
45150Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = kstat_create("usba", instance,
45160Sstevel@tonic-gate kstatname, "usb_byte_count", KSTAT_TYPE_IO, 1,
45170Sstevel@tonic-gate KSTAT_FLAG_PERSISTENT);
45180Sstevel@tonic-gate
45190Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) {
45200Sstevel@tonic-gate kstat_install(EHCI_TOTAL_STATS(ehcip));
45210Sstevel@tonic-gate }
45220Sstevel@tonic-gate }
45230Sstevel@tonic-gate
45240Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
45250Sstevel@tonic-gate if (ehcip->ehci_count_stats[i] == NULL) {
45260Sstevel@tonic-gate (void) snprintf(kstatname, KSTAT_STRLEN, "%s%d,%s",
45270Sstevel@tonic-gate dname, instance, usbtypes[i]);
45280Sstevel@tonic-gate ehcip->ehci_count_stats[i] = kstat_create("usba",
45290Sstevel@tonic-gate instance, kstatname, "usb_byte_count",
45300Sstevel@tonic-gate KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
45310Sstevel@tonic-gate
45320Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) {
45330Sstevel@tonic-gate kstat_install(ehcip->ehci_count_stats[i]);
45340Sstevel@tonic-gate }
45350Sstevel@tonic-gate }
45360Sstevel@tonic-gate }
45370Sstevel@tonic-gate }
45380Sstevel@tonic-gate
45390Sstevel@tonic-gate
45400Sstevel@tonic-gate /*
45410Sstevel@tonic-gate * ehci_destroy_stats:
45420Sstevel@tonic-gate *
45430Sstevel@tonic-gate * Clean up ehci kstat structures
45440Sstevel@tonic-gate */
45450Sstevel@tonic-gate void
ehci_destroy_stats(ehci_state_t * ehcip)45460Sstevel@tonic-gate ehci_destroy_stats(ehci_state_t *ehcip)
45470Sstevel@tonic-gate {
45480Sstevel@tonic-gate int i;
45490Sstevel@tonic-gate
45500Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) {
45510Sstevel@tonic-gate kstat_delete(EHCI_INTRS_STATS(ehcip));
45520Sstevel@tonic-gate EHCI_INTRS_STATS(ehcip) = NULL;
45530Sstevel@tonic-gate }
45540Sstevel@tonic-gate
45550Sstevel@tonic-gate if (EHCI_TOTAL_STATS(ehcip)) {
45560Sstevel@tonic-gate kstat_delete(EHCI_TOTAL_STATS(ehcip));
45570Sstevel@tonic-gate EHCI_TOTAL_STATS(ehcip) = NULL;
45580Sstevel@tonic-gate }
45590Sstevel@tonic-gate
45600Sstevel@tonic-gate for (i = 0; i < USB_N_COUNT_KSTATS; i++) {
45610Sstevel@tonic-gate if (ehcip->ehci_count_stats[i]) {
45620Sstevel@tonic-gate kstat_delete(ehcip->ehci_count_stats[i]);
45630Sstevel@tonic-gate ehcip->ehci_count_stats[i] = NULL;
45640Sstevel@tonic-gate }
45650Sstevel@tonic-gate }
45660Sstevel@tonic-gate }
45670Sstevel@tonic-gate
45680Sstevel@tonic-gate
45690Sstevel@tonic-gate /*
45700Sstevel@tonic-gate * ehci_do_intrs_stats:
45710Sstevel@tonic-gate *
45720Sstevel@tonic-gate * ehci status information
45730Sstevel@tonic-gate */
45740Sstevel@tonic-gate void
ehci_do_intrs_stats(ehci_state_t * ehcip,int val)45750Sstevel@tonic-gate ehci_do_intrs_stats(
45760Sstevel@tonic-gate ehci_state_t *ehcip,
45770Sstevel@tonic-gate int val)
45780Sstevel@tonic-gate {
45790Sstevel@tonic-gate if (EHCI_INTRS_STATS(ehcip)) {
45800Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->ehci_sts_total.value.ui64++;
45810Sstevel@tonic-gate switch (val) {
45820Sstevel@tonic-gate case EHCI_STS_ASYNC_SCHED_STATUS:
45830Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
45840Sstevel@tonic-gate ehci_sts_async_sched_status.value.ui64++;
45850Sstevel@tonic-gate break;
45860Sstevel@tonic-gate case EHCI_STS_PERIODIC_SCHED_STATUS:
45870Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
45880Sstevel@tonic-gate ehci_sts_periodic_sched_status.value.ui64++;
45890Sstevel@tonic-gate break;
45900Sstevel@tonic-gate case EHCI_STS_EMPTY_ASYNC_SCHEDULE:
45910Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
45920Sstevel@tonic-gate ehci_sts_empty_async_schedule.value.ui64++;
45930Sstevel@tonic-gate break;
45940Sstevel@tonic-gate case EHCI_STS_HOST_CTRL_HALTED:
45950Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
45960Sstevel@tonic-gate ehci_sts_host_ctrl_halted.value.ui64++;
45970Sstevel@tonic-gate break;
45980Sstevel@tonic-gate case EHCI_STS_ASYNC_ADVANCE_INTR:
45990Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
46000Sstevel@tonic-gate ehci_sts_async_advance_intr.value.ui64++;
46010Sstevel@tonic-gate break;
46020Sstevel@tonic-gate case EHCI_STS_HOST_SYSTEM_ERROR_INTR:
46030Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
46040Sstevel@tonic-gate ehci_sts_host_system_error_intr.value.ui64++;
46050Sstevel@tonic-gate break;
46060Sstevel@tonic-gate case EHCI_STS_FRM_LIST_ROLLOVER_INTR:
46070Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
46080Sstevel@tonic-gate ehci_sts_frm_list_rollover_intr.value.ui64++;
46090Sstevel@tonic-gate break;
46100Sstevel@tonic-gate case EHCI_STS_RH_PORT_CHANGE_INTR:
46110Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
46120Sstevel@tonic-gate ehci_sts_rh_port_change_intr.value.ui64++;
46130Sstevel@tonic-gate break;
46140Sstevel@tonic-gate case EHCI_STS_USB_ERROR_INTR:
46150Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
46160Sstevel@tonic-gate ehci_sts_usb_error_intr.value.ui64++;
46170Sstevel@tonic-gate break;
46180Sstevel@tonic-gate case EHCI_STS_USB_INTR:
46190Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
46200Sstevel@tonic-gate ehci_sts_usb_intr.value.ui64++;
46210Sstevel@tonic-gate break;
46220Sstevel@tonic-gate default:
46230Sstevel@tonic-gate EHCI_INTRS_STATS_DATA(ehcip)->
46240Sstevel@tonic-gate ehci_sts_not_claimed.value.ui64++;
46250Sstevel@tonic-gate break;
46260Sstevel@tonic-gate }
46270Sstevel@tonic-gate }
46280Sstevel@tonic-gate }
46290Sstevel@tonic-gate
46300Sstevel@tonic-gate
46310Sstevel@tonic-gate /*
46320Sstevel@tonic-gate * ehci_do_byte_stats:
46330Sstevel@tonic-gate *
46340Sstevel@tonic-gate * ehci data xfer information
46350Sstevel@tonic-gate */
46360Sstevel@tonic-gate void
ehci_do_byte_stats(ehci_state_t * ehcip,size_t len,uint8_t attr,uint8_t addr)46370Sstevel@tonic-gate ehci_do_byte_stats(
46380Sstevel@tonic-gate ehci_state_t *ehcip,
46390Sstevel@tonic-gate size_t len,
46400Sstevel@tonic-gate uint8_t attr,
46410Sstevel@tonic-gate uint8_t addr)
46420Sstevel@tonic-gate {
46430Sstevel@tonic-gate uint8_t type = attr & USB_EP_ATTR_MASK;
46440Sstevel@tonic-gate uint8_t dir = addr & USB_EP_DIR_MASK;
46450Sstevel@tonic-gate
46460Sstevel@tonic-gate if (dir == USB_EP_DIR_IN) {
46470Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->reads++;
46480Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nread += len;
46490Sstevel@tonic-gate switch (type) {
46500Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
46510Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->reads++;
46520Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nread += len;
46530Sstevel@tonic-gate break;
46540Sstevel@tonic-gate case USB_EP_ATTR_BULK:
46550Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->reads++;
46560Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nread += len;
46570Sstevel@tonic-gate break;
46580Sstevel@tonic-gate case USB_EP_ATTR_INTR:
46590Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->reads++;
46600Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nread += len;
46610Sstevel@tonic-gate break;
46620Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
46630Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->reads++;
46640Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nread += len;
46650Sstevel@tonic-gate break;
46660Sstevel@tonic-gate }
46670Sstevel@tonic-gate } else if (dir == USB_EP_DIR_OUT) {
46680Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->writes++;
46690Sstevel@tonic-gate EHCI_TOTAL_STATS_DATA(ehcip)->nwritten += len;
46700Sstevel@tonic-gate switch (type) {
46710Sstevel@tonic-gate case USB_EP_ATTR_CONTROL:
46720Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->writes++;
46730Sstevel@tonic-gate EHCI_CTRL_STATS(ehcip)->nwritten += len;
46740Sstevel@tonic-gate break;
46750Sstevel@tonic-gate case USB_EP_ATTR_BULK:
46760Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->writes++;
46770Sstevel@tonic-gate EHCI_BULK_STATS(ehcip)->nwritten += len;
46780Sstevel@tonic-gate break;
46790Sstevel@tonic-gate case USB_EP_ATTR_INTR:
46800Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->writes++;
46810Sstevel@tonic-gate EHCI_INTR_STATS(ehcip)->nwritten += len;
46820Sstevel@tonic-gate break;
46830Sstevel@tonic-gate case USB_EP_ATTR_ISOCH:
46840Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->writes++;
46850Sstevel@tonic-gate EHCI_ISOC_STATS(ehcip)->nwritten += len;
46860Sstevel@tonic-gate break;
46870Sstevel@tonic-gate }
46880Sstevel@tonic-gate }
46890Sstevel@tonic-gate }
4690