1993e3fafSRobert Mustacchi /*
2993e3fafSRobert Mustacchi * This file and its contents are supplied under the terms of the
3993e3fafSRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
4993e3fafSRobert Mustacchi * You may only use this file in accordance with the terms of version
5993e3fafSRobert Mustacchi * 1.0 of the CDDL.
6993e3fafSRobert Mustacchi *
7993e3fafSRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
8993e3fafSRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
9993e3fafSRobert Mustacchi * http://www.illumos.org/license/CDDL.
10993e3fafSRobert Mustacchi */
11993e3fafSRobert Mustacchi
12993e3fafSRobert Mustacchi /*
13c78b1a45SRobert Mustacchi * Copyright (c) 2019, Joyent, Inc.
14*0ae0ab6fSJoshua M. Clulow * Copyright 2022 Oxide Computer Company
15993e3fafSRobert Mustacchi */
16993e3fafSRobert Mustacchi
17993e3fafSRobert Mustacchi /*
18993e3fafSRobert Mustacchi * Extensible Host Controller Interface (xHCI) USB Driver
19993e3fafSRobert Mustacchi *
20993e3fafSRobert Mustacchi * The xhci driver is an HCI driver for USB that bridges the gap between client
21993e3fafSRobert Mustacchi * device drivers and implements the actual way that we talk to devices. The
22993e3fafSRobert Mustacchi * xhci specification provides access to USB 3.x capable devices, as well as all
23993e3fafSRobert Mustacchi * prior generations. Like other host controllers, it both provides the way to
24993e3fafSRobert Mustacchi * talk to devices and also is treated like a hub (often called the root hub).
25993e3fafSRobert Mustacchi *
26993e3fafSRobert Mustacchi * This driver is part of the USBA (USB Architecture). It implements the HCDI
27993e3fafSRobert Mustacchi * (host controller device interface) end of USBA. These entry points are used
28993e3fafSRobert Mustacchi * by the USBA on behalf of client device drivers to access their devices. The
29993e3fafSRobert Mustacchi * driver also provides notifications to deal with hot plug events, which are
30993e3fafSRobert Mustacchi * quite common in USB.
31993e3fafSRobert Mustacchi *
32993e3fafSRobert Mustacchi * ----------------
33993e3fafSRobert Mustacchi * USB Introduction
34993e3fafSRobert Mustacchi * ----------------
35993e3fafSRobert Mustacchi *
36993e3fafSRobert Mustacchi * To properly understand the xhci driver and the design of the USBA HCDI
37993e3fafSRobert Mustacchi * interfaces it implements, it helps to have a bit of background into how USB
38993e3fafSRobert Mustacchi * devices are structured and understand how they work at a high-level.
39993e3fafSRobert Mustacchi *
40993e3fafSRobert Mustacchi * USB devices, like PCI devices, are broken down into different classes of
41993e3fafSRobert Mustacchi * device. For example, with USB you have hubs, human-input devices (keyboards,
42993e3fafSRobert Mustacchi * mice, etc.), mass storage, etc. Every device also has a vendor and device ID.
43993e3fafSRobert Mustacchi * Many client drivers bind to an entire class of device, for example, the hubd
44993e3fafSRobert Mustacchi * driver (to hubs) or scsa2usb (USB storage). However, there are other drivers
45993e3fafSRobert Mustacchi * that bind to explicit IDs such as usbsprl (specific USB to Serial devices).
46993e3fafSRobert Mustacchi *
47993e3fafSRobert Mustacchi * USB SPEEDS AND VERSIONS
48993e3fafSRobert Mustacchi *
49993e3fafSRobert Mustacchi * USB devices are often referred to in two different ways. One way they're
50993e3fafSRobert Mustacchi * described is with the USB version that they conform to. In the wild, you're
51993e3fafSRobert Mustacchi * most likely going to see USB 1.1, 2.0, 2.1, and 3.0. However, you may also
52993e3fafSRobert Mustacchi * see devices referred to as 'full-', 'low-', 'high-', and 'super-' speed
53993e3fafSRobert Mustacchi * devices.
54993e3fafSRobert Mustacchi *
55993e3fafSRobert Mustacchi * The latter description describes the maximum theoretical speed of a given
56993e3fafSRobert Mustacchi * device. For example, a super-speed device theoretically caps out around 5
57993e3fafSRobert Mustacchi * Gbit/s, whereas a low-speed device caps out at 1.5 Mbit/s.
58993e3fafSRobert Mustacchi *
59993e3fafSRobert Mustacchi * In general, each speed usually corresponds to a specific USB protocol
60993e3fafSRobert Mustacchi * generation. For example, all USB 3.0 devices are super-speed devices. All
61993e3fafSRobert Mustacchi * 'high-speed' devices are USB 2.x devices. Full-speed devices are special in
62993e3fafSRobert Mustacchi * that they can either be USB 1.x or USB 2.x devices. Low-speed devices are
63993e3fafSRobert Mustacchi * only a USB 1.x thing, they did not jump the fire line to USB 2.x.
64993e3fafSRobert Mustacchi *
65993e3fafSRobert Mustacchi * USB 3.0 devices and ports generally have the wiring for both USB 2.0 and USB
66993e3fafSRobert Mustacchi * 3.0. When a USB 3.x device is plugged into a USB 2.0 port or hub, then it
67993e3fafSRobert Mustacchi * will report its version as USB 2.1, to indicate that it is actually a USB 3.x
68993e3fafSRobert Mustacchi * device.
69993e3fafSRobert Mustacchi *
70993e3fafSRobert Mustacchi * USB ENDPOINTS
71993e3fafSRobert Mustacchi *
72993e3fafSRobert Mustacchi * A given USB device is made up of endpoints. A request, or transfer, is made
73993e3fafSRobert Mustacchi * to a specific USB endpoint. These endpoints can provide different services
74993e3fafSRobert Mustacchi * and have different expectations around the size of the data that'll be used
75993e3fafSRobert Mustacchi * in a given request and the periodicity of requests. Endpoints themselves are
76993e3fafSRobert Mustacchi * either used to make one-shot requests, for example, making requests to a mass
77993e3fafSRobert Mustacchi * storage device for a given sector, or for making periodic requests where you
78993e3fafSRobert Mustacchi * end up polling on the endpoint, for example, polling on a USB keyboard for
79993e3fafSRobert Mustacchi * keystrokes.
80993e3fafSRobert Mustacchi *
81993e3fafSRobert Mustacchi * Each endpoint encodes two different pieces of information: a direction and a
82993e3fafSRobert Mustacchi * type. There are two different directions: IN and OUT. These refer to the
83993e3fafSRobert Mustacchi * general direction that data moves relative to the operating system. For
84993e3fafSRobert Mustacchi * example, an IN transfer transfers data in to the operating system, from the
85993e3fafSRobert Mustacchi * device. An OUT transfer transfers data from the operating system, out to the
86993e3fafSRobert Mustacchi * device.
87993e3fafSRobert Mustacchi *
88993e3fafSRobert Mustacchi * There are four different kinds of endpoints:
89993e3fafSRobert Mustacchi *
90672fc84aSRobert Mustacchi * BULK These transfers are large transfers of data to or from
91672fc84aSRobert Mustacchi * a device. The most common use for bulk transfers is for
92672fc84aSRobert Mustacchi * mass storage devices. Though they are often also used by
93672fc84aSRobert Mustacchi * network devices and more. Bulk endpoints do not have an
94672fc84aSRobert Mustacchi * explicit time component to them. They are always used
95672fc84aSRobert Mustacchi * for one-shot transfers.
96672fc84aSRobert Mustacchi *
97672fc84aSRobert Mustacchi * CONTROL These transfers are used to manipulate devices
98672fc84aSRobert Mustacchi * themselves and are used for USB protocol level
99672fc84aSRobert Mustacchi * operations (whether device-specific, class-specific, or
100672fc84aSRobert Mustacchi * generic across all of USB). Unlike other transfers,
101672fc84aSRobert Mustacchi * control transfers are always bi-directional and use
102672fc84aSRobert Mustacchi * different kinds of transfers.
103672fc84aSRobert Mustacchi *
104672fc84aSRobert Mustacchi * INTERRUPT Interrupt transfers are used for small transfers that
105672fc84aSRobert Mustacchi * happen infrequently, but need reasonable latency. A good
106672fc84aSRobert Mustacchi * example of interrupt transfers is to receive input from
107672fc84aSRobert Mustacchi * a USB keyboard. Interrupt-IN transfers are generally
108672fc84aSRobert Mustacchi * polled. Meaning that a client (device driver) opens up
109672fc84aSRobert Mustacchi * an interrupt-IN pipe to poll on it, and receives
110672fc84aSRobert Mustacchi * periodic updates whenever there is information
111672fc84aSRobert Mustacchi * available. However, Interrupt transfers can be used
112672fc84aSRobert Mustacchi * as one-shot transfers both going IN and OUT.
113672fc84aSRobert Mustacchi *
114672fc84aSRobert Mustacchi * ISOCHRONOUS These transfers are things that happen once per
115672fc84aSRobert Mustacchi * time-interval at a very regular rate. A good example of
116672fc84aSRobert Mustacchi * these transfers are for audio and video. A device may
117672fc84aSRobert Mustacchi * describe an interval as 10ms at which point it will read
118672fc84aSRobert Mustacchi * or write the next batch of data every 10ms and transform
119672fc84aSRobert Mustacchi * it for the user. There are no one-shot Isochronous-IN
120672fc84aSRobert Mustacchi * transfers. There are one-shot Isochronous-OUT transfers,
121672fc84aSRobert Mustacchi * but these are used by device drivers to always provide
122672fc84aSRobert Mustacchi * the system with sufficient data.
123993e3fafSRobert Mustacchi *
124993e3fafSRobert Mustacchi * To find out information about the endpoints, USB devices have a series of
125993e3fafSRobert Mustacchi * descriptors that cover different aspects of the device. For example, there
126993e3fafSRobert Mustacchi * are endpoint descriptors which cover the properties of endpoints such as the
127993e3fafSRobert Mustacchi * maximum packet size or polling interval.
128993e3fafSRobert Mustacchi *
129993e3fafSRobert Mustacchi * Descriptors exist at all levels of USB. For example, there are general
130993e3fafSRobert Mustacchi * descriptors for every device. The USB device descriptor is described in
131993e3fafSRobert Mustacchi * usb_dev_descr(9S). Host controllers will look at these descriptors to ensure
132993e3fafSRobert Mustacchi * that they program the device correctly; however, they are more often used by
133993e3fafSRobert Mustacchi * client device drivers. There are also descriptors that exist at a class
134993e3fafSRobert Mustacchi * level. For example, the hub class has a class-specific descriptor which
135993e3fafSRobert Mustacchi * describes properties of the hub. That information is requested for and used
136993e3fafSRobert Mustacchi * by the hub driver.
137993e3fafSRobert Mustacchi *
138993e3fafSRobert Mustacchi * All of the different descriptors are gathered by the system and placed into a
139993e3fafSRobert Mustacchi * tree which USBA sometimes calls the 'Configuration Cloud'. Client device
140993e3fafSRobert Mustacchi * drivers gain access to this cloud and then use them to open endpoints, which
141993e3fafSRobert Mustacchi * are called pipes in USBA (and some revisions of the USB specification).
142993e3fafSRobert Mustacchi *
143993e3fafSRobert Mustacchi * Each pipe gives access to a specific endpoint on the device which can be used
144993e3fafSRobert Mustacchi * to perform transfers of a specific type and direction. For example, a mass
145993e3fafSRobert Mustacchi * storage device often has three different endpoints, the default control
146993e3fafSRobert Mustacchi * endpoint (which every device has), a Bulk-IN endpoint, and a Bulk-OUT
147993e3fafSRobert Mustacchi * endpoint. The device driver ends up with three open pipes. One to the default
148993e3fafSRobert Mustacchi * control endpoint to configure the device, and then the other two are used to
149993e3fafSRobert Mustacchi * perform I/O.
150993e3fafSRobert Mustacchi *
151993e3fafSRobert Mustacchi * These routines translate more or less directly into calls to a host
152993e3fafSRobert Mustacchi * controller driver. A request to open a pipe takes an endpoint descriptor that
153993e3fafSRobert Mustacchi * describes the properties of the pipe, and the host controller driver (this
154993e3fafSRobert Mustacchi * driver) goes through and does any work necessary to allow the client device
155993e3fafSRobert Mustacchi * driver to access it. Once the pipe is open, it either makes one-shot
156993e3fafSRobert Mustacchi * transfers specific to the transfer type or it starts performing a periodic
157993e3fafSRobert Mustacchi * poll of an endpoint.
158993e3fafSRobert Mustacchi *
159993e3fafSRobert Mustacchi * All of these different actions translate into requests to the host
160993e3fafSRobert Mustacchi * controller. The host controller driver itself is in charge of making sure
161993e3fafSRobert Mustacchi * that all of the required resources for polling are allocated with a request
162993e3fafSRobert Mustacchi * and then proceed to give the driver's periodic callbacks.
163993e3fafSRobert Mustacchi *
164993e3fafSRobert Mustacchi * HUBS AND HOST CONTROLLERS
165993e3fafSRobert Mustacchi *
166993e3fafSRobert Mustacchi * Every device is always plugged into a hub, even if the device is itself a
167993e3fafSRobert Mustacchi * hub. This continues until we reach what we call the root-hub. The root-hub is
168993e3fafSRobert Mustacchi * special in that it is not an actual USB hub, but is integrated into the host
169993e3fafSRobert Mustacchi * controller and is manipulated in its own way. For example, the host
170993e3fafSRobert Mustacchi * controller is used to turn on and off a given port's power. This may happen
171993e3fafSRobert Mustacchi * over any interface, though the most common way is through PCI.
172993e3fafSRobert Mustacchi *
173993e3fafSRobert Mustacchi * In addition to the normal character device that exists for a host controller
174993e3fafSRobert Mustacchi * driver, as part of attaching, the host controller binds to an instance of the
175993e3fafSRobert Mustacchi * hubd driver. While the root-hub is a bit of a fiction, everyone models the
176993e3fafSRobert Mustacchi * root-hub as the same as any other hub that's plugged in. The hub kernel
177993e3fafSRobert Mustacchi * module doesn't know that the hub isn't a physical device that's been plugged
178993e3fafSRobert Mustacchi * in. The host controller driver simulates that view by taking hub requests
179993e3fafSRobert Mustacchi * that are made and translating them into corresponding requests that are
180993e3fafSRobert Mustacchi * understood by the host controller, for example, reading and writing to a
181993e3fafSRobert Mustacchi * memory mapped register.
182993e3fafSRobert Mustacchi *
183993e3fafSRobert Mustacchi * The hub driver polls for changes in device state using an Interrupt-IN
184993e3fafSRobert Mustacchi * request, which is the same as is done for the root-hub. This allows the host
185993e3fafSRobert Mustacchi * controller driver to not have to know about the implementation of device hot
186993e3fafSRobert Mustacchi * plug, merely react to requests from a hub, the same as if it were an external
187993e3fafSRobert Mustacchi * device. When the hub driver detects a change, it will go through the
188993e3fafSRobert Mustacchi * corresponding state machine and attach or detach the corresponding client
189993e3fafSRobert Mustacchi * device driver, depending if the device was inserted or removed.
190993e3fafSRobert Mustacchi *
191993e3fafSRobert Mustacchi * We detect the changes for the Interrupt-IN primarily based on the port state
192993e3fafSRobert Mustacchi * change events that are delivered to the event ring. Whenever any event is
193993e3fafSRobert Mustacchi * fired, we use this to update the hub driver about _all_ ports with
194993e3fafSRobert Mustacchi * outstanding events. This more closely matches how a hub is supposed to behave
195993e3fafSRobert Mustacchi * and leaves things less likely for the hub driver to end up without clearing a
196993e3fafSRobert Mustacchi * flag on a port.
197993e3fafSRobert Mustacchi *
198993e3fafSRobert Mustacchi * PACKET SIZES AND BURSTING
199993e3fafSRobert Mustacchi *
200993e3fafSRobert Mustacchi * A given USB endpoint has an explicit packet size and a number of packets that
201993e3fafSRobert Mustacchi * can be sent per time interval. These concepts are abstracted away from client
202993e3fafSRobert Mustacchi * device drives usually, though they sometimes inform the upper bounds of what
203993e3fafSRobert Mustacchi * a device can perform.
204993e3fafSRobert Mustacchi *
205993e3fafSRobert Mustacchi * The host controller uses this information to transform arbitrary transfer
206993e3fafSRobert Mustacchi * requests into USB protocol packets. One of the nice things about the host
207993e3fafSRobert Mustacchi * controllers is that they abstract away all of the signaling and semantics of
208993e3fafSRobert Mustacchi * the actual USB protocols, allowing for life to be slightly easier in the
209993e3fafSRobert Mustacchi * operating system.
210993e3fafSRobert Mustacchi *
211993e3fafSRobert Mustacchi * That said, if the host controller is not programmed correctly, these can end
212993e3fafSRobert Mustacchi * up causing transaction errors and other problems in response to the data that
213993e3fafSRobert Mustacchi * the host controller is trying to send or receive.
214993e3fafSRobert Mustacchi *
215993e3fafSRobert Mustacchi * ------------
216993e3fafSRobert Mustacchi * Organization
217993e3fafSRobert Mustacchi * ------------
218993e3fafSRobert Mustacchi *
219993e3fafSRobert Mustacchi * The driver is made up of the following files. Many of these have their own
220993e3fafSRobert Mustacchi * theory statements to describe what they do. Here, we touch on each of the
221993e3fafSRobert Mustacchi * purpose of each of these files.
222993e3fafSRobert Mustacchi *
223993e3fafSRobert Mustacchi * xhci_command.c: This file contains the logic to issue commands to the
224672fc84aSRobert Mustacchi * controller as well as the actual functions that the
225672fc84aSRobert Mustacchi * other parts of the driver use to cause those commands.
226993e3fafSRobert Mustacchi *
227993e3fafSRobert Mustacchi * xhci_context.c: This file manages various data structures used by the
228672fc84aSRobert Mustacchi * controller to manage the controller's and device's
229672fc84aSRobert Mustacchi * context data structures. See more in the xHCI Overview
230672fc84aSRobert Mustacchi * and General Design for more information.
231993e3fafSRobert Mustacchi *
232993e3fafSRobert Mustacchi * xhci_dma.c: This manages the allocation of DMA memory and DMA
233672fc84aSRobert Mustacchi * attributes for controller, whether memory is for a
234672fc84aSRobert Mustacchi * transfer or something else. This file also deals with
235672fc84aSRobert Mustacchi * all the logic of getting data in and out of DMA buffers.
236993e3fafSRobert Mustacchi *
237993e3fafSRobert Mustacchi * xhci_endpoint.c: This manages all of the logic of handling endpoints or
238672fc84aSRobert Mustacchi * pipes. It deals with endpoint configuration, I/O
239672fc84aSRobert Mustacchi * scheduling, timeouts, and callbacks to USBA.
240993e3fafSRobert Mustacchi *
241993e3fafSRobert Mustacchi * xhci_event.c: This manages callbacks from the hardware to the driver.
242672fc84aSRobert Mustacchi * This covers command completion notifications and I/O
243672fc84aSRobert Mustacchi * notifications.
244993e3fafSRobert Mustacchi *
245993e3fafSRobert Mustacchi * xhci_hub.c: This manages the virtual root-hub. It basically
246672fc84aSRobert Mustacchi * implements and translates all of the USB level requests
247672fc84aSRobert Mustacchi * into xhci specific implements. It also contains the
248672fc84aSRobert Mustacchi * functions to register this hub with USBA.
249993e3fafSRobert Mustacchi *
250993e3fafSRobert Mustacchi * xhci_intr.c: This manages the underlying interrupt allocation,
251672fc84aSRobert Mustacchi * interrupt moderation, and interrupt routines.
252993e3fafSRobert Mustacchi *
253993e3fafSRobert Mustacchi * xhci_quirks.c: This manages information about buggy hardware that's
254672fc84aSRobert Mustacchi * been collected and experienced primarily from other
255672fc84aSRobert Mustacchi * systems.
256993e3fafSRobert Mustacchi *
257993e3fafSRobert Mustacchi * xhci_ring.c: This manages the abstraction of a ring in xhci, which is
258672fc84aSRobert Mustacchi * the primary of communication between the driver and the
259672fc84aSRobert Mustacchi * hardware, whether for the controller or a device.
260993e3fafSRobert Mustacchi *
261993e3fafSRobert Mustacchi * xhci_usba.c: This implements all of the HCDI functions required by
262672fc84aSRobert Mustacchi * USBA. This is the main entry point that drivers and the
263672fc84aSRobert Mustacchi * kernel frameworks will reach to start any operation.
264672fc84aSRobert Mustacchi * Many functions here will end up in the command and
265672fc84aSRobert Mustacchi * endpoint code.
266993e3fafSRobert Mustacchi *
267993e3fafSRobert Mustacchi * xhci.c: This provides the main kernel DDI interfaces and
268672fc84aSRobert Mustacchi * performs device initialization.
269993e3fafSRobert Mustacchi *
270ec82ef79SMatthias Scheler * xhci_polled.c: This provides the polled I/O functions that the
271ec82ef79SMatthias Scheler * kernel debugger can use.
272ec82ef79SMatthias Scheler *
273993e3fafSRobert Mustacchi * xhci.h: This is the primary header file which defines
274672fc84aSRobert Mustacchi * illumos-specific data structures and constants to manage
275672fc84aSRobert Mustacchi * the system.
276993e3fafSRobert Mustacchi *
277993e3fafSRobert Mustacchi * xhcireg.h: This header file defines all of the register offsets,
278672fc84aSRobert Mustacchi * masks, and related macros. It also contains all of the
279672fc84aSRobert Mustacchi * constants that are used in various structures as defined
280672fc84aSRobert Mustacchi * by the specification, such as command offsets, etc.
281993e3fafSRobert Mustacchi *
282993e3fafSRobert Mustacchi * xhci_ioctl.h: This contains a few private ioctls that are used by a
283672fc84aSRobert Mustacchi * private debugging command. These are private.
284993e3fafSRobert Mustacchi *
285993e3fafSRobert Mustacchi * cmd/xhci/xhci_portsc: This is a private utility that can be useful for
286672fc84aSRobert Mustacchi * debugging xhci state. It is the only consumer of
287672fc84aSRobert Mustacchi * xhci_ioctl.h and the private ioctls.
288993e3fafSRobert Mustacchi *
289993e3fafSRobert Mustacchi * ----------------------------------
290993e3fafSRobert Mustacchi * xHCI Overview and Structure Layout
291993e3fafSRobert Mustacchi * ----------------------------------
292993e3fafSRobert Mustacchi *
293993e3fafSRobert Mustacchi * The design and structure of this driver follows from the way that the xHCI
294993e3fafSRobert Mustacchi * specification tells us that we have to work with hardware. First we'll give a
295993e3fafSRobert Mustacchi * rough summary of how that works, though the xHCI 1.1 specification should be
296993e3fafSRobert Mustacchi * referenced when going through this.
297993e3fafSRobert Mustacchi *
298993e3fafSRobert Mustacchi * There are three primary parts of the hardware -- registers, contexts, and
299993e3fafSRobert Mustacchi * rings. The registers are memory mapped registers that come in four sets,
300993e3fafSRobert Mustacchi * though all are found within the first BAR. These are used to program and
301993e3fafSRobert Mustacchi * control the hardware and aspects of the devices. Beyond more traditional
302993e3fafSRobert Mustacchi * device programming there are two primary sets of registers that are
303993e3fafSRobert Mustacchi * important:
304993e3fafSRobert Mustacchi *
305993e3fafSRobert Mustacchi * o Port Status and Control Registers (XHCI_PORTSC)
306993e3fafSRobert Mustacchi * o Doorbell Array (XHCI_DOORBELL)
307993e3fafSRobert Mustacchi *
308993e3fafSRobert Mustacchi * The port status and control registers are used to get and manipulate the
309993e3fafSRobert Mustacchi * status of a given device. For example, turning on and off the power to it.
310993e3fafSRobert Mustacchi * The Doorbell Array is used to kick off I/O operations and start the
311993e3fafSRobert Mustacchi * processing of an I/O ring.
312993e3fafSRobert Mustacchi *
313993e3fafSRobert Mustacchi * The contexts are data structures that represent various pieces of information
314993e3fafSRobert Mustacchi * in the controller. These contexts are generally filled out by the driver and
315993e3fafSRobert Mustacchi * then acknowledged and consumed by the hardware. There are controller-wide
316993e3fafSRobert Mustacchi * contexts (mostly managed in xhci_context.c) that are used to point to the
317993e3fafSRobert Mustacchi * contexts that exist for each device in the system. The primary context is
318993e3fafSRobert Mustacchi * called the Device Context Base Address Array (DCBAA).
319993e3fafSRobert Mustacchi *
320993e3fafSRobert Mustacchi * Each device in the system is allocated a 'slot', which is used to index into
321993e3fafSRobert Mustacchi * the DCBAA. Slots are assigned based on issuing commands to the controller.
322993e3fafSRobert Mustacchi * There are a fixed number of slots that determine the maximum number of
323993e3fafSRobert Mustacchi * devices that can end up being supported in the system. Note this includes all
324993e3fafSRobert Mustacchi * the devices plugged into the USB device tree, not just devices plugged into
325993e3fafSRobert Mustacchi * ports on the chassis.
326993e3fafSRobert Mustacchi *
327993e3fafSRobert Mustacchi * For each device, there is a context structure that describes properties of
328993e3fafSRobert Mustacchi * the device. For example, what speed is the device, is it a hub, etc. The
329993e3fafSRobert Mustacchi * context has slots for the device and for each endpoint on the device. As
330993e3fafSRobert Mustacchi * endpoints are enabled, their context information which describes things like
331993e3fafSRobert Mustacchi * the maximum packet size, is filled in and enabled. The mapping between these
332993e3fafSRobert Mustacchi * contexts look like:
333993e3fafSRobert Mustacchi *
334993e3fafSRobert Mustacchi *
335993e3fafSRobert Mustacchi * DCBAA
336993e3fafSRobert Mustacchi * +--------+ Device Context
337993e3fafSRobert Mustacchi * | Slot 0 |------------------>+--------------+
338993e3fafSRobert Mustacchi * +--------+ | Slot Context |
339993e3fafSRobert Mustacchi * | ... | +--------------+ +----------+
340993e3fafSRobert Mustacchi * +--------+ +------+ | Endpoint 0 |------>| I/O Ring |
341993e3fafSRobert Mustacchi * | Slot n |-->| NULL | | Context (Bi) | +----------+
342993e3fafSRobert Mustacchi * +--------+ +------+ +--------------+
343993e3fafSRobert Mustacchi * | Endpoint 1 |
344993e3fafSRobert Mustacchi * | Context (Out)|
345993e3fafSRobert Mustacchi * +--------------+
346993e3fafSRobert Mustacchi * | Endpoint 1 |
347993e3fafSRobert Mustacchi * | Context (In) |
348993e3fafSRobert Mustacchi * +--------------+
349993e3fafSRobert Mustacchi * | ... |
350993e3fafSRobert Mustacchi * +--------------+
351993e3fafSRobert Mustacchi * | Endpoint 15 |
352993e3fafSRobert Mustacchi * | Context (In) |
353993e3fafSRobert Mustacchi * +--------------+
354993e3fafSRobert Mustacchi *
355993e3fafSRobert Mustacchi * These contexts are always owned by the controller, though we can read them
356993e3fafSRobert Mustacchi * after various operations complete. Commands that toggle device state use a
357993e3fafSRobert Mustacchi * specific input context, which is a variant of the device context. The only
358993e3fafSRobert Mustacchi * difference is that it has an input context structure ahead of it to say which
359993e3fafSRobert Mustacchi * sections of the device context should be evaluated.
360993e3fafSRobert Mustacchi *
361993e3fafSRobert Mustacchi * Each active endpoint points us to an I/O ring, which leads us to the third
362993e3fafSRobert Mustacchi * main data structure that's used by the device: rings. Rings are made up of
363993e3fafSRobert Mustacchi * transfer request blocks (TRBs), which are joined together to form a given
364993e3fafSRobert Mustacchi * transfer description (TD) which represents a single I/O request.
365993e3fafSRobert Mustacchi *
366993e3fafSRobert Mustacchi * These rings are used to issue I/O to individual endpoints, to issue commands
367993e3fafSRobert Mustacchi * to the controller, and to receive notification of changes and completions.
368993e3fafSRobert Mustacchi * Issued commands go on the special ring called the command ring while the
369993e3fafSRobert Mustacchi * change and completion notifications go on the event ring. More details are
370993e3fafSRobert Mustacchi * available in xhci_ring.c. Each of these structures is represented by an
371993e3fafSRobert Mustacchi * xhci_ring_t.
372993e3fafSRobert Mustacchi *
373993e3fafSRobert Mustacchi * Each ring can be made up of one or more disjoint regions of DMA; however, we
374993e3fafSRobert Mustacchi * only use a single one. This also impacts some additional registers and
375993e3fafSRobert Mustacchi * structures that exist. The event ring has an indirection table called the
376993e3fafSRobert Mustacchi * Event Ring Segment Table (ERST). Each entry in the table (a segment)
377993e3fafSRobert Mustacchi * describes a chunk of the event ring.
378993e3fafSRobert Mustacchi *
379993e3fafSRobert Mustacchi * One other thing worth calling out is the scratchpad. The scratchpad is a way
380993e3fafSRobert Mustacchi * for the controller to be given arbitrary memory by the OS that it can use.
381993e3fafSRobert Mustacchi * There are two parts to the scratchpad. The first part is an array whose
382993e3fafSRobert Mustacchi * entries contain pointers to the actual addresses for the pages. The second
383993e3fafSRobert Mustacchi * part that we allocate are the actual pages themselves.
384993e3fafSRobert Mustacchi *
385993e3fafSRobert Mustacchi * -----------------------------
386993e3fafSRobert Mustacchi * Endpoint State and Management
387993e3fafSRobert Mustacchi * -----------------------------
388993e3fafSRobert Mustacchi *
389993e3fafSRobert Mustacchi * Endpoint management is one of the key parts to the xhci driver as every
390993e3fafSRobert Mustacchi * endpoint is a pipe that a device driver uses, so they are our primary
391*0ae0ab6fSJoshua M. Clulow * currency. An endpoint is enabled when the client device driver opens the
392*0ae0ab6fSJoshua M. Clulow * associated pipe for the first time. When an endpoint is enabled, we have to
393*0ae0ab6fSJoshua M. Clulow * fill in an endpoint's context structure with information about the endpoint.
394*0ae0ab6fSJoshua M. Clulow * These basically tell the controller important properties which it uses to
395*0ae0ab6fSJoshua M. Clulow * ensure that there is adequate bandwidth for the device.
396*0ae0ab6fSJoshua M. Clulow *
397*0ae0ab6fSJoshua M. Clulow * If the client device closes the pipe again we explicitly stop the endpoint,
398*0ae0ab6fSJoshua M. Clulow * moving it to the Halted state, and take ownership of any transfers
399*0ae0ab6fSJoshua M. Clulow * previously submitted to the ring but which have not yet completed. A client
400*0ae0ab6fSJoshua M. Clulow * may open and close a pipe several times -- ugen(4D) in particular is known
401*0ae0ab6fSJoshua M. Clulow * for this -- and we will stop and start the ring accordingly.
402*0ae0ab6fSJoshua M. Clulow *
403*0ae0ab6fSJoshua M. Clulow * It is tempting to fully unconfigure an endpoint when a pipe is closed, but
404*0ae0ab6fSJoshua M. Clulow * some host controllers appear to exhibit undefined behaviour each time the
405*0ae0ab6fSJoshua M. Clulow * endpoint is re-enabled this way; e.g., silently dropped transfers. As such,
406*0ae0ab6fSJoshua M. Clulow * we wait until the whole device is being torn down to disable all previously
407*0ae0ab6fSJoshua M. Clulow * enabled endpoints at once, as part of disabling the device slot.
408993e3fafSRobert Mustacchi *
409993e3fafSRobert Mustacchi * Each endpoint has its own ring as described in the previous section. We place
410993e3fafSRobert Mustacchi * TRBs (transfer request blocks) onto a given ring to request I/O be performed.
411993e3fafSRobert Mustacchi * Responses are placed on the event ring, in other words, the rings associated
412993e3fafSRobert Mustacchi * with an endpoint are purely for producing I/O.
413993e3fafSRobert Mustacchi *
414993e3fafSRobert Mustacchi * Endpoints have a defined state machine as described in xHCI 1.1 / 4.8.3.
415993e3fafSRobert Mustacchi * These states generally correspond with the state of the endpoint to process
416993e3fafSRobert Mustacchi * I/O and handle timeouts. The driver basically follows a similar state machine
417993e3fafSRobert Mustacchi * as described there. There are some deviations. For example, what they
418993e3fafSRobert Mustacchi * describe as 'running' we break into both the Idle and Running states below.
419993e3fafSRobert Mustacchi * We also have a notion of timed out and quiescing. The following image
420993e3fafSRobert Mustacchi * summarizes the states and transitions:
421993e3fafSRobert Mustacchi *
422993e3fafSRobert Mustacchi * +------+ +-----------+
423993e3fafSRobert Mustacchi * | Idle |---------*--------------------->| Running |<-+
424993e3fafSRobert Mustacchi * +------+ . I/O queued on +-----------+ |
425993e3fafSRobert Mustacchi * ^ ring and timeout | | | |
426993e3fafSRobert Mustacchi * | scheduled. | | | |
427993e3fafSRobert Mustacchi * | | | | |
428993e3fafSRobert Mustacchi * +-----*---------------------------------+ | | |
429993e3fafSRobert Mustacchi * | . No I/Os remain | | |
430993e3fafSRobert Mustacchi * | | | |
431993e3fafSRobert Mustacchi * | +------*------------------+ | |
432993e3fafSRobert Mustacchi * | | . Timeout | |
433993e3fafSRobert Mustacchi * | | fires for | |
434993e3fafSRobert Mustacchi * | | I/O | |
435993e3fafSRobert Mustacchi * | v v |
436993e3fafSRobert Mustacchi * | +-----------+ +--------+ |
437993e3fafSRobert Mustacchi * | | Timed Out | | Halted | |
438993e3fafSRobert Mustacchi * | +-----------+ +--------+ |
439993e3fafSRobert Mustacchi * | | | |
440993e3fafSRobert Mustacchi * | | +-----------+ | |
441993e3fafSRobert Mustacchi * | +-->| Quiescing |<----------+ |
442993e3fafSRobert Mustacchi * | +-----------+ |
443993e3fafSRobert Mustacchi * | No TRBs. | . TRBs |
444993e3fafSRobert Mustacchi * | remain . | . Remain |
445993e3fafSRobert Mustacchi * +----------*----<------+-------->-------*-----------+
446993e3fafSRobert Mustacchi *
447993e3fafSRobert Mustacchi * Normally, a given endpoint will oscillate between having TRBs scheduled and
448993e3fafSRobert Mustacchi * not. Every time a new I/O is added to the endpoint, we'll ring the doorbell,
449993e3fafSRobert Mustacchi * making sure that we're processing the ring, presuming that the endpoint isn't
450993e3fafSRobert Mustacchi * in one of the error states.
451993e3fafSRobert Mustacchi *
452993e3fafSRobert Mustacchi * To detect device hangs, we have an active timeout(9F) per active endpoint
453993e3fafSRobert Mustacchi * that ticks at a one second rate while we still have TRBs outstanding on an
454993e3fafSRobert Mustacchi * endpoint. Once all outstanding TRBs have been processed, the timeout will
455993e3fafSRobert Mustacchi * stop itself and there will be no active checking until the endpoint has I/O
456993e3fafSRobert Mustacchi * scheduled on it again.
457993e3fafSRobert Mustacchi *
458993e3fafSRobert Mustacchi * There are two primary ways that things can go wrong on the endpoint. We can
459993e3fafSRobert Mustacchi * either have a timeout or an event that transitions the endpoint to the Halted
460993e3fafSRobert Mustacchi * state. In the halted state, we need to issue explicit commands to reset the
461993e3fafSRobert Mustacchi * endpoint before removing the I/O.
462993e3fafSRobert Mustacchi *
463993e3fafSRobert Mustacchi * The way we handle both a timeout and a halted condition is similar, but the
464993e3fafSRobert Mustacchi * way they are triggered is different. When we detect a halted condition, we
465993e3fafSRobert Mustacchi * don't immediately clean it up, and wait for the client device driver (or USBA
466993e3fafSRobert Mustacchi * on its behalf) to issue a pipe reset. When we detect a timeout, we
467993e3fafSRobert Mustacchi * immediately take action (assuming no other action is ongoing).
468993e3fafSRobert Mustacchi *
469993e3fafSRobert Mustacchi * In both cases, we quiesce the device, which takes care of dealing with taking
470993e3fafSRobert Mustacchi * the endpoint from whatever state it may be in and taking the appropriate
471993e3fafSRobert Mustacchi * actions based on the state machine in xHCI 1.1 / 4.8.3. The end of quiescing
472993e3fafSRobert Mustacchi * leaves the device stopped, which allows us to update the ring's pointer and
473993e3fafSRobert Mustacchi * remove any TRBs that are causing problems.
474993e3fafSRobert Mustacchi *
475993e3fafSRobert Mustacchi * As part of all this, we ensure that we can only be quiescing the device from
476993e3fafSRobert Mustacchi * a given path at a time. Any requests to schedule I/O during this time will
477993e3fafSRobert Mustacchi * generally fail.
478993e3fafSRobert Mustacchi *
479993e3fafSRobert Mustacchi * The following image describes the state machine for the timeout logic. It
480993e3fafSRobert Mustacchi * ties into the image above.
481993e3fafSRobert Mustacchi *
482993e3fafSRobert Mustacchi * +----------+ +---------+
483993e3fafSRobert Mustacchi * | Disabled |-----*--------------------->| Enabled |<--+
484993e3fafSRobert Mustacchi * +----------+ . TRBs scheduled +---------+ *. 1 sec timer
485993e3fafSRobert Mustacchi * ^ and no active | | | | fires and
486993e3fafSRobert Mustacchi * | timer. | | | | another
487993e3fafSRobert Mustacchi * | | | +--+--+ quiesce, in
488993e3fafSRobert Mustacchi * | | | | a bad state,
489993e3fafSRobert Mustacchi * +------*------------------------------+ | ^ or decrement
490993e3fafSRobert Mustacchi * | . 1 sec timer | | I/O timeout
491993e3fafSRobert Mustacchi * | fires and | |
492993e3fafSRobert Mustacchi * | no TRBs or | +--------------+
493993e3fafSRobert Mustacchi * | endpoint shutdown | |
494993e3fafSRobert Mustacchi * | *. . timer counter |
495993e3fafSRobert Mustacchi * ^ | reaches zero |
496993e3fafSRobert Mustacchi * | v |
497993e3fafSRobert Mustacchi * | +--------------+ |
498993e3fafSRobert Mustacchi * +-------------*---------------<--| Quiesce ring |->---*-------+
499993e3fafSRobert Mustacchi * . No more | and fail I/O | . restart
500993e3fafSRobert Mustacchi * I/Os +--------------+ timer as
501993e3fafSRobert Mustacchi * more I/Os
502993e3fafSRobert Mustacchi *
503993e3fafSRobert Mustacchi * As we described above, when there are active TRBs and I/Os, a 1 second
504993e3fafSRobert Mustacchi * timeout(9F) will be active. Each second, we decrement a counter on the
505993e3fafSRobert Mustacchi * current, active I/O until either a new I/O takes the head, or the counter
506993e3fafSRobert Mustacchi * reaches zero. If the counter reaches zero, then we go through, quiesce the
507993e3fafSRobert Mustacchi * ring, and then clean things up.
508993e3fafSRobert Mustacchi *
509993e3fafSRobert Mustacchi * ------------------
510993e3fafSRobert Mustacchi * Periodic Endpoints
511993e3fafSRobert Mustacchi * ------------------
512993e3fafSRobert Mustacchi *
513993e3fafSRobert Mustacchi * It's worth calling out periodic endpoints explicitly, as they operate
514993e3fafSRobert Mustacchi * somewhat differently. Periodic endpoints are limited to Interrupt-IN and
515993e3fafSRobert Mustacchi * Isochronous-IN. The USBA often uses the term polling for these. That's
516993e3fafSRobert Mustacchi * because the client only needs to make a single API call; however, they'll
517993e3fafSRobert Mustacchi * receive multiple callbacks until either an error occurs or polling is
518993e3fafSRobert Mustacchi * requested to be terminated.
519993e3fafSRobert Mustacchi *
520993e3fafSRobert Mustacchi * When we have one of these periodic requests, we end up always rescheduling
521993e3fafSRobert Mustacchi * I/O requests, as well as, having a specific number of pre-existing I/O
522993e3fafSRobert Mustacchi * requests to cover the periodic needs, in case of latency spikes. Normally,
523993e3fafSRobert Mustacchi * when replying to a request, we use the request handle that we were given.
524993e3fafSRobert Mustacchi * However, when we have a periodic request, we're required to duplicate the
525993e3fafSRobert Mustacchi * handle before giving them data.
526993e3fafSRobert Mustacchi *
527993e3fafSRobert Mustacchi * However, the duplication is a bit tricky. For everything that was duplicated,
528993e3fafSRobert Mustacchi * the framework expects us to submit data. Because of that we, don't duplicate
529993e3fafSRobert Mustacchi * them until they are needed. This minimizes the likelihood that we have
530993e3fafSRobert Mustacchi * outstanding requests to deal with when we encounter a fatal polling failure.
531993e3fafSRobert Mustacchi *
532993e3fafSRobert Mustacchi * Most of the polling setup logic happens in xhci_usba.c in
533993e3fafSRobert Mustacchi * xhci_hcdi_periodic_init(). The consumption and duplication is handled in
534993e3fafSRobert Mustacchi * xhci_endpoint.c.
535993e3fafSRobert Mustacchi *
536993e3fafSRobert Mustacchi * ----------------
537993e3fafSRobert Mustacchi * Structure Layout
538993e3fafSRobert Mustacchi * ----------------
539993e3fafSRobert Mustacchi *
540993e3fafSRobert Mustacchi * The following images relate the core data structures. The primary structure
541993e3fafSRobert Mustacchi * in the system is the xhci_t. This is the per-controller data structure that
542993e3fafSRobert Mustacchi * exists for each instance of the driver. From there, each device in the system
543993e3fafSRobert Mustacchi * is represented by an xhci_device_t and each endpoint is represented by an
544993e3fafSRobert Mustacchi * xhci_endpoint_t. For each client that opens a given endpoint, there is an
545993e3fafSRobert Mustacchi * xhci_pipe_t. For each I/O related ring, there is an xhci_ring_t in the
546993e3fafSRobert Mustacchi * system.
547993e3fafSRobert Mustacchi *
548993e3fafSRobert Mustacchi * +------------------------+
549993e3fafSRobert Mustacchi * | Per-Controller |
550993e3fafSRobert Mustacchi * | Structure |
551993e3fafSRobert Mustacchi * | xhci_t |
552993e3fafSRobert Mustacchi * | |
553993e3fafSRobert Mustacchi * | uint_t ---+--> Capability regs offset
554993e3fafSRobert Mustacchi * | uint_t ---+--> Operational regs offset
555993e3fafSRobert Mustacchi * | uint_t ---+--> Runtime regs offset
556993e3fafSRobert Mustacchi * | uint_t ---+--> Doorbell regs offset
557993e3fafSRobert Mustacchi * | xhci_state_flags_t ---+--> Device state flags
558993e3fafSRobert Mustacchi * | xhci_quirks_t ---+--> Device quirk flags
559993e3fafSRobert Mustacchi * | xhci_capability_t ---+--> Controller capability structure
560993e3fafSRobert Mustacchi * | xhci_dcbaa_t ---+----------------------------------+
561993e3fafSRobert Mustacchi * | xhci_scratchpad_t ---+---------+ |
562993e3fafSRobert Mustacchi * | xhci_command_ing_t ---+------+ | v
563993e3fafSRobert Mustacchi * | xhci_event_ring_t ---+----+ | | +---------------------+
564993e3fafSRobert Mustacchi * | xhci_usba_t ---+--+ | | | | Device Context |
565993e3fafSRobert Mustacchi * +------------------------+ | | | | | Base Address |
566993e3fafSRobert Mustacchi * | | | | | Array Structure |
567993e3fafSRobert Mustacchi * | | | | | xhci_dcbaa_t |
568993e3fafSRobert Mustacchi * +-------------------------------+ | | | | |
569993e3fafSRobert Mustacchi * | +-------------------------------+ | | DCBAA KVA <-+-- uint64_t * |
570993e3fafSRobert Mustacchi * | | +----------------------------+ | DMA Buffer <-+-- xhci_dma_buffer_t |
571993e3fafSRobert Mustacchi * | | v | +---------------------+
572993e3fafSRobert Mustacchi * | | +--------------------------+ +-----------------------+
573993e3fafSRobert Mustacchi * | | | Event Ring | |
574993e3fafSRobert Mustacchi * | | | Management | |
575993e3fafSRobert Mustacchi * | | | xhci_event_ring_t | v
576993e3fafSRobert Mustacchi * | | | | Event Ring +----------------------+
577993e3fafSRobert Mustacchi * | | | xhci_event_segment_t * --|-> Segment VA | Scratchpad (Extra |
578993e3fafSRobert Mustacchi * | | | xhci_dma_buffer_t --|-> Segment DMA Buf. | Controller Memory) |
579993e3fafSRobert Mustacchi * | | | xhci_ring_t --|--+ | xhci_scratchpad_t |
580993e3fafSRobert Mustacchi * | | +--------------------------+ | Scratchpad | |
581993e3fafSRobert Mustacchi * | | | Base Array KVA <-+- uint64_t * |
582993e3fafSRobert Mustacchi * | +------------+ | Array DMA Buf. <-+- xhci_dma_buffer_t |
583993e3fafSRobert Mustacchi * | v | Scratchpad DMA <-+- xhci_dma_buffer_t * |
584993e3fafSRobert Mustacchi * | +---------------------------+ | Buffer per page +----------------------+
585993e3fafSRobert Mustacchi * | | Command Ring | |
586993e3fafSRobert Mustacchi * | | xhci_command_ring_t | +------------------------------+
587993e3fafSRobert Mustacchi * | | | |
588993e3fafSRobert Mustacchi * | | xhci_ring_t --+-> Command Ring --->------------+
589993e3fafSRobert Mustacchi * | | list_t --+-> Command List v
590993e3fafSRobert Mustacchi * | | timeout_id_t --+-> Timeout State +---------------------+
591993e3fafSRobert Mustacchi * | | xhci_command_ring_state_t +-> State Flags | I/O Ring |
592993e3fafSRobert Mustacchi * | +---------------------------+ | xhci_ring_t |
593993e3fafSRobert Mustacchi * | | |
594993e3fafSRobert Mustacchi * | Ring DMA Buf. <-+-- xhci_dma_buffer_t |
595993e3fafSRobert Mustacchi * | Ring Length <-+-- uint_t |
596993e3fafSRobert Mustacchi * | Ring Entry KVA <-+-- xhci_trb_t * |
597993e3fafSRobert Mustacchi * | +---------------------------+ Ring Head <-+-- uint_t |
598993e3fafSRobert Mustacchi * +--->| USBA State | Ring Tail <-+-- uint_t |
599993e3fafSRobert Mustacchi * | xhci_usba_t | Ring Cycle <-+-- uint_t |
600993e3fafSRobert Mustacchi * | | +---------------------+
601993e3fafSRobert Mustacchi * | usba_hcdi_ops_t * -+-> USBA Ops Vector ^
602993e3fafSRobert Mustacchi * | usb_dev_dscr_t -+-> USB Virtual Device Descriptor |
603993e3fafSRobert Mustacchi * | usb_ss_hub_descr_t -+-> USB Virtual Hub Descriptor |
604993e3fafSRobert Mustacchi * | usba_pipe_handle_data_t * +-> Interrupt polling client |
605993e3fafSRobert Mustacchi * | usb_intr_req_t -+-> Interrupt polling request |
606993e3fafSRobert Mustacchi * | uint32_t --+-> Interrupt polling device mask |
607993e3fafSRobert Mustacchi * | list_t --+-> Pipe List (Active Users) |
608993e3fafSRobert Mustacchi * | list_t --+-------------------+ |
609993e3fafSRobert Mustacchi * +---------------------------+ | ^
610993e3fafSRobert Mustacchi * | |
611993e3fafSRobert Mustacchi * v |
612993e3fafSRobert Mustacchi * +-------------------------------+ +---------------+ |
613993e3fafSRobert Mustacchi * | USB Device |------------>| USB Device |--> ... |
614993e3fafSRobert Mustacchi * | xhci_device_t | | xhci_device_t | |
615993e3fafSRobert Mustacchi * | | +---------------+ |
616993e3fafSRobert Mustacchi * | usb_port_t --+-> USB Port plugged into |
617993e3fafSRobert Mustacchi * | uint8_t --+-> Slot Number |
618993e3fafSRobert Mustacchi * | boolean_t --+-> Address Assigned |
619993e3fafSRobert Mustacchi * | usba_device_t * --+-> USBA Device State |
620993e3fafSRobert Mustacchi * | xhci_dma_buffer_t --+-> Input Context DMA Buffer |
621993e3fafSRobert Mustacchi * | xhci_input_context_t * --+-> Input Context KVA |
622993e3fafSRobert Mustacchi * | xhci_slot_contex_t * --+-> Input Slot Context KVA |
623993e3fafSRobert Mustacchi * | xhci_endpoint_context_t *[] --+-> Input Endpoint Context KVA |
624993e3fafSRobert Mustacchi * | xhci_dma_buffer_t --+-> Output Context DMA Buffer |
625993e3fafSRobert Mustacchi * | xhci_slot_context_t * --+-> Output Slot Context KVA ^
626993e3fafSRobert Mustacchi * | xhci_endpoint_context_t *[] --+-> Output Endpoint Context KVA |
627993e3fafSRobert Mustacchi * | xhci_endpoint_t *[] --+-> Endpoint Tracking ---+ |
628993e3fafSRobert Mustacchi * +-------------------------------+ | |
629993e3fafSRobert Mustacchi * | |
630993e3fafSRobert Mustacchi * v |
631993e3fafSRobert Mustacchi * +------------------------------+ +-----------------+ |
632993e3fafSRobert Mustacchi * | Endpoint Data |----------->| Endpoint Data |--> ... |
633993e3fafSRobert Mustacchi * | xhci_endpoint_t | | xhci_endpoint_t | |
634993e3fafSRobert Mustacchi * | | +-----------------+ |
635993e3fafSRobert Mustacchi * | int --+-> Endpoint Number |
636993e3fafSRobert Mustacchi * | int --+-> Endpoint Type |
637993e3fafSRobert Mustacchi * | xhci_endpoint_state_t --+-> Endpoint State |
638993e3fafSRobert Mustacchi * | timeout_id_t --+-> Endpoint Timeout State |
639993e3fafSRobert Mustacchi * | usba_pipe_handle_data_t * --+-> USBA Client Handle |
640993e3fafSRobert Mustacchi * | xhci_ring_t --+-> Endpoint I/O Ring -------->--------+
641993e3fafSRobert Mustacchi * | list_t --+-> Transfer List --------+
642993e3fafSRobert Mustacchi * +------------------------------+ |
643993e3fafSRobert Mustacchi * v
644993e3fafSRobert Mustacchi * +-------------------------+ +--------------------+
645993e3fafSRobert Mustacchi * | Transfer Structure |----------------->| Transfer Structure |-> ...
646993e3fafSRobert Mustacchi * | xhci_transfer_t | | xhci_transfer_t |
647993e3fafSRobert Mustacchi * | | +--------------------+
648993e3fafSRobert Mustacchi * | xhci_dma_buffer_t --+-> I/O DMA Buffer
649993e3fafSRobert Mustacchi * | uint_t --+-> Number of TRBs
650993e3fafSRobert Mustacchi * | uint_t --+-> Short transfer data
651993e3fafSRobert Mustacchi * | uint_t --+-> Timeout seconds remaining
652993e3fafSRobert Mustacchi * | usb_cr_t --+-> USB Transfer return value
653993e3fafSRobert Mustacchi * | boolean_t --+-> Data direction
654993e3fafSRobert Mustacchi * | xhci_trb_t * --+-> Host-order transfer requests for I/O
655993e3fafSRobert Mustacchi * | usb_isoc_pkt_descr_t * -+-> Isochronous only response data
656993e3fafSRobert Mustacchi * | usb_opaque_t --+-> USBA Request Handle
657993e3fafSRobert Mustacchi * +-------------------------+
658993e3fafSRobert Mustacchi *
659993e3fafSRobert Mustacchi * -------------
660993e3fafSRobert Mustacchi * Lock Ordering
661993e3fafSRobert Mustacchi * -------------
662993e3fafSRobert Mustacchi *
663993e3fafSRobert Mustacchi * There are three different tiers of locks that exist in the driver. First,
664993e3fafSRobert Mustacchi * there is a lock for each controller: xhci_t`xhci_lock. This protects all the
665993e3fafSRobert Mustacchi * data for that instance of the controller. If there are multiple instances of
666993e3fafSRobert Mustacchi * the xHCI controller in the system, each one is independent and protected
667993e3fafSRobert Mustacchi * separately. The two do not share any data.
668993e3fafSRobert Mustacchi *
669993e3fafSRobert Mustacchi * From there, there are two other, specific locks in the system:
670993e3fafSRobert Mustacchi *
671993e3fafSRobert Mustacchi * o xhci_command_ring_t`xcr_lock
672993e3fafSRobert Mustacchi * o xhci_device_t`xd_imtx
673993e3fafSRobert Mustacchi *
674993e3fafSRobert Mustacchi * There is only one xcr_lock per controller, like the xhci_lock. It protects
675993e3fafSRobert Mustacchi * the state of the command ring. However, there is on xd_imtx per device.
676993e3fafSRobert Mustacchi * Recall that each device is scoped to a given controller. This protects the
677993e3fafSRobert Mustacchi * input slot context for a given device.
678993e3fafSRobert Mustacchi *
679993e3fafSRobert Mustacchi * There are a few important rules to keep in mind here that are true
680993e3fafSRobert Mustacchi * universally throughout the driver:
681993e3fafSRobert Mustacchi *
682993e3fafSRobert Mustacchi * 1) Always grab the xhci_t`xhci_lock, before grabbing any of the other locks.
683993e3fafSRobert Mustacchi * 2) A given xhci_device_t`xd_imtx, must be taken before grabbing the
684993e3fafSRobert Mustacchi * xhci_command_ring_t`xcr_lock.
685993e3fafSRobert Mustacchi * 3) A given thread can only hold one of the given xhci_device_t`xd_imtx locks
686993e3fafSRobert Mustacchi * at a given time. In other words, we should never be manipulating the input
687993e3fafSRobert Mustacchi * context of two different devices at once.
688993e3fafSRobert Mustacchi * 4) It is safe to hold the xhci_device_t`xd_imtx while tearing down the
689993e3fafSRobert Mustacchi * endpoint timer. Conversely, the endpoint specific logic should never enter
690993e3fafSRobert Mustacchi * this lock.
691993e3fafSRobert Mustacchi *
692ec82ef79SMatthias Scheler * ----------
693ec82ef79SMatthias Scheler * Polled I/O
694ec82ef79SMatthias Scheler * ----------
695ec82ef79SMatthias Scheler *
696ec82ef79SMatthias Scheler * There is limited support for polled I/O in this driver for use by
697ec82ef79SMatthias Scheler * the kernel debugger. The driver currently only supports input from
698ec82ef79SMatthias Scheler * interrupt endpoints which is good enough for USB HID keyboard devices.
699ec82ef79SMatthias Scheler * Input from bulk endpoints and output are not supported which prevents
700ec82ef79SMatthias Scheler * using a serial console over USB for kernel debugging.
701ec82ef79SMatthias Scheler *
702993e3fafSRobert Mustacchi * --------------------
703993e3fafSRobert Mustacchi * Relationship to EHCI
704993e3fafSRobert Mustacchi * --------------------
705993e3fafSRobert Mustacchi *
706993e3fafSRobert Mustacchi * On some Intel chipsets, a given physical port on the system may be routed to
707993e3fafSRobert Mustacchi * one of the EHCI or xHCI controllers. This association can be dynamically
708993e3fafSRobert Mustacchi * changed by writing to platform specific registers as handled by the quirk
709993e3fafSRobert Mustacchi * logic in xhci_quirk.c.
710993e3fafSRobert Mustacchi *
711993e3fafSRobert Mustacchi * As these ports may support USB 3.x speeds, we always route all such ports to
712993e3fafSRobert Mustacchi * the xHCI controller, when supported. In addition, to minimize disruptions
713993e3fafSRobert Mustacchi * from devices being enumerated and attached to the EHCI driver and then
714993e3fafSRobert Mustacchi * disappearing, we generally attempt to load the xHCI controller before the
715993e3fafSRobert Mustacchi * EHCI controller. This logic is not done in the driver; however, it is done in
716993e3fafSRobert Mustacchi * other parts of the kernel like in uts/common/io/consconfig_dacf.c in the
717*0ae0ab6fSJoshua M. Clulow * function consconfig_load_drivers().
718993e3fafSRobert Mustacchi *
719993e3fafSRobert Mustacchi * -----------
720993e3fafSRobert Mustacchi * Future Work
721993e3fafSRobert Mustacchi * -----------
722993e3fafSRobert Mustacchi *
723993e3fafSRobert Mustacchi * The primary future work in this driver spans two different, but related
724993e3fafSRobert Mustacchi * areas. The first area is around controller resets and how they tie into FM.
725993e3fafSRobert Mustacchi * Presently, we do not have a good way to handle controllers coming and going
726993e3fafSRobert Mustacchi * in the broader USB stack or properly reconfigure the device after a reset.
727993e3fafSRobert Mustacchi * Secondly, we don't handle the suspend and resume of devices and drivers.
728993e3fafSRobert Mustacchi */
729993e3fafSRobert Mustacchi
730993e3fafSRobert Mustacchi #include <sys/param.h>
731993e3fafSRobert Mustacchi #include <sys/modctl.h>
732993e3fafSRobert Mustacchi #include <sys/conf.h>
733993e3fafSRobert Mustacchi #include <sys/devops.h>
734993e3fafSRobert Mustacchi #include <sys/ddi.h>
735993e3fafSRobert Mustacchi #include <sys/sunddi.h>
736993e3fafSRobert Mustacchi #include <sys/cmn_err.h>
737993e3fafSRobert Mustacchi #include <sys/ddifm.h>
738993e3fafSRobert Mustacchi #include <sys/pci.h>
739993e3fafSRobert Mustacchi #include <sys/class.h>
740993e3fafSRobert Mustacchi #include <sys/policy.h>
741993e3fafSRobert Mustacchi
742993e3fafSRobert Mustacchi #include <sys/usb/hcd/xhci/xhci.h>
743993e3fafSRobert Mustacchi #include <sys/usb/hcd/xhci/xhci_ioctl.h>
744993e3fafSRobert Mustacchi
745993e3fafSRobert Mustacchi /*
746993e3fafSRobert Mustacchi * We want to use the first BAR to access its registers. The regs[] array is
747993e3fafSRobert Mustacchi * ordered based on the rules for the PCI supplement to IEEE 1275. So regs[1]
748993e3fafSRobert Mustacchi * will always be the first BAR.
749993e3fafSRobert Mustacchi */
750993e3fafSRobert Mustacchi #define XHCI_REG_NUMBER 1
751993e3fafSRobert Mustacchi
752993e3fafSRobert Mustacchi /*
753993e3fafSRobert Mustacchi * This task queue exists as a global taskq that is used for resetting the
754993e3fafSRobert Mustacchi * device in the face of FM or runtime errors. Each instance of the device
755993e3fafSRobert Mustacchi * (xhci_t) happens to have a single taskq_dispatch_ent already allocated so we
756993e3fafSRobert Mustacchi * know that we should always be able to dispatch such an event.
757993e3fafSRobert Mustacchi */
758993e3fafSRobert Mustacchi static taskq_t *xhci_taskq;
759993e3fafSRobert Mustacchi
760993e3fafSRobert Mustacchi /*
761993e3fafSRobert Mustacchi * Global soft state for per-instance data. Note that we must use the soft state
762993e3fafSRobert Mustacchi * routines and cannot use the ddi_set_driver_private() routines. The USB
763993e3fafSRobert Mustacchi * framework presumes that it can use the dip's private data.
764993e3fafSRobert Mustacchi */
765993e3fafSRobert Mustacchi void *xhci_soft_state;
766993e3fafSRobert Mustacchi
767993e3fafSRobert Mustacchi /*
768993e3fafSRobert Mustacchi * This is the time in us that we wait after a controller resets before we
769993e3fafSRobert Mustacchi * consider reading any register. There are some controllers that want at least
770993e3fafSRobert Mustacchi * 1 ms, therefore we default to 10 ms.
771993e3fafSRobert Mustacchi */
772993e3fafSRobert Mustacchi clock_t xhci_reset_delay = 10000;
773993e3fafSRobert Mustacchi
774993e3fafSRobert Mustacchi void
xhci_error(xhci_t * xhcip,const char * fmt,...)775993e3fafSRobert Mustacchi xhci_error(xhci_t *xhcip, const char *fmt, ...)
776993e3fafSRobert Mustacchi {
777993e3fafSRobert Mustacchi va_list ap;
778993e3fafSRobert Mustacchi
779993e3fafSRobert Mustacchi va_start(ap, fmt);
780993e3fafSRobert Mustacchi if (xhcip != NULL && xhcip->xhci_dip != NULL) {
781993e3fafSRobert Mustacchi vdev_err(xhcip->xhci_dip, CE_WARN, fmt, ap);
782993e3fafSRobert Mustacchi } else {
783993e3fafSRobert Mustacchi vcmn_err(CE_WARN, fmt, ap);
784993e3fafSRobert Mustacchi }
785993e3fafSRobert Mustacchi va_end(ap);
786993e3fafSRobert Mustacchi }
787993e3fafSRobert Mustacchi
788993e3fafSRobert Mustacchi void
xhci_log(xhci_t * xhcip,const char * fmt,...)789993e3fafSRobert Mustacchi xhci_log(xhci_t *xhcip, const char *fmt, ...)
790993e3fafSRobert Mustacchi {
791993e3fafSRobert Mustacchi va_list ap;
792993e3fafSRobert Mustacchi
793993e3fafSRobert Mustacchi va_start(ap, fmt);
794993e3fafSRobert Mustacchi if (xhcip != NULL && xhcip->xhci_dip != NULL) {
795993e3fafSRobert Mustacchi vdev_err(xhcip->xhci_dip, CE_NOTE, fmt, ap);
796993e3fafSRobert Mustacchi } else {
797993e3fafSRobert Mustacchi vcmn_err(CE_NOTE, fmt, ap);
798993e3fafSRobert Mustacchi }
799993e3fafSRobert Mustacchi va_end(ap);
800993e3fafSRobert Mustacchi }
801993e3fafSRobert Mustacchi
802993e3fafSRobert Mustacchi /*
803993e3fafSRobert Mustacchi * USBA is in charge of creating device nodes for us. USBA explicitly ORs in the
804993e3fafSRobert Mustacchi * constant HUBD_IS_ROOT_HUB, so we have to undo that when we're looking at
805993e3fafSRobert Mustacchi * things here. A simple bitwise-and will take care of this. And hey, it could
806993e3fafSRobert Mustacchi * always be more complex, USBA could clone!
807993e3fafSRobert Mustacchi */
808993e3fafSRobert Mustacchi static dev_info_t *
xhci_get_dip(dev_t dev)809993e3fafSRobert Mustacchi xhci_get_dip(dev_t dev)
810993e3fafSRobert Mustacchi {
811993e3fafSRobert Mustacchi xhci_t *xhcip;
812993e3fafSRobert Mustacchi int instance = getminor(dev) & ~HUBD_IS_ROOT_HUB;
813993e3fafSRobert Mustacchi
814993e3fafSRobert Mustacchi xhcip = ddi_get_soft_state(xhci_soft_state, instance);
815993e3fafSRobert Mustacchi if (xhcip != NULL)
816993e3fafSRobert Mustacchi return (xhcip->xhci_dip);
817993e3fafSRobert Mustacchi return (NULL);
818993e3fafSRobert Mustacchi }
819993e3fafSRobert Mustacchi
820993e3fafSRobert Mustacchi uint8_t
xhci_get8(xhci_t * xhcip,xhci_reg_type_t rtt,uintptr_t off)821993e3fafSRobert Mustacchi xhci_get8(xhci_t *xhcip, xhci_reg_type_t rtt, uintptr_t off)
822993e3fafSRobert Mustacchi {
823993e3fafSRobert Mustacchi uintptr_t addr, roff;
824993e3fafSRobert Mustacchi
825993e3fafSRobert Mustacchi switch (rtt) {
826993e3fafSRobert Mustacchi case XHCI_R_CAP:
827993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_capoff;
828993e3fafSRobert Mustacchi break;
829993e3fafSRobert Mustacchi case XHCI_R_OPER:
830993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_operoff;
831993e3fafSRobert Mustacchi break;
832993e3fafSRobert Mustacchi case XHCI_R_RUN:
833993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_runoff;
834993e3fafSRobert Mustacchi break;
835993e3fafSRobert Mustacchi case XHCI_R_DOOR:
836993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_dooroff;
837993e3fafSRobert Mustacchi break;
838993e3fafSRobert Mustacchi default:
839993e3fafSRobert Mustacchi panic("called %s with bad reg type: %d", __func__, rtt);
840993e3fafSRobert Mustacchi }
841993e3fafSRobert Mustacchi ASSERT(roff != PCI_EINVAL32);
842993e3fafSRobert Mustacchi addr = roff + off + (uintptr_t)xhcip->xhci_regs_base;
843993e3fafSRobert Mustacchi
844993e3fafSRobert Mustacchi return (ddi_get8(xhcip->xhci_regs_handle, (void *)addr));
845993e3fafSRobert Mustacchi }
846993e3fafSRobert Mustacchi
847993e3fafSRobert Mustacchi uint16_t
xhci_get16(xhci_t * xhcip,xhci_reg_type_t rtt,uintptr_t off)848993e3fafSRobert Mustacchi xhci_get16(xhci_t *xhcip, xhci_reg_type_t rtt, uintptr_t off)
849993e3fafSRobert Mustacchi {
850993e3fafSRobert Mustacchi uintptr_t addr, roff;
851993e3fafSRobert Mustacchi
852993e3fafSRobert Mustacchi switch (rtt) {
853993e3fafSRobert Mustacchi case XHCI_R_CAP:
854993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_capoff;
855993e3fafSRobert Mustacchi break;
856993e3fafSRobert Mustacchi case XHCI_R_OPER:
857993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_operoff;
858993e3fafSRobert Mustacchi break;
859993e3fafSRobert Mustacchi case XHCI_R_RUN:
860993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_runoff;
861993e3fafSRobert Mustacchi break;
862993e3fafSRobert Mustacchi case XHCI_R_DOOR:
863993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_dooroff;
864993e3fafSRobert Mustacchi break;
865993e3fafSRobert Mustacchi default:
866993e3fafSRobert Mustacchi panic("called %s with bad reg type: %d", __func__, rtt);
867993e3fafSRobert Mustacchi }
868993e3fafSRobert Mustacchi ASSERT(roff != PCI_EINVAL32);
869993e3fafSRobert Mustacchi addr = roff + off + (uintptr_t)xhcip->xhci_regs_base;
870993e3fafSRobert Mustacchi
871993e3fafSRobert Mustacchi return (ddi_get16(xhcip->xhci_regs_handle, (void *)addr));
872993e3fafSRobert Mustacchi }
873993e3fafSRobert Mustacchi
874993e3fafSRobert Mustacchi uint32_t
xhci_get32(xhci_t * xhcip,xhci_reg_type_t rtt,uintptr_t off)875993e3fafSRobert Mustacchi xhci_get32(xhci_t *xhcip, xhci_reg_type_t rtt, uintptr_t off)
876993e3fafSRobert Mustacchi {
877993e3fafSRobert Mustacchi uintptr_t addr, roff;
878993e3fafSRobert Mustacchi
879993e3fafSRobert Mustacchi switch (rtt) {
880993e3fafSRobert Mustacchi case XHCI_R_CAP:
881993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_capoff;
882993e3fafSRobert Mustacchi break;
883993e3fafSRobert Mustacchi case XHCI_R_OPER:
884993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_operoff;
885993e3fafSRobert Mustacchi break;
886993e3fafSRobert Mustacchi case XHCI_R_RUN:
887993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_runoff;
888993e3fafSRobert Mustacchi break;
889993e3fafSRobert Mustacchi case XHCI_R_DOOR:
890993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_dooroff;
891993e3fafSRobert Mustacchi break;
892993e3fafSRobert Mustacchi default:
893993e3fafSRobert Mustacchi panic("called %s with bad reg type: %d", __func__, rtt);
894993e3fafSRobert Mustacchi }
895993e3fafSRobert Mustacchi ASSERT(roff != PCI_EINVAL32);
896993e3fafSRobert Mustacchi addr = roff + off + (uintptr_t)xhcip->xhci_regs_base;
897993e3fafSRobert Mustacchi
898993e3fafSRobert Mustacchi return (ddi_get32(xhcip->xhci_regs_handle, (void *)addr));
899993e3fafSRobert Mustacchi }
900993e3fafSRobert Mustacchi
901993e3fafSRobert Mustacchi uint64_t
xhci_get64(xhci_t * xhcip,xhci_reg_type_t rtt,uintptr_t off)902993e3fafSRobert Mustacchi xhci_get64(xhci_t *xhcip, xhci_reg_type_t rtt, uintptr_t off)
903993e3fafSRobert Mustacchi {
904993e3fafSRobert Mustacchi uintptr_t addr, roff;
905993e3fafSRobert Mustacchi
906993e3fafSRobert Mustacchi switch (rtt) {
907993e3fafSRobert Mustacchi case XHCI_R_CAP:
908993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_capoff;
909993e3fafSRobert Mustacchi break;
910993e3fafSRobert Mustacchi case XHCI_R_OPER:
911993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_operoff;
912993e3fafSRobert Mustacchi break;
913993e3fafSRobert Mustacchi case XHCI_R_RUN:
914993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_runoff;
915993e3fafSRobert Mustacchi break;
916993e3fafSRobert Mustacchi case XHCI_R_DOOR:
917993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_dooroff;
918993e3fafSRobert Mustacchi break;
919993e3fafSRobert Mustacchi default:
920993e3fafSRobert Mustacchi panic("called %s with bad reg type: %d", __func__, rtt);
921993e3fafSRobert Mustacchi }
922993e3fafSRobert Mustacchi ASSERT(roff != PCI_EINVAL32);
923993e3fafSRobert Mustacchi addr = roff + off + (uintptr_t)xhcip->xhci_regs_base;
924993e3fafSRobert Mustacchi
925993e3fafSRobert Mustacchi return (ddi_get64(xhcip->xhci_regs_handle, (void *)addr));
926993e3fafSRobert Mustacchi }
927993e3fafSRobert Mustacchi
928993e3fafSRobert Mustacchi void
xhci_put8(xhci_t * xhcip,xhci_reg_type_t rtt,uintptr_t off,uint8_t val)929993e3fafSRobert Mustacchi xhci_put8(xhci_t *xhcip, xhci_reg_type_t rtt, uintptr_t off, uint8_t val)
930993e3fafSRobert Mustacchi {
931993e3fafSRobert Mustacchi uintptr_t addr, roff;
932993e3fafSRobert Mustacchi
933993e3fafSRobert Mustacchi switch (rtt) {
934993e3fafSRobert Mustacchi case XHCI_R_CAP:
935993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_capoff;
936993e3fafSRobert Mustacchi break;
937993e3fafSRobert Mustacchi case XHCI_R_OPER:
938993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_operoff;
939993e3fafSRobert Mustacchi break;
940993e3fafSRobert Mustacchi case XHCI_R_RUN:
941993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_runoff;
942993e3fafSRobert Mustacchi break;
943993e3fafSRobert Mustacchi case XHCI_R_DOOR:
944993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_dooroff;
945993e3fafSRobert Mustacchi break;
946993e3fafSRobert Mustacchi default:
947993e3fafSRobert Mustacchi panic("called %s with bad reg type: %d", __func__, rtt);
948993e3fafSRobert Mustacchi }
949993e3fafSRobert Mustacchi ASSERT(roff != PCI_EINVAL32);
950993e3fafSRobert Mustacchi addr = roff + off + (uintptr_t)xhcip->xhci_regs_base;
951993e3fafSRobert Mustacchi
952993e3fafSRobert Mustacchi ddi_put8(xhcip->xhci_regs_handle, (void *)addr, val);
953993e3fafSRobert Mustacchi }
954993e3fafSRobert Mustacchi
955993e3fafSRobert Mustacchi void
xhci_put16(xhci_t * xhcip,xhci_reg_type_t rtt,uintptr_t off,uint16_t val)956993e3fafSRobert Mustacchi xhci_put16(xhci_t *xhcip, xhci_reg_type_t rtt, uintptr_t off, uint16_t val)
957993e3fafSRobert Mustacchi {
958993e3fafSRobert Mustacchi uintptr_t addr, roff;
959993e3fafSRobert Mustacchi
960993e3fafSRobert Mustacchi switch (rtt) {
961993e3fafSRobert Mustacchi case XHCI_R_CAP:
962993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_capoff;
963993e3fafSRobert Mustacchi break;
964993e3fafSRobert Mustacchi case XHCI_R_OPER:
965993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_operoff;
966993e3fafSRobert Mustacchi break;
967993e3fafSRobert Mustacchi case XHCI_R_RUN:
968993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_runoff;
969993e3fafSRobert Mustacchi break;
970993e3fafSRobert Mustacchi case XHCI_R_DOOR:
971993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_dooroff;
972993e3fafSRobert Mustacchi break;
973993e3fafSRobert Mustacchi default:
974993e3fafSRobert Mustacchi panic("called %s with bad reg type: %d", __func__, rtt);
975993e3fafSRobert Mustacchi }
976993e3fafSRobert Mustacchi ASSERT(roff != PCI_EINVAL32);
977993e3fafSRobert Mustacchi addr = roff + off + (uintptr_t)xhcip->xhci_regs_base;
978993e3fafSRobert Mustacchi
979993e3fafSRobert Mustacchi ddi_put16(xhcip->xhci_regs_handle, (void *)addr, val);
980993e3fafSRobert Mustacchi }
981993e3fafSRobert Mustacchi
982993e3fafSRobert Mustacchi void
xhci_put32(xhci_t * xhcip,xhci_reg_type_t rtt,uintptr_t off,uint32_t val)983993e3fafSRobert Mustacchi xhci_put32(xhci_t *xhcip, xhci_reg_type_t rtt, uintptr_t off, uint32_t val)
984993e3fafSRobert Mustacchi {
985993e3fafSRobert Mustacchi uintptr_t addr, roff;
986993e3fafSRobert Mustacchi
987993e3fafSRobert Mustacchi switch (rtt) {
988993e3fafSRobert Mustacchi case XHCI_R_CAP:
989993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_capoff;
990993e3fafSRobert Mustacchi break;
991993e3fafSRobert Mustacchi case XHCI_R_OPER:
992993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_operoff;
993993e3fafSRobert Mustacchi break;
994993e3fafSRobert Mustacchi case XHCI_R_RUN:
995993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_runoff;
996993e3fafSRobert Mustacchi break;
997993e3fafSRobert Mustacchi case XHCI_R_DOOR:
998993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_dooroff;
999993e3fafSRobert Mustacchi break;
1000993e3fafSRobert Mustacchi default:
1001993e3fafSRobert Mustacchi panic("called %s with bad reg type: %d", __func__, rtt);
1002993e3fafSRobert Mustacchi }
1003993e3fafSRobert Mustacchi ASSERT(roff != PCI_EINVAL32);
1004993e3fafSRobert Mustacchi addr = roff + off + (uintptr_t)xhcip->xhci_regs_base;
1005993e3fafSRobert Mustacchi
1006993e3fafSRobert Mustacchi ddi_put32(xhcip->xhci_regs_handle, (void *)addr, val);
1007993e3fafSRobert Mustacchi }
1008993e3fafSRobert Mustacchi
1009993e3fafSRobert Mustacchi void
xhci_put64(xhci_t * xhcip,xhci_reg_type_t rtt,uintptr_t off,uint64_t val)1010993e3fafSRobert Mustacchi xhci_put64(xhci_t *xhcip, xhci_reg_type_t rtt, uintptr_t off, uint64_t val)
1011993e3fafSRobert Mustacchi {
1012993e3fafSRobert Mustacchi uintptr_t addr, roff;
1013993e3fafSRobert Mustacchi
1014993e3fafSRobert Mustacchi switch (rtt) {
1015993e3fafSRobert Mustacchi case XHCI_R_CAP:
1016993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_capoff;
1017993e3fafSRobert Mustacchi break;
1018993e3fafSRobert Mustacchi case XHCI_R_OPER:
1019993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_operoff;
1020993e3fafSRobert Mustacchi break;
1021993e3fafSRobert Mustacchi case XHCI_R_RUN:
1022993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_runoff;
1023993e3fafSRobert Mustacchi break;
1024993e3fafSRobert Mustacchi case XHCI_R_DOOR:
1025993e3fafSRobert Mustacchi roff = xhcip->xhci_regs_dooroff;
1026993e3fafSRobert Mustacchi break;
1027993e3fafSRobert Mustacchi default:
1028993e3fafSRobert Mustacchi panic("called %s with bad reg type: %d", __func__, rtt);
1029993e3fafSRobert Mustacchi }
1030993e3fafSRobert Mustacchi ASSERT(roff != PCI_EINVAL32);
1031993e3fafSRobert Mustacchi addr = roff + off + (uintptr_t)xhcip->xhci_regs_base;
1032993e3fafSRobert Mustacchi
1033993e3fafSRobert Mustacchi ddi_put64(xhcip->xhci_regs_handle, (void *)addr, val);
1034993e3fafSRobert Mustacchi }
1035993e3fafSRobert Mustacchi
1036993e3fafSRobert Mustacchi int
xhci_check_regs_acc(xhci_t * xhcip)1037993e3fafSRobert Mustacchi xhci_check_regs_acc(xhci_t *xhcip)
1038993e3fafSRobert Mustacchi {
1039993e3fafSRobert Mustacchi ddi_fm_error_t de;
1040993e3fafSRobert Mustacchi
1041993e3fafSRobert Mustacchi /*
1042993e3fafSRobert Mustacchi * Treat the case where we can't check as fine so we can treat the code
1043993e3fafSRobert Mustacchi * more simply.
1044993e3fafSRobert Mustacchi */
1045993e3fafSRobert Mustacchi if (!DDI_FM_ACC_ERR_CAP(xhcip->xhci_fm_caps))
1046993e3fafSRobert Mustacchi return (DDI_FM_OK);
1047993e3fafSRobert Mustacchi
1048993e3fafSRobert Mustacchi ddi_fm_acc_err_get(xhcip->xhci_regs_handle, &de, DDI_FME_VERSION);
1049993e3fafSRobert Mustacchi ddi_fm_acc_err_clear(xhcip->xhci_regs_handle, DDI_FME_VERSION);
1050993e3fafSRobert Mustacchi return (de.fme_status);
1051993e3fafSRobert Mustacchi }
1052993e3fafSRobert Mustacchi
1053993e3fafSRobert Mustacchi /*
1054993e3fafSRobert Mustacchi * As a leaf PCIe driver, we just post the ereport and continue on.
1055993e3fafSRobert Mustacchi */
1056993e3fafSRobert Mustacchi /* ARGSUSED */
1057993e3fafSRobert Mustacchi static int
xhci_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)1058993e3fafSRobert Mustacchi xhci_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
1059993e3fafSRobert Mustacchi {
1060993e3fafSRobert Mustacchi pci_ereport_post(dip, err, NULL);
1061993e3fafSRobert Mustacchi return (err->fme_status);
1062993e3fafSRobert Mustacchi }
1063993e3fafSRobert Mustacchi
1064993e3fafSRobert Mustacchi static void
xhci_fm_fini(xhci_t * xhcip)1065993e3fafSRobert Mustacchi xhci_fm_fini(xhci_t *xhcip)
1066993e3fafSRobert Mustacchi {
1067993e3fafSRobert Mustacchi if (xhcip->xhci_fm_caps == 0)
1068993e3fafSRobert Mustacchi return;
1069993e3fafSRobert Mustacchi
1070993e3fafSRobert Mustacchi if (DDI_FM_ERRCB_CAP(xhcip->xhci_fm_caps))
1071993e3fafSRobert Mustacchi ddi_fm_handler_unregister(xhcip->xhci_dip);
1072993e3fafSRobert Mustacchi
1073993e3fafSRobert Mustacchi if (DDI_FM_EREPORT_CAP(xhcip->xhci_fm_caps) ||
1074993e3fafSRobert Mustacchi DDI_FM_ERRCB_CAP(xhcip->xhci_fm_caps))
1075993e3fafSRobert Mustacchi pci_ereport_teardown(xhcip->xhci_dip);
1076993e3fafSRobert Mustacchi
1077993e3fafSRobert Mustacchi ddi_fm_fini(xhcip->xhci_dip);
1078993e3fafSRobert Mustacchi }
1079993e3fafSRobert Mustacchi
1080993e3fafSRobert Mustacchi static void
xhci_fm_init(xhci_t * xhcip)1081993e3fafSRobert Mustacchi xhci_fm_init(xhci_t *xhcip)
1082993e3fafSRobert Mustacchi {
1083993e3fafSRobert Mustacchi ddi_iblock_cookie_t iblk;
1084993e3fafSRobert Mustacchi int def = DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
1085993e3fafSRobert Mustacchi DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE;
1086993e3fafSRobert Mustacchi
1087993e3fafSRobert Mustacchi xhcip->xhci_fm_caps = ddi_prop_get_int(DDI_DEV_T_ANY, xhcip->xhci_dip,
1088993e3fafSRobert Mustacchi DDI_PROP_DONTPASS, "fm_capable", def);
1089993e3fafSRobert Mustacchi
1090993e3fafSRobert Mustacchi if (xhcip->xhci_fm_caps < 0) {
1091993e3fafSRobert Mustacchi xhcip->xhci_fm_caps = 0;
1092993e3fafSRobert Mustacchi } else if (xhcip->xhci_fm_caps & ~def) {
1093993e3fafSRobert Mustacchi xhcip->xhci_fm_caps &= def;
1094993e3fafSRobert Mustacchi }
1095993e3fafSRobert Mustacchi
1096993e3fafSRobert Mustacchi if (xhcip->xhci_fm_caps == 0)
1097993e3fafSRobert Mustacchi return;
1098993e3fafSRobert Mustacchi
1099993e3fafSRobert Mustacchi ddi_fm_init(xhcip->xhci_dip, &xhcip->xhci_fm_caps, &iblk);
1100993e3fafSRobert Mustacchi if (DDI_FM_EREPORT_CAP(xhcip->xhci_fm_caps) ||
1101993e3fafSRobert Mustacchi DDI_FM_ERRCB_CAP(xhcip->xhci_fm_caps)) {
1102993e3fafSRobert Mustacchi pci_ereport_setup(xhcip->xhci_dip);
1103993e3fafSRobert Mustacchi }
1104993e3fafSRobert Mustacchi
1105993e3fafSRobert Mustacchi if (DDI_FM_ERRCB_CAP(xhcip->xhci_fm_caps)) {
1106993e3fafSRobert Mustacchi ddi_fm_handler_register(xhcip->xhci_dip,
1107993e3fafSRobert Mustacchi xhci_fm_error_cb, xhcip);
1108993e3fafSRobert Mustacchi }
1109993e3fafSRobert Mustacchi }
1110993e3fafSRobert Mustacchi
1111993e3fafSRobert Mustacchi static int
xhci_reg_poll(xhci_t * xhcip,xhci_reg_type_t rt,int reg,uint32_t mask,uint32_t targ,uint_t tries,int delay_ms)1112993e3fafSRobert Mustacchi xhci_reg_poll(xhci_t *xhcip, xhci_reg_type_t rt, int reg, uint32_t mask,
1113993e3fafSRobert Mustacchi uint32_t targ, uint_t tries, int delay_ms)
1114993e3fafSRobert Mustacchi {
1115993e3fafSRobert Mustacchi uint_t i;
1116993e3fafSRobert Mustacchi
1117993e3fafSRobert Mustacchi for (i = 0; i < tries; i++) {
1118993e3fafSRobert Mustacchi uint32_t val = xhci_get32(xhcip, rt, reg);
1119993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1120993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip,
1121993e3fafSRobert Mustacchi DDI_SERVICE_LOST);
1122993e3fafSRobert Mustacchi return (EIO);
1123993e3fafSRobert Mustacchi }
1124993e3fafSRobert Mustacchi
1125993e3fafSRobert Mustacchi if ((val & mask) == targ)
1126993e3fafSRobert Mustacchi return (0);
1127993e3fafSRobert Mustacchi
1128993e3fafSRobert Mustacchi delay(drv_usectohz(delay_ms * 1000));
1129993e3fafSRobert Mustacchi }
1130993e3fafSRobert Mustacchi return (ETIMEDOUT);
1131993e3fafSRobert Mustacchi }
1132993e3fafSRobert Mustacchi
1133993e3fafSRobert Mustacchi static boolean_t
xhci_regs_map(xhci_t * xhcip)1134993e3fafSRobert Mustacchi xhci_regs_map(xhci_t *xhcip)
1135993e3fafSRobert Mustacchi {
1136993e3fafSRobert Mustacchi off_t memsize;
1137993e3fafSRobert Mustacchi int ret;
1138993e3fafSRobert Mustacchi ddi_device_acc_attr_t da;
1139993e3fafSRobert Mustacchi
1140993e3fafSRobert Mustacchi if (ddi_dev_regsize(xhcip->xhci_dip, XHCI_REG_NUMBER, &memsize) !=
1141993e3fafSRobert Mustacchi DDI_SUCCESS) {
1142993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to get register set size");
1143993e3fafSRobert Mustacchi return (B_FALSE);
1144993e3fafSRobert Mustacchi }
1145993e3fafSRobert Mustacchi
1146993e3fafSRobert Mustacchi bzero(&da, sizeof (ddi_device_acc_attr_t));
1147993e3fafSRobert Mustacchi da.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1148993e3fafSRobert Mustacchi da.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1149993e3fafSRobert Mustacchi da.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1150993e3fafSRobert Mustacchi if (DDI_FM_ACC_ERR_CAP(xhcip->xhci_fm_caps)) {
1151993e3fafSRobert Mustacchi da.devacc_attr_access = DDI_FLAGERR_ACC;
1152993e3fafSRobert Mustacchi } else {
1153993e3fafSRobert Mustacchi da.devacc_attr_access = DDI_DEFAULT_ACC;
1154993e3fafSRobert Mustacchi }
1155993e3fafSRobert Mustacchi
1156993e3fafSRobert Mustacchi ret = ddi_regs_map_setup(xhcip->xhci_dip, XHCI_REG_NUMBER,
1157993e3fafSRobert Mustacchi &xhcip->xhci_regs_base, 0, memsize, &da, &xhcip->xhci_regs_handle);
1158993e3fafSRobert Mustacchi
1159993e3fafSRobert Mustacchi if (ret != DDI_SUCCESS) {
1160993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to map device registers: %d", ret);
1161993e3fafSRobert Mustacchi return (B_FALSE);
1162993e3fafSRobert Mustacchi }
1163993e3fafSRobert Mustacchi
1164993e3fafSRobert Mustacchi return (B_TRUE);
1165993e3fafSRobert Mustacchi }
1166993e3fafSRobert Mustacchi
1167993e3fafSRobert Mustacchi static boolean_t
xhci_regs_init(xhci_t * xhcip)1168993e3fafSRobert Mustacchi xhci_regs_init(xhci_t *xhcip)
1169993e3fafSRobert Mustacchi {
1170993e3fafSRobert Mustacchi /*
1171993e3fafSRobert Mustacchi * The capabilities always begin at offset zero.
1172993e3fafSRobert Mustacchi */
1173993e3fafSRobert Mustacchi xhcip->xhci_regs_capoff = 0;
1174993e3fafSRobert Mustacchi xhcip->xhci_regs_operoff = xhci_get8(xhcip, XHCI_R_CAP, XHCI_CAPLENGTH);
1175993e3fafSRobert Mustacchi xhcip->xhci_regs_runoff = xhci_get32(xhcip, XHCI_R_CAP, XHCI_RTSOFF);
1176993e3fafSRobert Mustacchi xhcip->xhci_regs_runoff &= ~0x1f;
1177993e3fafSRobert Mustacchi xhcip->xhci_regs_dooroff = xhci_get32(xhcip, XHCI_R_CAP, XHCI_DBOFF);
1178993e3fafSRobert Mustacchi xhcip->xhci_regs_dooroff &= ~0x3;
1179993e3fafSRobert Mustacchi
1180993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1181993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to initialize controller register "
1182993e3fafSRobert Mustacchi "offsets: encountered FM register error");
1183993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1184993e3fafSRobert Mustacchi return (B_FALSE);
1185993e3fafSRobert Mustacchi }
1186993e3fafSRobert Mustacchi
1187993e3fafSRobert Mustacchi return (B_TRUE);
1188993e3fafSRobert Mustacchi }
1189993e3fafSRobert Mustacchi
1190993e3fafSRobert Mustacchi /*
1191993e3fafSRobert Mustacchi * Read various parameters from PCI configuration space and from the Capability
1192993e3fafSRobert Mustacchi * registers that we'll need to register the device. We cache all of the
1193993e3fafSRobert Mustacchi * Capability registers.
1194993e3fafSRobert Mustacchi */
1195993e3fafSRobert Mustacchi static boolean_t
xhci_read_params(xhci_t * xhcip)1196993e3fafSRobert Mustacchi xhci_read_params(xhci_t *xhcip)
1197993e3fafSRobert Mustacchi {
1198993e3fafSRobert Mustacchi uint8_t usb;
1199993e3fafSRobert Mustacchi uint16_t vers;
1200993e3fafSRobert Mustacchi uint32_t struc1, struc2, struc3, cap1, cap2, pgsz;
12016f2302d2SRobert Mustacchi uint32_t psize, pbit, capreg;
1202993e3fafSRobert Mustacchi xhci_capability_t *xcap;
1203993e3fafSRobert Mustacchi unsigned long ps;
1204993e3fafSRobert Mustacchi
12056f2302d2SRobert Mustacchi /*
12066f2302d2SRobert Mustacchi * While it's tempting to do a 16-bit read at offset 0x2, unfortunately,
12076f2302d2SRobert Mustacchi * a few emulated systems don't support reading at offset 0x2 for the
12086f2302d2SRobert Mustacchi * version. Instead we need to read the caplength register and get the
12096f2302d2SRobert Mustacchi * upper two bytes.
12106f2302d2SRobert Mustacchi */
12116f2302d2SRobert Mustacchi capreg = xhci_get32(xhcip, XHCI_R_CAP, XHCI_CAPLENGTH);
12126f2302d2SRobert Mustacchi vers = XHCI_VERSION_MASK(capreg);
1213993e3fafSRobert Mustacchi usb = pci_config_get8(xhcip->xhci_cfg_handle, PCI_XHCI_USBREV);
1214993e3fafSRobert Mustacchi struc1 = xhci_get32(xhcip, XHCI_R_CAP, XHCI_HCSPARAMS1);
1215993e3fafSRobert Mustacchi struc2 = xhci_get32(xhcip, XHCI_R_CAP, XHCI_HCSPARAMS2);
1216993e3fafSRobert Mustacchi struc3 = xhci_get32(xhcip, XHCI_R_CAP, XHCI_HCSPARAMS3);
1217993e3fafSRobert Mustacchi cap1 = xhci_get32(xhcip, XHCI_R_CAP, XHCI_HCCPARAMS1);
1218993e3fafSRobert Mustacchi cap2 = xhci_get32(xhcip, XHCI_R_CAP, XHCI_HCCPARAMS2);
1219993e3fafSRobert Mustacchi pgsz = xhci_get32(xhcip, XHCI_R_OPER, XHCI_PAGESIZE);
1220993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1221993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to read controller parameters: "
1222993e3fafSRobert Mustacchi "encountered FM register error");
1223993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1224993e3fafSRobert Mustacchi return (B_FALSE);
1225993e3fafSRobert Mustacchi }
1226993e3fafSRobert Mustacchi
1227993e3fafSRobert Mustacchi xcap = &xhcip->xhci_caps;
1228993e3fafSRobert Mustacchi xcap->xcap_usb_vers = usb;
1229993e3fafSRobert Mustacchi xcap->xcap_hci_vers = vers;
1230993e3fafSRobert Mustacchi xcap->xcap_max_slots = XHCI_HCS1_DEVSLOT_MAX(struc1);
1231993e3fafSRobert Mustacchi xcap->xcap_max_intrs = XHCI_HCS1_IRQ_MAX(struc1);
1232993e3fafSRobert Mustacchi xcap->xcap_max_ports = XHCI_HCS1_N_PORTS(struc1);
1233993e3fafSRobert Mustacchi if (xcap->xcap_max_ports > MAX_PORTS) {
1234993e3fafSRobert Mustacchi xhci_error(xhcip, "Root hub has %d ports, but system only "
1235993e3fafSRobert Mustacchi "supports %d, limiting to %d\n", xcap->xcap_max_ports,
1236993e3fafSRobert Mustacchi MAX_PORTS, MAX_PORTS);
1237993e3fafSRobert Mustacchi xcap->xcap_max_ports = MAX_PORTS;
1238993e3fafSRobert Mustacchi }
1239993e3fafSRobert Mustacchi
1240993e3fafSRobert Mustacchi xcap->xcap_ist_micro = XHCI_HCS2_IST_MICRO(struc2);
1241993e3fafSRobert Mustacchi xcap->xcap_ist = XHCI_HCS2_IST(struc2);
1242993e3fafSRobert Mustacchi xcap->xcap_max_esrt = XHCI_HCS2_ERST_MAX(struc2);
1243993e3fafSRobert Mustacchi xcap->xcap_scratch_restore = XHCI_HCS2_SPR(struc2);
1244993e3fafSRobert Mustacchi xcap->xcap_max_scratch = XHCI_HCS2_SPB_MAX(struc2);
1245993e3fafSRobert Mustacchi
1246993e3fafSRobert Mustacchi xcap->xcap_u1_lat = XHCI_HCS3_U1_DEL(struc3);
1247993e3fafSRobert Mustacchi xcap->xcap_u2_lat = XHCI_HCS3_U2_DEL(struc3);
1248993e3fafSRobert Mustacchi
1249993e3fafSRobert Mustacchi xcap->xcap_flags = XHCI_HCC1_FLAGS_MASK(cap1);
1250993e3fafSRobert Mustacchi xcap->xcap_max_psa = XHCI_HCC1_PSA_SZ_MAX(cap1);
1251993e3fafSRobert Mustacchi xcap->xcap_xecp_off = XHCI_HCC1_XECP(cap1);
1252993e3fafSRobert Mustacchi xcap->xcap_flags2 = XHCI_HCC2_FLAGS_MASK(cap2);
1253993e3fafSRobert Mustacchi
1254993e3fafSRobert Mustacchi /*
1255993e3fafSRobert Mustacchi * We don't have documentation for what changed from before xHCI 0.96,
1256993e3fafSRobert Mustacchi * so we just refuse to support versions before 0.96. We also will
1257993e3fafSRobert Mustacchi * ignore anything with a major version greater than 1.
1258993e3fafSRobert Mustacchi */
1259993e3fafSRobert Mustacchi if (xcap->xcap_hci_vers < 0x96 || xcap->xcap_hci_vers >= 0x200) {
1260993e3fafSRobert Mustacchi xhci_error(xhcip, "Encountered unsupported xHCI version 0.%2x",
1261993e3fafSRobert Mustacchi xcap->xcap_hci_vers);
1262993e3fafSRobert Mustacchi return (B_FALSE);
1263993e3fafSRobert Mustacchi }
1264993e3fafSRobert Mustacchi
1265993e3fafSRobert Mustacchi /*
1266993e3fafSRobert Mustacchi * Determine the smallest size page that the controller supports and
1267993e3fafSRobert Mustacchi * make sure that it matches our pagesize. We basically check here for
1268993e3fafSRobert Mustacchi * the presence of 4k and 8k pages. The basis of the pagesize is used
1269993e3fafSRobert Mustacchi * extensively throughout the code and specification. While we could
1270993e3fafSRobert Mustacchi * support other page sizes here, given that we don't support systems
1271993e3fafSRobert Mustacchi * with it at this time, it doesn't make much sense.
1272993e3fafSRobert Mustacchi */
1273993e3fafSRobert Mustacchi ps = PAGESIZE;
1274993e3fafSRobert Mustacchi if (ps == 0x1000) {
1275993e3fafSRobert Mustacchi pbit = XHCI_PAGESIZE_4K;
1276993e3fafSRobert Mustacchi psize = 0x1000;
1277993e3fafSRobert Mustacchi } else if (ps == 0x2000) {
1278993e3fafSRobert Mustacchi pbit = XHCI_PAGESIZE_8K;
1279993e3fafSRobert Mustacchi psize = 0x2000;
1280993e3fafSRobert Mustacchi } else {
1281993e3fafSRobert Mustacchi xhci_error(xhcip, "Encountered host page size that the driver "
1282993e3fafSRobert Mustacchi "doesn't know how to handle: %lx\n", ps);
1283993e3fafSRobert Mustacchi return (B_FALSE);
1284993e3fafSRobert Mustacchi }
1285993e3fafSRobert Mustacchi
1286993e3fafSRobert Mustacchi if (!(pgsz & pbit)) {
1287993e3fafSRobert Mustacchi xhci_error(xhcip, "Encountered controller that didn't support "
1288993e3fafSRobert Mustacchi "the host page size (%d), supports: %x", psize, pgsz);
1289993e3fafSRobert Mustacchi return (B_FALSE);
1290993e3fafSRobert Mustacchi }
1291993e3fafSRobert Mustacchi xcap->xcap_pagesize = psize;
1292993e3fafSRobert Mustacchi
1293993e3fafSRobert Mustacchi return (B_TRUE);
1294993e3fafSRobert Mustacchi }
1295993e3fafSRobert Mustacchi
1296993e3fafSRobert Mustacchi /*
1297993e3fafSRobert Mustacchi * Apply known workarounds and issues. These reports come from other
1298993e3fafSRobert Mustacchi * Operating Systems and have been collected over time.
1299993e3fafSRobert Mustacchi */
1300993e3fafSRobert Mustacchi static boolean_t
xhci_identify(xhci_t * xhcip)1301993e3fafSRobert Mustacchi xhci_identify(xhci_t *xhcip)
1302993e3fafSRobert Mustacchi {
1303993e3fafSRobert Mustacchi xhci_quirks_populate(xhcip);
1304993e3fafSRobert Mustacchi
1305993e3fafSRobert Mustacchi if (xhcip->xhci_quirks & XHCI_QUIRK_NO_MSI) {
1306993e3fafSRobert Mustacchi xhcip->xhci_caps.xcap_intr_types = DDI_INTR_TYPE_FIXED;
1307993e3fafSRobert Mustacchi } else {
1308993e3fafSRobert Mustacchi xhcip->xhci_caps.xcap_intr_types = DDI_INTR_TYPE_FIXED |
1309993e3fafSRobert Mustacchi DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_MSIX;
1310993e3fafSRobert Mustacchi }
1311993e3fafSRobert Mustacchi
1312993e3fafSRobert Mustacchi if (xhcip->xhci_quirks & XHCI_QUIRK_32_ONLY) {
1313993e3fafSRobert Mustacchi xhcip->xhci_caps.xcap_flags &= ~XCAP_AC64;
1314993e3fafSRobert Mustacchi }
1315993e3fafSRobert Mustacchi
1316993e3fafSRobert Mustacchi return (B_TRUE);
1317993e3fafSRobert Mustacchi }
1318993e3fafSRobert Mustacchi
1319993e3fafSRobert Mustacchi static boolean_t
xhci_alloc_intr_handle(xhci_t * xhcip,int type)1320993e3fafSRobert Mustacchi xhci_alloc_intr_handle(xhci_t *xhcip, int type)
1321993e3fafSRobert Mustacchi {
1322993e3fafSRobert Mustacchi int ret;
1323993e3fafSRobert Mustacchi
1324993e3fafSRobert Mustacchi /*
1325993e3fafSRobert Mustacchi * Normally a well-behaving driver would more carefully request an
1326993e3fafSRobert Mustacchi * amount of interrupts based on the number available, etc. But since we
1327993e3fafSRobert Mustacchi * only actually want a single interrupt, we're just going to go ahead
1328993e3fafSRobert Mustacchi * and ask for a single interrupt.
1329993e3fafSRobert Mustacchi */
1330993e3fafSRobert Mustacchi ret = ddi_intr_alloc(xhcip->xhci_dip, &xhcip->xhci_intr_hdl, type, 0,
1331993e3fafSRobert Mustacchi XHCI_NINTR, &xhcip->xhci_intr_num, DDI_INTR_ALLOC_NORMAL);
1332993e3fafSRobert Mustacchi if (ret != DDI_SUCCESS) {
1333993e3fafSRobert Mustacchi xhci_log(xhcip, "!failed to allocate interrupts of type %d: %d",
1334993e3fafSRobert Mustacchi type, ret);
1335993e3fafSRobert Mustacchi return (B_FALSE);
1336993e3fafSRobert Mustacchi }
1337993e3fafSRobert Mustacchi xhcip->xhci_intr_type = type;
1338993e3fafSRobert Mustacchi
1339993e3fafSRobert Mustacchi return (B_TRUE);
1340993e3fafSRobert Mustacchi }
1341993e3fafSRobert Mustacchi
1342993e3fafSRobert Mustacchi static boolean_t
xhci_alloc_intrs(xhci_t * xhcip)1343993e3fafSRobert Mustacchi xhci_alloc_intrs(xhci_t *xhcip)
1344993e3fafSRobert Mustacchi {
1345993e3fafSRobert Mustacchi int intr_types, ret;
1346993e3fafSRobert Mustacchi
1347993e3fafSRobert Mustacchi if (XHCI_NINTR > xhcip->xhci_caps.xcap_max_intrs) {
1348993e3fafSRobert Mustacchi xhci_error(xhcip, "controller does not support the minimum "
1349993e3fafSRobert Mustacchi "number of interrupts required (%d), supports %d",
1350993e3fafSRobert Mustacchi XHCI_NINTR, xhcip->xhci_caps.xcap_max_intrs);
1351993e3fafSRobert Mustacchi return (B_FALSE);
1352993e3fafSRobert Mustacchi }
1353993e3fafSRobert Mustacchi
1354993e3fafSRobert Mustacchi if ((ret = ddi_intr_get_supported_types(xhcip->xhci_dip,
1355993e3fafSRobert Mustacchi &intr_types)) != DDI_SUCCESS) {
1356993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to get supported interrupt types: "
1357993e3fafSRobert Mustacchi "%d", ret);
1358993e3fafSRobert Mustacchi return (B_FALSE);
1359993e3fafSRobert Mustacchi }
1360993e3fafSRobert Mustacchi
1361993e3fafSRobert Mustacchi /*
1362993e3fafSRobert Mustacchi * Mask off interrupt types we've already ruled out due to quirks or
1363993e3fafSRobert Mustacchi * other reasons.
1364993e3fafSRobert Mustacchi */
1365993e3fafSRobert Mustacchi intr_types &= xhcip->xhci_caps.xcap_intr_types;
1366993e3fafSRobert Mustacchi if (intr_types & DDI_INTR_TYPE_MSIX) {
1367993e3fafSRobert Mustacchi if (xhci_alloc_intr_handle(xhcip, DDI_INTR_TYPE_MSIX))
1368993e3fafSRobert Mustacchi return (B_TRUE);
1369993e3fafSRobert Mustacchi }
1370993e3fafSRobert Mustacchi
1371993e3fafSRobert Mustacchi if (intr_types & DDI_INTR_TYPE_MSI) {
1372993e3fafSRobert Mustacchi if (xhci_alloc_intr_handle(xhcip, DDI_INTR_TYPE_MSI))
1373993e3fafSRobert Mustacchi return (B_TRUE);
1374993e3fafSRobert Mustacchi }
1375993e3fafSRobert Mustacchi
1376993e3fafSRobert Mustacchi if (intr_types & DDI_INTR_TYPE_FIXED) {
1377993e3fafSRobert Mustacchi if (xhci_alloc_intr_handle(xhcip, DDI_INTR_TYPE_FIXED))
1378993e3fafSRobert Mustacchi return (B_TRUE);
1379993e3fafSRobert Mustacchi }
1380993e3fafSRobert Mustacchi
1381993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to allocate an interrupt, supported types: "
1382993e3fafSRobert Mustacchi "0x%x", intr_types);
1383993e3fafSRobert Mustacchi return (B_FALSE);
1384993e3fafSRobert Mustacchi }
1385993e3fafSRobert Mustacchi
1386993e3fafSRobert Mustacchi static boolean_t
xhci_add_intr_handler(xhci_t * xhcip)1387993e3fafSRobert Mustacchi xhci_add_intr_handler(xhci_t *xhcip)
1388993e3fafSRobert Mustacchi {
1389993e3fafSRobert Mustacchi int ret;
1390993e3fafSRobert Mustacchi
1391993e3fafSRobert Mustacchi if ((ret = ddi_intr_get_pri(xhcip->xhci_intr_hdl,
1392993e3fafSRobert Mustacchi &xhcip->xhci_intr_pri)) != DDI_SUCCESS) {
1393993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to get interrupt priority: %d", ret);
1394993e3fafSRobert Mustacchi return (B_FALSE);
1395993e3fafSRobert Mustacchi }
1396993e3fafSRobert Mustacchi
1397993e3fafSRobert Mustacchi if ((ret = ddi_intr_get_cap(xhcip->xhci_intr_hdl,
1398993e3fafSRobert Mustacchi &xhcip->xhci_intr_caps)) != DDI_SUCCESS) {
1399993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to get interrupt capabilities: %d",
1400993e3fafSRobert Mustacchi ret);
1401993e3fafSRobert Mustacchi return (B_FALSE);
1402993e3fafSRobert Mustacchi }
1403993e3fafSRobert Mustacchi
1404993e3fafSRobert Mustacchi if ((ret = ddi_intr_add_handler(xhcip->xhci_intr_hdl, xhci_intr, xhcip,
1405993e3fafSRobert Mustacchi (uintptr_t)0)) != DDI_SUCCESS) {
1406993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to add interrupt handler: %d", ret);
1407993e3fafSRobert Mustacchi return (B_FALSE);
1408993e3fafSRobert Mustacchi }
1409993e3fafSRobert Mustacchi return (B_TRUE);
1410993e3fafSRobert Mustacchi }
1411993e3fafSRobert Mustacchi
1412993e3fafSRobert Mustacchi /*
1413993e3fafSRobert Mustacchi * Find a capability with an identifier whose value is 'id'. The 'init' argument
1414993e3fafSRobert Mustacchi * gives us the offset to start searching at. See xHCI 1.1 / 7 for more
1415993e3fafSRobert Mustacchi * information. This is more or less exactly like PCI capabilities.
1416993e3fafSRobert Mustacchi */
1417993e3fafSRobert Mustacchi static boolean_t
xhci_find_ext_cap(xhci_t * xhcip,uint32_t id,uint32_t init,uint32_t * outp)1418993e3fafSRobert Mustacchi xhci_find_ext_cap(xhci_t *xhcip, uint32_t id, uint32_t init, uint32_t *outp)
1419993e3fafSRobert Mustacchi {
1420993e3fafSRobert Mustacchi uint32_t off;
1421993e3fafSRobert Mustacchi uint8_t next = 0;
1422993e3fafSRobert Mustacchi
1423993e3fafSRobert Mustacchi /*
1424993e3fafSRobert Mustacchi * If we have no offset, we're done.
1425993e3fafSRobert Mustacchi */
1426993e3fafSRobert Mustacchi if (xhcip->xhci_caps.xcap_xecp_off == 0)
1427993e3fafSRobert Mustacchi return (B_FALSE);
1428993e3fafSRobert Mustacchi
1429993e3fafSRobert Mustacchi off = xhcip->xhci_caps.xcap_xecp_off << 2;
1430993e3fafSRobert Mustacchi do {
1431993e3fafSRobert Mustacchi uint32_t cap_hdr;
1432993e3fafSRobert Mustacchi
1433993e3fafSRobert Mustacchi off += next << 2;
1434993e3fafSRobert Mustacchi cap_hdr = xhci_get32(xhcip, XHCI_R_CAP, off);
1435993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1436993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to read xhci extended "
1437993e3fafSRobert Mustacchi "capabilities at offset 0x%x: encountered FM "
1438993e3fafSRobert Mustacchi "register error", off);
1439993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip,
1440993e3fafSRobert Mustacchi DDI_SERVICE_LOST);
1441993e3fafSRobert Mustacchi break;
1442993e3fafSRobert Mustacchi }
1443993e3fafSRobert Mustacchi
1444993e3fafSRobert Mustacchi if (cap_hdr == PCI_EINVAL32)
1445993e3fafSRobert Mustacchi break;
1446993e3fafSRobert Mustacchi if (XHCI_XECP_ID(cap_hdr) == id &&
1447993e3fafSRobert Mustacchi (init == UINT32_MAX || off > init)) {
1448993e3fafSRobert Mustacchi *outp = off;
1449993e3fafSRobert Mustacchi return (B_TRUE);
1450993e3fafSRobert Mustacchi }
1451993e3fafSRobert Mustacchi next = XHCI_XECP_NEXT(cap_hdr);
1452993e3fafSRobert Mustacchi /*
1453993e3fafSRobert Mustacchi * Watch out for overflow if we somehow end up with a more than
1454993e3fafSRobert Mustacchi * 2 GiB space.
1455993e3fafSRobert Mustacchi */
1456993e3fafSRobert Mustacchi if (next << 2 > (INT32_MAX - off))
1457993e3fafSRobert Mustacchi return (B_FALSE);
1458993e3fafSRobert Mustacchi } while (next != 0);
1459993e3fafSRobert Mustacchi
1460993e3fafSRobert Mustacchi return (B_FALSE);
1461993e3fafSRobert Mustacchi }
1462993e3fafSRobert Mustacchi
1463993e3fafSRobert Mustacchi /*
1464993e3fafSRobert Mustacchi * For mostly information purposes, we'd like to walk to augment the devinfo
1465993e3fafSRobert Mustacchi * tree with the number of ports that support USB 2 and USB 3. Note though that
1466993e3fafSRobert Mustacchi * these ports may be overlapping. Many ports can support both USB 2 and USB 3
1467993e3fafSRobert Mustacchi * and are wired up to the same physical port, even though they show up as
1468993e3fafSRobert Mustacchi * separate 'ports' in the xhci sense.
1469993e3fafSRobert Mustacchi */
1470993e3fafSRobert Mustacchi static boolean_t
xhci_port_count(xhci_t * xhcip)1471993e3fafSRobert Mustacchi xhci_port_count(xhci_t *xhcip)
1472993e3fafSRobert Mustacchi {
1473672fc84aSRobert Mustacchi uint_t nusb2 = 0, fusb2 = 0;
1474672fc84aSRobert Mustacchi uint_t nusb30 = 0, fusb30 = 0;
1475672fc84aSRobert Mustacchi uint_t nusb31 = 0, fusb31 = 0;
1476993e3fafSRobert Mustacchi uint32_t off = UINT32_MAX;
1477993e3fafSRobert Mustacchi
1478993e3fafSRobert Mustacchi while (xhci_find_ext_cap(xhcip, XHCI_ID_PROTOCOLS, off, &off) ==
1479993e3fafSRobert Mustacchi B_TRUE) {
1480993e3fafSRobert Mustacchi uint32_t rvers, rport;
1481672fc84aSRobert Mustacchi uint8_t maj, min, count, first;
1482993e3fafSRobert Mustacchi
1483993e3fafSRobert Mustacchi /*
1484993e3fafSRobert Mustacchi * See xHCI 1.1 / 7.2 for the format of this. The first uint32_t
1485993e3fafSRobert Mustacchi * has version information while the third uint32_t has the port
1486993e3fafSRobert Mustacchi * count.
1487993e3fafSRobert Mustacchi */
1488993e3fafSRobert Mustacchi rvers = xhci_get32(xhcip, XHCI_R_CAP, off);
1489993e3fafSRobert Mustacchi rport = xhci_get32(xhcip, XHCI_R_CAP, off + 8);
1490993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1491993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to read xhci port counts: "
1492993e3fafSRobert Mustacchi "encountered fatal FM register error");
1493993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip,
1494993e3fafSRobert Mustacchi DDI_SERVICE_LOST);
1495993e3fafSRobert Mustacchi return (B_FALSE);
1496993e3fafSRobert Mustacchi }
1497993e3fafSRobert Mustacchi
1498672fc84aSRobert Mustacchi maj = XHCI_XECP_PROT_MAJOR(rvers);
1499672fc84aSRobert Mustacchi min = XHCI_XECP_PROT_MINOR(rvers);
1500672fc84aSRobert Mustacchi count = XHCI_XECP_PROT_PCOUNT(rport);
1501672fc84aSRobert Mustacchi first = XHCI_XECP_PROT_FPORT(rport);
1502672fc84aSRobert Mustacchi
15032ac15736SRobert Mustacchi /*
15042ac15736SRobert Mustacchi * In the wild, we've seen some systems that are using a minor
15052ac15736SRobert Mustacchi * version of 0x10 and some that are using 0x01 in this field.
15062ac15736SRobert Mustacchi * While the xhci spec says that we should expect it to be a
15072ac15736SRobert Mustacchi * minor of 0x01 based on the xHCI 1.1 specification Table 155:
15082ac15736SRobert Mustacchi * xHCI Supported Protocols. However, the USB 3.1 specification
15092ac15736SRobert Mustacchi * defines the version to be 0x10 when encoded as a BCD style.
15102ac15736SRobert Mustacchi * As such, handle both and hope we never get to revision 16 of
15112ac15736SRobert Mustacchi * USB 3.
15122ac15736SRobert Mustacchi */
15132ac15736SRobert Mustacchi if (maj == 3 && (min == 0x10 || min == 0x01)) {
1514672fc84aSRobert Mustacchi nusb31 = count;
1515672fc84aSRobert Mustacchi fusb31 = first;
1516672fc84aSRobert Mustacchi } else if (maj == 3 && min == 0) {
1517672fc84aSRobert Mustacchi nusb30 = count;
1518672fc84aSRobert Mustacchi fusb30 = first;
1519672fc84aSRobert Mustacchi } else if (maj <= 2) {
1520672fc84aSRobert Mustacchi nusb2 = count;
1521672fc84aSRobert Mustacchi fusb2 = first;
1522993e3fafSRobert Mustacchi } else {
1523993e3fafSRobert Mustacchi xhci_error(xhcip, "encountered port capabilities with "
1524c78b1a45SRobert Mustacchi "unknown USB version: %x.%x\n", maj, min);
1525993e3fafSRobert Mustacchi }
1526993e3fafSRobert Mustacchi }
1527993e3fafSRobert Mustacchi
1528672fc84aSRobert Mustacchi /*
1529672fc84aSRobert Mustacchi * These properties are used by FMA and the USB topo module.
1530672fc84aSRobert Mustacchi */
1531672fc84aSRobert Mustacchi if (nusb2 > 0) {
1532672fc84aSRobert Mustacchi (void) ddi_prop_update_int(DDI_DEV_T_NONE, xhcip->xhci_dip,
1533672fc84aSRobert Mustacchi "usb2.0-port-count", nusb2);
1534672fc84aSRobert Mustacchi (void) ddi_prop_update_int(DDI_DEV_T_NONE, xhcip->xhci_dip,
1535672fc84aSRobert Mustacchi "usb2.0-first-port", fusb2);
1536672fc84aSRobert Mustacchi }
1537672fc84aSRobert Mustacchi if (nusb30 > 0) {
1538672fc84aSRobert Mustacchi (void) ddi_prop_update_int(DDI_DEV_T_NONE, xhcip->xhci_dip,
1539672fc84aSRobert Mustacchi "usb3.0-port-count", nusb30);
1540672fc84aSRobert Mustacchi (void) ddi_prop_update_int(DDI_DEV_T_NONE, xhcip->xhci_dip,
1541672fc84aSRobert Mustacchi "usb3.0-first-port", fusb30);
1542672fc84aSRobert Mustacchi }
1543672fc84aSRobert Mustacchi
1544672fc84aSRobert Mustacchi if (nusb31 > 0) {
1545672fc84aSRobert Mustacchi (void) ddi_prop_update_int(DDI_DEV_T_NONE, xhcip->xhci_dip,
15462ac15736SRobert Mustacchi "usb3.1-port-count", nusb31);
1547672fc84aSRobert Mustacchi (void) ddi_prop_update_int(DDI_DEV_T_NONE, xhcip->xhci_dip,
1548672fc84aSRobert Mustacchi "usb3.1-first-port", fusb31);
1549672fc84aSRobert Mustacchi }
1550993e3fafSRobert Mustacchi
1551993e3fafSRobert Mustacchi return (B_TRUE);
1552993e3fafSRobert Mustacchi }
1553993e3fafSRobert Mustacchi
1554993e3fafSRobert Mustacchi /*
1555993e3fafSRobert Mustacchi * Take over control from the BIOS or other firmware, if applicable.
1556993e3fafSRobert Mustacchi */
1557993e3fafSRobert Mustacchi static boolean_t
xhci_controller_takeover(xhci_t * xhcip)1558993e3fafSRobert Mustacchi xhci_controller_takeover(xhci_t *xhcip)
1559993e3fafSRobert Mustacchi {
1560993e3fafSRobert Mustacchi int ret;
1561993e3fafSRobert Mustacchi uint32_t val, off;
1562993e3fafSRobert Mustacchi
1563993e3fafSRobert Mustacchi /*
1564993e3fafSRobert Mustacchi * If we can't find the legacy capability, then there's nothing to do.
1565993e3fafSRobert Mustacchi */
1566993e3fafSRobert Mustacchi if (xhci_find_ext_cap(xhcip, XHCI_ID_USB_LEGACY, UINT32_MAX, &off) ==
1567993e3fafSRobert Mustacchi B_FALSE)
1568993e3fafSRobert Mustacchi return (B_TRUE);
1569993e3fafSRobert Mustacchi val = xhci_get32(xhcip, XHCI_R_CAP, off);
1570993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1571993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to read BIOS take over registers: "
1572993e3fafSRobert Mustacchi "encountered fatal FM register error");
1573993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1574993e3fafSRobert Mustacchi return (B_FALSE);
1575993e3fafSRobert Mustacchi }
1576993e3fafSRobert Mustacchi
1577993e3fafSRobert Mustacchi if (val & XHCI_BIOS_OWNED) {
1578993e3fafSRobert Mustacchi val |= XHCI_OS_OWNED;
1579993e3fafSRobert Mustacchi xhci_put32(xhcip, XHCI_R_CAP, off, val);
1580993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1581993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to write BIOS take over "
1582993e3fafSRobert Mustacchi "registers: encountered fatal FM register error");
1583993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip,
1584993e3fafSRobert Mustacchi DDI_SERVICE_LOST);
1585993e3fafSRobert Mustacchi return (B_FALSE);
1586993e3fafSRobert Mustacchi }
1587993e3fafSRobert Mustacchi
1588993e3fafSRobert Mustacchi /*
1589993e3fafSRobert Mustacchi * Wait up to 5 seconds for things to change. While this number
1590993e3fafSRobert Mustacchi * isn't specified in the xHCI spec, it seems to be the de facto
1591993e3fafSRobert Mustacchi * value that various systems are using today. We'll use a 10ms
1592993e3fafSRobert Mustacchi * interval to check.
1593993e3fafSRobert Mustacchi */
1594993e3fafSRobert Mustacchi ret = xhci_reg_poll(xhcip, XHCI_R_CAP, off,
1595993e3fafSRobert Mustacchi XHCI_BIOS_OWNED | XHCI_OS_OWNED, XHCI_OS_OWNED, 500, 10);
1596993e3fafSRobert Mustacchi if (ret == EIO)
1597993e3fafSRobert Mustacchi return (B_FALSE);
1598993e3fafSRobert Mustacchi if (ret == ETIMEDOUT) {
1599993e3fafSRobert Mustacchi xhci_log(xhcip, "!timed out waiting for firmware to "
1600993e3fafSRobert Mustacchi "hand off, taking over");
1601993e3fafSRobert Mustacchi val &= ~XHCI_BIOS_OWNED;
1602993e3fafSRobert Mustacchi xhci_put32(xhcip, XHCI_R_CAP, off, val);
1603993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1604993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to write forced "
1605993e3fafSRobert Mustacchi "takeover: encountered fatal FM register "
1606993e3fafSRobert Mustacchi "error");
1607993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip,
1608993e3fafSRobert Mustacchi DDI_SERVICE_LOST);
1609993e3fafSRobert Mustacchi return (B_FALSE);
1610993e3fafSRobert Mustacchi }
1611993e3fafSRobert Mustacchi }
1612993e3fafSRobert Mustacchi }
1613993e3fafSRobert Mustacchi
1614993e3fafSRobert Mustacchi val = xhci_get32(xhcip, XHCI_R_CAP, off + XHCI_XECP_LEGCTLSTS);
1615993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1616993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to read legacy control registers: "
1617993e3fafSRobert Mustacchi "encountered fatal FM register error");
1618993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1619993e3fafSRobert Mustacchi return (B_FALSE);
1620993e3fafSRobert Mustacchi }
1621993e3fafSRobert Mustacchi val &= XHCI_XECP_SMI_MASK;
1622993e3fafSRobert Mustacchi val |= XHCI_XECP_CLEAR_SMI;
1623993e3fafSRobert Mustacchi xhci_put32(xhcip, XHCI_R_CAP, off + XHCI_XECP_LEGCTLSTS, val);
1624993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1625993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to write legacy control registers: "
1626993e3fafSRobert Mustacchi "encountered fatal FM register error");
1627993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1628993e3fafSRobert Mustacchi return (B_FALSE);
1629993e3fafSRobert Mustacchi }
1630993e3fafSRobert Mustacchi
1631993e3fafSRobert Mustacchi return (B_TRUE);
1632993e3fafSRobert Mustacchi }
1633993e3fafSRobert Mustacchi
1634993e3fafSRobert Mustacchi static int
xhci_controller_stop(xhci_t * xhcip)1635993e3fafSRobert Mustacchi xhci_controller_stop(xhci_t *xhcip)
1636993e3fafSRobert Mustacchi {
1637993e3fafSRobert Mustacchi uint32_t cmdreg;
1638993e3fafSRobert Mustacchi
1639993e3fafSRobert Mustacchi cmdreg = xhci_get32(xhcip, XHCI_R_OPER, XHCI_USBCMD);
1640993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1641993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to read USB Command register: "
1642993e3fafSRobert Mustacchi "encountered fatal FM register error");
1643993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1644993e3fafSRobert Mustacchi return (EIO);
1645993e3fafSRobert Mustacchi }
1646993e3fafSRobert Mustacchi
1647993e3fafSRobert Mustacchi cmdreg &= ~(XHCI_CMD_RS | XHCI_CMD_INTE);
1648993e3fafSRobert Mustacchi xhci_put32(xhcip, XHCI_R_OPER, XHCI_USBCMD, cmdreg);
1649993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1650993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to write USB Command register: "
1651993e3fafSRobert Mustacchi "encountered fatal FM register error");
1652993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1653993e3fafSRobert Mustacchi return (EIO);
1654993e3fafSRobert Mustacchi }
1655993e3fafSRobert Mustacchi
1656993e3fafSRobert Mustacchi /*
1657993e3fafSRobert Mustacchi * Wait up to 50ms for this to occur. The specification says that this
1658993e3fafSRobert Mustacchi * should stop within 16ms, but we give ourselves a bit more time just
1659993e3fafSRobert Mustacchi * in case.
1660993e3fafSRobert Mustacchi */
1661993e3fafSRobert Mustacchi return (xhci_reg_poll(xhcip, XHCI_R_OPER, XHCI_USBSTS, XHCI_STS_HCH,
1662993e3fafSRobert Mustacchi XHCI_STS_HCH, 50, 10));
1663993e3fafSRobert Mustacchi }
1664993e3fafSRobert Mustacchi
1665993e3fafSRobert Mustacchi static int
xhci_controller_reset(xhci_t * xhcip)1666993e3fafSRobert Mustacchi xhci_controller_reset(xhci_t *xhcip)
1667993e3fafSRobert Mustacchi {
1668993e3fafSRobert Mustacchi int ret;
1669993e3fafSRobert Mustacchi uint32_t cmdreg;
1670993e3fafSRobert Mustacchi
1671993e3fafSRobert Mustacchi cmdreg = xhci_get32(xhcip, XHCI_R_OPER, XHCI_USBCMD);
1672993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1673993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to read USB Command register for "
1674993e3fafSRobert Mustacchi "reset: encountered fatal FM register error");
1675993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1676993e3fafSRobert Mustacchi return (EIO);
1677993e3fafSRobert Mustacchi }
1678993e3fafSRobert Mustacchi
1679993e3fafSRobert Mustacchi cmdreg |= XHCI_CMD_HCRST;
1680993e3fafSRobert Mustacchi xhci_put32(xhcip, XHCI_R_OPER, XHCI_USBCMD, cmdreg);
1681993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1682993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to write USB Command register for "
1683993e3fafSRobert Mustacchi "reset: encountered fatal FM register error");
1684993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1685993e3fafSRobert Mustacchi return (EIO);
1686993e3fafSRobert Mustacchi }
1687993e3fafSRobert Mustacchi
1688993e3fafSRobert Mustacchi /*
1689993e3fafSRobert Mustacchi * Some controllers apparently don't want to be touched for at least 1ms
1690993e3fafSRobert Mustacchi * after we initiate the reset. Therefore give all controllers this
1691993e3fafSRobert Mustacchi * moment to breathe.
1692993e3fafSRobert Mustacchi */
1693993e3fafSRobert Mustacchi delay(drv_usectohz(xhci_reset_delay));
1694993e3fafSRobert Mustacchi
1695993e3fafSRobert Mustacchi /*
1696993e3fafSRobert Mustacchi * To tell that the reset has completed we first verify that the reset
1697993e3fafSRobert Mustacchi * has finished and that the USBCMD register no longer has the reset bit
1698993e3fafSRobert Mustacchi * asserted. However, once that's done we have to go verify that CNR
1699993e3fafSRobert Mustacchi * (Controller Not Ready) is no longer asserted.
1700993e3fafSRobert Mustacchi */
1701993e3fafSRobert Mustacchi if ((ret = xhci_reg_poll(xhcip, XHCI_R_OPER, XHCI_USBCMD,
1702993e3fafSRobert Mustacchi XHCI_CMD_HCRST, 0, 500, 10)) != 0)
1703993e3fafSRobert Mustacchi return (ret);
1704993e3fafSRobert Mustacchi
1705993e3fafSRobert Mustacchi return (xhci_reg_poll(xhcip, XHCI_R_OPER, XHCI_USBSTS,
1706993e3fafSRobert Mustacchi XHCI_STS_CNR, 0, 500, 10));
1707993e3fafSRobert Mustacchi }
1708993e3fafSRobert Mustacchi
1709993e3fafSRobert Mustacchi /*
1710993e3fafSRobert Mustacchi * Take care of all the required initialization before we can actually enable
1711993e3fafSRobert Mustacchi * the controller. This means that we need to:
1712993e3fafSRobert Mustacchi *
1713993e3fafSRobert Mustacchi * o Program the maximum number of slots
1714993e3fafSRobert Mustacchi * o Program the DCBAAP and allocate the scratchpad
1715993e3fafSRobert Mustacchi * o Program the Command Ring
1716993e3fafSRobert Mustacchi * o Initialize the Event Ring
1717993e3fafSRobert Mustacchi * o Enable interrupts (set imod)
1718993e3fafSRobert Mustacchi */
1719993e3fafSRobert Mustacchi static int
xhci_controller_configure(xhci_t * xhcip)1720993e3fafSRobert Mustacchi xhci_controller_configure(xhci_t *xhcip)
1721993e3fafSRobert Mustacchi {
1722993e3fafSRobert Mustacchi int ret;
1723993e3fafSRobert Mustacchi uint32_t config;
1724993e3fafSRobert Mustacchi
1725993e3fafSRobert Mustacchi config = xhci_get32(xhcip, XHCI_R_OPER, XHCI_CONFIG);
1726993e3fafSRobert Mustacchi config &= ~XHCI_CONFIG_SLOTS_MASK;
1727993e3fafSRobert Mustacchi config |= xhcip->xhci_caps.xcap_max_slots;
1728993e3fafSRobert Mustacchi xhci_put32(xhcip, XHCI_R_OPER, XHCI_CONFIG, config);
1729993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1730993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1731993e3fafSRobert Mustacchi return (EIO);
1732993e3fafSRobert Mustacchi }
1733993e3fafSRobert Mustacchi
1734993e3fafSRobert Mustacchi if ((ret = xhci_context_init(xhcip)) != 0) {
1735993e3fafSRobert Mustacchi const char *reason;
1736993e3fafSRobert Mustacchi if (ret == EIO) {
1737993e3fafSRobert Mustacchi reason = "fatal FM I/O error occurred";
1738993e3fafSRobert Mustacchi } else if (ret == ENOMEM) {
1739993e3fafSRobert Mustacchi reason = "unable to allocate DMA memory";
1740993e3fafSRobert Mustacchi } else {
1741993e3fafSRobert Mustacchi reason = "unexpected error occurred";
1742993e3fafSRobert Mustacchi }
1743993e3fafSRobert Mustacchi
1744993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to initialize xhci context "
1745993e3fafSRobert Mustacchi "registers: %s (%d)", reason, ret);
1746993e3fafSRobert Mustacchi return (ret);
1747993e3fafSRobert Mustacchi }
1748993e3fafSRobert Mustacchi
1749993e3fafSRobert Mustacchi if ((ret = xhci_command_ring_init(xhcip)) != 0) {
1750993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to initialize commands: %d", ret);
1751993e3fafSRobert Mustacchi return (ret);
1752993e3fafSRobert Mustacchi }
1753993e3fafSRobert Mustacchi
1754993e3fafSRobert Mustacchi if ((ret = xhci_event_init(xhcip)) != 0) {
1755993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to initialize events: %d", ret);
1756993e3fafSRobert Mustacchi return (ret);
1757993e3fafSRobert Mustacchi }
1758993e3fafSRobert Mustacchi
1759993e3fafSRobert Mustacchi if ((ret = xhci_intr_conf(xhcip)) != 0) {
1760993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to configure interrupts: %d", ret);
1761993e3fafSRobert Mustacchi return (ret);
1762993e3fafSRobert Mustacchi }
1763993e3fafSRobert Mustacchi
1764993e3fafSRobert Mustacchi return (0);
1765993e3fafSRobert Mustacchi }
1766993e3fafSRobert Mustacchi
1767993e3fafSRobert Mustacchi static int
xhci_controller_start(xhci_t * xhcip)1768993e3fafSRobert Mustacchi xhci_controller_start(xhci_t *xhcip)
1769993e3fafSRobert Mustacchi {
1770993e3fafSRobert Mustacchi uint32_t reg;
1771993e3fafSRobert Mustacchi
1772993e3fafSRobert Mustacchi reg = xhci_get32(xhcip, XHCI_R_OPER, XHCI_USBCMD);
1773993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1774993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to read USB Command register for "
1775993e3fafSRobert Mustacchi "start: encountered fatal FM register error");
1776993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1777993e3fafSRobert Mustacchi return (EIO);
1778993e3fafSRobert Mustacchi }
1779993e3fafSRobert Mustacchi
1780993e3fafSRobert Mustacchi reg |= XHCI_CMD_RS;
1781993e3fafSRobert Mustacchi xhci_put32(xhcip, XHCI_R_OPER, XHCI_USBCMD, reg);
1782993e3fafSRobert Mustacchi if (xhci_check_regs_acc(xhcip) != DDI_FM_OK) {
1783993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to write USB Command register for "
1784993e3fafSRobert Mustacchi "start: encountered fatal FM register error");
1785993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1786993e3fafSRobert Mustacchi return (EIO);
1787993e3fafSRobert Mustacchi }
1788993e3fafSRobert Mustacchi
1789993e3fafSRobert Mustacchi return (xhci_reg_poll(xhcip, XHCI_R_OPER, XHCI_USBSTS,
1790993e3fafSRobert Mustacchi XHCI_STS_HCH, 0, 500, 10));
1791993e3fafSRobert Mustacchi }
1792993e3fafSRobert Mustacchi
1793993e3fafSRobert Mustacchi /* ARGSUSED */
1794993e3fafSRobert Mustacchi static void
xhci_reset_task(void * arg)1795993e3fafSRobert Mustacchi xhci_reset_task(void *arg)
1796993e3fafSRobert Mustacchi {
1797993e3fafSRobert Mustacchi /*
1798993e3fafSRobert Mustacchi * Longer term, we'd like to properly perform a controller reset.
1799993e3fafSRobert Mustacchi * However, that requires a bit more assistance from USBA to work
1800993e3fafSRobert Mustacchi * properly and tear down devices. In the meantime, we panic.
1801993e3fafSRobert Mustacchi */
1802993e3fafSRobert Mustacchi panic("XHCI runtime reset required");
1803993e3fafSRobert Mustacchi }
1804993e3fafSRobert Mustacchi
1805993e3fafSRobert Mustacchi /*
1806993e3fafSRobert Mustacchi * This function is called when we've detected a fatal FM condition that has
1807993e3fafSRobert Mustacchi * resulted in a loss of service and we need to force a reset of the controller
1808993e3fafSRobert Mustacchi * as a whole. Only one such reset may be ongoing at a time.
1809993e3fafSRobert Mustacchi */
1810993e3fafSRobert Mustacchi void
xhci_fm_runtime_reset(xhci_t * xhcip)1811993e3fafSRobert Mustacchi xhci_fm_runtime_reset(xhci_t *xhcip)
1812993e3fafSRobert Mustacchi {
1813993e3fafSRobert Mustacchi boolean_t locked = B_FALSE;
1814993e3fafSRobert Mustacchi
1815993e3fafSRobert Mustacchi if (mutex_owned(&xhcip->xhci_lock)) {
1816993e3fafSRobert Mustacchi locked = B_TRUE;
1817993e3fafSRobert Mustacchi } else {
1818993e3fafSRobert Mustacchi mutex_enter(&xhcip->xhci_lock);
1819993e3fafSRobert Mustacchi }
1820993e3fafSRobert Mustacchi
1821993e3fafSRobert Mustacchi /*
1822993e3fafSRobert Mustacchi * If we're already in the error state than a reset is already ongoing
1823993e3fafSRobert Mustacchi * and there is nothing for us to do here.
1824993e3fafSRobert Mustacchi */
1825993e3fafSRobert Mustacchi if (xhcip->xhci_state & XHCI_S_ERROR) {
1826993e3fafSRobert Mustacchi goto out;
1827993e3fafSRobert Mustacchi }
1828993e3fafSRobert Mustacchi
1829993e3fafSRobert Mustacchi xhcip->xhci_state |= XHCI_S_ERROR;
1830993e3fafSRobert Mustacchi ddi_fm_service_impact(xhcip->xhci_dip, DDI_SERVICE_LOST);
1831993e3fafSRobert Mustacchi taskq_dispatch_ent(xhci_taskq, xhci_reset_task, xhcip, 0,
1832993e3fafSRobert Mustacchi &xhcip->xhci_tqe);
1833993e3fafSRobert Mustacchi out:
1834993e3fafSRobert Mustacchi if (!locked) {
1835993e3fafSRobert Mustacchi mutex_exit(&xhcip->xhci_lock);
1836993e3fafSRobert Mustacchi }
1837993e3fafSRobert Mustacchi }
1838993e3fafSRobert Mustacchi
1839993e3fafSRobert Mustacchi static int
xhci_ioctl_portsc(xhci_t * xhcip,intptr_t arg)1840993e3fafSRobert Mustacchi xhci_ioctl_portsc(xhci_t *xhcip, intptr_t arg)
1841993e3fafSRobert Mustacchi {
1842993e3fafSRobert Mustacchi int i;
1843993e3fafSRobert Mustacchi xhci_ioctl_portsc_t xhi;
1844993e3fafSRobert Mustacchi
1845993e3fafSRobert Mustacchi bzero(&xhi, sizeof (xhci_ioctl_portsc_t));
1846993e3fafSRobert Mustacchi xhi.xhi_nports = xhcip->xhci_caps.xcap_max_ports;
1847993e3fafSRobert Mustacchi for (i = 1; i <= xhcip->xhci_caps.xcap_max_ports; i++) {
1848993e3fafSRobert Mustacchi xhi.xhi_portsc[i] = xhci_get32(xhcip, XHCI_R_OPER,
1849993e3fafSRobert Mustacchi XHCI_PORTSC(i));
1850993e3fafSRobert Mustacchi }
1851993e3fafSRobert Mustacchi
1852993e3fafSRobert Mustacchi if (ddi_copyout(&xhi, (void *)(uintptr_t)arg, sizeof (xhi), 0) != 0)
1853993e3fafSRobert Mustacchi return (EFAULT);
1854993e3fafSRobert Mustacchi
1855993e3fafSRobert Mustacchi return (0);
1856993e3fafSRobert Mustacchi }
1857993e3fafSRobert Mustacchi
1858993e3fafSRobert Mustacchi static int
xhci_ioctl_clear(xhci_t * xhcip,intptr_t arg)1859993e3fafSRobert Mustacchi xhci_ioctl_clear(xhci_t *xhcip, intptr_t arg)
1860993e3fafSRobert Mustacchi {
1861993e3fafSRobert Mustacchi uint32_t reg;
1862993e3fafSRobert Mustacchi xhci_ioctl_clear_t xic;
1863993e3fafSRobert Mustacchi
1864993e3fafSRobert Mustacchi if (ddi_copyin((const void *)(uintptr_t)arg, &xic, sizeof (xic),
1865993e3fafSRobert Mustacchi 0) != 0)
1866993e3fafSRobert Mustacchi return (EFAULT);
1867993e3fafSRobert Mustacchi
1868993e3fafSRobert Mustacchi if (xic.xic_port == 0 || xic.xic_port >
1869993e3fafSRobert Mustacchi xhcip->xhci_caps.xcap_max_ports)
1870993e3fafSRobert Mustacchi return (EINVAL);
1871993e3fafSRobert Mustacchi
1872993e3fafSRobert Mustacchi reg = xhci_get32(xhcip, XHCI_R_OPER, XHCI_PORTSC(xic.xic_port));
1873993e3fafSRobert Mustacchi reg &= ~XHCI_PS_CLEAR;
1874993e3fafSRobert Mustacchi reg |= XHCI_PS_CSC | XHCI_PS_PEC | XHCI_PS_WRC | XHCI_PS_OCC |
1875993e3fafSRobert Mustacchi XHCI_PS_PRC | XHCI_PS_PLC | XHCI_PS_CEC;
1876993e3fafSRobert Mustacchi xhci_put32(xhcip, XHCI_R_OPER, XHCI_PORTSC(xic.xic_port), reg);
1877993e3fafSRobert Mustacchi
1878993e3fafSRobert Mustacchi return (0);
1879993e3fafSRobert Mustacchi }
1880993e3fafSRobert Mustacchi
1881993e3fafSRobert Mustacchi static int
xhci_ioctl_setpls(xhci_t * xhcip,intptr_t arg)1882993e3fafSRobert Mustacchi xhci_ioctl_setpls(xhci_t *xhcip, intptr_t arg)
1883993e3fafSRobert Mustacchi {
1884993e3fafSRobert Mustacchi uint32_t reg;
1885993e3fafSRobert Mustacchi xhci_ioctl_setpls_t xis;
1886993e3fafSRobert Mustacchi
1887993e3fafSRobert Mustacchi if (ddi_copyin((const void *)(uintptr_t)arg, &xis, sizeof (xis),
1888993e3fafSRobert Mustacchi 0) != 0)
1889993e3fafSRobert Mustacchi return (EFAULT);
1890993e3fafSRobert Mustacchi
1891993e3fafSRobert Mustacchi if (xis.xis_port == 0 || xis.xis_port >
1892993e3fafSRobert Mustacchi xhcip->xhci_caps.xcap_max_ports)
1893993e3fafSRobert Mustacchi return (EINVAL);
1894993e3fafSRobert Mustacchi
1895993e3fafSRobert Mustacchi if (xis.xis_pls & ~0xf)
1896993e3fafSRobert Mustacchi return (EINVAL);
1897993e3fafSRobert Mustacchi
1898993e3fafSRobert Mustacchi reg = xhci_get32(xhcip, XHCI_R_OPER, XHCI_PORTSC(xis.xis_port));
1899993e3fafSRobert Mustacchi reg &= ~XHCI_PS_CLEAR;
1900993e3fafSRobert Mustacchi reg |= XHCI_PS_PLS_SET(xis.xis_pls);
1901993e3fafSRobert Mustacchi reg |= XHCI_PS_LWS;
1902993e3fafSRobert Mustacchi xhci_put32(xhcip, XHCI_R_OPER, XHCI_PORTSC(xis.xis_port), reg);
1903993e3fafSRobert Mustacchi
1904993e3fafSRobert Mustacchi return (0);
1905993e3fafSRobert Mustacchi }
1906993e3fafSRobert Mustacchi
1907993e3fafSRobert Mustacchi static int
xhci_open(dev_t * devp,int flags,int otyp,cred_t * credp)1908993e3fafSRobert Mustacchi xhci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1909993e3fafSRobert Mustacchi {
1910993e3fafSRobert Mustacchi dev_info_t *dip = xhci_get_dip(*devp);
1911993e3fafSRobert Mustacchi
1912993e3fafSRobert Mustacchi return (usba_hubdi_open(dip, devp, flags, otyp, credp));
1913993e3fafSRobert Mustacchi }
1914993e3fafSRobert Mustacchi
1915993e3fafSRobert Mustacchi static int
xhci_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1916993e3fafSRobert Mustacchi xhci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1917993e3fafSRobert Mustacchi int *rvalp)
1918993e3fafSRobert Mustacchi {
1919993e3fafSRobert Mustacchi dev_info_t *dip = xhci_get_dip(dev);
1920993e3fafSRobert Mustacchi
1921993e3fafSRobert Mustacchi if (cmd == XHCI_IOCTL_PORTSC ||
1922993e3fafSRobert Mustacchi cmd == XHCI_IOCTL_CLEAR ||
1923993e3fafSRobert Mustacchi cmd == XHCI_IOCTL_SETPLS) {
1924993e3fafSRobert Mustacchi xhci_t *xhcip = ddi_get_soft_state(xhci_soft_state,
1925993e3fafSRobert Mustacchi getminor(dev) & ~HUBD_IS_ROOT_HUB);
1926993e3fafSRobert Mustacchi
1927047043c2SRobert Mustacchi if (secpolicy_hwmanip(credp) != 0 ||
1928993e3fafSRobert Mustacchi crgetzoneid(credp) != GLOBAL_ZONEID)
1929993e3fafSRobert Mustacchi return (EPERM);
1930993e3fafSRobert Mustacchi
1931993e3fafSRobert Mustacchi if (mode & FKIOCTL)
1932993e3fafSRobert Mustacchi return (ENOTSUP);
1933993e3fafSRobert Mustacchi
1934993e3fafSRobert Mustacchi if (!(mode & FWRITE))
1935993e3fafSRobert Mustacchi return (EBADF);
1936993e3fafSRobert Mustacchi
1937993e3fafSRobert Mustacchi if (cmd == XHCI_IOCTL_PORTSC)
1938993e3fafSRobert Mustacchi return (xhci_ioctl_portsc(xhcip, arg));
1939993e3fafSRobert Mustacchi else if (cmd == XHCI_IOCTL_CLEAR)
1940993e3fafSRobert Mustacchi return (xhci_ioctl_clear(xhcip, arg));
1941993e3fafSRobert Mustacchi else
1942993e3fafSRobert Mustacchi return (xhci_ioctl_setpls(xhcip, arg));
1943993e3fafSRobert Mustacchi }
1944993e3fafSRobert Mustacchi
1945993e3fafSRobert Mustacchi return (usba_hubdi_ioctl(dip, dev, cmd, arg, mode, credp, rvalp));
1946993e3fafSRobert Mustacchi }
1947993e3fafSRobert Mustacchi
1948993e3fafSRobert Mustacchi static int
xhci_close(dev_t dev,int flag,int otyp,cred_t * credp)1949993e3fafSRobert Mustacchi xhci_close(dev_t dev, int flag, int otyp, cred_t *credp)
1950993e3fafSRobert Mustacchi {
1951993e3fafSRobert Mustacchi dev_info_t *dip = xhci_get_dip(dev);
1952993e3fafSRobert Mustacchi
1953993e3fafSRobert Mustacchi return (usba_hubdi_close(dip, dev, flag, otyp, credp));
1954993e3fafSRobert Mustacchi }
1955993e3fafSRobert Mustacchi
1956993e3fafSRobert Mustacchi /*
1957993e3fafSRobert Mustacchi * We try to clean up everything that we can. The only thing that we let stop us
1958993e3fafSRobert Mustacchi * at this time is a failure to remove the root hub, which is realistically the
1959993e3fafSRobert Mustacchi * equivalent of our EBUSY case.
1960993e3fafSRobert Mustacchi */
1961993e3fafSRobert Mustacchi static int
xhci_cleanup(xhci_t * xhcip)1962993e3fafSRobert Mustacchi xhci_cleanup(xhci_t *xhcip)
1963993e3fafSRobert Mustacchi {
1964993e3fafSRobert Mustacchi int ret, inst;
1965993e3fafSRobert Mustacchi
1966993e3fafSRobert Mustacchi if (xhcip->xhci_seq & XHCI_ATTACH_ROOT_HUB) {
1967993e3fafSRobert Mustacchi if ((ret = xhci_root_hub_fini(xhcip)) != 0)
1968993e3fafSRobert Mustacchi return (ret);
1969993e3fafSRobert Mustacchi }
1970993e3fafSRobert Mustacchi
1971993e3fafSRobert Mustacchi if (xhcip->xhci_seq & XHCI_ATTACH_USBA) {
1972993e3fafSRobert Mustacchi xhci_hcd_fini(xhcip);
1973993e3fafSRobert Mustacchi }
1974993e3fafSRobert Mustacchi
1975993e3fafSRobert Mustacchi if (xhcip->xhci_seq & XHCI_ATTACH_STARTED) {
1976993e3fafSRobert Mustacchi mutex_enter(&xhcip->xhci_lock);
1977993e3fafSRobert Mustacchi while (xhcip->xhci_state & XHCI_S_ERROR)
1978993e3fafSRobert Mustacchi cv_wait(&xhcip->xhci_statecv, &xhcip->xhci_lock);
1979993e3fafSRobert Mustacchi mutex_exit(&xhcip->xhci_lock);
1980993e3fafSRobert Mustacchi
1981993e3fafSRobert Mustacchi (void) xhci_controller_stop(xhcip);
1982993e3fafSRobert Mustacchi }
1983993e3fafSRobert Mustacchi
1984993e3fafSRobert Mustacchi /*
1985993e3fafSRobert Mustacchi * Always release the context, command, and event data. They handle the
1986993e3fafSRobert Mustacchi * fact that they me be in an arbitrary state or unallocated.
1987993e3fafSRobert Mustacchi */
1988993e3fafSRobert Mustacchi xhci_event_fini(xhcip);
1989993e3fafSRobert Mustacchi xhci_command_ring_fini(xhcip);
1990993e3fafSRobert Mustacchi xhci_context_fini(xhcip);
1991993e3fafSRobert Mustacchi
1992993e3fafSRobert Mustacchi if (xhcip->xhci_seq & XHCI_ATTACH_INTR_ENABLE) {
1993993e3fafSRobert Mustacchi (void) xhci_ddi_intr_disable(xhcip);
1994993e3fafSRobert Mustacchi }
1995993e3fafSRobert Mustacchi
1996993e3fafSRobert Mustacchi if (xhcip->xhci_seq & XHCI_ATTACH_SYNCH) {
1997993e3fafSRobert Mustacchi cv_destroy(&xhcip->xhci_statecv);
1998993e3fafSRobert Mustacchi mutex_destroy(&xhcip->xhci_lock);
1999993e3fafSRobert Mustacchi }
2000993e3fafSRobert Mustacchi
2001993e3fafSRobert Mustacchi if (xhcip->xhci_seq & XHCI_ATTACH_INTR_ADD) {
2002993e3fafSRobert Mustacchi if ((ret = ddi_intr_remove_handler(xhcip->xhci_intr_hdl)) !=
2003993e3fafSRobert Mustacchi DDI_SUCCESS) {
2004993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to remove interrupt "
2005993e3fafSRobert Mustacchi "handler: %d", ret);
2006993e3fafSRobert Mustacchi }
2007993e3fafSRobert Mustacchi }
2008993e3fafSRobert Mustacchi
2009993e3fafSRobert Mustacchi if (xhcip->xhci_seq & XHCI_ATTACH_INTR_ALLOC) {
2010993e3fafSRobert Mustacchi if ((ret = ddi_intr_free(xhcip->xhci_intr_hdl)) !=
2011993e3fafSRobert Mustacchi DDI_SUCCESS) {
2012993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to free interrupts: %d", ret);
2013993e3fafSRobert Mustacchi }
2014993e3fafSRobert Mustacchi }
2015993e3fafSRobert Mustacchi
2016993e3fafSRobert Mustacchi if (xhcip->xhci_seq & XHCI_ATTACH_REGS_MAP) {
2017993e3fafSRobert Mustacchi ddi_regs_map_free(&xhcip->xhci_regs_handle);
2018993e3fafSRobert Mustacchi xhcip->xhci_regs_handle = NULL;
2019993e3fafSRobert Mustacchi }
2020993e3fafSRobert Mustacchi
2021993e3fafSRobert Mustacchi if (xhcip->xhci_seq & XHCI_ATTACH_PCI_CONFIG) {
2022993e3fafSRobert Mustacchi pci_config_teardown(&xhcip->xhci_cfg_handle);
2023993e3fafSRobert Mustacchi xhcip->xhci_cfg_handle = NULL;
2024993e3fafSRobert Mustacchi }
2025993e3fafSRobert Mustacchi
2026993e3fafSRobert Mustacchi if (xhcip->xhci_seq & XHCI_ATTACH_FM) {
2027993e3fafSRobert Mustacchi xhci_fm_fini(xhcip);
2028993e3fafSRobert Mustacchi xhcip->xhci_fm_caps = 0;
2029993e3fafSRobert Mustacchi }
2030993e3fafSRobert Mustacchi
2031993e3fafSRobert Mustacchi inst = ddi_get_instance(xhcip->xhci_dip);
2032993e3fafSRobert Mustacchi xhcip->xhci_dip = NULL;
2033993e3fafSRobert Mustacchi ddi_soft_state_free(xhci_soft_state, inst);
2034993e3fafSRobert Mustacchi
2035993e3fafSRobert Mustacchi return (DDI_SUCCESS);
2036993e3fafSRobert Mustacchi }
2037993e3fafSRobert Mustacchi
2038993e3fafSRobert Mustacchi static int
xhci_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2039993e3fafSRobert Mustacchi xhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2040993e3fafSRobert Mustacchi {
2041993e3fafSRobert Mustacchi int ret, inst, route;
2042993e3fafSRobert Mustacchi xhci_t *xhcip;
2043993e3fafSRobert Mustacchi
2044993e3fafSRobert Mustacchi if (cmd != DDI_ATTACH)
2045993e3fafSRobert Mustacchi return (DDI_FAILURE);
2046993e3fafSRobert Mustacchi
2047993e3fafSRobert Mustacchi inst = ddi_get_instance(dip);
2048993e3fafSRobert Mustacchi if (ddi_soft_state_zalloc(xhci_soft_state, inst) != 0)
2049993e3fafSRobert Mustacchi return (DDI_FAILURE);
2050993e3fafSRobert Mustacchi xhcip = ddi_get_soft_state(xhci_soft_state, ddi_get_instance(dip));
2051993e3fafSRobert Mustacchi xhcip->xhci_dip = dip;
2052993e3fafSRobert Mustacchi
2053993e3fafSRobert Mustacchi xhcip->xhci_regs_capoff = PCI_EINVAL32;
2054993e3fafSRobert Mustacchi xhcip->xhci_regs_operoff = PCI_EINVAL32;
2055993e3fafSRobert Mustacchi xhcip->xhci_regs_runoff = PCI_EINVAL32;
2056993e3fafSRobert Mustacchi xhcip->xhci_regs_dooroff = PCI_EINVAL32;
2057993e3fafSRobert Mustacchi
2058993e3fafSRobert Mustacchi xhci_fm_init(xhcip);
2059993e3fafSRobert Mustacchi xhcip->xhci_seq |= XHCI_ATTACH_FM;
2060993e3fafSRobert Mustacchi
2061993e3fafSRobert Mustacchi if (pci_config_setup(xhcip->xhci_dip, &xhcip->xhci_cfg_handle) !=
2062993e3fafSRobert Mustacchi DDI_SUCCESS) {
2063993e3fafSRobert Mustacchi goto err;
2064993e3fafSRobert Mustacchi }
2065993e3fafSRobert Mustacchi xhcip->xhci_seq |= XHCI_ATTACH_PCI_CONFIG;
2066993e3fafSRobert Mustacchi xhcip->xhci_vendor_id = pci_config_get16(xhcip->xhci_cfg_handle,
2067993e3fafSRobert Mustacchi PCI_CONF_VENID);
2068993e3fafSRobert Mustacchi xhcip->xhci_device_id = pci_config_get16(xhcip->xhci_cfg_handle,
2069993e3fafSRobert Mustacchi PCI_CONF_DEVID);
2070993e3fafSRobert Mustacchi
2071993e3fafSRobert Mustacchi if (xhci_regs_map(xhcip) == B_FALSE) {
2072993e3fafSRobert Mustacchi goto err;
2073993e3fafSRobert Mustacchi }
2074993e3fafSRobert Mustacchi
2075993e3fafSRobert Mustacchi xhcip->xhci_seq |= XHCI_ATTACH_REGS_MAP;
2076993e3fafSRobert Mustacchi
2077993e3fafSRobert Mustacchi if (xhci_regs_init(xhcip) == B_FALSE)
2078993e3fafSRobert Mustacchi goto err;
2079993e3fafSRobert Mustacchi
2080993e3fafSRobert Mustacchi if (xhci_read_params(xhcip) == B_FALSE)
2081993e3fafSRobert Mustacchi goto err;
2082993e3fafSRobert Mustacchi
2083993e3fafSRobert Mustacchi if (xhci_identify(xhcip) == B_FALSE)
2084993e3fafSRobert Mustacchi goto err;
2085993e3fafSRobert Mustacchi
2086993e3fafSRobert Mustacchi if (xhci_alloc_intrs(xhcip) == B_FALSE)
2087993e3fafSRobert Mustacchi goto err;
2088993e3fafSRobert Mustacchi xhcip->xhci_seq |= XHCI_ATTACH_INTR_ALLOC;
2089993e3fafSRobert Mustacchi
2090993e3fafSRobert Mustacchi if (xhci_add_intr_handler(xhcip) == B_FALSE)
2091993e3fafSRobert Mustacchi goto err;
2092993e3fafSRobert Mustacchi xhcip->xhci_seq |= XHCI_ATTACH_INTR_ADD;
2093993e3fafSRobert Mustacchi
2094993e3fafSRobert Mustacchi mutex_init(&xhcip->xhci_lock, NULL, MUTEX_DRIVER,
2095993e3fafSRobert Mustacchi (void *)(uintptr_t)xhcip->xhci_intr_pri);
2096993e3fafSRobert Mustacchi cv_init(&xhcip->xhci_statecv, NULL, CV_DRIVER, NULL);
2097993e3fafSRobert Mustacchi xhcip->xhci_seq |= XHCI_ATTACH_SYNCH;
2098993e3fafSRobert Mustacchi
2099993e3fafSRobert Mustacchi if (xhci_port_count(xhcip) == B_FALSE)
2100993e3fafSRobert Mustacchi goto err;
2101993e3fafSRobert Mustacchi
2102993e3fafSRobert Mustacchi if (xhci_controller_takeover(xhcip) == B_FALSE)
2103993e3fafSRobert Mustacchi goto err;
2104993e3fafSRobert Mustacchi
2105993e3fafSRobert Mustacchi /*
2106993e3fafSRobert Mustacchi * We don't enable interrupts until after we take over the controller
2107993e3fafSRobert Mustacchi * from the BIOS. We've observed cases where this can cause spurious
2108993e3fafSRobert Mustacchi * interrupts.
2109993e3fafSRobert Mustacchi */
2110993e3fafSRobert Mustacchi if (xhci_ddi_intr_enable(xhcip) == B_FALSE)
2111993e3fafSRobert Mustacchi goto err;
2112993e3fafSRobert Mustacchi xhcip->xhci_seq |= XHCI_ATTACH_INTR_ENABLE;
2113993e3fafSRobert Mustacchi
2114993e3fafSRobert Mustacchi if ((ret = xhci_controller_stop(xhcip)) != 0) {
2115993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to stop controller: %s",
2116993e3fafSRobert Mustacchi ret == EIO ? "encountered FM register error" :
2117993e3fafSRobert Mustacchi "timed out while waiting for controller");
2118993e3fafSRobert Mustacchi goto err;
2119993e3fafSRobert Mustacchi }
2120993e3fafSRobert Mustacchi
2121993e3fafSRobert Mustacchi if ((ret = xhci_controller_reset(xhcip)) != 0) {
2122993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to reset controller: %s",
2123993e3fafSRobert Mustacchi ret == EIO ? "encountered FM register error" :
2124993e3fafSRobert Mustacchi "timed out while waiting for controller");
2125993e3fafSRobert Mustacchi goto err;
2126993e3fafSRobert Mustacchi }
2127993e3fafSRobert Mustacchi
2128993e3fafSRobert Mustacchi if ((ret = xhci_controller_configure(xhcip)) != 0) {
2129993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to configure controller: %d", ret);
2130993e3fafSRobert Mustacchi goto err;
2131993e3fafSRobert Mustacchi }
2132993e3fafSRobert Mustacchi
2133993e3fafSRobert Mustacchi /*
2134993e3fafSRobert Mustacchi * Some systems support having ports routed to both an ehci and xhci
2135993e3fafSRobert Mustacchi * controller. If we support it and the user hasn't requested otherwise
2136993e3fafSRobert Mustacchi * via a driver.conf tuning, we reroute it now.
2137993e3fafSRobert Mustacchi */
2138993e3fafSRobert Mustacchi route = ddi_prop_get_int(DDI_DEV_T_ANY, xhcip->xhci_dip,
2139993e3fafSRobert Mustacchi DDI_PROP_DONTPASS, "xhci-reroute", XHCI_PROP_REROUTE_DEFAULT);
2140993e3fafSRobert Mustacchi if (route != XHCI_PROP_REROUTE_DISABLE &&
2141993e3fafSRobert Mustacchi (xhcip->xhci_quirks & XHCI_QUIRK_INTC_EHCI))
2142993e3fafSRobert Mustacchi (void) xhci_reroute_intel(xhcip);
2143993e3fafSRobert Mustacchi
2144993e3fafSRobert Mustacchi if ((ret = xhci_controller_start(xhcip)) != 0) {
2145993e3fafSRobert Mustacchi xhci_log(xhcip, "failed to reset controller: %s",
2146993e3fafSRobert Mustacchi ret == EIO ? "encountered FM register error" :
2147993e3fafSRobert Mustacchi "timed out while waiting for controller");
2148993e3fafSRobert Mustacchi goto err;
2149993e3fafSRobert Mustacchi }
2150993e3fafSRobert Mustacchi xhcip->xhci_seq |= XHCI_ATTACH_STARTED;
2151993e3fafSRobert Mustacchi
2152993e3fafSRobert Mustacchi /*
2153993e3fafSRobert Mustacchi * Finally, register ourselves with the USB framework itself.
2154993e3fafSRobert Mustacchi */
2155993e3fafSRobert Mustacchi if ((ret = xhci_hcd_init(xhcip)) != 0) {
2156993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to register hcd with usba");
2157993e3fafSRobert Mustacchi goto err;
2158993e3fafSRobert Mustacchi }
2159993e3fafSRobert Mustacchi xhcip->xhci_seq |= XHCI_ATTACH_USBA;
2160993e3fafSRobert Mustacchi
2161993e3fafSRobert Mustacchi if ((ret = xhci_root_hub_init(xhcip)) != 0) {
2162993e3fafSRobert Mustacchi xhci_error(xhcip, "failed to load the root hub driver");
2163993e3fafSRobert Mustacchi goto err;
2164993e3fafSRobert Mustacchi }
2165993e3fafSRobert Mustacchi xhcip->xhci_seq |= XHCI_ATTACH_ROOT_HUB;
2166993e3fafSRobert Mustacchi
2167993e3fafSRobert Mustacchi return (DDI_SUCCESS);
2168993e3fafSRobert Mustacchi
2169993e3fafSRobert Mustacchi err:
2170993e3fafSRobert Mustacchi (void) xhci_cleanup(xhcip);
2171993e3fafSRobert Mustacchi return (DDI_FAILURE);
2172993e3fafSRobert Mustacchi }
2173993e3fafSRobert Mustacchi
2174993e3fafSRobert Mustacchi static int
xhci_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2175993e3fafSRobert Mustacchi xhci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2176993e3fafSRobert Mustacchi {
2177993e3fafSRobert Mustacchi xhci_t *xhcip;
2178993e3fafSRobert Mustacchi
2179993e3fafSRobert Mustacchi if (cmd != DDI_DETACH)
2180993e3fafSRobert Mustacchi return (DDI_FAILURE);
2181993e3fafSRobert Mustacchi
2182993e3fafSRobert Mustacchi xhcip = ddi_get_soft_state(xhci_soft_state, ddi_get_instance(dip));
2183993e3fafSRobert Mustacchi if (xhcip == NULL) {
2184993e3fafSRobert Mustacchi dev_err(dip, CE_WARN, "detach called without soft state!");
2185993e3fafSRobert Mustacchi return (DDI_FAILURE);
2186993e3fafSRobert Mustacchi }
2187993e3fafSRobert Mustacchi
2188993e3fafSRobert Mustacchi return (xhci_cleanup(xhcip));
2189993e3fafSRobert Mustacchi }
2190993e3fafSRobert Mustacchi
2191993e3fafSRobert Mustacchi /* ARGSUSED */
2192993e3fafSRobert Mustacchi static int
xhci_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** outp)2193993e3fafSRobert Mustacchi xhci_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **outp)
2194993e3fafSRobert Mustacchi {
2195993e3fafSRobert Mustacchi dev_t dev;
2196993e3fafSRobert Mustacchi int inst;
2197993e3fafSRobert Mustacchi
2198993e3fafSRobert Mustacchi switch (cmd) {
2199993e3fafSRobert Mustacchi case DDI_INFO_DEVT2DEVINFO:
2200993e3fafSRobert Mustacchi dev = (dev_t)arg;
2201993e3fafSRobert Mustacchi *outp = xhci_get_dip(dev);
2202993e3fafSRobert Mustacchi if (*outp == NULL)
2203993e3fafSRobert Mustacchi return (DDI_FAILURE);
2204993e3fafSRobert Mustacchi break;
2205993e3fafSRobert Mustacchi case DDI_INFO_DEVT2INSTANCE:
2206993e3fafSRobert Mustacchi dev = (dev_t)arg;
2207993e3fafSRobert Mustacchi inst = getminor(dev) & ~HUBD_IS_ROOT_HUB;
2208993e3fafSRobert Mustacchi *outp = (void *)(uintptr_t)inst;
2209993e3fafSRobert Mustacchi break;
2210993e3fafSRobert Mustacchi default:
2211993e3fafSRobert Mustacchi return (DDI_FAILURE);
2212993e3fafSRobert Mustacchi }
2213993e3fafSRobert Mustacchi
2214993e3fafSRobert Mustacchi return (DDI_SUCCESS);
2215993e3fafSRobert Mustacchi }
2216993e3fafSRobert Mustacchi
2217993e3fafSRobert Mustacchi static struct cb_ops xhci_cb_ops = {
2218993e3fafSRobert Mustacchi xhci_open, /* cb_open */
2219993e3fafSRobert Mustacchi xhci_close, /* cb_close */
2220993e3fafSRobert Mustacchi nodev, /* cb_strategy */
2221993e3fafSRobert Mustacchi nodev, /* cb_print */
2222993e3fafSRobert Mustacchi nodev, /* cb_dump */
2223993e3fafSRobert Mustacchi nodev, /* cb_read */
2224993e3fafSRobert Mustacchi nodev, /* cb_write */
2225993e3fafSRobert Mustacchi xhci_ioctl, /* cb_ioctl */
2226993e3fafSRobert Mustacchi nodev, /* cb_devmap */
2227993e3fafSRobert Mustacchi nodev, /* cb_mmap */
2228993e3fafSRobert Mustacchi nodev, /* cb_segmap */
2229993e3fafSRobert Mustacchi nochpoll, /* cb_chpoll */
2230993e3fafSRobert Mustacchi ddi_prop_op, /* cb_prop_op */
2231993e3fafSRobert Mustacchi NULL, /* cb_stream */
2232993e3fafSRobert Mustacchi D_MP | D_HOTPLUG, /* cb_flag */
2233993e3fafSRobert Mustacchi CB_REV, /* cb_rev */
2234993e3fafSRobert Mustacchi nodev, /* cb_aread */
2235993e3fafSRobert Mustacchi nodev /* cb_awrite */
2236993e3fafSRobert Mustacchi };
2237993e3fafSRobert Mustacchi
2238993e3fafSRobert Mustacchi static struct dev_ops xhci_dev_ops = {
2239993e3fafSRobert Mustacchi DEVO_REV, /* devo_rev */
2240993e3fafSRobert Mustacchi 0, /* devo_refcnt */
2241993e3fafSRobert Mustacchi xhci_getinfo, /* devo_getinfo */
2242993e3fafSRobert Mustacchi nulldev, /* devo_identify */
2243993e3fafSRobert Mustacchi nulldev, /* devo_probe */
2244993e3fafSRobert Mustacchi xhci_attach, /* devo_attach */
2245993e3fafSRobert Mustacchi xhci_detach, /* devo_detach */
2246993e3fafSRobert Mustacchi nodev, /* devo_reset */
2247993e3fafSRobert Mustacchi &xhci_cb_ops, /* devo_cb_ops */
2248993e3fafSRobert Mustacchi &usba_hubdi_busops, /* devo_bus_ops */
2249993e3fafSRobert Mustacchi usba_hubdi_root_hub_power, /* devo_power */
2250672fc84aSRobert Mustacchi ddi_quiesce_not_supported /* devo_quiesce */
2251993e3fafSRobert Mustacchi };
2252993e3fafSRobert Mustacchi
2253993e3fafSRobert Mustacchi static struct modldrv xhci_modldrv = {
2254993e3fafSRobert Mustacchi &mod_driverops,
2255993e3fafSRobert Mustacchi "USB xHCI Driver",
2256993e3fafSRobert Mustacchi &xhci_dev_ops
2257993e3fafSRobert Mustacchi };
2258993e3fafSRobert Mustacchi
2259993e3fafSRobert Mustacchi static struct modlinkage xhci_modlinkage = {
2260993e3fafSRobert Mustacchi MODREV_1,
2261993e3fafSRobert Mustacchi &xhci_modldrv,
2262993e3fafSRobert Mustacchi NULL
2263993e3fafSRobert Mustacchi };
2264993e3fafSRobert Mustacchi
2265993e3fafSRobert Mustacchi int
_init(void)2266993e3fafSRobert Mustacchi _init(void)
2267993e3fafSRobert Mustacchi {
2268993e3fafSRobert Mustacchi int ret;
2269993e3fafSRobert Mustacchi
2270993e3fafSRobert Mustacchi if ((ret = ddi_soft_state_init(&xhci_soft_state, sizeof (xhci_t),
2271993e3fafSRobert Mustacchi 0)) != 0) {
2272993e3fafSRobert Mustacchi return (ret);
2273993e3fafSRobert Mustacchi }
2274993e3fafSRobert Mustacchi
2275993e3fafSRobert Mustacchi xhci_taskq = taskq_create("xhci_taskq", 1, minclsyspri, 0, 0, 0);
2276993e3fafSRobert Mustacchi if (xhci_taskq == NULL) {
2277993e3fafSRobert Mustacchi ddi_soft_state_fini(&xhci_soft_state);
2278993e3fafSRobert Mustacchi return (ENOMEM);
2279993e3fafSRobert Mustacchi }
2280993e3fafSRobert Mustacchi
2281993e3fafSRobert Mustacchi if ((ret = mod_install(&xhci_modlinkage)) != 0) {
2282993e3fafSRobert Mustacchi taskq_destroy(xhci_taskq);
2283993e3fafSRobert Mustacchi xhci_taskq = NULL;
2284993e3fafSRobert Mustacchi }
2285993e3fafSRobert Mustacchi
2286993e3fafSRobert Mustacchi return (ret);
2287993e3fafSRobert Mustacchi }
2288993e3fafSRobert Mustacchi
2289993e3fafSRobert Mustacchi int
_info(struct modinfo * modinfop)2290993e3fafSRobert Mustacchi _info(struct modinfo *modinfop)
2291993e3fafSRobert Mustacchi {
2292993e3fafSRobert Mustacchi return (mod_info(&xhci_modlinkage, modinfop));
2293993e3fafSRobert Mustacchi }
2294993e3fafSRobert Mustacchi
2295993e3fafSRobert Mustacchi int
_fini(void)2296993e3fafSRobert Mustacchi _fini(void)
2297993e3fafSRobert Mustacchi {
2298993e3fafSRobert Mustacchi int ret;
2299993e3fafSRobert Mustacchi
2300993e3fafSRobert Mustacchi if ((ret = mod_remove(&xhci_modlinkage)) != 0)
2301993e3fafSRobert Mustacchi return (ret);
2302993e3fafSRobert Mustacchi
2303993e3fafSRobert Mustacchi if (xhci_taskq != NULL) {
2304993e3fafSRobert Mustacchi taskq_destroy(xhci_taskq);
2305993e3fafSRobert Mustacchi xhci_taskq = NULL;
2306993e3fafSRobert Mustacchi }
2307993e3fafSRobert Mustacchi
2308993e3fafSRobert Mustacchi ddi_soft_state_fini(&xhci_soft_state);
2309993e3fafSRobert Mustacchi
2310993e3fafSRobert Mustacchi return (0);
2311993e3fafSRobert Mustacchi }
2312