]> Git Repo - qemu.git/blame - tests/libqos/ahci.c
libqos/ahci: Add port_check_nonbusy helper
[qemu.git] / tests / libqos / ahci.c
CommitLineData
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 */
40uint64_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
47void 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 */
57QPCIDevice *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
85void 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 */
99void 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 */
122void 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 */
137void 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 */
274unsigned 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 */
301void 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 */
317void 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
336void 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
350void 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. */
369void 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. */
383void 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
398void 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
420unsigned 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}
This page took 0.06872 seconds and 4 git commands to generate.