[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 03/12] fdc: Introduce fdctrl->phase
From: |
John Snow |
Subject: |
[Qemu-devel] [PULL 03/12] fdc: Introduce fdctrl->phase |
Date: |
Fri, 5 Jun 2015 16:00:40 -0400 |
From: Kevin Wolf <address@hidden>
The floppy controller spec describes three different controller phases,
which are currently not explicitly modelled in our emulation. Instead,
each phase is represented by a combination of flags in registers.
This patch makes explicit in which phase the controller currently is.
Signed-off-by: Kevin Wolf <address@hidden>
Acked-by: John Snow <address@hidden>
Message-id: address@hidden
Signed-off-by: John Snow <address@hidden>
---
hw/block/fdc.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 8c41434..f5bcf0b 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -495,6 +495,33 @@ enum {
FD_DIR_DSKCHG = 0x80,
};
+/*
+ * See chapter 5.0 "Controller phases" of the spec:
+ *
+ * Command phase:
+ * The host writes a command and its parameters into the FIFO. The command
+ * phase is completed when all parameters for the command have been supplied,
+ * and execution phase is entered.
+ *
+ * Execution phase:
+ * Data transfers, either DMA or non-DMA. For non-DMA transfers, the FIFO
+ * contains the payload now, otherwise it's unused. When all bytes of the
+ * required data have been transferred, the state is switched to either result
+ * phase (if the command produces status bytes) or directly back into the
+ * command phase for the next command.
+ *
+ * Result phase:
+ * The host reads out the FIFO, which contains one or more result bytes now.
+ */
+enum {
+ /* Only for migration: reconstruct phase from registers like qemu 2.3 */
+ FD_PHASE_RECONSTRUCT = 0,
+
+ FD_PHASE_COMMAND = 1,
+ FD_PHASE_EXECUTION = 2,
+ FD_PHASE_RESULT = 3,
+};
+
#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
@@ -504,6 +531,7 @@ struct FDCtrl {
/* Controller state */
QEMUTimer *result_timer;
int dma_chann;
+ uint8_t phase;
/* Controller's identification */
uint8_t version;
/* HW */
@@ -744,6 +772,28 @@ static const VMStateDescription vmstate_fdrive = {
}
};
+/*
+ * Reconstructs the phase from register values according to the logic that was
+ * implemented in qemu 2.3. This is the default value that is used if the phase
+ * subsection is not present on migration.
+ *
+ * Don't change this function to reflect newer qemu versions, it is part of
+ * the migration ABI.
+ */
+static int reconstruct_phase(FDCtrl *fdctrl)
+{
+ if (fdctrl->msr & FD_MSR_NONDMA) {
+ return FD_PHASE_EXECUTION;
+ } else if ((fdctrl->msr & FD_MSR_RQM) == 0) {
+ /* qemu 2.3 disabled RQM only during DMA transfers */
+ return FD_PHASE_EXECUTION;
+ } else if (fdctrl->msr & FD_MSR_DIO) {
+ return FD_PHASE_RESULT;
+ } else {
+ return FD_PHASE_COMMAND;
+ }
+}
+
static void fdc_pre_save(void *opaque)
{
FDCtrl *s = opaque;
@@ -751,12 +801,24 @@ static void fdc_pre_save(void *opaque)
s->dor_vmstate = s->dor | GET_CUR_DRV(s);
}
+static int fdc_pre_load(void *opaque)
+{
+ FDCtrl *s = opaque;
+ s->phase = FD_PHASE_RECONSTRUCT;
+ return 0;
+}
+
static int fdc_post_load(void *opaque, int version_id)
{
FDCtrl *s = opaque;
SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
+
+ if (s->phase == FD_PHASE_RECONSTRUCT) {
+ s->phase = reconstruct_phase(s);
+ }
+
return 0;
}
@@ -794,11 +856,29 @@ static const VMStateDescription vmstate_fdc_result_timer
= {
}
};
+static bool fdc_phase_needed(void *opaque)
+{
+ FDCtrl *fdctrl = opaque;
+
+ return reconstruct_phase(fdctrl) != fdctrl->phase;
+}
+
+static const VMStateDescription vmstate_fdc_phase = {
+ .name = "fdc/phase",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(phase, FDCtrl),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_fdc = {
.name = "fdc",
.version_id = 2,
.minimum_version_id = 2,
.pre_save = fdc_pre_save,
+ .pre_load = fdc_pre_load,
.post_load = fdc_post_load,
.fields = (VMStateField[]) {
/* Controller State */
@@ -839,6 +919,9 @@ static const VMStateDescription vmstate_fdc = {
.vmsd = &vmstate_fdc_result_timer,
.needed = fdc_result_timer_needed,
} , {
+ .vmsd = &vmstate_fdc_phase,
+ .needed = fdc_phase_needed,
+ } , {
/* empty */
}
}
@@ -1137,6 +1220,7 @@ static uint32_t fdctrl_read_dir(FDCtrl *fdctrl)
/* Clear the FIFO and update the state for receiving the next command */
static void fdctrl_to_command_phase(FDCtrl *fdctrl)
{
+ fdctrl->phase = FD_PHASE_COMMAND;
fdctrl->data_dir = FD_DIR_WRITE;
fdctrl->data_pos = 0;
fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
@@ -1146,6 +1230,7 @@ static void fdctrl_to_command_phase(FDCtrl *fdctrl)
* @fifo_len is the number of result bytes to be read out. */
static void fdctrl_to_result_phase(FDCtrl *fdctrl, int fifo_len)
{
+ fdctrl->phase = FD_PHASE_RESULT;
fdctrl->data_dir = FD_DIR_READ;
fdctrl->data_len = fifo_len;
fdctrl->data_pos = 0;
@@ -1912,6 +1997,9 @@ static void fdctrl_handle_relative_seek_out(FDCtrl
*fdctrl, int direction)
fdctrl_raise_irq(fdctrl);
}
+/*
+ * Handlers for the execution phase of each command
+ */
static const struct {
uint8_t value;
uint8_t mask;
@@ -2015,6 +2103,7 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t
value)
/* We now have all parameters
* and will be able to treat the command
*/
+ fdctrl->phase = FD_PHASE_EXECUTION;
if (fdctrl->data_state & FD_STATE_FORMAT) {
fdctrl_format_sector(fdctrl);
return;
--
2.1.0
- [Qemu-devel] [PULL 00/12] Ide patches, John Snow, 2015/06/05
- [Qemu-devel] [PULL 01/12] fdc: Rename fdctrl_reset_fifo() to fdctrl_to_command_phase(), John Snow, 2015/06/05
- [Qemu-devel] [PULL 02/12] fdc: Rename fdctrl_set_fifo() to fdctrl_to_result_phase(), John Snow, 2015/06/05
- [Qemu-devel] [PULL 05/12] fdc: Code cleanup in fdctrl_write_data(), John Snow, 2015/06/05
- [Qemu-devel] [PULL 07/12] fdc: Fix MSR.RQM flag, John Snow, 2015/06/05
- [Qemu-devel] [PULL 10/12] macio: switch pmac_dma_write() over to new offset/len implementation, John Snow, 2015/06/05
- [Qemu-devel] [PULL 09/12] macio: switch pmac_dma_read() over to new offset/len implementation, John Snow, 2015/06/05
- [Qemu-devel] [PULL 03/12] fdc: Introduce fdctrl->phase,
John Snow <=
- [Qemu-devel] [PULL 11/12] macio: update comment/constants to reflect the new code, John Snow, 2015/06/05
- [Qemu-devel] [PULL 04/12] fdc: Use phase in fdctrl_write_data(), John Snow, 2015/06/05
- [Qemu-devel] [PULL 06/12] fdc: Disentangle phases in fdctrl_read_data(), John Snow, 2015/06/05
- [Qemu-devel] [PULL 12/12] macio: remove remainder_len DBDMA_io property, John Snow, 2015/06/05
- [Qemu-devel] [PULL 08/12] fdc-test: Test state for existing cases more thoroughly, John Snow, 2015/06/05
- Re: [Qemu-devel] [PULL 00/12] Ide patches, Peter Maydell, 2015/06/08