static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) { AHCIPortRegs *pr = &s->dev[port].port_regs; DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val); switch (offset) { case PORT_LST_ADDR: pr->lst_addr = val; map_page(&s->dev[port].lst, ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024); s->dev[port].cur_cmd = NULL; break; case PORT_LST_ADDR_HI: pr->lst_addr_hi = val; map_page(&s->dev[port].lst, ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024); s->dev[port].cur_cmd = NULL; break; case PORT_FIS_ADDR: pr->fis_addr = val; map_page(&s->dev[port].res_fis, ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256); break; case PORT_FIS_ADDR_HI: pr->fis_addr_hi = val; map_page(&s->dev[port].res_fis, ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256); break; case PORT_IRQ_STAT: pr->irq_stat &= ~val; ahci_check_irq(s); break; case PORT_IRQ_MASK: pr->irq_mask = val & 0xfdc000ff; ahci_check_irq(s); break; case PORT_CMD: pr->cmd = val & ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON); if (pr->cmd & PORT_CMD_START) { pr->cmd |= PORT_CMD_LIST_ON; } if (pr->cmd & PORT_CMD_FIS_RX) { pr->cmd |= PORT_CMD_FIS_ON; } /* XXX usually the FIS would be pending on the bus here and issuing deferred until the OS enables FIS receival. Instead, we only submit it once - which works in most cases, but is a hack. */ if ((pr->cmd & PORT_CMD_FIS_ON) && !s->dev[port].init_d2h_sent) { ahci_init_d2h(&s->dev[port]); s->dev[port].init_d2h_sent = true; } check_cmd(s, port); break; case PORT_TFDATA: s->dev[port].port.ifs[0].error = (val >> 8) & 0xff; s->dev[port].port.ifs[0].status = val & 0xff; break; case PORT_SIG: pr->sig = val; break; case PORT_SCR_STAT: pr->scr_stat = val; break; case PORT_SCR_CTL: if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) && ((val & AHCI_SCR_SCTL_DET) == 0)) { ahci_reset_port(s, port); } pr->scr_ctl = val; break; case PORT_SCR_ERR: pr->scr_err &= ~val; break; case PORT_SCR_ACT: /* RW1 */ pr->scr_act |= val; break; case PORT_CMD_ISSUE: pr->cmd_issue |= val; check_cmd(s, port); break; default: break; } }
static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) { AHCIPortRegs *pr = &s->dev[port].port_regs; DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val); switch (offset) { case PORT_LST_ADDR: pr->lst_addr = val; break; case PORT_LST_ADDR_HI: pr->lst_addr_hi = val; break; case PORT_FIS_ADDR: pr->fis_addr = val; break; case PORT_FIS_ADDR_HI: pr->fis_addr_hi = val; break; case PORT_IRQ_STAT: pr->irq_stat &= ~val; ahci_check_irq(s); break; case PORT_IRQ_MASK: pr->irq_mask = val & 0xfdc000ff; ahci_check_irq(s); break; case PORT_CMD: /* Block any Read-only fields from being set; * including LIST_ON and FIS_ON. * The spec requires to set ICC bits to zero after the ICC change * is done. We don't support ICC state changes, therefore always * force the ICC bits to zero. */ pr->cmd = (pr->cmd & PORT_CMD_RO_MASK) | (val & ~(PORT_CMD_RO_MASK|PORT_CMD_ICC_MASK)); /* Check FIS RX and CLB engines, allow transition to false: */ ahci_cond_start_engines(&s->dev[port], true); /* XXX usually the FIS would be pending on the bus here and issuing deferred until the OS enables FIS receival. Instead, we only submit it once - which works in most cases, but is a hack. */ if ((pr->cmd & PORT_CMD_FIS_ON) && !s->dev[port].init_d2h_sent) { ahci_init_d2h(&s->dev[port]); } check_cmd(s, port); break; case PORT_TFDATA: /* Read Only. */ break; case PORT_SIG: /* Read Only */ break; case PORT_SCR_STAT: /* Read Only */ break; case PORT_SCR_CTL: if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) && ((val & AHCI_SCR_SCTL_DET) == 0)) { ahci_reset_port(s, port); } pr->scr_ctl = val; break; case PORT_SCR_ERR: pr->scr_err &= ~val; break; case PORT_SCR_ACT: /* RW1 */ pr->scr_act |= val; break; case PORT_CMD_ISSUE: pr->cmd_issue |= val; check_cmd(s, port); break; default: break; } }
static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) { AHCIPortRegs *pr = &s->dev[port].port_regs; DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val); switch (offset) { case PORT_LST_ADDR: pr->lst_addr = val; break; case PORT_LST_ADDR_HI: pr->lst_addr_hi = val; break; case PORT_FIS_ADDR: pr->fis_addr = val; break; case PORT_FIS_ADDR_HI: pr->fis_addr_hi = val; break; case PORT_IRQ_STAT: pr->irq_stat &= ~val; ahci_check_irq(s); break; case PORT_IRQ_MASK: pr->irq_mask = val & 0xfdc000ff; ahci_check_irq(s); break; case PORT_CMD: /* Block any Read-only fields from being set; * including LIST_ON and FIS_ON. */ pr->cmd = (pr->cmd & PORT_CMD_RO_MASK) | (val & ~PORT_CMD_RO_MASK); if (pr->cmd & PORT_CMD_START) { if (ahci_map_clb_address(&s->dev[port])) { pr->cmd |= PORT_CMD_LIST_ON; } else { error_report("AHCI: Failed to start DMA engine: " "bad command list buffer address"); } } else if (pr->cmd & PORT_CMD_LIST_ON) { ahci_unmap_clb_address(&s->dev[port]); pr->cmd = pr->cmd & ~(PORT_CMD_LIST_ON); } if (pr->cmd & PORT_CMD_FIS_RX) { if (ahci_map_fis_address(&s->dev[port])) { pr->cmd |= PORT_CMD_FIS_ON; } else { error_report("AHCI: Failed to start FIS receive engine: " "bad FIS receive buffer address"); } } else if (pr->cmd & PORT_CMD_FIS_ON) { ahci_unmap_fis_address(&s->dev[port]); pr->cmd = pr->cmd & ~(PORT_CMD_FIS_ON); } /* XXX usually the FIS would be pending on the bus here and issuing deferred until the OS enables FIS receival. Instead, we only submit it once - which works in most cases, but is a hack. */ if ((pr->cmd & PORT_CMD_FIS_ON) && !s->dev[port].init_d2h_sent) { ahci_init_d2h(&s->dev[port]); s->dev[port].init_d2h_sent = true; } check_cmd(s, port); break; case PORT_TFDATA: /* Read Only. */ break; case PORT_SIG: /* Read Only */ break; case PORT_SCR_STAT: /* Read Only */ break; case PORT_SCR_CTL: if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) && ((val & AHCI_SCR_SCTL_DET) == 0)) { ahci_reset_port(s, port); } pr->scr_ctl = val; break; case PORT_SCR_ERR: pr->scr_err &= ~val; break; case PORT_SCR_ACT: /* RW1 */ pr->scr_act |= val; break; case PORT_CMD_ISSUE: pr->cmd_issue |= val; check_cmd(s, port); break; default: break; } }