]>
Commit | Line | Data |
---|---|---|
9a75b0a0 JS |
1 | /* |
2 | * libqos AHCI functions | |
3 | * | |
4 | * Copyright (c) 2014 John Snow <[email protected]> | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | * of this software and associated documentation files (the "Software"), to deal | |
8 | * in the Software without restriction, including without limitation the rights | |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | * copies of the Software, and to permit persons to whom the Software is | |
11 | * furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in | |
14 | * all copies or substantial portions of the Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | * THE SOFTWARE. | |
23 | */ | |
24 | ||
25 | #include <glib.h> | |
26 | ||
27 | #include "libqtest.h" | |
28 | #include "libqos/ahci.h" | |
29 | #include "libqos/pci-pc.h" | |
30 | ||
31 | #include "qemu-common.h" | |
32 | #include "qemu/host-utils.h" | |
33 | ||
34 | #include "hw/pci/pci_ids.h" | |
35 | #include "hw/pci/pci_regs.h" | |
36 | ||
37 | /** | |
38 | * Allocate space in the guest using information in the AHCIQState object. | |
39 | */ | |
40 | uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes) | |
41 | { | |
42 | g_assert(ahci); | |
43 | g_assert(ahci->parent); | |
44 | return qmalloc(ahci->parent, bytes); | |
45 | } | |
46 | ||
47 | void ahci_free(AHCIQState *ahci, uint64_t addr) | |
48 | { | |
49 | g_assert(ahci); | |
50 | g_assert(ahci->parent); | |
51 | qfree(ahci->parent, addr); | |
52 | } | |
53 | ||
54 | /** | |
55 | * Locate, verify, and return a handle to the AHCI device. | |
56 | */ | |
57 | QPCIDevice *get_ahci_device(uint32_t *fingerprint) | |
58 | { | |
59 | QPCIDevice *ahci; | |
60 | uint32_t ahci_fingerprint; | |
61 | QPCIBus *pcibus; | |
62 | ||
63 | pcibus = qpci_init_pc(); | |
64 | ||
65 | /* Find the AHCI PCI device and verify it's the right one. */ | |
66 | ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02)); | |
67 | g_assert(ahci != NULL); | |
68 | ||
69 | ahci_fingerprint = qpci_config_readl(ahci, PCI_VENDOR_ID); | |
70 | ||
71 | switch (ahci_fingerprint) { | |
72 | case AHCI_INTEL_ICH9: | |
73 | break; | |
74 | default: | |
75 | /* Unknown device. */ | |
76 | g_assert_not_reached(); | |
77 | } | |
78 | ||
79 | if (fingerprint) { | |
80 | *fingerprint = ahci_fingerprint; | |
81 | } | |
82 | return ahci; | |
83 | } | |
84 | ||
85 | void free_ahci_device(QPCIDevice *dev) | |
86 | { | |
87 | QPCIBus *pcibus = dev ? dev->bus : NULL; | |
88 | ||
89 | /* libqos doesn't have a function for this, so free it manually */ | |
90 | g_free(dev); | |
91 | qpci_free_pc(pcibus); | |
92 | } | |
93 | ||
94 | /*** Logical Device Initialization ***/ | |
95 | ||
96 | /** | |
97 | * Start the PCI device and sanity-check default operation. | |
98 | */ | |
99 | void ahci_pci_enable(AHCIQState *ahci) | |
100 | { | |
101 | uint8_t reg; | |
102 | ||
103 | start_ahci_device(ahci); | |
104 | ||
105 | switch (ahci->fingerprint) { | |
106 | case AHCI_INTEL_ICH9: | |
107 | /* ICH9 has a register at PCI 0x92 that | |
108 | * acts as a master port enabler mask. */ | |
109 | reg = qpci_config_readb(ahci->dev, 0x92); | |
110 | reg |= 0x3F; | |
111 | qpci_config_writeb(ahci->dev, 0x92, reg); | |
112 | /* 0...0111111b -- bit significant, ports 0-5 enabled. */ | |
113 | ASSERT_BIT_SET(qpci_config_readb(ahci->dev, 0x92), 0x3F); | |
114 | break; | |
115 | } | |
116 | ||
117 | } | |
118 | ||
119 | /** | |
120 | * Map BAR5/ABAR, and engage the PCI device. | |
121 | */ | |
122 | void start_ahci_device(AHCIQState *ahci) | |
123 | { | |
124 | /* Map AHCI's ABAR (BAR5) */ | |
125 | ahci->hba_base = qpci_iomap(ahci->dev, 5, &ahci->barsize); | |
126 | g_assert(ahci->hba_base); | |
127 | ||
128 | /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */ | |
129 | qpci_device_enable(ahci->dev); | |
130 | } | |
131 | ||
132 | /** | |
133 | * Test and initialize the AHCI's HBA memory areas. | |
134 | * Initialize and start any ports with devices attached. | |
135 | * Bring the HBA into the idle state. | |
136 | */ | |
137 | void ahci_hba_enable(AHCIQState *ahci) | |
138 | { | |
139 | /* Bits of interest in this section: | |
140 | * GHC.AE Global Host Control / AHCI Enable | |
141 | * PxCMD.ST Port Command: Start | |
142 | * PxCMD.SUD "Spin Up Device" | |
143 | * PxCMD.POD "Power On Device" | |
144 | * PxCMD.FRE "FIS Receive Enable" | |
145 | * PxCMD.FR "FIS Receive Running" | |
146 | * PxCMD.CR "Command List Running" | |
147 | */ | |
148 | uint32_t reg, ports_impl; | |
149 | uint16_t i; | |
150 | uint8_t num_cmd_slots; | |
151 | ||
152 | g_assert(ahci != NULL); | |
153 | ||
154 | /* Set GHC.AE to 1 */ | |
155 | ahci_set(ahci, AHCI_GHC, AHCI_GHC_AE); | |
156 | reg = ahci_rreg(ahci, AHCI_GHC); | |
157 | ASSERT_BIT_SET(reg, AHCI_GHC_AE); | |
158 | ||
159 | /* Cache CAP and CAP2. */ | |
160 | ahci->cap = ahci_rreg(ahci, AHCI_CAP); | |
161 | ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2); | |
162 | ||
163 | /* Read CAP.NCS, how many command slots do we have? */ | |
164 | num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1; | |
165 | g_test_message("Number of Command Slots: %u", num_cmd_slots); | |
166 | ||
167 | /* Determine which ports are implemented. */ | |
168 | ports_impl = ahci_rreg(ahci, AHCI_PI); | |
169 | ||
170 | for (i = 0; ports_impl; ports_impl >>= 1, ++i) { | |
171 | if (!(ports_impl & 0x01)) { | |
172 | continue; | |
173 | } | |
174 | ||
175 | g_test_message("Initializing port %u", i); | |
176 | ||
177 | reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); | |
178 | if (BITCLR(reg, AHCI_PX_CMD_ST | AHCI_PX_CMD_CR | | |
179 | AHCI_PX_CMD_FRE | AHCI_PX_CMD_FR)) { | |
180 | g_test_message("port is idle"); | |
181 | } else { | |
182 | g_test_message("port needs to be idled"); | |
183 | ahci_px_clr(ahci, i, AHCI_PX_CMD, | |
184 | (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE)); | |
185 | /* The port has 500ms to disengage. */ | |
186 | usleep(500000); | |
187 | reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); | |
188 | ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR); | |
189 | ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR); | |
190 | g_test_message("port is now idle"); | |
191 | /* The spec does allow for possibly needing a PORT RESET | |
192 | * or HBA reset if we fail to idle the port. */ | |
193 | } | |
194 | ||
195 | /* Allocate Memory for the Command List Buffer & FIS Buffer */ | |
196 | /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */ | |
197 | ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20); | |
198 | qmemset(ahci->port[i].clb, 0x00, 0x100); | |
199 | g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb); | |
200 | ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb); | |
201 | g_assert_cmphex(ahci->port[i].clb, ==, | |
202 | ahci_px_rreg(ahci, i, AHCI_PX_CLB)); | |
203 | ||
204 | /* PxFB space ... 0x100, as in 4.2.1 p 35 */ | |
205 | ahci->port[i].fb = ahci_alloc(ahci, 0x100); | |
206 | qmemset(ahci->port[i].fb, 0x00, 0x100); | |
207 | g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb); | |
208 | ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb); | |
209 | g_assert_cmphex(ahci->port[i].fb, ==, | |
210 | ahci_px_rreg(ahci, i, AHCI_PX_FB)); | |
211 | ||
212 | /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */ | |
213 | ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF); | |
214 | ahci_px_wreg(ahci, i, AHCI_PX_IS, 0xFFFFFFFF); | |
215 | ahci_wreg(ahci, AHCI_IS, (1 << i)); | |
216 | ||
217 | /* Verify Interrupts Cleared */ | |
218 | reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); | |
219 | g_assert_cmphex(reg, ==, 0); | |
220 | ||
221 | reg = ahci_px_rreg(ahci, i, AHCI_PX_IS); | |
222 | g_assert_cmphex(reg, ==, 0); | |
223 | ||
224 | reg = ahci_rreg(ahci, AHCI_IS); | |
225 | ASSERT_BIT_CLEAR(reg, (1 << i)); | |
226 | ||
227 | /* Enable All Interrupts: */ | |
228 | ahci_px_wreg(ahci, i, AHCI_PX_IE, 0xFFFFFFFF); | |
229 | reg = ahci_px_rreg(ahci, i, AHCI_PX_IE); | |
230 | g_assert_cmphex(reg, ==, ~((uint32_t)AHCI_PX_IE_RESERVED)); | |
231 | ||
232 | /* Enable the FIS Receive Engine. */ | |
233 | ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_FRE); | |
234 | reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); | |
235 | ASSERT_BIT_SET(reg, AHCI_PX_CMD_FR); | |
236 | ||
237 | /* AHCI 1.3 spec: if !STS.BSY, !STS.DRQ and PxSSTS.DET indicates | |
238 | * physical presence, a device is present and may be started. However, | |
239 | * PxSERR.DIAG.X /may/ need to be cleared a priori. */ | |
240 | reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); | |
241 | if (BITSET(reg, AHCI_PX_SERR_DIAG_X)) { | |
242 | ahci_px_set(ahci, i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X); | |
243 | } | |
244 | ||
245 | reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD); | |
246 | if (BITCLR(reg, AHCI_PX_TFD_STS_BSY | AHCI_PX_TFD_STS_DRQ)) { | |
247 | reg = ahci_px_rreg(ahci, i, AHCI_PX_SSTS); | |
248 | if ((reg & AHCI_PX_SSTS_DET) == SSTS_DET_ESTABLISHED) { | |
249 | /* Device Found: set PxCMD.ST := 1 */ | |
250 | ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_ST); | |
251 | ASSERT_BIT_SET(ahci_px_rreg(ahci, i, AHCI_PX_CMD), | |
252 | AHCI_PX_CMD_CR); | |
253 | g_test_message("Started Device %u", i); | |
254 | } else if ((reg & AHCI_PX_SSTS_DET)) { | |
255 | /* Device present, but in some unknown state. */ | |
256 | g_assert_not_reached(); | |
257 | } | |
258 | } | |
259 | } | |
260 | ||
261 | /* Enable GHC.IE */ | |
262 | ahci_set(ahci, AHCI_GHC, AHCI_GHC_IE); | |
263 | reg = ahci_rreg(ahci, AHCI_GHC); | |
264 | ASSERT_BIT_SET(reg, AHCI_GHC_IE); | |
265 | ||
266 | /* TODO: The device should now be idling and waiting for commands. | |
267 | * In the future, a small test-case to inspect the Register D2H FIS | |
268 | * and clear the initial interrupts might be good. */ | |
269 | } | |
e77448a3 JS |
270 | |
271 | /** | |
272 | * Pick the first implemented and running port | |
273 | */ | |
274 | unsigned ahci_port_select(AHCIQState *ahci) | |
275 | { | |
276 | uint32_t ports, reg; | |
277 | unsigned i; | |
278 | ||
279 | ports = ahci_rreg(ahci, AHCI_PI); | |
280 | for (i = 0; i < 32; ports >>= 1, ++i) { | |
281 | if (ports == 0) { | |
282 | i = 32; | |
283 | } | |
284 | ||
285 | if (!(ports & 0x01)) { | |
286 | continue; | |
287 | } | |
288 | ||
289 | reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); | |
290 | if (BITSET(reg, AHCI_PX_CMD_ST)) { | |
291 | break; | |
292 | } | |
293 | } | |
294 | g_assert(i < 32); | |
295 | return i; | |
296 | } | |
e83fd96b JS |
297 | |
298 | /** | |
299 | * Clear a port's interrupts and status information prior to a test. | |
300 | */ | |
301 | void ahci_port_clear(AHCIQState *ahci, uint8_t port) | |
302 | { | |
303 | uint32_t reg; | |
304 | ||
305 | /* Clear out this port's interrupts (ignore the init register d2h fis) */ | |
306 | reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); | |
307 | ahci_px_wreg(ahci, port, AHCI_PX_IS, reg); | |
308 | g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0); | |
309 | ||
310 | /* Wipe the FIS-Recieve Buffer */ | |
311 | qmemset(ahci->port[port].fb, 0x00, 0x100); | |
312 | } | |
6cae27a6 | 313 | |
85c34e93 JS |
314 | /** |
315 | * Check a port for errors. | |
316 | */ | |
317 | void ahci_port_check_error(AHCIQState *ahci, uint8_t port) | |
318 | { | |
319 | uint32_t reg; | |
320 | ||
321 | /* The upper 9 bits of the IS register all indicate errors. */ | |
322 | reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); | |
323 | reg >>= 23; | |
324 | g_assert_cmphex(reg, ==, 0); | |
325 | ||
326 | /* The Sata Error Register should be empty. */ | |
327 | reg = ahci_px_rreg(ahci, port, AHCI_PX_SERR); | |
328 | g_assert_cmphex(reg, ==, 0); | |
329 | ||
330 | /* The TFD also has two error sections. */ | |
331 | reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD); | |
332 | ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR); | |
333 | ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR); | |
334 | } | |
335 | ||
5bf99aa1 JS |
336 | void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, |
337 | uint32_t intr_mask) | |
338 | { | |
339 | uint32_t reg; | |
340 | ||
341 | /* Check for expected interrupts */ | |
342 | reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); | |
343 | ASSERT_BIT_SET(reg, intr_mask); | |
344 | ||
345 | /* Clear expected interrupts and assert all interrupts now cleared. */ | |
346 | ahci_px_wreg(ahci, port, AHCI_PX_IS, intr_mask); | |
347 | g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0); | |
348 | } | |
349 | ||
89a46723 JS |
350 | void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot) |
351 | { | |
352 | uint32_t reg; | |
353 | ||
354 | /* Assert that the command slot is no longer busy (NCQ) */ | |
355 | reg = ahci_px_rreg(ahci, port, AHCI_PX_SACT); | |
356 | ASSERT_BIT_CLEAR(reg, (1 << slot)); | |
357 | ||
358 | /* Non-NCQ */ | |
359 | reg = ahci_px_rreg(ahci, port, AHCI_PX_CI); | |
360 | ASSERT_BIT_CLEAR(reg, (1 << slot)); | |
361 | ||
362 | /* And assert that we are generally not busy. */ | |
363 | reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD); | |
364 | ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_BSY); | |
365 | ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_DRQ); | |
366 | } | |
367 | ||
6cae27a6 JS |
368 | /* Get the command in #slot of port #port. */ |
369 | void ahci_get_command_header(AHCIQState *ahci, uint8_t port, | |
370 | uint8_t slot, AHCICommandHeader *cmd) | |
371 | { | |
372 | uint64_t ba = ahci->port[port].clb; | |
373 | ba += slot * sizeof(AHCICommandHeader); | |
374 | memread(ba, cmd, sizeof(AHCICommandHeader)); | |
375 | ||
376 | cmd->flags = le16_to_cpu(cmd->flags); | |
377 | cmd->prdtl = le16_to_cpu(cmd->prdtl); | |
378 | cmd->prdbc = le32_to_cpu(cmd->prdbc); | |
379 | cmd->ctba = le64_to_cpu(cmd->ctba); | |
380 | } | |
381 | ||
382 | /* Set the command in #slot of port #port. */ | |
383 | void ahci_set_command_header(AHCIQState *ahci, uint8_t port, | |
384 | uint8_t slot, AHCICommandHeader *cmd) | |
385 | { | |
386 | AHCICommandHeader tmp; | |
387 | uint64_t ba = ahci->port[port].clb; | |
388 | ba += slot * sizeof(AHCICommandHeader); | |
389 | ||
390 | tmp.flags = cpu_to_le16(cmd->flags); | |
391 | tmp.prdtl = cpu_to_le16(cmd->prdtl); | |
392 | tmp.prdbc = cpu_to_le32(cmd->prdbc); | |
393 | tmp.ctba = cpu_to_le64(cmd->ctba); | |
394 | ||
395 | memwrite(ba, &tmp, sizeof(AHCICommandHeader)); | |
396 | } | |
397 | ||
398 | void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot) | |
399 | { | |
400 | AHCICommandHeader cmd; | |
401 | ||
402 | /* Obtain the Nth Command Header */ | |
403 | ahci_get_command_header(ahci, port, slot, &cmd); | |
404 | if (cmd.ctba == 0) { | |
405 | /* No address in it, so just return -- it's empty. */ | |
406 | goto tidy; | |
407 | } | |
408 | ||
409 | /* Free the Table */ | |
410 | ahci_free(ahci, cmd.ctba); | |
411 | ||
412 | tidy: | |
413 | /* NULL the header. */ | |
414 | memset(&cmd, 0x00, sizeof(cmd)); | |
415 | ahci_set_command_header(ahci, port, slot, &cmd); | |
416 | ahci->port[port].ctba[slot] = 0; | |
417 | ahci->port[port].prdtl[slot] = 0; | |
418 | } | |
419 | ||
420 | unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port) | |
421 | { | |
422 | unsigned i; | |
423 | unsigned j; | |
424 | uint32_t reg; | |
425 | ||
426 | reg = ahci_px_rreg(ahci, port, AHCI_PX_CI); | |
427 | ||
428 | /* Pick the least recently used command slot that's available */ | |
429 | for (i = 0; i < 32; ++i) { | |
430 | j = ((ahci->port[port].next + i) % 32); | |
431 | if (reg & (1 << j)) { | |
432 | continue; | |
433 | } | |
434 | ahci_destroy_command(ahci, port, i); | |
435 | ahci->port[port].next = (j + 1) % 32; | |
436 | return j; | |
437 | } | |
438 | ||
439 | g_test_message("All command slots were busy."); | |
440 | g_assert_not_reached(); | |
441 | } |