* [Qemu-devel] [PATCH v2] add 1394 bus support
@ 2015-04-19 10:52 itamar.tal4
2015-04-19 10:52 ` [Qemu-devel] [PATCH v02] " itamar.tal4
0 siblings, 1 reply; 7+ messages in thread
From: itamar.tal4 @ 2015-04-19 10:52 UTC (permalink / raw)
To: qemu-devel; +Cc: thuth, ariel, afaerber, Itamar Tal
From: Itamar Tal <itamar@guardicore.com>
This patch add 1394 (firewire) support to x86_64 and i386 qemu
softmmu. It allows one virtual machine to be the server side and the
other to be the client side, connected by TCP stream socket (same
thing is possible using serial port). This is very useful in for
allowing legacy devices to communicate over the firewire channel, but
doesn't support USB communication. Especially, it's useful for remote
Windows kernel debugging over qemu for malware analysis and so on...
The patch was tested on major stable version 2.0.0, 2.2.1 and current
master (2.3.0rc?).
Itamar Tal (1):
add 1394 bus support
default-configs/i386-softmmu.mak | 1 +
default-configs/x86_64-softmmu.mak | 1 +
hw/1394/Makefile.objs | 1 +
hw/1394/hcd-ohci.c | 1754 ++++++++++++++++++++++++++++++++++++
hw/1394/hcd-ohci.h | 147 +++
hw/Makefile.objs | 1 +
6 files changed, 1905 insertions(+)
create mode 100644 hw/1394/Makefile.objs
create mode 100644 hw/1394/hcd-ohci.c
create mode 100644 hw/1394/hcd-ohci.h
--
2.3.4
^ permalink raw reply [flat|nested] 7+ messages in thread
* [Qemu-devel] [PATCH v02] add 1394 bus support
2015-04-19 10:52 [Qemu-devel] [PATCH v2] add 1394 bus support itamar.tal4
@ 2015-04-19 10:52 ` itamar.tal4
2015-04-19 15:47 ` Andreas Färber
2015-04-19 20:15 ` Peter Maydell
0 siblings, 2 replies; 7+ messages in thread
From: itamar.tal4 @ 2015-04-19 10:52 UTC (permalink / raw)
To: qemu-devel; +Cc: thuth, ariel, afaerber, Itamar Tal
From: Itamar Tal <itamar@guardicore.com>
---
default-configs/i386-softmmu.mak | 1 +
default-configs/x86_64-softmmu.mak | 1 +
hw/1394/Makefile.objs | 1 +
hw/1394/hcd-ohci.c | 1754 ++++++++++++++++++++++++++++++++++++
hw/1394/hcd-ohci.h | 147 +++
hw/Makefile.objs | 1 +
6 files changed, 1905 insertions(+)
create mode 100644 hw/1394/Makefile.objs
create mode 100644 hw/1394/hcd-ohci.c
create mode 100644 hw/1394/hcd-ohci.h
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 6a74e00..8742af9 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -45,3 +45,4 @@ CONFIG_MEM_HOTPLUG=y
CONFIG_XIO3130=y
CONFIG_IOH3420=y
CONFIG_I82801B11=y
+CONFIG_1394_OHCI=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 46b87dd..a47863d 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -45,3 +45,4 @@ CONFIG_MEM_HOTPLUG=y
CONFIG_XIO3130=y
CONFIG_IOH3420=y
CONFIG_I82801B11=y
+CONFIG_1394_OHCI=y
diff --git a/hw/1394/Makefile.objs b/hw/1394/Makefile.objs
new file mode 100644
index 0000000..bddc0e1
--- /dev/null
+++ b/hw/1394/Makefile.objs
@@ -0,0 +1 @@
+common-obj-$(CONFIG_1394_OHCI) += hcd-ohci.o
diff --git a/hw/1394/hcd-ohci.c b/hw/1394/hcd-ohci.c
new file mode 100644
index 0000000..3f7ad75
--- /dev/null
+++ b/hw/1394/hcd-ohci.c
@@ -0,0 +1,1754 @@
+/*
+ * FireWire (1394) support
+ *
+ * Copyright (c) 2015 Guardicore
+ * - address@hidden
+ * Originally Written by James Harper
+ *
+ * This is a `bare-bones' implementation of the Firewire 1394 OHCI
+ * for virtual->virtual firewire connections emulation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "hcd-ohci.h"
+#include <sys/time.h>
+
+#define OHCI_1394_MMIO_SIZE 0x800
+
+#define HCCONTROL_RESET 16
+#define HCCONTROL_LINK_ENABLE 17
+#define HCCONTROL_LPS 19
+
+#define HCCONTROL_RESET_MASK (1 << (HCCONTROL_RESET))
+#define HCCONTROL_LINK_ENABLE_MASK (1 << (HCCONTROL_LINK_ENABLE))
+#define HCCONTROL_LPS_MASK (1 << (HCCONTROL_LPS))
+
+#define HCD_STATE_UNPLUGGED 0 /* no connection */
+#define HCD_STATE_MAGIC 1 /* waiting for magic */
+#define HCD_STATE_DISCONNECTED 2 /* waiting for link packet */
+#define HCD_STATE_ARBITRATION1 3 /* send bid */
+#define HCD_STATE_ARBITRATION2 4 /* receive bid and compare */
+#define HCD_STATE_CONNECTED 5 /* connected and ready to go */
+
+#define IS_Ax_ACTIVE(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x000) >> 2] & (1 << 10))
+#define SET_Ax_ACTIVE(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x000) >> 2] |= (1 << 10))
+#define CLR_Ax_ACTIVE(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x000) >> 2] &= ~(1 << 10))
+
+#define IS_Ax_DEAD(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x000) >> 2] & (1 << 11))
+#define SET_Ax_DEAD(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x000) >> 2] |= (1 << 11))
+
+#define IS_Ax_WAKE(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x000) >> 2] & (1 << 12))
+#define CLR_Ax_WAKE(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x000) >> 2] &= ~(1 << 12))
+
+#define IS_Ax_RUN(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x000) >> 2] & (1 << 15))
+
+#define SET_Ax_EVENT_CODE(n, e) s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x000) >> 2] = ((s->mmio.regs[((0x180 + \
+ ((n) * 0x20)) + 0x00) >> 2] & \
+ 0xFFFFFFE0) | (e))
+
+#define Ax_COMMAND_PTR(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x00C) >> 2])
+#define SET_Ax_COMMAND_PTR(n, c) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x00C) >> 2] = (c))
+
+#define Ax_CONTEXT_CONTROL(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+ 0x00) >> 2])
+
+#define DECLARE_PHY \
+union { \
+ uint32_t PhyControl; \
+ struct { \
+ uint32_t PhyControl_wrData:8; \
+ uint32_t PhyControl_regAddr:4; \
+ uint32_t:2; \
+ uint32_t PhyControl_wrReg:1; \
+ uint32_t PhyControl_rdReg:1; \
+ uint32_t PhyControl_rdData:8; \
+ uint32_t PhyControl_rdAddr:4; \
+ uint32_t:3; \
+ uint32_t PhyControl_rdDone:1; \
+ }; \
+}
+
+#define DECLARE_INT(prefix) \
+union { \
+ uint32_t prefix; \
+ struct { \
+ uint32_t prefix##_reqTxComplete:1; \
+ uint32_t prefix##_respTxComplete:1; \
+ uint32_t prefix##_ARRQ:1; \
+ uint32_t prefix##_ARRS:1; \
+ uint32_t prefix##_RQPkt:1; \
+ uint32_t prefix##_RSPkt:1; \
+ uint32_t prefix##_isochTx:1; \
+ uint32_t prefix##_isockRx:1; \
+ uint32_t prefix##_postedWriteErr:1; \
+ uint32_t prefix##_lockRespErr:1; \
+ uint32_t:5; \
+ uint32_t prefix##_selfIDComplete2:1; \
+ uint32_t prefix##_selfIDComplete:1; \
+ uint32_t prefix##_busReset:1; \
+ uint32_t prefix##_regAccessFail:1; \
+ uint32_t prefix##_phy:1; \
+ uint32_t prefix##_cycleSynch:1; \
+ uint32_t prefix##_cycle64Seconds:1; \
+ uint32_t prefix##_cycleLost:1; \
+ uint32_t prefix##_cycleInconsistent:1; \
+ uint32_t prefix##_unrecoverableError:1; \
+ uint32_t prefix##_cycleTooLong:1; \
+ uint32_t prefix##_phyRegRcvd:1; \
+ uint32_t prefix##_ack_tardy:1; \
+ uint32_t:1; \
+ uint32_t prefix##_softInterrupt:1; \
+ uint32_t prefix##_vendorSpecific:1; \
+ uint32_t prefix##_masterIntEnable:1; \
+ }; \
+}
+
+#define DECLARE_CONFIG_ROM_HDR \
+union { \
+ uint32_t ConfigROMhdr; \
+ struct { \
+ uint32_t ConfigRomhdr_rom_crc_value:16; \
+ uint32_t ConfigRomhdr_crc_length:8; \
+ uint32_t ConfigRomhdr_info_length:8; \
+ }; \
+}
+
+#define DECLARE_NODE_ID \
+union { \
+ uint32_t NodeID; \
+ struct { \
+ uint32_t NodeID_nodeNumber:6; \
+ uint32_t NodeID_busNumber:10; \
+ uint32_t:11; \
+ uint32_t NodeID_CPS:1; \
+ uint32_t:2; \
+ uint32_t NodeID_root:1; \
+ uint32_t NodeID_iDValid:1; \
+ }; \
+}
+
+#define DECLARE_SELF_ID_COUNT \
+union { \
+ uint32_t SelfIDCount; \
+ struct { \
+ uint32_t:2; \
+ uint32_t SelfIDCount_Size:9; \
+ uint32_t:5; \
+ uint32_t SelfIDCount_Generation:8; \
+ uint32_t:7; \
+ uint32_t SelfIDCount_Error:1; \
+ }; \
+}
+
+#define DECLARE_ASYNC(prefix) \
+struct { \
+ union { \
+ struct { \
+ uint32_t prefix##ContextControl; \
+ uint32_t prefix##ContextControl_Alt; \
+ }; \
+ struct { \
+ uint32_t prefix##ContextControlSet; \
+ uint32_t prefix##ContextControlClear; \
+ }; \
+ }; \
+ uint32_t prefix##Reserved_08; \
+ uint32_t prefix##CommandPtr; \
+ uint32_t prefix##Reserved_10; \
+ uint32_t prefix##Reserved_14; \
+ uint32_t prefix##Reserved_18; \
+ uint32_t prefix##Reserved_1c; \
+}
+
+typedef union {
+ struct {
+ uint32_t Version;
+ uint32_t GUID_ROM;
+ uint32_t ATRetries;
+ union {
+ uint32_t CSRReadData; /* 00c */
+ uint32_t CSRWriteData; /* 00c */
+ };
+ uint32_t CSRCompareData;
+ uint32_t CSRControl;
+ DECLARE_CONFIG_ROM_HDR;
+ uint32_t BusID;
+ uint32_t BusOptions;
+ uint32_t GUIDHi;
+ uint32_t GUIDLo;
+ uint32_t Reserved_002c;
+ uint32_t Reserved_0030;
+ uint32_t ConfigROMMap;
+ uint32_t PostedWriteAddressLo;
+ uint32_t PostedWriteAddressHi;;
+ uint32_t VendorID;
+ uint32_t Reserved_0044;
+ uint32_t Reserved_0048;
+ uint32_t Reserved_004c;
+ union {
+ struct {
+ /* read */
+ uint32_t HCControl;
+ uint32_t HCControl_Alt;
+ };
+ struct {
+ /* write */
+ uint32_t HCControlSet;
+ uint32_t HCControlClear;
+ };
+ };
+ uint32_t Reserved_0058;
+ uint32_t Reserved_005c;
+ uint32_t Reserved_0060;
+ uint32_t SelfIDBuffer;
+ DECLARE_SELF_ID_COUNT;
+ uint32_t Reserved_006c;
+ union {
+ struct {
+ /* read */
+ uint32_t IRMultiChanMaskHi;
+ uint32_t IRMultiChanMaskHi_Alt;
+ };
+ struct {
+ /* write */
+ uint32_t IRMultiChanMaskHiSet;
+ uint32_t IRMultiChanMaskHiClear;
+ };
+ };
+ union {
+ struct {
+ /* read */
+ uint32_t IRMultiChanMaskLo;
+ uint32_t IRMultiChanMaskLo_Alt;
+ };
+ struct {
+ /* write */
+ uint32_t IRMultiChanMaskLoSet;
+ uint32_t IRMultiChanMaskLoClear;
+ };
+ };
+ union {
+ struct {
+ /* read */
+ DECLARE_INT(IntEvent); /* 0080 */
+ DECLARE_INT(IntEventMasked); /* 0084 */
+ };
+ struct {
+ /* write */
+ DECLARE_INT(IntEventSet); /* 0080 */
+ DECLARE_INT(IntEventClear); /* 0084 */
+ };
+ };
+ union {
+ struct {
+ /* read */
+ DECLARE_INT(IntMask);
+ DECLARE_INT(IntMask_Alt);
+ };
+ struct {
+ /* write */
+ DECLARE_INT(IntMaskSet);
+ DECLARE_INT(IntMaskClear);
+ };
+ };
+ union {
+ struct {
+ /* read */
+ uint32_t IsoXmitIntEvent;
+ uint32_t IsoXmitIntEventMasked;
+ };
+ struct {
+ /* write */
+ uint32_t IsoXmitIntEventSet;
+ uint32_t IsoXmitIntEventClear;
+ };
+ };
+ union {
+ struct {
+ /* read */
+ uint32_t IsoXmitIntMask;
+ uint32_t IsoXmitIntMask_Alt;
+ };
+ struct {
+ /* write */
+ uint32_t IsoXmitIntMaskSet;
+ uint32_t IsoXmitIntMaskClear;
+ };
+ };
+ union {
+ struct {
+ /* read */
+ uint32_t IsoRecvIntEvent;
+ uint32_t IsoRecvIntEventMasked;
+ };
+ struct {
+ /* write */
+ uint32_t IsoRecvIntEventSet;
+ uint32_t IsoRecvIntEventClear;
+ };
+ };
+ union {
+ struct {
+ /* read */
+ uint32_t IsoRecvIntMask;
+ uint32_t IsoRecvIntMask_Alt;
+ };
+ struct {
+ /* write */
+ uint32_t IsoRecvIntMaskSet;
+ uint32_t IsoRecvIntMaskClear;
+ };
+ };
+ uint32_t InitialBandwidthAvailable; /* 00B0 */
+ uint32_t InitialChannelsAvailableHi; /* 00B4 */
+ uint32_t InitialChannelsAvailableLo; /* 00B8 */
+ uint32_t Reserved_00bc;
+ uint32_t Reserved_00c0;
+ uint32_t Reserved_00c4;
+ uint32_t Reserved_00c8;
+ uint32_t Reserved_00dc;
+ uint32_t Reserved_00d0;
+ uint32_t Reserved_00d4;
+ uint32_t Reserved_00d8;
+ uint32_t FairnessControl; /* 00dc */
+ union {
+ struct {
+ /* read */
+ uint32_t LinkControl; /* 0xe0 */
+ uint32_t LinkControl_Alt; /* 0xe4 */
+ };
+ struct {
+ /* write */
+ uint32_t LinkControlSet; /* 0xe0 */
+ uint32_t LinkControlClear; /* 0xe4 */
+ };
+ };
+ DECLARE_NODE_ID; /* 00e8 */
+ DECLARE_PHY; /* 00ec */
+ uint32_t IsochronousCycleTimer; /* 00f0 */
+ uint32_t Reserved_00f4;
+ uint32_t Reserved_00f8;
+ uint32_t Reserved_00fc;
+ union {
+ struct {
+ /* read */
+ uint32_t AsynchronousRequestFilterHi; /* 0100 */
+ uint32_t AsynchronousRequestFilterHi_Alt; /* 0104 */
+ };
+ struct {
+ /* write */
+ uint32_t AsynchronousRequestFilterHiSet; /* 0100 */
+ uint32_t AsynchronousRequestFilterHiClear; /* 0104 */
+ };
+ };
+ union {
+ struct {
+ /* read */
+ uint32_t AsynchronousRequestFilterLo; /* 0108 */
+ uint32_t AsynchronousRequestFilterLo_Alt; /* 010c */
+ };
+ struct {
+ /* write */
+ uint32_t AsynchronousRequestFilterLoSet; /* 0108 */
+ uint32_t AsynchronousRequestFilterLoClear; /* 010c */
+ };
+ };
+ union {
+ struct {
+ /* read */
+ uint32_t PhysicalRequestFilterHi; /* 0110 */
+ uint32_t PhysicalRequestFilterHi_Alt; /* 0114 */
+ };
+ struct {
+ /* write */
+ uint32_t PhysicalRequestFilterHiSet; /* 0110 */
+ uint32_t PhysicalRequestFilterHiClear; /* 0114 */
+ };
+ };
+ union {
+ struct {
+ /* read */
+ uint32_t PhysicalRequestFilterLo; /* 0118 */
+ uint32_t PhysicalRequestFilterLo_Alt; /* 011c */
+ };
+ struct {
+ /* write */
+ uint32_t PhysicalRequestFilterLoSet; /* 0118 */
+ uint32_t PhysicalRequestFilterLoClear; /* 011c */
+ };
+ };
+ uint32_t PhyiscalUpperBound; /* 0120 */
+ uint32_t Reserved_0124;
+ uint32_t Reserved_0128;
+ uint32_t Reserved_012c;
+ uint32_t Reserved_0130;
+ uint32_t Reserved_0134;
+ uint32_t Reserved_0138;
+ uint32_t Reserved_013c;
+ uint32_t Reserved_0140;
+ uint32_t Reserved_0144;
+ uint32_t Reserved_0148;
+ uint32_t Reserved_014c;
+ uint32_t Reserved_0150;
+ uint32_t Reserved_0154;
+ uint32_t Reserved_0158;
+ uint32_t Reserved_015c;
+ uint32_t Reserved_0160;
+ uint32_t Reserved_0164;
+ uint32_t Reserved_0168;
+ uint32_t Reserved_016c;
+ uint32_t Reserved_0170;
+ uint32_t Reserved_0174;
+ uint32_t Reserved_0178;
+ uint32_t Reserved_017c;
+ DECLARE_ASYNC(AsyncRequestTransmit);
+ DECLARE_ASYNC(AsyncResponseTransmit);
+ DECLARE_ASYNC(AsyncRequestReceive);
+ DECLARE_ASYNC(AsyncResponseReceive);
+ /* Isoch stuff */
+ };
+ uint32_t regs[OHCI_1394_MMIO_SIZE >> 2];
+} mmio_regs_t;
+
+typedef union {
+ uint8_t bytes[1024];
+ uint32_t quads[1024 / 4];
+ struct {
+ DECLARE_CONFIG_ROM_HDR;
+ uint32_t BusID;
+ uint32_t BusOptions;
+ uint32_t GUIDHi;
+ uint32_t GUIDLo;
+ };
+} config_rom_t;
+
+typedef union {
+ uint8_t bytes[16];
+ struct {
+ /* 00 */
+ uint8_t CPS:1;
+ uint8_t Root:1;
+ uint8_t PhysicalID:6;
+ /* 01 */
+ uint8_t GapCount:6;
+ uint8_t IBR:1;
+ uint8_t RHB:1;
+ /* 02 */
+ uint8_t NumPorts:4;
+ uint8_t:1;
+ uint8_t Extended:3;
+ /* 03 */
+ uint8_t Delay:4;
+ uint8_t:1;
+ uint8_t PHYSpeed:3;
+ /* 04 */
+ uint8_t PwrClass:3;
+ uint8_t Jitter:3;
+ uint8_t C:1;
+ uint8_t L:1;
+ /* 05 */
+ uint8_t EMC:1;
+ uint8_t EAA:1;
+ uint8_t PEI:1;
+ uint8_t STOI:1;
+ uint8_t CPSI:1;
+ uint8_t CTOI:1;
+ uint8_t ISBR:1;
+ uint8_t RPIE:1;
+ /* 06 */
+ uint8_t reg6;
+ /* 07 */
+ uint8_t PortSelect:4;
+ uint8_t:1;
+ uint8_t PageSelect:3;
+ };
+} phy_t;
+
+#define REG_OFFSET(field) ((uint32_t)(uintptr_t)&(((mmio_regs_t *)0)->field))
+
+typedef union {
+ uint32_t val;
+ struct {
+ uint32_t m:1; /* = 0 */
+ uint32_t initiated:1; /* = 1 for root node */
+ uint32_t p2:2; /* = 0 */
+ uint32_t p1:2; /* = 0 */
+ uint32_t p0:2; /* = 3, maybe 2 when "child" compared to root */
+ uint32_t pwr:3; /* = 0 */
+ uint32_t c:1; /* = 1 when root */
+ uint32_t del:2; /* = 0? */
+ uint32_t sp:2; /* = 0? */
+ uint32_t gap_cnt:6; /* = 0? */
+ uint32_t L:1; /* = 1? maybe just when connected */
+ uint32_t:1; /* = 0 */
+ uint32_t node_id:6;
+ uint32_t type:2; /* = 2 */
+ };
+} self_id_t;
+
+struct _hcd_state_t;
+
+typedef struct _hcd_state_t hcd_state_t;
+
+typedef struct {
+ uint16_t req_count;
+ uint16_t:2;
+ uint16_t branch:2;
+ uint16_t interrupt:2;
+ uint16_t:1;
+ uint16_t ping:1;
+ uint16_t key:3;
+ uint16_t:1;
+ uint16_t cmd:4;
+ uint32_t data_address;
+ uint32_t branch_address;
+ uint16_t timestamp;
+ uint16_t transfer_status;
+} hcd_at_db_t;
+
+typedef struct {
+ hcd_state_t *s;
+ QEMUTimer *timer;
+ uint32_t num; /* base register is 0x180 + num * 0x20 */
+ uint32_t address; /* current address */
+ uint32_t response;
+} hcd_timer_state_t;
+
+struct _hcd_state_t {
+ PCIDevice pci_dev;
+ MemoryRegion mmio_bar;
+ mmio_regs_t mmio;
+ hcd_timer_state_t at_req_timer;
+ hcd_timer_state_t at_rsp_timer;
+ phy_t phy;
+ uint8_t phy_pages[8][8];
+ qemu_irq irq;
+ uint32_t irq_asserted;
+ /* properties from init */
+ CharDriverState *chr;
+ int state;
+ int other_link;
+ uint16_t bid;
+ int root;
+ int bufpos;
+ uint8_t buf[16 + 65536]; /* maximum request size + maximum data size */
+};
+
+static void hcd_bus_reset(hcd_state_t *s);
+static void hcd_chr_event(void *opaque, int event);
+
+static const VMStateDescription vmstate_pci_hcd = {
+ .name = "ohci-1394",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(pci_dev, hcd_state_t),
+ VMSTATE_UINT32_ARRAY(mmio.regs, hcd_state_t, OHCI_1394_MMIO_SIZE >> 2),
+ VMSTATE_UINT8_ARRAY(phy.bytes, hcd_state_t, 16),
+ VMSTATE_UINT8_2DARRAY(phy_pages, hcd_state_t, 8, 8),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static void
+hcd_check_irq(hcd_state_t *s) {
+ if ((s->mmio.IntMask & 0x80000000) &&
+ (s->mmio.IntEvent & s->mmio.IntMask)) {
+ if (!s->irq_asserted) {
+ qemu_set_irq(s->irq, 1);
+ s->irq_asserted = 1;
+ }
+ } else {
+ if (s->irq_asserted) {
+ qemu_set_irq(s->irq, 0);
+ s->irq_asserted = 0;
+ }
+ }
+}
+
+static void
+hcd_soft_reset(hcd_state_t *s) {
+ s->mmio.BusOptions = 0x00008002; /* 5.11 */
+ s->mmio.HCControl &= 0x00C00000; /* 5.7.2 */
+}
+
+static void
+hcd_hard_reset(hcd_state_t *s) {
+ memset(&s->mmio, 0, sizeof(s->mmio));
+ s->mmio.Version = 0x00010010; /* Release 1.1 of OHCI spec */
+ s->mmio.BusID = 0x31333934; /* 1394 */
+ s->mmio.BusOptions = 0x00008002; /* 5.11 */
+ s->mmio.GUIDHi = 0x89abcdef;
+ s->mmio.GUIDLo = 0x01234567;
+ memset(&s->phy, 0, sizeof(s->phy));
+ s->phy.NumPorts = 1;
+ s->phy.L = 1;
+ s->phy.C = 1;
+ s->phy_pages[0][0] = 0x08; /* 0xFE; */
+ hcd_soft_reset(s);
+}
+
+static void
+hcd_complete_self_id(hcd_state_t *s) {
+ s->mmio.NodeID_nodeNumber = (s->root) ? 0 : 1; /* 5.11 */
+ s->mmio.NodeID_busNumber = 0x3ff;
+ s->mmio.NodeID_CPS = (s->state != HCD_STATE_CONNECTED) ? 0 : 1;
+ s->mmio.NodeID_root = s->root;
+ s->mmio.NodeID_iDValid = 1;
+ s->mmio.SelfIDCount_Size = 0;
+ s->mmio.SelfIDCount_Error = 0;
+ if (s->mmio.LinkControl & 0x00000200) { /* if RcvSelfID */
+ uint32_t tmp = 0;
+ self_id_t sid;
+
+ sid.val = 0;
+ sid.initiated = 1;
+ sid.p0 = 2;
+ sid.c = 1;
+ sid.L = 1;
+ sid.node_id = 0;
+ sid.type = 2;
+ dma_memory_write(&address_space_memory,
+ s->mmio.SelfIDBuffer + 4,
+ &sid.val, 4);
+ sid.val = ~sid.val;
+ dma_memory_write(&address_space_memory,
+ s->mmio.SelfIDBuffer + 8,
+ &sid.val, 4);
+ s->mmio.SelfIDCount_Size += 2;
+
+ if (s->state == HCD_STATE_CONNECTED) {
+ sid.val = 0;
+ sid.initiated = 0;
+ sid.p0 = 3;
+ sid.c = 0;
+ sid.L = 1;
+ sid.node_id = 1;
+ sid.type = 2;
+ dma_memory_write(&address_space_memory,
+ s->mmio.SelfIDBuffer + 12,
+ &sid.val, 4);
+ sid.val = ~sid.val;
+ dma_memory_write(&address_space_memory,
+ s->mmio.SelfIDBuffer + 16,
+ &sid.val, 4);
+ s->mmio.SelfIDCount_Size += 2;
+ }
+
+ tmp = (s->mmio.SelfIDCount_Generation << 16) | 1;
+ dma_memory_write(&address_space_memory,
+ s->mmio.SelfIDBuffer,
+ &tmp, 4);
+ s->mmio.SelfIDCount_Size++;
+ }
+ s->mmio.IntEvent |= 0x00018000; /* selfIDcomplete | selfIDcomplete2 */
+ hcd_check_irq(s);
+}
+
+typedef struct {
+ uint32_t req_count:16;
+ uint32_t:2;
+ uint32_t branch:2;
+ uint32_t interrupt:2;
+ uint32_t:2;
+ uint32_t key:3;
+ uint32_t status:1;
+ uint32_t cmd:4;
+ uint32_t data_address;
+ uint32_t branch_address;
+ uint32_t res_count:16;
+ uint32_t transfer_status:16;
+} hcd_ar_db_t;
+
+static void
+hcd_async_rx_rsp_packet(hcd_state_t *s, uint8_t *buf, uint32_t size,
+ uint8_t response) {
+ int num = 3;
+ hcd_ar_db_t db;
+ uint32_t data_address = 0;
+ uint32_t status = 0;
+ int state = 0;
+
+ if (size == 0) {
+ return;
+ }
+ SET_Ax_EVENT_CODE(num, response);
+ dma_memory_read(&address_space_memory,
+ Ax_COMMAND_PTR(num) & 0xFFFFFFF0,
+ &db, sizeof(db));
+ data_address = db.data_address + db.req_count - db.res_count;
+ while (state != 3) {
+ int write_size;
+
+ db.transfer_status =
+ s->mmio.AsyncResponseReceiveContextControl & 0xFFFF;
+ if (db.res_count == 0) {
+ dma_memory_write(&address_space_memory,
+ Ax_COMMAND_PTR(num) & 0xFFFFFFF0,
+ &db, sizeof(db));
+ if (db.branch_address == 0) {
+ CLR_Ax_ACTIVE(num);
+ /* TODO: need to roll back if this happens */
+ }
+ SET_Ax_COMMAND_PTR(num, db.branch_address);
+ dma_memory_read(&address_space_memory,
+ Ax_COMMAND_PTR(num) & 0xFFFFFFF0,
+ &db, sizeof(db));
+ data_address = db.data_address + db.req_count - db.res_count;
+ }
+ switch (state) {
+ case 0:
+ if (db.res_count > size) {
+ write_size = size;
+ } else {
+ write_size = db.res_count;
+ }
+ dma_memory_write(&address_space_memory,
+ data_address,
+ buf, write_size);
+ db.res_count -= write_size;
+ data_address += write_size;
+ size -= write_size;
+ buf += write_size;
+ if (size == 0) {
+ state = 1;
+ }
+ break;
+ case 1:
+ status = s->mmio.AsyncResponseReceiveContextControl << 16;
+ db.transfer_status =
+ s->mmio.AsyncResponseReceiveContextControl & 0xFFFF;
+ dma_memory_write(&address_space_memory, data_address, &status, 4);
+ db.res_count -= 4;
+ data_address += 4;
+ dma_memory_write(&address_space_memory,
+ Ax_COMMAND_PTR(num) & 0xFFFFFFF0,
+ &db, sizeof(db));
+ state = 2;
+ break;
+ case 2:
+ /* this state exists to go around the loop again and update the db
+ if required */
+ state = 3;
+ break;
+ }
+ }
+ s->mmio.IntEvent |= (1 << 5);
+ hcd_check_irq(s);
+}
+
+static void
+hcd_async_rx_run(hcd_state_t *s, uint32_t addr) {
+ int num;
+
+ num = (addr & 0x0180) >> 7;
+ SET_Ax_ACTIVE(num);
+}
+
+static void
+hcd_async_rx_stop(hcd_state_t *s, uint32_t addr) {
+ int num;
+
+ num = (addr & 0x0180) >> 7;
+ CLR_Ax_ACTIVE(num);
+}
+
+static void
+hcd_async_rx_wake(hcd_state_t *s, uint32_t addr) {
+ uint32_t address;
+ hcd_ar_db_t db;
+ int num;
+
+ num = (addr & 0x0180) >> 7;
+ if (IS_Ax_ACTIVE(num)) {
+ return;
+ }
+ address = s->mmio.regs[(addr >> 2) + 0x00c];
+ dma_memory_read(&address_space_memory,
+ address & 0xFFFFFFF0,
+ &db, sizeof(db));
+ if ((db.branch_address & 0x0000000f) != 0) {
+ SET_Ax_ACTIVE(num);
+ SET_Ax_COMMAND_PTR(num, db.branch_address);
+ }
+}
+
+static void
+hcd_at_run(hcd_timer_state_t *t) {
+ hcd_state_t *s = t->s;
+ t->address = Ax_COMMAND_PTR(t->num) & 0xfffffff0;
+ t->response = EVT_TCODE_ERR;
+ SET_Ax_ACTIVE(t->num);
+}
+
+static void
+hcd_at_timer(void *o) {
+ hcd_timer_state_t *t = (hcd_timer_state_t *)o;
+ hcd_state_t *s = t->s;
+ ohci_packet_header_t packet_header;
+ hcd_at_db_t db;
+
+ if (IS_Ax_DEAD(t->num) || !IS_Ax_RUN(t->num)) {
+ CLR_Ax_WAKE(t->num);
+ CLR_Ax_ACTIVE(t->num);
+ return;
+ }
+ if (!IS_Ax_ACTIVE(t->num)) {
+ if (!IS_Ax_WAKE(t->num)) {
+ return;
+ }
+ CLR_Ax_WAKE(t->num);
+ dma_memory_read(&address_space_memory,
+ t->address, &db,
+ sizeof(hcd_at_db_t));
+ if (!(db.branch_address & 0x0000000f)) {
+ return;
+ }
+ SET_Ax_COMMAND_PTR(t->num, db.branch_address);
+ hcd_at_run(t); /* also sets active */
+ }
+ CLR_Ax_WAKE(t->num);
+ dma_memory_read(&address_space_memory,
+ t->address, &db,
+ sizeof(hcd_at_db_t));
+ if (db.cmd == 0 && db.key == 0) {
+ /* Do nothing */
+ } else if (db.cmd == 0 && db.key == 2) {
+ /* OUTPUT_MORE_Immediate */
+ } else if (db.cmd == 1 && db.key == 0) {
+ /* OUTPUT_LAST */
+ } else if (db.cmd == 1 && db.key == 2) {
+ /* OUTPUT_LAST_Immediate */
+ } else {
+ /* UNKNOWN COMMAND */
+ return ;
+ }
+
+ switch (db.key) {
+ case 0: { /* non-Immediate */
+ uint8_t buf[65536];
+ dma_memory_read(&address_space_memory,
+ db.data_address, buf,
+ db.req_count);
+ qemu_chr_fe_write(s->chr, buf, db.req_count);
+ break;
+ }
+ case 2: { /* Immediate */
+ uint32_t data[4];
+ dma_memory_read(&address_space_memory,
+ t->address + sizeof(hcd_at_db_t),
+ data, db.req_count);
+
+ packet_header = *(ohci_packet_header_t *)data;
+ switch (packet_header.t_code) {
+ case 0x00: { /* quadlet write - quadlet format */
+ ohci_req_quadlet_packet_t at_packet =
+ *(ohci_req_quadlet_packet_t *)data;
+ qemu_chr_fe_write(s->chr, (uint8_t *)data, sizeof(at_packet));
+ t->response = ACK_PENDING;
+ break;
+ }
+ case 0x01: { /* block write - block write format */
+ qemu_chr_fe_write(s->chr, (uint8_t *)data, db.req_count);
+ t->response = ACK_PENDING;
+ break;
+ }
+ case 0x04: { /* quadlet read - nodata format */
+ qemu_chr_fe_write(s->chr, (uint8_t *)data, db.req_count);
+ t->response = ACK_PENDING;
+ break;
+ }
+ case 0x05: { /* read bytes from target */
+ qemu_chr_fe_write(s->chr, (uint8_t *)data, db.req_count);
+ t->response = ACK_PENDING;
+ break;
+ }
+ case 0x0e: { /* PHY packet */
+ /* probably just configuring the gap count... */
+ t->response = ACK_COMPLETE;
+ /* reset because PHY packet */
+ hcd_bus_reset(s); /* not all PHY packets require reset... */
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (db.cmd == 0) { /* more */
+ if (db.key == 2) {
+ t->address += sizeof(hcd_at_db_t) + sizeof(int32_t) * 4;
+ } else {
+ t->address += sizeof(hcd_at_db_t);
+ }
+ } else { /* last */
+ if (db.interrupt == 3) {
+ s->mmio.IntEvent |= (1 << t->num);
+ }
+ SET_Ax_EVENT_CODE(t->num, t->response);
+ db.transfer_status = (uint16_t)Ax_CONTEXT_CONTROL(t->num);
+ dma_memory_write(&address_space_memory, t->address, &db, sizeof(db));
+ if ((db.branch_address & 0x0000000f) == 0) {
+ CLR_Ax_ACTIVE(t->num);
+ return;
+ }
+ SET_Ax_COMMAND_PTR(t->num, db.branch_address);
+ hcd_at_run(t);
+ }
+ timer_mod(t->timer, 0);
+ /* maybe
+ t_now + get_ticks_per_sec() / 100000);
+ 100/sec isn't going to be right */
+}
+
+static void
+hcd_bus_reset(hcd_state_t *s) {
+ uint32_t bus_reset_packet[3] = {0x000000e0, 0x00000000, 0x00000000};
+ s->mmio.NodeID_busNumber = 0x3ff;
+ s->mmio.NodeID_CPS = 0;
+ s->mmio.NodeID_root = 0;
+ s->mmio.NodeID_iDValid = 0;
+ s->mmio.SelfIDCount_Generation++;
+ s->mmio.IntEvent |= 0x00020000; /* bus reset complete */
+ if (s->state != HCD_STATE_CONNECTED) {
+ s->root = 1;
+ }
+ s->mmio.AsyncRequestTransmitContextControl &= 0xFFFFFBFF;
+ s->mmio.AsyncResponseTransmitContextControl &= 0xFFFFFBFF;
+ if (s->mmio.AsyncResponseReceiveContextControl & 0x00008000) {
+ bus_reset_packet[2] |= s->mmio.SelfIDCount_Generation << 16;
+ hcd_async_rx_rsp_packet(s, (uint8_t *)bus_reset_packet,
+ sizeof(bus_reset_packet), EVT_BUS_RESET);
+ }
+ hcd_complete_self_id(s);
+}
+
+static uint8_t
+hcd_phy_read(hcd_state_t *s, uint8_t reg) {
+ if (reg < 8) {
+ return s->phy.bytes[reg];
+ } else {
+ return s->phy_pages[s->phy.PageSelect][reg & 7];
+ }
+}
+
+static void
+hcd_phy_write(hcd_state_t *s, uint8_t reg, uint8_t data) {
+ if (reg < 8) {
+ switch (reg) {
+ case 0: /* not allowed? */
+ break;
+ case 1:
+ s->phy.bytes[reg] = data & 0xBF;
+ if (data & 0x40) {
+ hcd_bus_reset(s);
+ }
+ break;
+ case 5:
+ s->phy.bytes[reg] = data & 0xBF;
+ if (data & 0x40) {
+ hcd_bus_reset(s);
+ }
+ break;
+ default:
+ s->phy.bytes[reg] = data;
+ break;
+ }
+ } else {
+ s->phy_pages[s->phy.PageSelect][reg & 7] = data;
+ }
+}
+
+static uint64_t hcd_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+ uint64_t ret;
+ hcd_state_t *s = (hcd_state_t *)opaque;
+ switch (addr) {
+ case REG_OFFSET(IntEventMasked): /* 0084 */
+ ret = s->mmio.IntEvent & s->mmio.IntMask;
+ break;
+ default:
+ ret = s->mmio.regs[addr >> 2];
+ break;
+ }
+ if (addr != 0x0080) {
+ /* what to do? */
+ }
+ return ret;
+}
+
+static void hcd_mmio_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned size)
+{
+ hcd_state_t *s = (hcd_state_t *)opaque;
+ DECLARE_PHY phy_control;
+ DECLARE_NODE_ID NodeID;
+
+ if ((addr & 0xFFE0) != 0x0100) {
+ /* what to do? */
+ }
+ switch (addr) {
+ case REG_OFFSET(ATRetries): /* 0008 */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(CSRWriteData): /* 00c */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(CSRCompareData): /* 010 */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(CSRControl): /* 014 */
+ switch (data & 0x00000003) {
+ case 0: /* BUS_MANAGER_ID */
+ /* TODO: set bus manager somewhere... */
+ s->mmio.CSRReadData = s->mmio.CSRCompareData;
+ s->mmio.CSRControl = 0x80000000 | (data & 0x00000003);
+ break;
+ case 1: /* BANDWIDTH_AVAILABLE */
+ /* not actioned */
+ s->mmio.CSRControl = 0x80000000 | (data & 0x00000003);
+ break;
+ case 2: /* CHANNELS_AVAILABLE_HI */
+ /* not actioned */
+ s->mmio.CSRControl = 0x80000000 | (data & 0x00000003);
+ break;
+ case 3: /* CHANNELS_AVAILABLE_LO */
+ /* not actioned */
+ s->mmio.CSRControl = 0x80000000 | (data & 0x00000003);
+ break;
+ }
+ break;
+ case REG_OFFSET(ConfigROMhdr): /* 0018 */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(BusID): /* 001c */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(BusOptions): /* 0020 */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(GUIDHi): /* 0024 */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(GUIDLo): /* 0028 */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(ConfigROMMap): /* 0034 */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(HCControlSet): /* 0050 */
+ data &= 0xE0CF0000;
+ s->mmio.HCControl |= data;
+ if (data & HCCONTROL_RESET_MASK) {
+ /* do a reset */
+ hcd_soft_reset(s);
+ }
+ if (data & HCCONTROL_LINK_ENABLE_MASK) {
+ if ((s->state == HCD_STATE_DISCONNECTED) ||
+ (s->state == HCD_STATE_ARBITRATION1)) {
+ uint32_t buf = 0xFFFFFFFF;
+ qemu_chr_fe_write(s->chr, (uint8_t *)&buf, 4);
+ }
+ }
+ break;
+ case REG_OFFSET(HCControlClear): /* 0054 */
+ data &= 0xE0CE0000;
+ s->mmio.HCControl &= ~data;
+ break;
+ case REG_OFFSET(SelfIDBuffer): /* 0064 */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(SelfIDCount): /* 0068 */
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ case REG_OFFSET(IRMultiChanMaskHiSet): /* 0070 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(IRMultiChanMaskHiClear): /* 0074 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(IRMultiChanMaskLoSet): /* 0078 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(IRMultiChanMaskLoClear): /* 007c */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(IntEventSet): /* 0080 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ break;
+ case REG_OFFSET(IntEventClear): /* 0084 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ break;
+ case REG_OFFSET(IntMaskSet): /* 0088 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ break;
+ case REG_OFFSET(IntMaskClear): /* 008c */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ break;
+ case REG_OFFSET(IsoXmitIntMaskSet):
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ break;
+ case REG_OFFSET(IsoXmitIntMaskClear):
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ break;
+ case REG_OFFSET(IsoRecvIntMaskSet):
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ break;
+ case REG_OFFSET(IsoRecvIntMaskClear):
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ break;
+ case REG_OFFSET(LinkControlSet):
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ break;
+ case REG_OFFSET(LinkControlClear):
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ break;
+ case REG_OFFSET(NodeID): /* 00E8 */
+ NodeID.NodeID = data;
+ s->mmio.NodeID_busNumber = NodeID.NodeID_busNumber;
+ break;
+ case REG_OFFSET(PhyControl): /* 00ec */
+ *(uint32_t *)&phy_control = data;
+ s->mmio.PhyControl_regAddr = phy_control.PhyControl_regAddr;
+ if (phy_control.PhyControl_rdReg) {
+ s->mmio.PhyControl_rdAddr = phy_control.PhyControl_regAddr;
+ s->mmio.PhyControl_rdData =
+ hcd_phy_read(s, phy_control.PhyControl_regAddr);
+ s->mmio.PhyControl_rdDone = 1;
+ s->mmio.IntEvent_phyRegRcvd = 1;
+ }
+ if (phy_control.PhyControl_wrReg) {
+ hcd_phy_write(s, phy_control.PhyControl_regAddr,
+ phy_control.PhyControl_wrData);
+ s->mmio.PhyControl_wrData = phy_control.PhyControl_wrData;
+ s->mmio.PhyControl_rdDone = 0;
+ }
+ break;
+ case REG_OFFSET(AsynchronousRequestFilterHiSet): /* 0x100 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(AsynchronousRequestFilterHiClear): /* 0x104 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(AsynchronousRequestFilterLoSet): /* 0x108 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(AsynchronousRequestFilterLoClear): /* 0x10c */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(PhysicalRequestFilterHiSet): /* 0x110 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(PhysicalRequestFilterHiClear): /* 0x114 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(PhysicalRequestFilterLoSet): /* 0x118 */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(PhysicalRequestFilterLoClear): /* 0x11c */
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(AsyncRequestTransmitContextControlSet):
+ case REG_OFFSET(AsyncResponseTransmitContextControlSet):
+ data &= 0x00009000;
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ if (data & 0x00009000) {
+ hcd_timer_state_t *t = NULL;
+ if (addr == REG_OFFSET(AsyncRequestTransmitContextControlSet)) {
+ t = &s->at_req_timer;
+ } else {
+ t = &s->at_rsp_timer;
+ }
+ if (data & 0x00008000) {
+ hcd_at_run(t);
+ }
+ timer_mod(t->timer, 0);
+ }
+ break;
+ case REG_OFFSET(AsyncRequestReceiveContextControlSet):
+ case REG_OFFSET(AsyncResponseReceiveContextControlSet):
+ data &= 0x00009000;
+ s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ if (data & 0x00008000) {
+ hcd_async_rx_run(s, addr & 0xFFE0);
+ }
+ if (data & 0x00001000) {
+ hcd_async_rx_wake(s, addr & 0xFFE0);
+ }
+ break;
+ case REG_OFFSET(AsyncRequestTransmitContextControlClear):
+ case REG_OFFSET(AsyncResponseTransmitContextControlClear):
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ break;
+ case REG_OFFSET(AsyncRequestReceiveContextControlClear):
+ case REG_OFFSET(AsyncResponseReceiveContextControlClear):
+ data &= 0x00008000;
+ s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+ s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+ s->mmio.regs[((addr >> 2) & 0xFFFE)];
+ if (data & 0x00008000) {
+ hcd_async_rx_stop(s, addr & 0xFFE0);
+ }
+ break;
+ default:
+ s->mmio.regs[addr >> 2] = data;
+ break;
+ }
+ hcd_check_irq(s);
+}
+
+static const MemoryRegionOps hcd_mmio_ops = {
+ .read = hcd_mmio_read,
+ .write = hcd_mmio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN, /* TODO: might change with arch */
+};
+
+static int hcd_chr_can_receive(void *opaque)
+{
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ /* this seems to race with the restore
+ RUN_STATE_INMIGRATE */
+ return 0;
+ } else {
+ return 8192;
+ }
+}
+
+static void hcd_fill_buffer(hcd_state_t *s, const uint8_t **buf, int *len,
+ int required)
+{
+ int to_copy;
+
+ if (s->bufpos >= required) {
+ return;
+ }
+ if (required - s->bufpos > *len) {
+ to_copy = *len;
+ } else {
+ to_copy = required - s->bufpos;
+ }
+
+ memcpy(s->buf + s->bufpos, *buf, to_copy);
+ *buf += to_copy;
+ *len -= to_copy;
+ s->bufpos += to_copy;
+}
+
+static void hcd_chr_receive(void *opaque, const uint8_t *buf, int len)
+{
+ hcd_state_t *s = (hcd_state_t *)opaque;
+ uint16_t received_bid;
+ struct timeval tv;
+ ohci_packet_header_t *packet_header;
+
+ while (len) {
+ switch (s->state) {
+ case HCD_STATE_UNPLUGGED:
+ /* restore races with chr event, just fake it here */
+ hcd_chr_event(s, CHR_EVENT_OPENED);
+ break;
+ case HCD_STATE_MAGIC: /* waiting for magic */
+ hcd_fill_buffer(s, &buf, &len, 4);
+ if (s->bufpos < 4) {
+ /* not enough data yet HCD_MAGIC */
+ break;
+ }
+ if (s->bufpos > 4) {
+ /* overflow HCD_MAGIC */
+ break;
+ }
+ if (memcmp(s->buf, "1394", 4) != 0) {
+ /* TODO: what do we do here? drop the connection I suppose */
+ break;
+ } else {
+ s->state = HCD_STATE_DISCONNECTED;
+ }
+ s->bufpos = 0;
+ break;
+ case HCD_STATE_DISCONNECTED:
+ hcd_fill_buffer(s, &buf, &len, 4);
+ if (s->bufpos < 4) {
+ /* not enough data yet HCD_STATE_DISCONNECTED */
+ return;
+ }
+ s->bufpos = 0;
+ if (*(uint32_t *)s->buf != 0xFFFFFFFF) {
+ /* unknown data */
+ break;
+ }
+ s->other_link = 1;
+ /* link change - connected */
+ s->state = HCD_STATE_ARBITRATION1;
+ if (!(s->mmio.HCControl & HCCONTROL_LINK_ENABLE_MASK)) {
+ /* we will progress when our link comes up and the other end
+ sends a bid */
+ break;
+ }
+ /* fall through as we won't go around again because len == 0 */
+ case HCD_STATE_ARBITRATION1:
+ gettimeofday(&tv, NULL);
+ s->bid = 0;
+ s->bid ^= (tv.tv_sec >> 0) & 0xFFFF;
+ s->bid ^= (tv.tv_sec >> 16) & 0xFFFF;
+ s->bid ^= (tv.tv_sec >> 32) & 0xFFFF;
+ s->bid ^= (tv.tv_sec >> 48) & 0xFFFF;
+ s->bid ^= (tv.tv_usec >> 0) & 0xFFFF;
+ s->bid ^= (tv.tv_usec >> 16) & 0xFFFF;
+ s->bid ^= (tv.tv_usec >> 32) & 0xFFFF;
+ s->bid ^= (tv.tv_usec >> 48) & 0xFFFF;
+ s->bid &= 0x7FFF;
+ /* TODO: set high bit based on preference to become root */
+ qemu_chr_fe_write(s->chr, (uint8_t *)&s->bid, 2);
+ s->state = HCD_STATE_ARBITRATION2;
+ break;
+ case HCD_STATE_ARBITRATION2:
+ hcd_fill_buffer(s, &buf, &len, 2);
+ if (s->bufpos < 2) {
+ /* not enough data yet HCD_STATE_ARBITRATION2 */
+ break;
+ }
+ received_bid = *(uint16_t *)s->buf;
+ s->bufpos = 0;
+ if (received_bid == s->bid) {
+ s->state = HCD_STATE_ARBITRATION1;
+ break;
+ } else if (received_bid < s->bid) {
+ s->root = 1;
+ s->state = HCD_STATE_CONNECTED;
+ } else {
+ s->root = 0;
+ s->state = HCD_STATE_CONNECTED;
+ }
+ hcd_bus_reset(s);
+ break;
+ case HCD_STATE_CONNECTED:
+ if (!(s->mmio.HCControl & HCCONTROL_LINK_ENABLE_MASK)) {
+ return;
+ }
+ hcd_fill_buffer(s, &buf, &len, 4);
+ if (s->bufpos < 4) {
+ /* not enough data yet HCD_STATE_CONNECTED */
+ return;
+ }
+ if (*(uint32_t *)s->buf == 0xFFFFFFFE) {
+ /* Reset because link change */
+ s->bufpos = 0;
+ s->state = HCD_STATE_DISCONNECTED;
+ hcd_bus_reset(s);
+ break;
+ }
+ packet_header = (ohci_packet_header_t *)s->buf;
+
+ switch (packet_header->t_code) {
+ case 0x00: { /* request - quadlet write */
+ ohci_req_quadlet_packet_t *req_packet;
+ ohci_rsp_nodata_packet_t rsp_packet;
+ hcd_fill_buffer(s, &buf, &len, sizeof(*req_packet));
+ if (s->bufpos < sizeof(*req_packet)) {
+ /* not enough data yet HCD_STATE_CONNECTED 00 */
+ return;
+ }
+ if (s->bufpos > sizeof(*req_packet)) {
+ /* overflow HCD_STATE_CONNECTED 00 */
+ return;
+ }
+ req_packet = (ohci_req_quadlet_packet_t *)s->buf;
+ dma_memory_write(&address_space_memory,
+ req_packet->destination_offset_low,
+ &req_packet->data, sizeof(uint32_t));
+ /* forward to ar or handle here?? */
+ rsp_packet.t_code = 0x02;
+ rsp_packet.rt = req_packet->rt;
+ rsp_packet.t_label = req_packet->t_label;
+ rsp_packet.r_code = RESP_COMPLETE;
+ rsp_packet.destination_id = req_packet->destination_id ^ 1;
+ rsp_packet.source_id = req_packet->destination_id;
+ qemu_chr_fe_write(s->chr, (uint8_t *)&rsp_packet,
+ sizeof(rsp_packet));
+ s->bufpos = 0;
+ break;
+ }
+ case 0x01: { /* request - block write */
+ ohci_req_block_packet_t *req_packet;
+ ohci_rsp_nodata_packet_t rsp_packet;
+ hcd_fill_buffer(s, &buf, &len, sizeof(*req_packet));
+ if (s->bufpos < sizeof(*req_packet)) {
+ /* not enough data yet HCD_STATE_CONNECTED 01 */
+ return;
+ }
+ req_packet = (ohci_req_block_packet_t *)s->buf;
+ hcd_fill_buffer(s, &buf, &len,
+ sizeof(*req_packet) + req_packet->data_length);
+ if (s->bufpos < (sizeof(*req_packet) +
+ req_packet->data_length)) {
+ /* not enough data yet HCD_STATE_CONNECTED 01 */
+ return;
+ }
+ if (s->bufpos > (sizeof(*req_packet) +
+ req_packet->data_length)) {
+ /* overflow HCD_STATE_CONNECTED 01 */
+ return;
+ }
+ dma_memory_write(&address_space_memory,
+ req_packet->destination_offset_low,
+ s->buf + sizeof(*req_packet),
+ req_packet->data_length);
+ /* forward to ar or handle here?? */
+ rsp_packet.t_code = 0x02;
+ rsp_packet.rt = req_packet->rt;
+ rsp_packet.t_label = req_packet->t_label;
+ rsp_packet.r_code = RESP_COMPLETE;
+ rsp_packet.destination_id = req_packet->destination_id ^ 1;
+ rsp_packet.source_id = req_packet->destination_id;
+ qemu_chr_fe_write(s->chr, (uint8_t *)&rsp_packet,
+ sizeof(rsp_packet));
+ s->bufpos = 0;
+ break;
+ }
+ case 0x02: { /* response - quadlet write */
+ ohci_rsp_nodata_packet_t *rsp_packet;
+ hcd_fill_buffer(s, &buf, &len, sizeof(*rsp_packet));
+ if (s->bufpos < sizeof(*rsp_packet)) {
+ /* not enough data yet HCD_STATE_CONNECTED 02 */
+ return;
+ }
+ if (s->bufpos > sizeof(*rsp_packet)) {
+ /* overflow HCD_STATE_CONNECTED 02 */
+ return;
+ }
+ rsp_packet = (ohci_rsp_nodata_packet_t *)s->buf;
+ hcd_async_rx_rsp_packet(s, (uint8_t *)rsp_packet,
+ sizeof(*rsp_packet), ACK_COMPLETE);
+ s->bufpos = 0;
+ break;
+ }
+ case 0x04: { /* request - quadlet read */
+ ohci_req_nodata_packet_t *req_nodata_packet;
+ ohci_rsp_quadlet_packet_t rsp_quadlet_packet;
+ hcd_fill_buffer(s, &buf, &len, 12);
+ if (s->bufpos < 12) {
+ /* not enough data yet HCD_STATE_CONNECTED 04 */
+ return;
+ }
+ if (s->bufpos > 12) {
+ /* overflow HCD_STATE_CONNECTED 04 */
+ return;
+ }
+ req_nodata_packet = (ohci_req_nodata_packet_t *)s->buf;
+ /* forward to ar or handle here?? */
+ rsp_quadlet_packet.t_code = 0x06;
+ rsp_quadlet_packet.rt = req_nodata_packet->rt;
+ rsp_quadlet_packet.t_label = req_nodata_packet->t_label;
+ rsp_quadlet_packet.destination_id =
+ req_nodata_packet->destination_id ^ 1;
+ rsp_quadlet_packet.source_id =
+ req_nodata_packet->destination_id;
+ if (req_nodata_packet->destination_offset_high == 0xFFFF) {
+ if (0xF0000400 ==
+ (req_nodata_packet->destination_offset_low &
+ 0xFFFFFC00)) {
+ uint32_t tmp_addr = s->mmio.ConfigROMMap +
+ (req_nodata_packet->destination_offset_low & 0x3ff);
+
+ dma_memory_read(&address_space_memory,
+ tmp_addr,
+ &rsp_quadlet_packet.data,
+ sizeof(uint32_t));
+ rsp_quadlet_packet.r_code = RESP_COMPLETE;
+ } else {
+ /* Unknown address */
+ rsp_quadlet_packet.r_code = RESP_ADDRESS_ERROR;
+ }
+ } else if ((req_nodata_packet->destination_offset_high) ==
+ 0x0000) {
+ if (dma_memory_read(
+ &address_space_memory,
+ req_nodata_packet->destination_offset_low,
+ &rsp_quadlet_packet.data, sizeof(uint32_t))) {
+ rsp_quadlet_packet.r_code = RESP_ADDRESS_ERROR;
+ } else {
+ rsp_quadlet_packet.r_code = RESP_COMPLETE;
+ }
+ } else {
+ /* Unknown address */
+ rsp_quadlet_packet.r_code = RESP_ADDRESS_ERROR;
+ }
+
+ qemu_chr_fe_write(s->chr, (uint8_t *)&rsp_quadlet_packet,
+ sizeof(rsp_quadlet_packet));
+ s->bufpos = 0;
+ break;
+ }
+ case 0x05: { /* request - block read */
+ ohci_req_block_packet_t *req_packet;
+ ohci_rsp_block_packet_t rsp_packet;
+ uint8_t bounce_buffer[65536];
+ hcd_fill_buffer(s, &buf, &len, sizeof(*req_packet));
+ if (s->bufpos < sizeof(*req_packet)) {
+ /* not enough data yet HCD_STATE_CONNECTED 05 */
+ return;
+ }
+ if (s->bufpos > sizeof(*req_packet)) {
+ /* overflow HCD_STATE_CONNECTED 05 */
+ return;
+ }
+ req_packet = (ohci_req_block_packet_t *)s->buf;
+ /* forward to ar or handle here?? */
+ rsp_packet.t_code = 0x07;
+ rsp_packet.rt = req_packet->rt;
+ rsp_packet.t_label = req_packet->t_label;
+ rsp_packet.destination_id = req_packet->destination_id ^ 1;
+ rsp_packet.source_id = req_packet->destination_id;
+ rsp_packet.data_length = req_packet->data_length;
+ if (req_packet->destination_offset_high == 0xFFFF) {
+ if ((req_packet->destination_offset_low & 0xFFFFFC00) ==
+ 0xF0000400) {
+ uint32_t tmp_addr = s->mmio.ConfigROMMap +
+ (req_packet->destination_offset_low & 0x3ff);
+ dma_memory_read(&address_space_memory,
+ tmp_addr,
+ bounce_buffer, rsp_packet.data_length);
+ rsp_packet.r_code = RESP_COMPLETE;
+ } else {
+ /* Unknown address */
+ rsp_packet.r_code = RESP_ADDRESS_ERROR;
+ }
+ } else if ((req_packet->destination_offset_high) == 0x0000) {
+ if (dma_memory_read(&address_space_memory,
+ req_packet->destination_offset_low,
+ bounce_buffer,
+ rsp_packet.data_length)) {
+ /* address error */
+ rsp_packet.r_code = RESP_ADDRESS_ERROR;
+ } else {
+ rsp_packet.r_code = RESP_COMPLETE;
+ }
+ } else {
+ /* Unknown address */
+ rsp_packet.r_code = RESP_ADDRESS_ERROR;
+ }
+ qemu_chr_fe_write(s->chr, (uint8_t *)&rsp_packet,
+ sizeof(rsp_packet));
+ if (rsp_packet.r_code == RESP_COMPLETE) {
+ qemu_chr_fe_write(s->chr, bounce_buffer,
+ rsp_packet.data_length);
+ }
+ s->bufpos = 0;
+ break;
+ }
+ case 0x06: { /* response - quadlet read */
+ ohci_rsp_quadlet_packet_t *rsp_packet;
+ hcd_fill_buffer(s, &buf, &len, sizeof(*rsp_packet));
+ if (s->bufpos < sizeof(*rsp_packet)) {
+ /* not enough data yet HCD_STATE_CONNECTED 4 */
+ return;
+ }
+ if (s->bufpos > sizeof(*rsp_packet)) {
+ /* overflow HCD_STATE_CONNECTED 4 */
+ return;
+ }
+ rsp_packet = (ohci_rsp_quadlet_packet_t *)s->buf;
+
+ hcd_async_rx_rsp_packet(s, (uint8_t *)rsp_packet,
+ sizeof(*rsp_packet), ACK_COMPLETE);
+ s->bufpos = 0;
+ break;
+ }
+ case 0x07: { /* response - block read */
+ ohci_rsp_block_packet_t *rsp_packet;
+ hcd_fill_buffer(s, &buf, &len, sizeof(*rsp_packet));
+ if (s->bufpos < sizeof(*rsp_packet)) {
+ /* not enough data yet HCD_STATE_CONNECTED 07 */
+ return;
+ }
+ rsp_packet = (ohci_rsp_block_packet_t *)s->buf;
+ hcd_fill_buffer(s, &buf, &len,
+ sizeof(*rsp_packet) + rsp_packet->data_length);
+ if (s->bufpos <
+ (sizeof(*rsp_packet) + rsp_packet->data_length)) {
+ /* not enough data yet HCD_STATE_CONNECTED 07 */
+ return;
+ }
+ if (s->bufpos >
+ (sizeof(*rsp_packet) + rsp_packet->data_length)) {
+ /* overflow HCD_STATE_CONNECTED 07 */
+ return;
+ }
+ hcd_async_rx_rsp_packet(s, (uint8_t *)rsp_packet,
+ sizeof(*rsp_packet) +
+ rsp_packet->data_length,
+ ACK_COMPLETE);
+ s->bufpos = 0;
+ break;
+ }
+ default:
+ /* unknown t_code */
+ break;
+ }
+ return;
+ }
+ }
+}
+
+static void hcd_chr_event(void *opaque, int event)
+{
+ hcd_state_t *s = (hcd_state_t *)opaque;
+
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ /* RUN_STATE_INMIGRATE */
+ return;
+ }
+
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ s->state = HCD_STATE_MAGIC;
+ qemu_chr_fe_write(s->chr, (uint8_t *)"1394", 4);
+ if (s->mmio.HCControl & HCCONTROL_LINK_ENABLE_MASK) {
+ uint32_t buf = 0xFFFFFFFF;
+ qemu_chr_fe_write(s->chr, (uint8_t *)&buf, 4);
+ if (s->other_link) {
+ hcd_bus_reset(s);
+ }
+ }
+ break;
+ case CHR_EVENT_CLOSED:
+ s->state = HCD_STATE_UNPLUGGED;
+ s->phy_pages[0][0] = 0x08; /* 0xFE ? */
+ /* TODO: interrupt? */
+ s->phy.PEI = 1;
+ s->mmio.IntEvent |= (1 << 19);
+ hcd_bus_reset(s);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+hcd_pci_init(PCIDevice *pci_dev) {
+ hcd_state_t *s = DO_UPCAST(hcd_state_t, pci_dev, pci_dev);
+ uint8_t *pci_conf = pci_dev->config;
+
+ pci_set_byte(pci_conf + PCI_CLASS_PROG, 0x10);
+ pci_set_word(pci_conf + PCI_STATUS,
+ PCI_STATUS_DEVSEL_MEDIUM | PCI_STATUS_FAST_BACK);
+ pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 1);
+ pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
+
+ memory_region_init_io(&s->mmio_bar, OBJECT(s), &hcd_mmio_ops, s,
+ "ohci-1394-mmio", OHCI_1394_MMIO_SIZE);
+ pci_register_bar(&s->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ &s->mmio_bar);
+ s->irq = pci_allocate_irq(&s->pci_dev);
+ s->at_req_timer.s = s;
+ s->at_req_timer.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hcd_at_timer,
+ &s->at_req_timer);
+ s->at_req_timer.num = 0;
+ s->at_rsp_timer.s = s;
+ s->at_rsp_timer.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hcd_at_timer,
+ &s->at_rsp_timer);
+ s->at_rsp_timer.num = 1;
+ qemu_chr_add_handlers(s->chr, hcd_chr_can_receive, hcd_chr_receive,
+ hcd_chr_event, s);
+ hcd_hard_reset(s);
+ return 0;
+}
+
+static void
+hcd_pci_exit(PCIDevice *pci_dev)
+{
+ /*
+ hcd_state_t *s = DO_UPCAST(hcd_state_t, pci_dev, pci_dev);
+ memory_region_destroy(&s->mmio_bar); */
+}
+
+static Property hcd_properties[] = {
+ DEFINE_PROP_CHR("chardev", hcd_state_t, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void
+hcd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = hcd_pci_init;
+ k->exit = hcd_pci_exit;
+ k->vendor_id = PCI_VENDOR_ID_QEMU;
+ k->device_id = 0x1394;
+ k->class_id = 0x0C00;
+ dc->vmsd = &vmstate_pci_hcd;
+ dc->props = hcd_properties;
+}
+
+static const TypeInfo hcd_info = {
+ .name = "ohci-1394",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(hcd_state_t),
+ .class_init = hcd_class_init,
+};
+
diff --git a/hw/1394/hcd-ohci.h b/hw/1394/hcd-ohci.h
new file mode 100644
index 0000000..b150175
--- /dev/null
+++ b/hw/1394/hcd-ohci.h
@@ -0,0 +1,147 @@
+#ifndef HCD_OHCI_H
+#define HCD_OHCI_H
+
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hcd-ohci.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/char.h"
+#include "qemu/timer.h"
+
+#define EVT_NO_STATUS 0x00
+#define EVT_UNDERRUN 0x04
+#define EVT_OVERRUN 0x05
+#define EVT_DATA_READ 0x07
+#define EVT_DATA_WRITE 0x08
+#define EVT_BUS_RESET 0x09
+#define EVT_TCODE_ERR 0x0B
+#define EVT_UNKNOWN 0x0E
+#define EVT_FLUSHED 0x0F
+#define ACK_COMPLETE 0x11
+#define ACK_PENDING 0x12
+
+#define RESP_COMPLETE 0x00
+#define RESP_CONFLICT_ERROR 0x04
+#define RESP_DATA_ERROR 0x05
+#define RESP_TYPE_ERROR 0x06
+#define RESP_ADDRESS_ERROR 0x07
+
+typedef union {
+ uint32_t qdata[3];
+ struct {
+ uint32_t:4;
+ uint32_t t_code:4;
+ uint32_t rt:2;
+ uint32_t t_label:6;
+ uint32_t spd:3;
+ uint32_t:4;
+ uint32_t src_bus_id:1;
+ uint32_t:8;
+ };
+} ohci_packet_header_t;
+
+typedef union {
+ uint32_t qdata[3];
+ struct {
+ uint32_t:4;
+ uint32_t t_code:4;
+ uint32_t rt:2;
+ uint32_t t_label:6;
+ uint32_t spd:3;
+ uint32_t:4;
+ uint32_t src_bus_id:1;
+ uint32_t:8;
+ uint32_t destination_offset_high:16;
+ uint32_t destination_id:16;
+ uint32_t destination_offset_low:32;
+ };
+} ohci_req_nodata_packet_t;
+
+typedef union {
+ uint32_t qdata[3];
+ struct {
+ uint32_t:4;
+ uint32_t t_code:4;
+ uint32_t rt:2;
+ uint32_t t_label:6;
+ uint32_t spd:3;
+ uint32_t:4;
+ uint32_t src_bus_id:1;
+ uint32_t:8;
+ uint32_t destination_offset_high:16;
+ uint32_t destination_id:16;
+ uint32_t destination_offset_low:32;
+ uint32_t data;
+ };
+} ohci_req_quadlet_packet_t;
+
+typedef union {
+ uint32_t qdata[4];
+ struct {
+ uint32_t:4;
+ uint32_t t_code:4;
+ uint32_t rt:2;
+ uint32_t t_label:6;
+ uint32_t spd:3;
+ uint32_t:4;
+ uint32_t src_bus_id:1;
+ uint32_t:8;
+ uint32_t destination_offset_high:16;
+ uint32_t destination_id:16;
+ uint32_t destination_offset_low:32;
+ uint32_t:16;
+ uint32_t data_length:16;
+ };
+} ohci_req_block_packet_t;
+
+typedef union {
+ uint32_t qdata[3];
+ struct {
+ uint32_t:4;
+ uint32_t t_code:4;
+ uint32_t rt:2;
+ uint32_t t_label:6;
+ uint32_t destination_id:16;
+ uint32_t:12;
+ uint32_t r_code:4;
+ uint32_t source_id:16;
+ uint32_t:32;
+ };
+} ohci_rsp_nodata_packet_t;
+
+typedef union {
+ uint32_t qdata[4];
+ struct {
+ uint32_t:4;
+ uint32_t t_code:4;
+ uint32_t rt:2;
+ uint32_t t_label:6;
+ uint32_t destination_id:16;
+ uint32_t:12;
+ uint32_t r_code:4;
+ uint32_t source_id:16;
+ uint32_t:32;
+ uint32_t data;
+ };
+} ohci_rsp_quadlet_packet_t;
+
+typedef union {
+ uint32_t qdata[4];
+ struct {
+ uint32_t:4;
+ uint32_t t_code:4;
+ uint32_t rt:2;
+ uint32_t t_label:6;
+ uint32_t destination_id:16;
+ uint32_t:12;
+ uint32_t r_code:4;
+ uint32_t source_id:16;
+ uint32_t:32;
+ uint32_t:16;
+ uint32_t data_length:16;
+ };
+} ohci_rsp_block_packet_t;
+
+#endif
+
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 73afa41..c3baffa 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -1,4 +1,5 @@
devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
+devices-dirs-$(CONFIG_SOFTMMU) += 1394/
devices-dirs-$(CONFIG_ACPI) += acpi/
devices-dirs-$(CONFIG_SOFTMMU) += audio/
devices-dirs-$(CONFIG_SOFTMMU) += block/
--
2.3.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH v02] add 1394 bus support
2015-04-19 10:52 ` [Qemu-devel] [PATCH v02] " itamar.tal4
@ 2015-04-19 15:47 ` Andreas Färber
2015-04-19 16:38 ` Itamar Tal
2015-04-19 20:15 ` Peter Maydell
1 sibling, 1 reply; 7+ messages in thread
From: Andreas Färber @ 2015-04-19 15:47 UTC (permalink / raw)
To: itamar.tal4, qemu-devel; +Cc: thuth, ariel, Itamar Tal
Am 19.04.2015 um 12:52 schrieb itamar.tal4@gmail.com:
> From: Itamar Tal <itamar@guardicore.com>
>
> ---
Still no Signed-off-by...
Regards,
Andreas
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Jennifer Guild, Dilip Upmanyu,
Graham Norton; HRB 21284 (AG Nürnberg)
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH v02] add 1394 bus support
2015-04-19 15:47 ` Andreas Färber
@ 2015-04-19 16:38 ` Itamar Tal
2015-04-19 17:21 ` Andreas Färber
0 siblings, 1 reply; 7+ messages in thread
From: Itamar Tal @ 2015-04-19 16:38 UTC (permalink / raw)
To: Andreas Färber; +Cc: thuth, ariel, Itamar Tal, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 537 bytes --]
I've set it just after the subject field in the patch? Should I add it
somewhere else and resubmit?
On Apr 19, 2015 6:47 PM, "Andreas Färber" <afaerber@suse.de> wrote:
> Am 19.04.2015 um 12:52 schrieb itamar.tal4@gmail.com:
> > From: Itamar Tal <itamar@guardicore.com>
> >
> > ---
>
> Still no Signed-off-by...
>
> Regards,
> Andreas
>
> --
> SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Felix Imendörffer, Jane Smithard, Jennifer Guild, Dilip Upmanyu,
> Graham Norton; HRB 21284 (AG Nürnberg)
>
[-- Attachment #2: Type: text/html, Size: 908 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH v02] add 1394 bus support
2015-04-19 16:38 ` Itamar Tal
@ 2015-04-19 17:21 ` Andreas Färber
2015-04-20 11:59 ` Itamar Tal
0 siblings, 1 reply; 7+ messages in thread
From: Andreas Färber @ 2015-04-19 17:21 UTC (permalink / raw)
To: Itamar Tal; +Cc: thuth, ariel, Itamar Tal, qemu-devel
Hi,
Am 19.04.2015 um 18:38 schrieb Itamar Tal:
> I've set it just after the subject field in the patch? Should I add it
> somewhere else and resubmit?
Please compare other QEMU or Linux patches: It needs to go before ---
into the commit message. git commit --amend -s will place it correctly.
BTW I'm missing a type_init() and type_register_static() in the bottom
of hcd-ohci.c and wonder how you managed to test it without.
Did you copy this code from some other codebase? For one, hcd-ohci.c has
"address@hidden", which looks like you copied it from some mailing list
archive (then you need to replicate those authors' Signed-off-bys), and
for another the Coding Style does not exactly match that of QEMU, in
particular you are using a lot of custom _t types whereas QEMU uses
CamelCase type names. BTW if you consistently used typedefs for your
unions, you could avoid those macros declaring phy etc. unions inline, no?
Please also drop the empty last line in the new files you add. Did you
run scripts/checkpatch.pl? Running git-am on a clean branch can also
help highlight whitespace errors.
hcd-ohci.h is missing a license/copyright header.
hcd_pci_exit() has commented-out code - please fix or remove.
hcd_pci_init() has the opening brace placed wrong.
It looks like a generic PCI device, so why are you placing the config
option into i386 and x86_64 configs only rather than pci.mak?
Regards,
Andreas
P.S. Please don't top-post.
> On Apr 19, 2015 6:47 PM, "Andreas Färber" <afaerber@suse.de
> <mailto:afaerber@suse.de>> wrote:
>
> Am 19.04.2015 um 12:52 schrieb itamar.tal4@gmail.com
> <mailto:itamar.tal4@gmail.com>:
> > From: Itamar Tal <itamar@guardicore.com
> <mailto:itamar@guardicore.com>>
> >
> > ---
>
> Still no Signed-off-by...
>
> Regards,
> Andreas
>
> --
> SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Felix Imendörffer, Jane Smithard, Jennifer Guild, Dilip Upmanyu,
> Graham Norton; HRB 21284 (AG Nürnberg)
>
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Jennifer Guild, Dilip Upmanyu,
Graham Norton; HRB 21284 (AG Nürnberg)
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH v02] add 1394 bus support
2015-04-19 10:52 ` [Qemu-devel] [PATCH v02] " itamar.tal4
2015-04-19 15:47 ` Andreas Färber
@ 2015-04-19 20:15 ` Peter Maydell
1 sibling, 0 replies; 7+ messages in thread
From: Peter Maydell @ 2015-04-19 20:15 UTC (permalink / raw)
To: itamar.tal4
Cc: Itamar Tal, Thomas Huth, ariel, QEMU Developers,
Andreas Färber
On 19 April 2015 at 11:52, <itamar.tal4@gmail.com> wrote:
> From: Itamar Tal <itamar@guardicore.com>
>
> ---
> default-configs/i386-softmmu.mak | 1 +
> default-configs/x86_64-softmmu.mak | 1 +
> hw/1394/Makefile.objs | 1 +
> hw/1394/hcd-ohci.c | 1754 ++++++++++++++++++++++++++++++++++++
> hw/1394/hcd-ohci.h | 147 +++
> hw/Makefile.objs | 1 +
> 6 files changed, 1905 insertions(+)
> create mode 100644 hw/1394/Makefile.objs
> create mode 100644 hw/1394/hcd-ohci.c
> create mode 100644 hw/1394/hcd-ohci.h
> +typedef union {
> + uint32_t val;
> + struct {
> + uint32_t m:1; /* = 0 */
> + uint32_t initiated:1; /* = 1 for root node */
> + uint32_t p2:2; /* = 0 */
> + uint32_t p1:2; /* = 0 */
> + uint32_t p0:2; /* = 3, maybe 2 when "child" compared to root */
> + uint32_t pwr:3; /* = 0 */
> + uint32_t c:1; /* = 1 when root */
> + uint32_t del:2; /* = 0? */
> + uint32_t sp:2; /* = 0? */
> + uint32_t gap_cnt:6; /* = 0? */
> + uint32_t L:1; /* = 1? maybe just when connected */
> + uint32_t:1; /* = 0 */
> + uint32_t node_id:6;
> + uint32_t type:2; /* = 2 */
> + };
> +} self_id_t;
> + self_id_t sid;
> +
> + sid.val = 0;
> + sid.initiated = 1;
> + sid.p0 = 2;
> + sid.c = 1;
> + sid.L = 1;
> + sid.node_id = 0;
> + sid.type = 2;
> + dma_memory_write(&address_space_memory,
> + s->mmio.SelfIDBuffer + 4,
> + &sid.val, 4);
This assumes that the layout of bitfields is portable -- it is
not. You can't use a C bitfield to describe the layout of data
in guest memory. You need to get rid of all these structs with
bitfields and replace them with explicit AND/OR bit operations
on uint32_t types.
thanks
-- PMM
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Qemu-devel] [PATCH v02] add 1394 bus support
2015-04-19 17:21 ` Andreas Färber
@ 2015-04-20 11:59 ` Itamar Tal
0 siblings, 0 replies; 7+ messages in thread
From: Itamar Tal @ 2015-04-20 11:59 UTC (permalink / raw)
To: Andreas Färber; +Cc: thuth, Ariel Zeitlin, Itamar Tal, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 3324 bytes --]
On Sun, Apr 19, 2015 at 8:21 PM, Andreas Färber <afaerber@suse.de> wrote:
> Hi,
>
> Am 19.04.2015 um 18:38 schrieb Itamar Tal:
> > I've set it just after the subject field in the patch? Should I add it
> > somewhere else and resubmit?
>
> Please compare other QEMU or Linux patches: It needs to go before ---
> into the commit message. git commit --amend -s will place it correctly.
>
OK - I'll do that
>
> BTW I'm missing a type_init() and type_register_static() in the bottom
> of hcd-ohci.c and wonder how you managed to test it without.
>
I test it adding the following commands the command line
-chardev socket,host=127.0.0.1,port=13940,nodelay,id=fw0 -device
ohci-1394,chardev=fw0
which creates a new ohci-1394 device which I can work with and connect
between machines.
>
> Did you copy this code from some other codebase? For one, hcd-ohci.c has
> "address@hidden", which looks like you copied it from some mailing list
> archive (then you need to replicate those authors' Signed-off-bys), and
> for another the Coding Style does not exactly match that of QEMU, in
> particular you are using a lot of custom _t types whereas QEMU uses
> CamelCase type names. BTW if you consistently used typedefs for your
> unions, you could avoid those macros declaring phy etc. unions inline, no?
>
- I've copied the patch from the last reply I've sent to qemu-dev so the
address is hidden.
- I ran checkpatch.pl to align the code with the QEMU code before
submitting (no errors/warnings). Other than the XXX_t types, anything else?
I'll fix it, no problem
>
> Please also drop the empty last line in the new files you add. Did you
> run scripts/checkpatch.pl? Running git-am on a clean branch can also
> help highlight whitespace errors.
>
- Did checkpatch.pl. I'll also try git-am.
>
> hcd-ohci.h is missing a license/copyright header.
>
- OK, I'll add it
>
> hcd_pci_exit() has commented-out code - please fix or remove.
>
- no problem
> hcd_pci_init() has the opening brace placed wrong.
>
- no problem
>
> It looks like a generic PCI device, so why are you placing the config
> option into i386 and x86_64 configs only rather than pci.mak?
>
- I've followed the suggestion by made by Thomas Huth, what do you suggest?
When trying to build it with other architectures, sometimes it worked but
many times I was missing some qemu dependencies APIs.
>
> Regards,
> Andreas
>
> P.S. Please don't top-post.
>
- gotcha
>
> > On Apr 19, 2015 6:47 PM, "Andreas Färber" <afaerber@suse.de
> > <mailto:afaerber@suse.de>> wrote:
> >
> > Am 19.04.2015 um 12:52 schrieb itamar.tal4@gmail.com
> > <mailto:itamar.tal4@gmail.com>:
> > > From: Itamar Tal <itamar@guardicore.com
> > <mailto:itamar@guardicore.com>>
> > >
> > > ---
> >
> > Still no Signed-off-by...
> >
> > Regards,
> > Andreas
> >
> > --
> > SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> > GF: Felix Imendörffer, Jane Smithard, Jennifer Guild, Dilip Upmanyu,
> > Graham Norton; HRB 21284 (AG Nürnberg)
> >
>
>
> --
> SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Felix Imendörffer, Jane Smithard, Jennifer Guild, Dilip Upmanyu,
> Graham Norton; HRB 21284 (AG Nürnberg)
>
[-- Attachment #2: Type: text/html, Size: 6280 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-04-20 11:59 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-04-19 10:52 [Qemu-devel] [PATCH v2] add 1394 bus support itamar.tal4
2015-04-19 10:52 ` [Qemu-devel] [PATCH v02] " itamar.tal4
2015-04-19 15:47 ` Andreas Färber
2015-04-19 16:38 ` Itamar Tal
2015-04-19 17:21 ` Andreas Färber
2015-04-20 11:59 ` Itamar Tal
2015-04-19 20:15 ` Peter Maydell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).