Lines Matching +full:hba +full:- +full:cap

29 #include "pci-pc.h"
31 #include "qemu/host-utils.h"
107 g_assert(ahci->parent); in ahci_alloc()
108 return qmalloc(ahci->parent, bytes); in ahci_alloc()
114 g_assert(ahci->parent); in ahci_free()
115 qfree(ahci->parent, addr); in ahci_free()
156 QPCIBus *pcibus = dev ? dev->bus : NULL; in free_ahci_device()
163 /* Free all memory in-use by the AHCI device. */
169 if (ahci->port[port].fb) { in ahci_clean_mem()
170 ahci_free(ahci, ahci->port[port].fb); in ahci_clean_mem()
171 ahci->port[port].fb = 0; in ahci_clean_mem()
173 if (ahci->port[port].clb) { in ahci_clean_mem()
177 ahci_free(ahci, ahci->port[port].clb); in ahci_clean_mem()
178 ahci->port[port].clb = 0; in ahci_clean_mem()
186 * Start the PCI device and sanity-check default operation.
194 switch (ahci->fingerprint) { in ahci_pci_enable()
198 reg = qpci_config_readb(ahci->dev, 0x92); in ahci_pci_enable()
200 qpci_config_writeb(ahci->dev, 0x92, reg); in ahci_pci_enable()
201 /* 0...0111111b -- bit significant, ports 0-5 enabled. */ in ahci_pci_enable()
202 ASSERT_BIT_SET(qpci_config_readb(ahci->dev, 0x92), 0x3F); in ahci_pci_enable()
214 ahci->hba_bar = qpci_iomap(ahci->dev, 5, &ahci->barsize); in start_ahci_device()
217 qpci_device_enable(ahci->dev); in start_ahci_device()
221 * Test and initialize the AHCI's HBA memory areas.
223 * Bring the HBA into the idle state.
247 /* Cache CAP and CAP2. */ in ahci_hba_enable()
248 ahci->cap = ahci_rreg(ahci, AHCI_CAP); in ahci_hba_enable()
249 ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2); in ahci_hba_enable()
251 /* Read CAP.NCS, how many command slots do we have? */ in ahci_hba_enable()
252 num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1; in ahci_hba_enable()
280 * or HBA reset if we fail to idle the port. */ in ahci_hba_enable()
285 ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20); in ahci_hba_enable()
286 qtest_memset(ahci->parent->qts, ahci->port[i].clb, 0x00, in ahci_hba_enable()
288 g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb); in ahci_hba_enable()
289 ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb); in ahci_hba_enable()
290 g_assert_cmphex(ahci->port[i].clb, ==, in ahci_hba_enable()
294 ahci->port[i].fb = ahci_alloc(ahci, 0x100); in ahci_hba_enable()
295 qtest_memset(ahci->parent->qts, ahci->port[i].fb, 0x00, 0x100); in ahci_hba_enable()
296 g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb); in ahci_hba_enable()
297 ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb); in ahci_hba_enable()
298 g_assert_cmphex(ahci->port[i].fb, ==, in ahci_hba_enable()
355 ahci->enabled = true; in ahci_hba_enable()
357 * In the future, a small test-case to inspect the Register D2H FIS in ahci_hba_enable()
400 /* Wipe the FIS-Receive Buffer */ in ahci_port_clear()
401 qtest_memset(ahci->parent->qts, ahci->port[port].fb, 0x00, 0x100); in ahci_port_clear()
409 uint8_t port = cmd->port; in ahci_port_check_error()
413 if (cmd->errors) { in ahci_port_check_error()
419 reg &= ~cmd->interrupts; in ahci_port_check_error()
430 if (cmd->errors) { in ahci_port_check_error()
455 if (!cmd->errors) { in ahci_port_check_error()
460 ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR & (~cmd->errors << 8)); in ahci_port_check_error()
461 ASSERT_BIT_SET(reg, AHCI_PX_TFD_ERR & (cmd->errors << 8)); in ahci_port_check_error()
466 uint8_t port = cmd->port; in ahci_port_check_interrupts()
472 if (cmd->errors) { in ahci_port_check_interrupts()
478 ASSERT_BIT_SET(reg, cmd->interrupts); in ahci_port_check_interrupts()
481 ahci_px_wreg(ahci, port, AHCI_PX_IS, cmd->interrupts); in ahci_port_check_interrupts()
487 uint8_t slot = cmd->slot; in ahci_port_check_nonbusy()
488 uint8_t port = cmd->port; in ahci_port_check_nonbusy()
493 * For non-NCQ command, PxSACT bit should always be cleared. */ in ahci_port_check_nonbusy()
495 if (cmd->props->ncq && cmd->errors) { in ahci_port_check_nonbusy()
501 /* For non-NCQ command with error, PxCI bit should still be set. in ahci_port_check_nonbusy()
502 * For non-NCQ command without error, PxCI bit should be cleared. in ahci_port_check_nonbusy()
506 if (!cmd->props->ncq && cmd->errors) { in ahci_port_check_nonbusy()
508 } else if (!cmd->errors) { in ahci_port_check_nonbusy()
523 qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x40, d2h, 0x20); in ahci_port_check_d2h_sanity()
524 g_assert_cmphex(d2h->fis_type, ==, 0x34); in ahci_port_check_d2h_sanity()
527 g_assert_cmphex((reg & AHCI_PX_TFD_ERR) >> 8, ==, d2h->error); in ahci_port_check_d2h_sanity()
528 g_assert_cmphex((reg & AHCI_PX_TFD_STS), ==, d2h->status); in ahci_port_check_d2h_sanity()
536 uint8_t port = cmd->port; in ahci_port_check_pio_sanity()
541 qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x20, pio, 0x20); in ahci_port_check_pio_sanity()
542 g_assert_cmphex(pio->fis_type, ==, 0x5f); in ahci_port_check_pio_sanity()
549 if (cmd->props->atapi && (cmd->xbytes == 0 || cmd->props->dma)) { in ahci_port_check_pio_sanity()
550 g_assert(le16_to_cpu(pio->tx_count) == 12 || in ahci_port_check_pio_sanity()
551 le16_to_cpu(pio->tx_count) == 16); in ahci_port_check_pio_sanity()
556 size_t pio_len = ((cmd->xbytes % cmd->sector_size) ? in ahci_port_check_pio_sanity()
557 (cmd->xbytes % cmd->sector_size) : cmd->sector_size); in ahci_port_check_pio_sanity()
558 g_assert_cmphex(le16_to_cpu(pio->tx_count), ==, pio_len); in ahci_port_check_pio_sanity()
567 ahci_get_command_header(ahci, cmd->port, cmd->slot, &cmdh); in ahci_port_check_cmd_sanity()
569 if (!cmd->props->ncq) { in ahci_port_check_cmd_sanity()
570 g_assert_cmphex(cmd->xbytes, ==, cmdh.prdbc); in ahci_port_check_cmd_sanity()
578 uint64_t ba = ahci->port[port].clb; in ahci_get_command_header()
580 qtest_memread(ahci->parent->qts, ba, cmd, sizeof(AHCICommandHeader)); in ahci_get_command_header()
582 cmd->flags = le16_to_cpu(cmd->flags); in ahci_get_command_header()
583 cmd->prdtl = le16_to_cpu(cmd->prdtl); in ahci_get_command_header()
584 cmd->prdbc = le32_to_cpu(cmd->prdbc); in ahci_get_command_header()
585 cmd->ctba = le64_to_cpu(cmd->ctba); in ahci_get_command_header()
593 uint64_t ba = ahci->port[port].clb; in ahci_set_command_header()
596 tmp.flags = cpu_to_le16(cmd->flags); in ahci_set_command_header()
597 tmp.prdtl = cpu_to_le16(cmd->prdtl); in ahci_set_command_header()
598 tmp.prdbc = cpu_to_le32(cmd->prdbc); in ahci_set_command_header()
599 tmp.ctba = cpu_to_le64(cmd->ctba); in ahci_set_command_header()
601 qtest_memwrite(ahci->parent->qts, ba, &tmp, sizeof(AHCICommandHeader)); in ahci_set_command_header()
611 /* No address in it, so just return -- it's empty. */ in ahci_destroy_command()
622 ahci->port[port].ctba[slot] = 0; in ahci_destroy_command()
623 ahci->port[port].prdtl[slot] = 0; in ahci_destroy_command()
628 RegH2DFIS tmp = cmd->fis; in ahci_write_fis()
629 uint64_t addr = cmd->header.ctba; in ahci_write_fis()
632 * Only the count field needs to be adjusted for non-NCQ commands. in ahci_write_fis()
633 * The auxiliary FIS fields are defined per-command and are not currently in ahci_write_fis()
635 if (!cmd->props->ncq) { in ahci_write_fis()
639 qtest_memwrite(ahci->parent->qts, addr, &tmp, sizeof(tmp)); in ahci_write_fis()
652 j = ((ahci->port[port].next + i) % 32); in ahci_pick_cmd()
657 ahci->port[port].next = (j + 1) % 32; in ahci_pick_cmd()
670 return (bytes + bytes_per_prd - 1) / bytes_per_prd; in size_to_prdtl()
697 buffer_in = opts->buffer; in ahci_exec()
700 if (opts->size && !opts->buffer) { in ahci_exec()
701 opts->buffer = ahci_alloc(ahci, opts->size); in ahci_exec()
702 g_assert(opts->buffer); in ahci_exec()
703 qtest_memset(ahci->parent->qts, opts->buffer, 0x00, opts->size); in ahci_exec()
707 if (opts->atapi) { in ahci_exec()
708 uint16_t bcl = opts->set_bcl ? opts->bcl : ATAPI_SECTOR_SIZE; in ahci_exec()
709 cmd = ahci_atapi_command_create(op, bcl, opts->atapi_dma); in ahci_exec()
713 ahci_command_adjust(cmd, opts->lba, opts->buffer, in ahci_exec()
714 opts->size, opts->prd_size); in ahci_exec()
716 if (opts->pre_cb) { in ahci_exec()
717 rc = opts->pre_cb(ahci, cmd, opts); in ahci_exec()
724 if (opts->error) { in ahci_exec()
725 qtest_qmp_eventwait(ahci->parent->qts, "STOP"); in ahci_exec()
727 if (opts->mid_cb) { in ahci_exec()
728 rc = opts->mid_cb(ahci, cmd, opts); in ahci_exec()
731 if (opts->error) { in ahci_exec()
732 qtest_qmp_send(ahci->parent->qts, "{'execute':'cont' }"); in ahci_exec()
733 qtest_qmp_eventwait(ahci->parent->qts, "RESUME"); in ahci_exec()
739 if (opts->post_cb) { in ahci_exec()
740 rc = opts->post_cb(ahci, cmd, opts); in ahci_exec()
744 if (opts->buffer != buffer_in) { in ahci_exec()
745 ahci_free(ahci, opts->buffer); in ahci_exec()
761 qtest_qmp_eventwait(ahci->parent->qts, "STOP"); in ahci_guest_io_halt()
770 qtest_qmp_send(ahci->parent->qts, "{'execute':'cont' }"); in ahci_guest_io_resume()
771 qtest_qmp_eventwait(ahci->parent->qts, "RESUME"); in ahci_guest_io_resume()
818 qtest_memset(ahci->parent->qts, ptr, 0x00, bufsize); in ahci_io()
820 if (bufsize && props->write) { in ahci_io()
821 qtest_bufwrite(ahci->parent->qts, ptr, buffer, bufsize); in ahci_io()
826 if (bufsize && props->read) { in ahci_io()
827 qtest_bufread(ahci->parent->qts, ptr, buffer, bufsize); in ahci_io()
839 AHCICommandHeader *hdr = &cmd->header; in command_header_init()
840 AHCICommandProp *props = cmd->props; in command_header_init()
842 hdr->flags = 5; /* RegH2DFIS is 5 DW long. Must be < 32 */ in command_header_init()
843 hdr->flags |= CMDH_CLR_BSY; /* Clear the BSY bit when done */ in command_header_init()
844 if (props->write) { in command_header_init()
845 hdr->flags |= CMDH_WRITE; in command_header_init()
847 if (props->atapi) { in command_header_init()
848 hdr->flags |= CMDH_ATAPI; in command_header_init()
851 hdr->prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size); in command_header_init()
852 hdr->prdbc = 0; in command_header_init()
853 hdr->ctba = 0; in command_header_init()
858 RegH2DFIS *fis = &(cmd->fis); in command_table_init()
859 uint16_t sect_count = (cmd->xbytes / cmd->sector_size); in command_table_init()
861 fis->fis_type = REG_H2D_FIS; in command_table_init()
862 fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */ in command_table_init()
863 fis->command = cmd->name; in command_table_init()
865 if (cmd->props->ncq) { in command_table_init()
867 /* NCQ is weird and re-uses FIS frames for unrelated data. in command_table_init()
869 ncqfis->sector_low = sect_count & 0xFF; in command_table_init()
870 ncqfis->sector_hi = (sect_count >> 8) & 0xFF; in command_table_init()
871 ncqfis->device = NCQ_DEVICE_MAGIC; in command_table_init()
873 ncqfis->tag = 0; /* bits 3-7 are the NCQ tag */ in command_table_init()
874 ncqfis->prio = 0; /* bits 6,7 are a prio tag */ in command_table_init()
877 fis->feature_low = 0x00; in command_table_init()
878 fis->feature_high = 0x00; in command_table_init()
879 if (cmd->props->lba28 || cmd->props->lba48) { in command_table_init()
880 fis->device = ATA_DEVICE_LBA; in command_table_init()
882 fis->count = (cmd->xbytes / cmd->sector_size); in command_table_init()
884 fis->icc = 0x00; in command_table_init()
885 fis->control = 0x00; in command_table_init()
886 memset(fis->aux, 0x00, ARRAY_SIZE(fis->aux)); in command_table_init()
891 RegH2DFIS *fis = &(cmd->fis); in ahci_command_enable_atapi_dma()
892 g_assert(cmd->props->atapi); in ahci_command_enable_atapi_dma()
893 fis->feature_low |= 0x01; in ahci_command_enable_atapi_dma()
895 g_assert(cmd->props->pio); in ahci_command_enable_atapi_dma()
896 cmd->props->dma = true; in ahci_command_enable_atapi_dma()
898 /* cmd->interrupts |= AHCI_PX_IS_DSS; */ in ahci_command_enable_atapi_dma()
908 g_assert(!(props->dma && props->pio) || props->atapi); in ahci_command_create()
909 g_assert(!(props->lba28 && props->lba48)); in ahci_command_create()
910 g_assert(!(props->read && props->write)); in ahci_command_create()
911 g_assert(!props->size || props->data); in ahci_command_create()
912 g_assert(!props->ncq || props->lba48); in ahci_command_create()
914 /* Defaults and book-keeping */ in ahci_command_create()
915 cmd->props = g_memdup2(props, sizeof(AHCICommandProp)); in ahci_command_create()
916 cmd->name = command_name; in ahci_command_create()
917 cmd->xbytes = props->size; in ahci_command_create()
918 cmd->prd_size = 4096; in ahci_command_create()
919 cmd->buffer = 0xabad1dea; in ahci_command_create()
920 cmd->sector_size = props->atapi ? ATAPI_SECTOR_SIZE : AHCI_SECTOR_SIZE; in ahci_command_create()
922 if (!cmd->props->ncq) { in ahci_command_create()
923 cmd->interrupts = AHCI_PX_IS_DHRS; in ahci_command_create()
926 /* cmd->interrupts |= props->data ? AHCI_PX_IS_DPS : 0; */ in ahci_command_create()
928 /* cmd->interrupts |= props->dma ? AHCI_PX_IS_DSS : 0; */ in ahci_command_create()
929 cmd->interrupts |= props->ncq ? AHCI_PX_IS_SDBS : 0; in ahci_command_create()
940 cmd->atapi_cmd = g_malloc0(16); in ahci_atapi_command_create()
941 cmd->atapi_cmd[0] = scsi_cmd; in ahci_atapi_command_create()
942 stw_le_p(&cmd->fis.lba_lo[1], bcl); in ahci_atapi_command_create()
946 cmd->interrupts |= bcl ? AHCI_PX_IS_PSS : 0; in ahci_atapi_command_create()
957 cmd->interrupts |= AHCI_PX_IS_TFES; in ahci_atapi_test_ready()
958 cmd->errors |= expected_sense << 4; in ahci_atapi_test_ready()
969 unsigned char *rx = opts->opaque; in copy_buffer()
970 qtest_bufread(ahci->parent->qts, opts->buffer, rx, opts->size); in copy_buffer()
999 cmd->atapi_cmd[4] = 0x02; /* loej = true */ in ahci_atapi_eject()
1011 cmd->atapi_cmd[4] = 0x03; /* loej,start = true */ in ahci_atapi_load()
1020 g_free(cmd->atapi_cmd); in ahci_command_free()
1021 g_free(cmd->props); in ahci_command_free()
1027 cmd->header.flags |= cmdh_flags; in ahci_command_set_flags()
1032 cmd->header.flags &= ~cmdh_flags; in ahci_command_clr_flags()
1037 unsigned char *cbd = cmd->atapi_cmd; in ahci_atapi_command_set_offset()
1064 RegH2DFIS *fis = &(cmd->fis); in ahci_command_set_offset()
1066 if (cmd->props->atapi) { in ahci_command_set_offset()
1069 } else if (!cmd->props->data && !lba_sect) { in ahci_command_set_offset()
1072 } else if (cmd->props->lba28) { in ahci_command_set_offset()
1074 } else if (cmd->props->lba48 || cmd->props->ncq) { in ahci_command_set_offset()
1082 fis->lba_lo[0] = (lba_sect & 0xFF); in ahci_command_set_offset()
1083 fis->lba_lo[1] = (lba_sect >> 8) & 0xFF; in ahci_command_set_offset()
1084 fis->lba_lo[2] = (lba_sect >> 16) & 0xFF; in ahci_command_set_offset()
1085 if (cmd->props->lba28) { in ahci_command_set_offset()
1086 fis->device = (fis->device & 0xF0) | ((lba_sect >> 24) & 0x0F); in ahci_command_set_offset()
1088 fis->lba_hi[0] = (lba_sect >> 24) & 0xFF; in ahci_command_set_offset()
1089 fis->lba_hi[1] = (lba_sect >> 32) & 0xFF; in ahci_command_set_offset()
1090 fis->lba_hi[2] = (lba_sect >> 40) & 0xFF; in ahci_command_set_offset()
1095 cmd->buffer = buffer; in ahci_command_set_buffer()
1100 unsigned char *cbd = cmd->atapi_cmd; in ahci_atapi_set_size()
1145 cmd->prd_size = prd_size; in ahci_command_set_sizes()
1147 cmd->xbytes = xbytes; in ahci_command_set_sizes()
1148 sect_count = (cmd->xbytes / cmd->sector_size); in ahci_command_set_sizes()
1150 if (cmd->props->ncq) { in ahci_command_set_sizes()
1151 NCQFIS *nfis = (NCQFIS *)&(cmd->fis); in ahci_command_set_sizes()
1152 nfis->sector_low = sect_count & 0xFF; in ahci_command_set_sizes()
1153 nfis->sector_hi = (sect_count >> 8) & 0xFF; in ahci_command_set_sizes()
1154 } else if (cmd->props->atapi) { in ahci_command_set_sizes()
1160 if (cmd->props->pio && sect_count > (cmd->props->read ? 0 : 1)) { in ahci_command_set_sizes()
1161 cmd->interrupts |= AHCI_PX_IS_PSS; in ahci_command_set_sizes()
1163 cmd->fis.count = sect_count; in ahci_command_set_sizes()
1165 cmd->header.prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size); in ahci_command_set_sizes()
1170 ahci_command_set_sizes(cmd, xbytes, cmd->prd_size); in ahci_command_set_size()
1175 ahci_command_set_sizes(cmd, cmd->xbytes, prd_size); in ahci_command_set_prd_size()
1193 cmd->port = port; in ahci_command_commit()
1194 cmd->slot = ahci_pick_cmd(ahci, port); in ahci_command_commit()
1196 if (cmd->props->ncq) { in ahci_command_commit()
1197 NCQFIS *nfis = (NCQFIS *)&cmd->fis; in ahci_command_commit()
1198 nfis->tag = (cmd->slot << 3) & 0xFC; in ahci_command_commit()
1202 prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size); in ahci_command_commit()
1208 cmd->header.ctba = table_ptr; in ahci_command_commit()
1211 ahci_set_command_header(ahci, port, cmd->slot, &(cmd->header)); in ahci_command_commit()
1212 /* Now, write the command table (FIS, ACMD, and PRDT) -- FIS first, */ in ahci_command_commit()
1215 if (cmd->props->atapi) { in ahci_command_commit()
1216 qtest_memwrite(ahci->parent->qts, table_ptr + 0x40, cmd->atapi_cmd, 16); in ahci_command_commit()
1220 g_assert_cmphex(prdtl, ==, cmd->header.prdtl); in ahci_command_commit()
1221 remaining = cmd->xbytes; in ahci_command_commit()
1223 prd.dba = cpu_to_le64(cmd->buffer + (cmd->prd_size * i)); in ahci_command_commit()
1225 if (remaining > cmd->prd_size) { in ahci_command_commit()
1226 /* Note that byte count is 0-based. */ in ahci_command_commit()
1227 prd.dbc = cpu_to_le32(cmd->prd_size - 1); in ahci_command_commit()
1228 remaining -= cmd->prd_size; in ahci_command_commit()
1230 /* Again, dbc is 0-based. */ in ahci_command_commit()
1231 prd.dbc = cpu_to_le32(remaining - 1); in ahci_command_commit()
1237 qtest_memwrite(ahci->parent->qts, table_ptr + 0x80 + (i * sizeof(PRD)), in ahci_command_commit()
1242 ahci->port[port].ctba[cmd->slot] = table_ptr; in ahci_command_commit()
1243 ahci->port[port].prdtl[cmd->slot] = prdtl; in ahci_command_commit()
1248 if (cmd->props->ncq) { in ahci_command_issue_async()
1249 ahci_px_wreg(ahci, cmd->port, AHCI_PX_SACT, (1 << cmd->slot)); in ahci_command_issue_async()
1252 ahci_px_wreg(ahci, cmd->port, AHCI_PX_CI, (1 << cmd->slot)); in ahci_command_issue_async()
1259 * a command in-flight. */ in ahci_command_wait()
1261 #define RSET(REG, MASK) (BITSET(ahci_px_rreg(ahci, cmd->port, (REG)), (MASK))) in ahci_command_wait()
1265 RSET(AHCI_PX_CI, 1 << cmd->slot) || in ahci_command_wait()
1266 (cmd->props->ncq && RSET(AHCI_PX_SACT, 1 << cmd->slot)))) { in ahci_command_wait()
1280 uint8_t slot = cmd->slot; in ahci_command_verify()
1281 uint8_t port = cmd->port; in ahci_command_verify()
1287 if (cmd->interrupts & AHCI_PX_IS_DHRS) { in ahci_command_verify()
1290 if (cmd->props->pio) { in ahci_command_verify()
1297 return cmd->slot; in ahci_command_slot()