All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
@ 2018-01-14 20:14 pisa
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 1/7] CAN bus simple messages transport implementation for QEMU pisa
                   ` (7 more replies)
  0 siblings, 8 replies; 45+ messages in thread
From: pisa @ 2018-01-14 20:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

Basic emulation of CAN bus controller and interconnection for QEMU.

Patches version 4:
Resolve comments longer than 80 characters to suppress
all warnings reported by scripts/checkpatch.pl.
Follow all suggestions from Frederic Konrad review.
Replace all printf and perror calls by QEMU equivalents.
Include Deniz Eren signed-off confimation.

Patches version 3:
Support to connect to host SocketCAN interface has been
separated from the core bus implementation. Only simple
statically initialize pointer to the connection function
is used, no QOM concept for now.
SJA1000 message filters redone and code unified where
possible.
Basic documentation added.
QEMU_ALIGNED used in definition of CAN frame structure,
structure and defines are separated from Linux/SocketCAN
API defined ones to allow to keep QEMU message format
independed from host system one. Check for correspondence
to socketcan defines added.

Patches version 2:
The bus emulation and the SJA1000 chip emulation introduced
by individual patches as suggested by Frederic Konrad.
Simple example board to test SJA1000 as single memory-mapped BAR
has been omitted in a new series because emulation of real
existing boards can provide same functions now.
Conditionalized debug printfs changed to be exposed to compiler
syntax check as suggested in review.

The work has been started by Jin Yang in the frame of GSoC 2013 slot
contributed by RTEMS project which has been looking for environment
to allow develop and test CAN drivers for multiple CPU architectures.

I have menthored the project and then done substantial code cleanup
and update to QOM. Deniz Eren then used emulation for SJA1000 base card
driver development for other operating system and contributed
PCM-3680I and MIOe-3680 support.

Some page about the project

  https://gitlab.fel.cvut.cz/canbus/qemu-canbus/wikis/home

FEE CTU GitLab repository with can-pci branch for 2.3, 2.4, 2.7, 2.8, 2.10
and 2.11 QEMU version is available in the repository

  https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci

mirror at GitHub

  https://github.com/CTU-IIG/qemu

There are many areas for improvement and extension of the code still
(for example freeze and migration is not implemented. CAN controllers
use proper QOM model but bus/interconnection emulation uses simple broadcast
connection which is required for CAN, but it is not based on QEMU bus model).
I have tried to look into QEMU VLANs implementation but it
does not map straightforward to CAN and I would need some help/opinion
from more advanced developers to decide what is their right
mapping to CAN.

CAN-FD support would be interesting requires other developers/
companies contributions or setup of some project to allow invite
some students and colleagues from my university into project.

But I believe that (even in its actual state) provided solution
is great help for embedded systems developers when they can connect
SocketCAN from one or more embedded systems running in virtual
environment together or with Linux host SocketCAN virtual
or real bus interfaces.

We have even tested our generic CANopen device configured
for CANopen 401 profile for generic I/O running in the virtual
system which can control GPIO inputs/outputs through virtual
industrial I/O card.

Generally QEMU can be interesting setup which allows
to test complete industrial and automotive applications
in virtual environment even before real hardware is availabe.

Deniz Eren (2):
  CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
  CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added.

Pavel Pisa (5):
  CAN bus simple messages transport implementation for QEMU
  CAN bus support to connect bust to Linux host SocketCAN interface.
  CAN bus SJA1000 chip register level emulation for QEMU
  CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
  QEMU CAN bus emulation documentation

 default-configs/pci.mak   |    3 +
 docs/can.txt              |   78 ++++
 hw/Makefile.objs          |    1 +
 hw/can/Makefile.objs      |   14 +
 hw/can/can_core.c         |  136 ++++++
 hw/can/can_host_stub.c    |   36 ++
 hw/can/can_kvaser_pci.c   |  375 +++++++++++++++++
 hw/can/can_mioe3680_pci.c |  336 +++++++++++++++
 hw/can/can_pcm3680_pci.c  |  336 +++++++++++++++
 hw/can/can_sja1000.c      | 1013 +++++++++++++++++++++++++++++++++++++++++++++
 hw/can/can_sja1000.h      |  167 ++++++++
 hw/can/can_socketcan.c    |  314 ++++++++++++++
 include/can/can_emu.h     |  131 ++++++
 13 files changed, 2940 insertions(+)
 create mode 100644 docs/can.txt
 create mode 100644 hw/can/Makefile.objs
 create mode 100644 hw/can/can_core.c
 create mode 100644 hw/can/can_host_stub.c
 create mode 100644 hw/can/can_kvaser_pci.c
 create mode 100644 hw/can/can_mioe3680_pci.c
 create mode 100644 hw/can/can_pcm3680_pci.c
 create mode 100644 hw/can/can_sja1000.c
 create mode 100644 hw/can/can_sja1000.h
 create mode 100644 hw/can/can_socketcan.c
 create mode 100644 include/can/can_emu.h

-- 
2.11.0

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH V4 1/7] CAN bus simple messages transport implementation for QEMU
  2018-01-14 20:14 [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
@ 2018-01-14 20:14 ` pisa
  2018-01-19 12:38   ` Philippe Mathieu-Daudé
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface pisa
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 45+ messages in thread
From: pisa @ 2018-01-14 20:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

The CanBusState state structure is created for each
emulated CAN channel. Individual clients/emulated
CAN interfaces or host interface connection registers
to the bus by CanBusClientState structure.

The CAN core is prepared to support connection to the
real host CAN bus network. The commit with such support
for Linux SocketCAN follows.

Implementation is as simple as possible, no migration,
messages prioritization and queuing considered for now.
But it is intended to be extended when need arises.

Development repository and more documentation at

https://gitlab.fel.cvut.cz/canbus/qemu-canbus

The work is based on Jin Yang GSoC 2013 work funded
by Google and mentored in frame of RTEMS project GSoC
slot donated to QEMU.

Rewritten for QEMU-2.0+ versions and architecture cleanup
by Pavel Pisa (Czech Technical University in Prague).

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 default-configs/pci.mak |   1 +
 hw/Makefile.objs        |   1 +
 hw/can/Makefile.objs    |   6 +++
 hw/can/can_core.c       | 136 ++++++++++++++++++++++++++++++++++++++++++++++++
 hw/can/can_host_stub.c  |  36 +++++++++++++
 include/can/can_emu.h   | 131 ++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 311 insertions(+)
 create mode 100644 hw/can/Makefile.objs
 create mode 100644 hw/can/can_core.c
 create mode 100644 hw/can/can_host_stub.c
 create mode 100644 include/can/can_emu.h

diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index e514bdef42..bbe11887a1 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -31,6 +31,7 @@ CONFIG_ESP_PCI=y
 CONFIG_SERIAL=y
 CONFIG_SERIAL_ISA=y
 CONFIG_SERIAL_PCI=y
+CONFIG_CAN_CORE=y
 CONFIG_IPACK=y
 CONFIG_WDT_IB6300ESB=y
 CONFIG_PCI_TESTDEV=y
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index cf4cb2010b..9d84b8faaa 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -6,6 +6,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += block/
 devices-dirs-$(CONFIG_SOFTMMU) += bt/
 devices-dirs-$(CONFIG_SOFTMMU) += char/
 devices-dirs-$(CONFIG_SOFTMMU) += cpu/
+devices-dirs-$(CONFIG_SOFTMMU) += can/
 devices-dirs-$(CONFIG_SOFTMMU) += display/
 devices-dirs-$(CONFIG_SOFTMMU) += dma/
 devices-dirs-$(CONFIG_SOFTMMU) += gpio/
diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
new file mode 100644
index 0000000000..1028d7c455
--- /dev/null
+++ b/hw/can/Makefile.objs
@@ -0,0 +1,6 @@
+# CAN bus interfaces emulation and infrastructure
+
+ifeq ($(CONFIG_CAN_CORE),y)
+common-obj-y += can_core.o
+common-obj-y += can_host_stub.o
+endif
diff --git a/hw/can/can_core.c b/hw/can/can_core.c
new file mode 100644
index 0000000000..41c458c792
--- /dev/null
+++ b/hw/can/can_core.c
@@ -0,0 +1,136 @@
+/*
+ * CAN common CAN bus emulation support
+ *
+ * Copyright (c) 2013-2014 Jin Yang
+ * Copyright (c) 2014-2018 Pavel Pisa
+ *
+ * Initial development supported by Google GSoC 2013 from RTEMS project slot
+ *
+ * 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 "qemu/osdep.h"
+#include "chardev/char.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "hw/hw.h"
+#include "can/can_emu.h"
+
+static QTAILQ_HEAD(, CanBusState) can_buses =
+    QTAILQ_HEAD_INITIALIZER(can_buses);
+
+CanBusState *can_bus_find_by_name(const char *name, bool create_missing)
+{
+    CanBusState *bus;
+
+    if (name == NULL) {
+        name = "canbus0";
+    }
+
+    QTAILQ_FOREACH(bus, &can_buses, next) {
+        if (!strcmp(bus->name, name)) {
+            return bus;
+        }
+    }
+
+    if (!create_missing) {
+        return 0;
+    }
+
+    bus = g_malloc0(sizeof(*bus));
+    if (bus == NULL) {
+        return NULL;
+    }
+
+    QTAILQ_INIT(&bus->clients);
+
+    bus->name = g_strdup(name);
+
+    QTAILQ_INSERT_TAIL(&can_buses, bus, next);
+    return bus;
+}
+
+int can_bus_insert_client(CanBusState *bus, CanBusClientState *client)
+{
+    client->bus = bus;
+    QTAILQ_INSERT_TAIL(&bus->clients, client, next);
+    return 0;
+}
+
+int can_bus_remove_client(CanBusClientState *client)
+{
+    CanBusState *bus = client->bus;
+    if (bus == NULL) {
+        return 0;
+    }
+
+    QTAILQ_REMOVE(&bus->clients, client, next);
+    client->bus = NULL;
+    return 1;
+}
+
+ssize_t can_bus_client_send(CanBusClientState *client,
+             const struct qemu_can_frame *frames, size_t frames_cnt)
+{
+    int ret = 0;
+    CanBusState *bus = client->bus;
+    CanBusClientState *peer;
+    if (bus == NULL) {
+        return -1;
+    }
+
+    QTAILQ_FOREACH(peer, &bus->clients, next) {
+        if (peer->info->can_receive(peer)) {
+            if (peer == client) {
+                /* No loopback support for now */
+                continue;
+            }
+            if (peer->info->receive(peer, frames, frames_cnt) > 0) {
+                ret = 1;
+            }
+        }
+    }
+
+    return ret;
+}
+
+int can_bus_filter_match(struct qemu_can_filter *filter, qemu_canid_t can_id)
+{
+    int m;
+    if (((can_id | filter->can_mask) & QEMU_CAN_ERR_FLAG)) {
+        return (filter->can_mask & QEMU_CAN_ERR_FLAG) != 0;
+    }
+    m = (can_id & filter->can_mask) == (filter->can_id & filter->can_mask);
+    return filter->can_id & QEMU_CAN_INV_FILTER ? !m : m;
+}
+
+int can_bus_client_set_filters(CanBusClientState *client,
+             const struct qemu_can_filter *filters, size_t filters_cnt)
+{
+    return 0;
+}
+
+int can_bus_connect_to_host_device(CanBusState *bus, const char *name)
+{
+    if (can_bus_connect_to_host_variant == NULL) {
+        error_report("CAN bus connect to host device is not "
+                     "supported on this system");
+        exit(1);
+    }
+    return can_bus_connect_to_host_variant(bus, name);
+}
diff --git a/hw/can/can_host_stub.c b/hw/can/can_host_stub.c
new file mode 100644
index 0000000000..748d25f995
--- /dev/null
+++ b/hw/can/can_host_stub.c
@@ -0,0 +1,36 @@
+/*
+ * CAN stub to connect to host system CAN interface
+ *
+ * Copyright (c) 2013-2014 Jin Yang
+ * Copyright (c) 2014-2018 Pavel Pisa
+ *
+ * Initial development supported by Google GSoC 2013 from RTEMS project slot
+ *
+ * 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 "qemu/osdep.h"
+#include "chardev/char.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "hw/hw.h"
+#include "can/can_emu.h"
+
+
+int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
+        NULL;
diff --git a/include/can/can_emu.h b/include/can/can_emu.h
new file mode 100644
index 0000000000..85237ee3c9
--- /dev/null
+++ b/include/can/can_emu.h
@@ -0,0 +1,131 @@
+/*
+ * CAN common CAN bus emulation support
+ *
+ * Copyright (c) 2013-2014 Jin Yang
+ * Copyright (c) 2014-2018 Pavel Pisa
+ *
+ * Initial development supported by Google GSoC 2013 from RTEMS project slot
+ *
+ * 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.
+ */
+
+#ifndef NET_CAN_EMU_H
+#define NET_CAN_EMU_H
+
+#include "qemu/queue.h"
+
+/* NOTE: the following two structures is copied from <linux/can.h>. */
+
+/*
+ * Controller Area Network Identifier structure
+ *
+ * bit 0-28    : CAN identifier (11/29 bit)
+ * bit 29      : error frame flag (0 = data frame, 1 = error frame)
+ * bit 30      : remote transmission request flag (1 = rtr frame)
+ * bit 31      : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
+ */
+typedef uint32_t qemu_canid_t;
+
+typedef struct qemu_can_frame {
+    qemu_canid_t    can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+    uint8_t         can_dlc; /* data length code: 0 .. 8 */
+    uint8_t         data[8] QEMU_ALIGNED(8);
+} qemu_can_frame;
+
+/* Keep defines for QEMU separate from Linux ones for now */
+
+#define QEMU_CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
+#define QEMU_CAN_RTR_FLAG 0x40000000U /* remote transmission request */
+#define QEMU_CAN_ERR_FLAG 0x20000000U /* error message frame */
+
+#define QEMU_CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
+#define QEMU_CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
+
+/**
+ * struct qemu_can_filter - CAN ID based filter in can_register().
+ * @can_id:   relevant bits of CAN ID which are not masked out.
+ * @can_mask: CAN mask (see description)
+ *
+ * Description:
+ * A filter matches, when
+ *
+ *          <received_can_id> & mask == can_id & mask
+ *
+ * The filter can be inverted (QEMU_CAN_INV_FILTER bit set in can_id) or it can
+ * filter for error message frames (QEMU_CAN_ERR_FLAG bit set in mask).
+ */
+typedef struct qemu_can_filter {
+    qemu_canid_t    can_id;
+    qemu_canid_t    can_mask;
+} qemu_can_filter;
+
+/* QEMU_CAN_INV_FILTER can be set in qemu_can_filter.can_id */
+#define QEMU_CAN_INV_FILTER 0x20000000U
+
+typedef struct CanBusClientState CanBusClientState;
+typedef struct CanBusState CanBusState;
+
+typedef struct CanBusClientInfo {
+    size_t size;
+    int (*can_receive)(CanBusClientState *);
+    ssize_t (*receive)(CanBusClientState *,
+        const struct qemu_can_frame *frames, size_t frames_cnt);
+    void (*cleanup) (CanBusClientState *);
+    void (*poll)(CanBusClientState *, bool enable);
+} CanBusClientInfo;
+
+struct CanBusClientState {
+    CanBusClientInfo *info;
+    CanBusState *bus;
+    int link_down;
+    QTAILQ_ENTRY(CanBusClientState) next;
+    CanBusClientState *peer;
+    char *model;
+    char *name;
+    void (*destructor)(CanBusClientState *);
+};
+
+struct CanBusState {
+    char *name;
+    QTAILQ_HEAD(, CanBusClientState) clients;
+    QTAILQ_ENTRY(CanBusState) next;
+};
+
+extern int (*can_bus_connect_to_host_variant)(CanBusState *bus,
+                                              const char *name);
+
+int can_bus_filter_match(struct qemu_can_filter *filter, qemu_canid_t can_id);
+
+CanBusState *can_bus_find_by_name(const char *name, bool create_missing);
+
+int can_bus_insert_client(CanBusState *bus, CanBusClientState *client);
+
+int can_bus_remove_client(CanBusClientState *client);
+
+ssize_t can_bus_client_send(CanBusClientState *,
+                            const struct qemu_can_frame *frames,
+                            size_t frames_cnt);
+
+int can_bus_client_set_filters(CanBusClientState *,
+                               const struct qemu_can_filter *filters,
+                               size_t filters_cnt);
+
+int can_bus_connect_to_host_device(CanBusState *bus, const char *host_dev_name);
+
+#endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-14 20:14 [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 1/7] CAN bus simple messages transport implementation for QEMU pisa
@ 2018-01-14 20:14 ` pisa
  2018-01-15  2:55   ` Philippe Mathieu-Daudé
  2018-01-19 12:57   ` Philippe Mathieu-Daudé
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 3/7] CAN bus SJA1000 chip register level emulation for QEMU pisa
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 45+ messages in thread
From: pisa @ 2018-01-14 20:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

Connection to the real host CAN bus network through
SocketCAN network interface is available only for Linux
host system. Mechanism is generic, support for another
CAN API and operating systems can be implemented in future.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 hw/can/Makefile.objs   |   4 +
 hw/can/can_socketcan.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 318 insertions(+)
 create mode 100644 hw/can/can_socketcan.c

diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index 1028d7c455..f999085f7a 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -2,5 +2,9 @@
 
 ifeq ($(CONFIG_CAN_CORE),y)
 common-obj-y += can_core.o
+ifeq ($(CONFIG_LINUX),y)
+common-obj-y += can_socketcan.o
+else
 common-obj-y += can_host_stub.o
 endif
+endif
diff --git a/hw/can/can_socketcan.c b/hw/can/can_socketcan.c
new file mode 100644
index 0000000000..f6df747c5a
--- /dev/null
+++ b/hw/can/can_socketcan.c
@@ -0,0 +1,314 @@
+/*
+ * CAN socketcan support to connect to the Linux host SocketCAN interfaces
+ *
+ * Copyright (c) 2013-2014 Jin Yang
+ * Copyright (c) 2014-2018 Pavel Pisa
+ *
+ * Initial development supported by Google GSoC 2013 from RTEMS project slot
+ *
+ * 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 "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "chardev/char.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "hw/hw.h"
+#include "can/can_emu.h"
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/can.h>
+#include <linux/can/raw.h>
+
+#ifndef DEBUG_CAN
+#define DEBUG_CAN 0
+#endif /*DEBUG_CAN*/
+
+#define CAN_READ_BUF_LEN  5
+typedef struct {
+    CanBusClientState  bus_client;
+    qemu_can_filter    *rfilter;
+    int                rfilter_num;
+    can_err_mask_t     err_mask;
+
+    qemu_can_frame     buf[CAN_READ_BUF_LEN];
+    int                bufcnt;
+    int                bufptr;
+
+    int                fd;
+} CanBusSocketcanConnectState;
+
+static void can_bus_socketcan_display_msg(struct qemu_can_frame *msg)
+{
+    int i;
+
+    /* Check that QEMU and Linux kernel flags encoding matches */
+    assert(QEMU_CAN_EFF_FLAG == CAN_EFF_FLAG);
+    assert(QEMU_CAN_RTR_FLAG == CAN_RTR_FLAG);
+    assert(QEMU_CAN_ERR_FLAG == CAN_ERR_FLAG);
+
+    assert(QEMU_CAN_INV_FILTER == CAN_INV_FILTER);
+
+    assert(offsetof(qemu_can_frame, data) == offsetof(struct can_frame, data));
+
+    qemu_log_lock();
+    qemu_log("[cansocketcan]: %03X [%01d] %s %s",
+             msg->can_id & QEMU_CAN_EFF_MASK,
+             msg->can_dlc,
+             msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF",
+             msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT");
+
+    for (i = 0; i < msg->can_dlc; i++) {
+        qemu_log(" %02X", msg->data[i]);
+    }
+    qemu_log("\n");
+    qemu_log_flush();
+    qemu_log_unlock();
+}
+
+static void can_bus_socketcan_read(void *opaque)
+{
+    CanBusSocketcanConnectState *c;
+    c = (CanBusSocketcanConnectState *)opaque;
+
+
+
+    /* CAN_READ_BUF_LEN for multiple messages syscall is possible for future */
+    c->bufcnt = read(c->fd, c->buf, sizeof(qemu_can_frame));
+    if (c->bufcnt < 0) {
+        warn_report("CAN bus host read failed (%s)", strerror(errno));
+        return;
+    }
+
+    can_bus_client_send(&c->bus_client, c->buf, 1);
+
+    if (DEBUG_CAN) {
+        can_bus_socketcan_display_msg(c->buf);
+    }
+}
+
+static int can_bus_socketcan_can_receive(CanBusClientState *client)
+{
+    CanBusSocketcanConnectState *c;
+    c = container_of(client, CanBusSocketcanConnectState, bus_client);
+
+    if (c->fd < 0) {
+        return -1;
+    }
+
+    return 1;
+}
+
+static ssize_t can_bus_socketcan_receive(CanBusClientState *client,
+                            const qemu_can_frame *frames, size_t frames_cnt)
+{
+    CanBusSocketcanConnectState *c;
+    c = container_of(client, CanBusSocketcanConnectState, bus_client);
+    size_t len = sizeof(qemu_can_frame);
+    int res;
+
+    if (c->fd < 0) {
+        return -1;
+    }
+
+    res = write(c->fd, frames, len);
+
+    if (!res) {
+        warn_report("[cansocketcan]: write message to host returns zero");
+        return -1;
+    }
+
+    if (res != len) {
+        if (res < 0) {
+            warn_report("[cansocketcan]: write to host failed (%s)",
+                        strerror(errno));
+        } else {
+            warn_report("[cansocketcan]: write to host truncated");
+        }
+        return -1;
+    }
+
+    return 1;
+}
+
+static void can_bus_socketcan_cleanup(CanBusClientState *client)
+{
+    CanBusSocketcanConnectState *c;
+    c = container_of(client, CanBusSocketcanConnectState, bus_client);
+
+    if (c->fd >= 0) {
+        qemu_set_fd_handler(c->fd, NULL, NULL, c);
+        close(c->fd);
+        c->fd = -1;
+    }
+
+    c->rfilter_num = 0;
+    if (c->rfilter != NULL) {
+        g_free(c->rfilter);
+    }
+}
+
+static int can_bus_socketcan_set_filters(CanBusClientState *client,
+                   const struct qemu_can_filter *filters, size_t filters_cnt)
+{
+    CanBusSocketcanConnectState *c;
+    c = container_of(client, CanBusSocketcanConnectState, bus_client);
+
+    int i;
+
+    if (DEBUG_CAN) {
+        qemu_log_lock();
+        qemu_log("[cansocketcan]: filters set for channel\n");
+        for (i = 0; i < filters_cnt; i++) {
+            fprintf(stderr, "[%i]  id=0x%08x maks=0x%08x\n",
+                   i, filters[i].can_id, filters[i].can_mask);
+        }
+        qemu_log("\n");
+        qemu_log_flush();
+        qemu_log_unlock();
+    }
+
+    setsockopt(c->fd, SOL_CAN_RAW, CAN_RAW_FILTER,
+               filters, filters_cnt * sizeof(qemu_can_filter));
+
+    return 0;
+}
+
+static
+void can_bus_socketcan_update_read_handler(CanBusSocketcanConnectState *c)
+{
+    if (c->fd >= 0) {
+        qemu_set_fd_handler(c->fd, can_bus_socketcan_read, NULL, c);
+    }
+}
+
+static CanBusClientInfo can_bus_socketcan_bus_client_info = {
+    .can_receive = can_bus_socketcan_can_receive,
+    .receive = can_bus_socketcan_receive,
+    .cleanup = can_bus_socketcan_cleanup,
+    .poll = NULL
+};
+
+static CanBusSocketcanConnectState *
+    can_bus_socketcan_connect_new(const char *host_dev_name)
+{
+    int s; /* can raw socket */
+    CanBusSocketcanConnectState    *c;
+    struct sockaddr_can addr;
+    struct ifreq ifr;
+
+    c = g_malloc0(sizeof(CanBusSocketcanConnectState));
+    if (c == NULL) {
+        goto fail1;
+    }
+
+    c->fd = -1;
+
+    /* open socket */
+    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
+    if (s < 0) {
+        error_report("[cansocketcan]: CAN_RAW socket create failed  (%s)",
+                        strerror(errno));
+        goto fail;
+    }
+
+    addr.can_family = AF_CAN;
+    memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
+    strcpy(ifr.ifr_name, host_dev_name);
+    if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+        error_report("[cansocketcan]: host interface %s not available (%s)",
+                     host_dev_name, strerror(errno));
+        goto fail;
+    }
+    addr.can_ifindex = ifr.ifr_ifindex;
+
+    c->err_mask = 0xffffffff; /* Receive error frame. */
+    setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
+                   &c->err_mask, sizeof(c->err_mask));
+
+    c->rfilter_num = 1;
+    c->rfilter = g_malloc0(c->rfilter_num * sizeof(struct qemu_can_filter));
+    if (c->rfilter == NULL) {
+        goto fail;
+    }
+
+    /* Receive all data frame. If |= CAN_INV_FILTER no data. */
+    c->rfilter[0].can_id = 0;
+    c->rfilter[0].can_mask = 0;
+    c->rfilter[0].can_mask &= ~CAN_ERR_FLAG;
+
+    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, c->rfilter,
+               c->rfilter_num * sizeof(struct qemu_can_filter));
+
+    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+        error_report("[cansocketcan]: bind to host interface %s failed (%s)",
+                     host_dev_name, strerror(errno));
+        goto fail;
+    }
+
+    c->fd = s;
+
+    c->bus_client.info = &can_bus_socketcan_bus_client_info;
+
+    can_bus_socketcan_update_read_handler(c);
+
+    return c;
+
+fail:
+    can_bus_socketcan_cleanup(&c->bus_client);
+    g_free(c);
+fail1:
+
+    return NULL;
+}
+
+static int can_bus_connect_to_host_socketcan(CanBusState *bus,
+                                             const char *host_dev_name)
+{
+    CanBusSocketcanConnectState *c;
+
+    c = can_bus_socketcan_connect_new(host_dev_name);
+    if (c == NULL) {
+        error_report("CAN bus setup of host connect to \"%s\" failed",
+                      host_dev_name);
+        exit(1);
+    }
+
+    if (can_bus_insert_client(bus, &c->bus_client) < 0) {
+        error_report("CAN host device \"%s\" connect to bus \"%s\" failed",
+                      host_dev_name, bus->name);
+        exit(1);
+    }
+
+    if (0) {
+        /*
+         * Not used there or as a CanBusSocketcanConnectState method
+         * for now but included there for documentation purposes
+         * and to suppress warning.
+         */
+        can_bus_socketcan_set_filters(&c->bus_client, NULL, 0);
+    }
+
+    return 0;
+}
+
+int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
+        can_bus_connect_to_host_socketcan;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH V4 3/7] CAN bus SJA1000 chip register level emulation for QEMU
  2018-01-14 20:14 [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 1/7] CAN bus simple messages transport implementation for QEMU pisa
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface pisa
@ 2018-01-14 20:14 ` pisa
  2018-01-15  3:03   ` Philippe Mathieu-Daudé
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added pisa
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 45+ messages in thread
From: pisa @ 2018-01-14 20:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

The core SJA1000 support is independent of following
patches which map SJA1000 chip to PCI boards.

The work is based on Jin Yang GSoC 2013 work funded
by Google and mentored in frame of RTEMS project GSoC
slot donated to QEMU.

Rewritten for QEMU-2.0+ versions and architecture cleanup
by Pavel Pisa (Czech Technical University in Prague).

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 default-configs/pci.mak |    1 +
 hw/can/Makefile.objs    |    1 +
 hw/can/can_sja1000.c    | 1013 +++++++++++++++++++++++++++++++++++++++++++++++
 hw/can/can_sja1000.h    |  167 ++++++++
 4 files changed, 1182 insertions(+)
 create mode 100644 hw/can/can_sja1000.c
 create mode 100644 hw/can/can_sja1000.h

diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index bbe11887a1..979b649fe5 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -32,6 +32,7 @@ CONFIG_SERIAL=y
 CONFIG_SERIAL_ISA=y
 CONFIG_SERIAL_PCI=y
 CONFIG_CAN_CORE=y
+CONFIG_CAN_SJA1000=y
 CONFIG_IPACK=y
 CONFIG_WDT_IB6300ESB=y
 CONFIG_PCI_TESTDEV=y
diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index f999085f7a..3c4bf3bfc1 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -7,4 +7,5 @@ common-obj-y += can_socketcan.o
 else
 common-obj-y += can_host_stub.o
 endif
+common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
 endif
diff --git a/hw/can/can_sja1000.c b/hw/can/can_sja1000.c
new file mode 100644
index 0000000000..7f7a6ea244
--- /dev/null
+++ b/hw/can/can_sja1000.c
@@ -0,0 +1,1013 @@
+/*
+ * CAN device - SJA1000 chip emulation for QEMU
+ *
+ * Copyright (c) 2013-2014 Jin Yang
+ * Copyright (c) 2014-2018 Pavel Pisa
+ *
+ * Initial development supported by Google GSoC 2013 from RTEMS project slot
+ *
+ * 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 "qemu/osdep.h"
+#include "qemu/log.h"
+#include "chardev/char.h"
+#include "hw/hw.h"
+#include "can/can_emu.h"
+
+#include "can_sja1000.h"
+
+#ifndef DEBUG_FILTER
+#define DEBUG_FILTER 0
+#endif /*DEBUG_FILTER*/
+
+#ifndef DEBUG_CAN
+#define DEBUG_CAN 0
+#endif /*DEBUG_CAN*/
+
+#define DPRINTF(fmt, ...) \
+    do { \
+        if (DEBUG_CAN) { \
+            qemu_log("[cansja]: " fmt , ## __VA_ARGS__); \
+        } \
+    } while (0)
+
+static void can_sja_software_reset(CanSJA1000State *s)
+{
+    s->mode        &= ~0x31;
+    s->mode        |= 0x01;
+    s->status_pel  &= ~0x37;
+    s->status_pel  |= 0x34;
+
+    s->rxbuf_start = 0x00;
+    s->rxmsg_cnt   = 0x00;
+    s->rx_cnt      = 0x00;
+}
+
+void can_sja_hardware_reset(CanSJA1000State *s)
+{
+    /* Reset by hardware, p10 */
+    s->mode        = 0x01;
+    s->status_pel  = 0x3c;
+    s->interrupt_pel = 0x00;
+    s->clock       = 0x00;
+    s->rxbuf_start = 0x00;
+    s->rxmsg_cnt   = 0x00;
+    s->rx_cnt      = 0x00;
+
+    s->control     = 0x01;
+    s->status_bas  = 0x0c;
+    s->interrupt_bas = 0x00;
+
+    s->irq_lower(s->irq_opaque);
+}
+
+static
+void can_sja_single_filter(struct qemu_can_filter *filter,
+            const uint8_t *acr,  const uint8_t *amr, int extended)
+{
+    if (extended) {
+        filter->can_id = (uint32_t)acr[0] << 21;
+        filter->can_id |= (uint32_t)acr[1] << 13;
+        filter->can_id |= (uint32_t)acr[2] << 5;
+        filter->can_id |= (uint32_t)acr[3] >> 3;
+        if (acr[3] & 4) {
+            filter->can_id |= QEMU_CAN_RTR_FLAG;
+        }
+
+        filter->can_mask = (uint32_t)amr[0] << 21;
+        filter->can_mask |= (uint32_t)amr[1] << 13;
+        filter->can_mask |= (uint32_t)amr[2] << 5;
+        filter->can_mask |= (uint32_t)amr[3] >> 3;
+        filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK;
+        if (!(amr[3] & 4)) {
+            filter->can_mask |= QEMU_CAN_RTR_FLAG;
+        }
+    } else {
+        filter->can_id = (uint32_t)acr[0] << 3;
+        filter->can_id |= (uint32_t)acr[1] >> 5;
+        if (acr[1] & 0x10) {
+            filter->can_id |= QEMU_CAN_RTR_FLAG;
+        }
+
+        filter->can_mask = (uint32_t)amr[0] << 3;
+        filter->can_mask |= (uint32_t)amr[1] << 5;
+        filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK;
+        if (!(amr[1] & 4)) {
+            filter->can_mask |= QEMU_CAN_RTR_FLAG;
+        }
+    }
+}
+
+static
+void can_sja_dual_filter(struct qemu_can_filter *filter,
+            const uint8_t *acr,  const uint8_t *amr, int extended)
+{
+    if (extended) {
+        filter->can_id = (uint32_t)acr[0] << 21;
+        filter->can_id |= (uint32_t)acr[1] << 13;
+
+        filter->can_mask = (uint32_t)amr[0] << 21;
+        filter->can_mask |= (uint32_t)amr[1] << 13;
+        filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK & ~0x1fff;
+    } else {
+        filter->can_id = (uint32_t)acr[0] << 3;
+        filter->can_id |= (uint32_t)acr[1] >> 5;
+        if (acr[1] & 0x10) {
+            filter->can_id |= QEMU_CAN_RTR_FLAG;
+        }
+
+        filter->can_mask = (uint32_t)amr[0] << 3;
+        filter->can_mask |= (uint32_t)amr[1] >> 5;
+        filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK;
+        if (!(amr[1] & 0x10)) {
+            filter->can_mask |= QEMU_CAN_RTR_FLAG;
+        }
+    }
+}
+
+/* Details in DS-p22, what we need to do here is to test the data. */
+static
+int can_sja_accept_filter(CanSJA1000State *s,
+                                 const qemu_can_frame *frame)
+{
+
+    struct qemu_can_filter filter;
+
+    if (s->clock & 0x80) { /* PeliCAN Mode */
+        if (s->mode & (1 << 3)) { /* Single mode. */
+            if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
+                can_sja_single_filter(&filter,
+                    s->code_mask + 0, s->code_mask + 4, 1);
+
+                if (!can_bus_filter_match(&filter, frame->can_id)) {
+                    return 0;
+                }
+            } else { /* SFF */
+                can_sja_single_filter(&filter,
+                    s->code_mask + 0, s->code_mask + 4, 0);
+
+                if (!can_bus_filter_match(&filter, frame->can_id)) {
+                    return 0;
+                }
+
+                if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
+                    return 1;
+                }
+
+                if (frame->can_dlc == 0) {
+                    return 1;
+                }
+
+                if ((frame->data[0] & ~(s->code_mask[6])) !=
+                   (s->code_mask[2] & ~(s->code_mask[6]))) {
+                    return 0;
+                }
+
+                if (frame->can_dlc < 2) {
+                    return 1;
+                }
+
+                if ((frame->data[1] & ~(s->code_mask[7])) ==
+                    (s->code_mask[3] & ~(s->code_mask[7]))) {
+                    return 1;
+                }
+
+                return 0;
+            }
+        } else { /* Dual mode */
+            if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
+                can_sja_dual_filter(&filter,
+                    s->code_mask + 0, s->code_mask + 4, 1);
+
+                if (can_bus_filter_match(&filter, frame->can_id)) {
+                    return 1;
+                }
+
+                can_sja_dual_filter(&filter,
+                    s->code_mask + 2, s->code_mask + 6, 1);
+
+                if (can_bus_filter_match(&filter, frame->can_id)) {
+                    return 1;
+                }
+
+                return 0;
+            } else {
+                can_sja_dual_filter(&filter,
+                    s->code_mask + 0, s->code_mask + 4, 0);
+
+                if (can_bus_filter_match(&filter, frame->can_id)) {
+                    uint8_t expect;
+                    uint8_t mask;
+                    expect = s->code_mask[1] << 4;
+                    expect |= s->code_mask[3] & 0x0f;
+
+                    mask = s->code_mask[5] << 4;
+                    mask |= s->code_mask[7] & 0x0f;
+                        mask = ~mask & 0xff;
+
+                    if ((frame->data[0] & mask) ==
+                        (expect & mask)) {
+                        return 1;
+                    }
+                }
+
+                can_sja_dual_filter(&filter,
+                    s->code_mask + 2, s->code_mask + 6, 0);
+
+                if (can_bus_filter_match(&filter, frame->can_id)) {
+                    return 1;
+                }
+
+                return 0;
+            }
+        }
+    }
+
+    return 1;
+}
+
+static void can_display_msg(const char *prefix, const qemu_can_frame *msg)
+{
+    int i;
+
+    qemu_log_lock();
+    qemu_log("%s%03X [%01d] %s %s",
+             prefix,
+             msg->can_id & QEMU_CAN_EFF_MASK,
+             msg->can_dlc,
+             msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF",
+             msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT");
+
+    for (i = 0; i < msg->can_dlc; i++) {
+        qemu_log(" %02X", msg->data[i]);
+    }
+    qemu_log("\n");
+    qemu_log_flush();
+    qemu_log_unlock();
+}
+
+static void buff2frame_pel(const uint8_t *buff, qemu_can_frame *frame)
+{
+    uint8_t i;
+
+    frame->can_id = 0;
+    if (buff[0] & 0x40) { /* RTR */
+        frame->can_id = QEMU_CAN_RTR_FLAG;
+    }
+    frame->can_dlc = buff[0] & 0x0f;
+
+    if (buff[0] & 0x80) { /* Extended */
+        frame->can_id |= QEMU_CAN_EFF_FLAG;
+        frame->can_id |= buff[1] << 21; /* ID.28~ID.21 */
+        frame->can_id |= buff[2] << 13; /* ID.20~ID.13 */
+        frame->can_id |= buff[3] <<  5;
+        frame->can_id |= buff[4] >>  3;
+        for (i = 0; i < frame->can_dlc; i++) {
+            frame->data[i] = buff[5 + i];
+        }
+        for (; i < 8; i++) {
+            frame->data[i] = 0;
+        }
+    } else {
+        frame->can_id |= buff[1] <<  3;
+        frame->can_id |= buff[2] >>  5;
+        for (i = 0; i < frame->can_dlc; i++) {
+            frame->data[i] = buff[3 + i];
+        }
+        for (; i < 8; i++) {
+            frame->data[i] = 0;
+        }
+    }
+}
+
+
+static void buff2frame_bas(const uint8_t *buff, qemu_can_frame *frame)
+{
+    uint8_t i;
+
+    frame->can_id = ((buff[0] << 3) & (0xff << 3)) + ((buff[1] >> 5) & 0x07);
+    if (buff[1] & 0x10) { /* RTR */
+        frame->can_id = QEMU_CAN_RTR_FLAG;
+    }
+    frame->can_dlc = buff[1] & 0x0f;
+
+    for (i = 0; i < frame->can_dlc; i++) {
+        frame->data[i] = buff[2 + i];
+    }
+    for (; i < 8; i++) {
+        frame->data[i] = 0;
+    }
+}
+
+
+static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff)
+{
+    int i;
+
+    if (frame->can_id & QEMU_CAN_ERR_FLAG) { /* error frame, NOT support now. */
+        return -1;
+    }
+
+    buff[0] = 0x0f & frame->can_dlc; /* DLC */
+    if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
+        buff[0] |= (1 << 6);
+    }
+    if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
+        buff[0] |= (1 << 7);
+        buff[1] = extract32(frame->can_id, 21, 8); /* ID.28~ID.21 */
+        buff[2] = extract32(frame->can_id, 13, 8); /* ID.20~ID.13 */
+        buff[3] = extract32(frame->can_id, 5, 8);  /* ID.12~ID.05 */
+        buff[4] = extract32(frame->can_id, 0, 5) << 3; /* ID.04~ID.00,xxx */
+        for (i = 0; i < frame->can_dlc; i++) {
+            buff[5 + i] = frame->data[i];
+        }
+        return frame->can_dlc + 5;
+    } else { /* SFF */
+        buff[1] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */
+        buff[2] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,xxxxx */
+        for (i = 0; i < frame->can_dlc; i++) {
+            buff[3 + i] = frame->data[i];
+        }
+
+        return frame->can_dlc + 3;
+    }
+
+    return -1;
+}
+
+static int frame2buff_bas(const qemu_can_frame *frame, uint8_t *buff)
+{
+    int i;
+
+     /*
+      * EFF, no support for BasicMode
+      * No use for Error frames now,
+      * they could be used in future to update SJA1000 error state
+      */
+    if ((frame->can_id & QEMU_CAN_EFF_FLAG) ||
+       (frame->can_id & QEMU_CAN_ERR_FLAG)) {
+        return -1;
+    }
+
+    buff[0] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */
+    buff[1] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,xxxxx */
+    if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
+        buff[1] |= (1 << 4);
+    }
+    buff[1] |= frame->can_dlc & 0x0f;
+    for (i = 0; i < frame->can_dlc; i++) {
+        buff[2 + i] = frame->data[i];
+    }
+
+    return frame->can_dlc + 2;
+}
+
+void can_sja_mem_write(CanSJA1000State *s, hwaddr addr, uint64_t val,
+                       unsigned size)
+{
+    qemu_can_frame   frame;
+    uint32_t         tmp;
+    uint8_t          tmp8, count;
+
+
+    DPRINTF("write 0x%02llx addr 0x%02x\n",
+            (unsigned long long)val, (unsigned int)addr);
+
+    if (addr > CAN_SJA_MEM_SIZE) {
+        return ;
+    }
+
+    if (s->clock & 0x80) { /* PeliCAN Mode */
+        switch (addr) {
+        case SJA_MOD: /* Mode register */
+            s->mode = 0x1f & val;
+            if ((s->mode & 0x01) && ((val & 0x01) == 0)) {
+                /* Go to operation mode from reset mode. */
+                if (s->mode & (1 << 3)) { /* Single mode. */
+                    /* For EFF */
+                    can_sja_single_filter(&s->filter[0],
+                        s->code_mask + 0, s->code_mask + 4, 1);
+
+                    /* For SFF */
+                    can_sja_single_filter(&s->filter[1],
+                        s->code_mask + 0, s->code_mask + 4, 0);
+
+                    can_bus_client_set_filters(&s->bus_client, s->filter, 2);
+                } else { /* Dual mode */
+                    /* For EFF */
+                    can_sja_dual_filter(&s->filter[0],
+                        s->code_mask + 0, s->code_mask + 4, 1);
+
+                    can_sja_dual_filter(&s->filter[1],
+                        s->code_mask + 2, s->code_mask + 6, 1);
+
+                    /* For SFF */
+                    can_sja_dual_filter(&s->filter[2],
+                        s->code_mask + 0, s->code_mask + 4, 0);
+
+                    can_sja_dual_filter(&s->filter[3],
+                        s->code_mask + 2, s->code_mask + 6, 0);
+
+                    can_bus_client_set_filters(&s->bus_client, s->filter, 4);
+                }
+
+                s->rxmsg_cnt = 0;
+                s->rx_cnt = 0;
+            }
+            break;
+
+        case SJA_CMR: /* Command register. */
+            if (0x01 & val) { /* Send transmission request. */
+                buff2frame_pel(s->tx_buff, &frame);
+                if (DEBUG_FILTER) {
+                    can_display_msg("[cansja]: Tx request " , &frame);
+                }
+
+                /*
+                 * Clear transmission complete status,
+                 * and Transmit Buffer Status.
+                 * write to the backends.
+                 */
+                s->status_pel &= ~(3 << 2);
+
+                can_bus_client_send(&s->bus_client, &frame, 1);
+
+                /*
+                 * Set transmission complete status
+                 * and Transmit Buffer Status.
+                 */
+                s->status_pel |= (3 << 2);
+
+                /* Clear transmit status. */
+                s->status_pel &= ~(1 << 5);
+                s->interrupt_pel |= 0x02;
+                if (s->interrupt_en & 0x02) {
+                    s->irq_raise(s->irq_opaque);
+                }
+            }
+            if (0x04 & val) { /* Release Receive Buffer */
+                if (s->rxmsg_cnt <= 0) {
+                    break;
+                }
+
+                tmp8 = s->rx_buff[s->rxbuf_start]; count = 0;
+                if (tmp8 & (1 << 7)) { /* EFF */
+                    count += 2;
+                }
+                count += 3;
+                if (!(tmp8 & (1 << 6))) { /* DATA */
+                    count += (tmp8 & 0x0f);
+                }
+
+                if (DEBUG_FILTER) {
+                    qemu_log("[cansja]: message released from "
+                             "Rx FIFO cnt=%d, count=%d\n", s->rx_cnt, count);
+                }
+
+                s->rxbuf_start += count;
+                s->rxbuf_start %= SJA_RCV_BUF_LEN;
+
+                s->rx_cnt -= count;
+                s->rxmsg_cnt--;
+                if (s->rxmsg_cnt == 0) {
+                    s->status_pel &= ~(1 << 0);
+                    s->interrupt_pel &= ~(1 << 0);
+                }
+                if ((s->interrupt_en & 0x01) && (s->interrupt_pel == 0)) {
+                    /* no other interrupts. */
+                    s->irq_lower(s->irq_opaque);
+                }
+            }
+            if (0x08 & val) { /* Clear data overrun */
+                s->status_pel &= ~(1 << 1);
+                s->interrupt_pel &= ~(1 << 3);
+                if ((s->interrupt_en & 0x80) && (s->interrupt_pel == 0)) {
+                    /* no other interrupts. */
+                    s->irq_lower(s->irq_opaque);
+                }
+            }
+            break;
+        case SJA_SR: /* Status register */
+        case SJA_IR: /* Interrupt register */
+            break; /* Do nothing */
+        case SJA_IER: /* Interrupt enable register */
+            s->interrupt_en = val;
+            break;
+        case 16: /* RX frame information addr16-28. */
+            s->status_pel |= (1 << 5); /* Set transmit status. */
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 21:
+        case 22:
+        case 23:
+        case 24:
+        case 25:
+        case 26:
+        case 27:
+        case 28:
+            if (s->mode & 0x01) { /* Reset mode */
+                if (addr < 24) {
+                    s->code_mask[addr - 16] = val;
+                }
+            } else { /* Operation mode */
+                s->tx_buff[addr - 16] = val; /* Store to TX buffer directly. */
+            }
+            break;
+        case SJA_CDR:
+            s->clock = val;
+            break;
+        }
+    } else { /* Basic Mode */
+        switch (addr) {
+        case SJA_BCAN_CTR: /* Control register, addr 0 */
+            if ((s->control & 0x01) && ((val & 0x01) == 0)) {
+                /* Go to operation mode from reset mode. */
+                s->filter[0].can_id = (s->code << 3) & (0xff << 3);
+                tmp = (~(s->mask << 3)) & (0xff << 3);
+                tmp |= QEMU_CAN_EFF_FLAG; /* Only Basic CAN Frame. */
+                s->filter[0].can_mask = tmp;
+                can_bus_client_set_filters(&s->bus_client, s->filter, 1);
+
+                s->rxmsg_cnt = 0;
+                s->rx_cnt = 0;
+            } else if (!(s->control & 0x01) && !(val & 0x01)) {
+                can_sja_software_reset(s);
+            }
+
+            s->control = 0x1f & val;
+            break;
+        case SJA_BCAN_CMR: /* Command register, addr 1 */
+            if (0x01 & val) { /* Send transmission request. */
+                buff2frame_bas(s->tx_buff, &frame);
+                if (DEBUG_FILTER) {
+                    can_display_msg("[cansja]: Tx request " , &frame);
+                }
+
+                /*
+                 * Clear transmission complete status,
+                 * and Transmit Buffer Status.
+                 */
+                s->status_bas &= ~(3 << 2);
+
+                /* write to the backends. */
+                can_bus_client_send(&s->bus_client, &frame, 1);
+
+                /*
+                 * Set transmission complete status,
+                 * and Transmit Buffer Status.
+                 */
+                s->status_bas |= (3 << 2);
+
+                /* Clear transmit status. */
+                s->status_bas &= ~(1 << 5);
+                s->interrupt_bas |= 0x02;
+                if (s->control & 0x04) {
+                    s->irq_raise(s->irq_opaque);
+                }
+            }
+            if (0x04 & val) { /* Release Receive Buffer */
+                if (s->rxmsg_cnt <= 0) {
+                    break;
+                }
+
+                qemu_mutex_lock(&s->rx_lock);
+                tmp8 = s->rx_buff[(s->rxbuf_start + 1) % SJA_RCV_BUF_LEN];
+                count = 2 + (tmp8 & 0x0f);
+
+                if (DEBUG_FILTER) {
+                    qemu_log("[cansja]: message released from "
+                             "Rx FIFO cnt=%d, count=%d\n", s->rx_cnt, count);
+                }
+
+                s->rxbuf_start += count;
+                s->rxbuf_start %= SJA_RCV_BUF_LEN;
+                s->rx_cnt -= count;
+                s->rxmsg_cnt--;
+                qemu_mutex_unlock(&s->rx_lock);
+
+                if (s->rxmsg_cnt == 0) {
+                    s->status_bas &= ~(1 << 0);
+                    s->interrupt_bas &= ~(1 << 0);
+                }
+                if ((s->control & 0x02) && (s->interrupt_bas == 0)) {
+                    /* no other interrupts. */
+                    s->irq_lower(s->irq_opaque);
+                }
+            }
+            if (0x08 & val) { /* Clear data overrun */
+                s->status_bas &= ~(1 << 1);
+                s->interrupt_bas &= ~(1 << 3);
+                if ((s->control & 0x10) && (s->interrupt_bas == 0)) {
+                    /* no other interrupts. */
+                    s->irq_lower(s->irq_opaque);
+                }
+            }
+            break;
+        case 4:
+            s->code = val;
+            break;
+        case 5:
+            s->mask = val;
+            break;
+        case 10:
+            s->status_bas |= (1 << 5); /* Set transmit status. */
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 15:
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+            if ((s->control & 0x01) == 0) { /* Operation mode */
+                s->tx_buff[addr - 10] = val; /* Store to TX buffer directly. */
+            }
+            break;
+        case SJA_CDR:
+            s->clock = val;
+            break;
+        }
+    }
+}
+
+uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size)
+{
+    uint64_t temp = 0;
+
+    DPRINTF("read addr 0x%02x ...\n", (unsigned int)addr);
+
+    if (addr > CAN_SJA_MEM_SIZE) {
+        return 0;
+    }
+
+    if (s->clock & 0x80) { /* PeliCAN Mode */
+        switch (addr) {
+        case SJA_MOD: /* Mode register, addr 0 */
+            temp = s->mode;
+            break;
+        case SJA_CMR: /* Command register, addr 1 */
+            temp = 0x00; /* Command register, cannot be read. */
+            break;
+        case SJA_SR: /* Status register, addr 2 */
+            temp = s->status_pel;
+            break;
+        case SJA_IR: /* Interrupt register, addr 3 */
+            temp = s->interrupt_pel;
+            s->interrupt_pel = 0;
+            if (s->rxmsg_cnt) {
+                s->interrupt_pel |= (1 << 0); /* Receive interrupt. */
+                break;
+            }
+            s->irq_lower(s->irq_opaque);
+            break;
+        case SJA_IER: /* Interrupt enable register, addr 4 */
+            temp = s->interrupt_en;
+            break;
+        case 5: /* Reserved */
+        case 6: /* Bus timing 0, hardware related, not support now. */
+        case 7: /* Bus timing 1, hardware related, not support now. */
+        case 8: /*
+                 * Output control register, hardware related,
+                 * not supported for now.
+                 */
+        case 9: /* Test. */
+        case 10: /* Reserved */
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 15:
+            temp = 0x00;
+            break;
+
+        case 16:
+        case 17:
+        case 18:
+        case 19:
+        case 20:
+        case 21:
+        case 22:
+        case 23:
+        case 24:
+        case 25:
+        case 26:
+        case 27:
+        case 28:
+            if (s->mode & 0x01) { /* Reset mode */
+                if (addr < 24) {
+                    temp = s->code_mask[addr - 16];
+                } else {
+                    temp = 0x00;
+                }
+            } else { /* Operation mode */
+                temp = s->rx_buff[(s->rxbuf_start + addr - 16) %
+                       SJA_RCV_BUF_LEN];
+            }
+            break;
+        case SJA_CDR:
+            temp = s->clock;
+            break;
+        default:
+            temp = 0xff;
+        }
+    } else { /* Basic Mode */
+        switch (addr) {
+        case SJA_BCAN_CTR: /* Control register, addr 0 */
+            temp = s->control;
+            break;
+        case SJA_BCAN_SR: /* Status register, addr 2 */
+            temp = s->status_bas;
+            break;
+        case SJA_BCAN_IR: /* Interrupt register, addr 3 */
+            temp = s->interrupt_bas;
+            s->interrupt_bas = 0;
+            if (s->rxmsg_cnt) {
+                s->interrupt_bas |= (1 << 0); /* Receive interrupt. */
+                break;
+            }
+            s->irq_lower(s->irq_opaque);
+            break;
+        case 4:
+            temp = s->code;
+            break;
+        case 5:
+            temp = s->mask;
+            break;
+        case 20:
+        case 21:
+        case 22:
+        case 23:
+        case 24:
+        case 25:
+        case 26:
+        case 27:
+        case 28:
+        case 29:
+            temp = s->rx_buff[(s->rxbuf_start + addr - 20) % SJA_RCV_BUF_LEN];
+            break;
+        case 31:
+            temp = s->clock;
+            break;
+        default:
+            temp = 0xff;
+            break;
+        }
+    }
+    DPRINTF("read addr 0x%02x, %d bytes, content 0x%02lx\n",
+            (int)addr, size, (long unsigned int)temp);
+
+    return temp;
+}
+
+int can_sja_can_receive(CanBusClientState *client)
+{
+    CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client);
+
+    if (s->clock & 0x80) { /* PeliCAN Mode */
+        if (s->mode & 0x01) { /* reset mode. */
+            return 0;
+        }
+    } else { /* BasicCAN mode */
+        if (s->control & 0x01) {
+            return 0;
+        }
+    }
+
+    return 1; /* always return 1, when operation mode */
+}
+
+ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames,
+                        size_t frames_cnt)
+{
+    CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client);
+    static uint8_t rcv[SJA_MSG_MAX_LEN];
+    int i;
+    int ret = -1;
+    const qemu_can_frame *frame = frames;
+
+    if (frames_cnt <= 0) {
+        return 0;
+    }
+    if (DEBUG_FILTER) {
+        can_display_msg("[cansja]: receive ", frame);
+    }
+
+    qemu_mutex_lock(&s->rx_lock); /* Just do it quickly :) */
+    if (s->clock & 0x80) { /* PeliCAN Mode */
+
+        /* the CAN controller is receiving a message */
+        s->status_pel |= (1 << 4);
+
+        if (can_sja_accept_filter(s, frame) == 0) {
+            s->status_pel &= ~(1 << 4);
+            if (DEBUG_FILTER) {
+                qemu_log("[cansja]: filter rejects message\n");
+            }
+            goto fail;
+        }
+
+        ret = frame2buff_pel(frame, rcv);
+        if (ret < 0) {
+            s->status_pel &= ~(1 << 4);
+            if (DEBUG_FILTER) {
+                qemu_log("[cansja]: message store failed\n");
+            }
+            goto fail; /* maybe not support now. */
+        }
+
+        if (s->rx_cnt + ret > SJA_RCV_BUF_LEN) { /* Data overrun. */
+            s->status_pel |= (1 << 1); /* Overrun status */
+            s->interrupt_pel |= (1 << 3);
+            if (s->interrupt_en & (1 << 3)) { /* Overrun interrupt enable */
+                s->irq_raise(s->irq_opaque);
+            }
+            s->status_pel &= ~(1 << 4);
+            if (DEBUG_FILTER) {
+                qemu_log("[cansja]: receive FIFO overrun\n");
+            }
+            goto fail;
+        }
+        s->rx_cnt += ret;
+        s->rxmsg_cnt++;
+        if (DEBUG_FILTER) {
+            qemu_log("[cansja]: message stored in receive FIFO\n");
+        }
+
+        for (i = 0; i < ret; i++) {
+            s->rx_buff[(s->rx_ptr++) % SJA_RCV_BUF_LEN] = rcv[i];
+        }
+        s->rx_ptr %= SJA_RCV_BUF_LEN; /* update the pointer. */
+
+        s->status_pel |= 0x01; /* Set the Receive Buffer Status. DS-p23 */
+        s->interrupt_pel |= 0x01;
+        s->status_pel &= ~(1 << 4);
+        s->status_pel |= (1 << 0);
+        if (s->interrupt_en & 0x01) { /* Receive Interrupt enable. */
+            s->irq_raise(s->irq_opaque);
+        }
+    } else { /* BasicCAN mode */
+
+        /* the CAN controller is receiving a message */
+        s->status_bas |= (1 << 4);
+
+        ret = frame2buff_bas(frame, rcv);
+        if (ret < 0) {
+            s->status_bas &= ~(1 << 4);
+            if (DEBUG_FILTER) {
+                qemu_log("[cansja]: message store failed\n");
+            }
+            goto fail; /* maybe not support now. */
+        }
+
+        if (s->rx_cnt + ret > SJA_RCV_BUF_LEN) { /* Data overrun. */
+            s->status_bas |= (1 << 1); /* Overrun status */
+            s->status_bas &= ~(1 << 4);
+            s->interrupt_bas |= (1 << 3);
+            if (s->control & (1 << 4)) { /* Overrun interrupt enable */
+                s->irq_raise(s->irq_opaque);
+            }
+            if (DEBUG_FILTER) {
+                qemu_log("[cansja]: receive FIFO overrun\n");
+            }
+            goto fail;
+        }
+        s->rx_cnt += ret;
+        s->rxmsg_cnt++;
+
+        if (DEBUG_FILTER) {
+            qemu_log("[cansja]: message stored\n");
+        }
+
+        for (i = 0; i < ret; i++) {
+            s->rx_buff[(s->rx_ptr++) % SJA_RCV_BUF_LEN] = rcv[i];
+        }
+        s->rx_ptr %= SJA_RCV_BUF_LEN; /* update the pointer. */
+
+        s->status_bas |= 0x01; /* Set the Receive Buffer Status. DS-p15 */
+        s->status_bas &= ~(1 << 4);
+        s->interrupt_bas |= 0x01;
+        if (s->control & 0x02) { /* Receive Interrupt enable. */
+            s->irq_raise(s->irq_opaque);
+        }
+    }
+    ret = 1;
+fail:
+    qemu_mutex_unlock(&s->rx_lock);
+
+    return ret;
+}
+
+static CanBusClientInfo can_sja_bus_client_info = {
+    .can_receive = can_sja_can_receive,
+    .receive = can_sja_receive,
+    .cleanup = NULL,
+    .poll = NULL
+};
+
+
+int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus)
+{
+    s->bus_client.info = &can_sja_bus_client_info;
+
+    if (can_bus_insert_client(bus, &s->bus_client) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+void can_sja_disconnect(CanSJA1000State *s)
+{
+    can_bus_remove_client(&s->bus_client);
+}
+
+int can_sja_init(CanSJA1000State *s, CanSJAIrqRaiseLower *irq_raise,
+                 CanSJAIrqRaiseLower *irq_lower, void *irq_opaque)
+{
+    qemu_mutex_init(&s->rx_lock);
+
+    s->irq_raise = irq_raise;
+    s->irq_lower = irq_lower;
+    s->irq_opaque = irq_opaque;
+
+    s->irq_lower(s->irq_opaque);
+
+    can_sja_hardware_reset(s);
+
+    return 0;
+}
+
+void can_sja_exit(CanSJA1000State *s)
+{
+    qemu_mutex_destroy(&s->rx_lock);
+}
+
+const VMStateDescription vmstate_qemu_can_filter = {
+    .name = "qemu_can_filter",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(can_id, qemu_can_filter),
+        VMSTATE_UINT32(can_mask, qemu_can_filter),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* VMState is needed for live migration of QEMU images */
+const VMStateDescription vmstate_can_sja = {
+    .name = "can_sja",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(mode, CanSJA1000State),
+
+        VMSTATE_UINT8(status_pel, CanSJA1000State),
+        VMSTATE_UINT8(interrupt_pel, CanSJA1000State),
+        VMSTATE_UINT8(interrupt_en, CanSJA1000State),
+        VMSTATE_UINT8(rxmsg_cnt, CanSJA1000State),
+        VMSTATE_UINT8(rxbuf_start, CanSJA1000State),
+        VMSTATE_UINT8(clock, CanSJA1000State),
+
+        VMSTATE_BUFFER(code_mask, CanSJA1000State),
+        VMSTATE_BUFFER(tx_buff, CanSJA1000State),
+
+        VMSTATE_BUFFER(rx_buff, CanSJA1000State),
+
+        VMSTATE_UINT32(rx_ptr, CanSJA1000State),
+        VMSTATE_UINT32(rx_cnt, CanSJA1000State),
+
+        VMSTATE_UINT8(control, CanSJA1000State),
+
+        VMSTATE_UINT8(status_bas, CanSJA1000State),
+        VMSTATE_UINT8(interrupt_bas, CanSJA1000State),
+        VMSTATE_UINT8(code, CanSJA1000State),
+        VMSTATE_UINT8(mask, CanSJA1000State),
+
+        VMSTATE_STRUCT_ARRAY(filter, CanSJA1000State, 4, 0,
+                             vmstate_qemu_can_filter, qemu_can_filter),
+
+
+        VMSTATE_END_OF_LIST()
+    }
+};
diff --git a/hw/can/can_sja1000.h b/hw/can/can_sja1000.h
new file mode 100644
index 0000000000..6f2cfbcb72
--- /dev/null
+++ b/hw/can/can_sja1000.h
@@ -0,0 +1,167 @@
+/*
+ * CAN device - SJA1000 chip emulation for QEMU
+ *
+ * Copyright (c) 2013-2014 Jin Yang
+ * Copyright (c) 2014-2018 Pavel Pisa
+ *
+ * Initial development supported by Google GSoC 2013 from RTEMS project slot
+ *
+ * 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.
+ */
+#ifndef HW_CAN_SJA1000_H
+#define HW_CAN_SJA1000_H
+
+#include "can/can_emu.h"
+
+#define CAN_SJA_MEM_SIZE      128
+
+/* The max size for a message buffer, EFF and DLC=8, DS-p39 */
+#define SJA_MSG_MAX_LEN       13
+/* The receive buffer size. */
+#define SJA_RCV_BUF_LEN       64
+
+typedef void (CanSJAIrqRaiseLower)(void *opaque);
+
+typedef struct CanSJA1000State {
+    /* PeliCAN state and registers sorted by address */
+    uint8_t         mode;          /* 0  .. Mode register, DS-p26 */
+                                   /* 1  .. Command register */
+    uint8_t         status_pel;    /* 2  .. Status register, p15 */
+    uint8_t         interrupt_pel; /* 3  .. Interrupt register */
+    uint8_t         interrupt_en;  /* 4  .. Interrupt Enable register */
+    uint8_t         rxmsg_cnt;     /* 29 .. RX message counter. DS-p49 */
+    uint8_t         rxbuf_start;   /* 30 .. RX buffer start address, DS-p49 */
+    uint8_t         clock;         /* 31 .. Clock Divider register, DS-p55 */
+
+    uint8_t         code_mask[8];  /* 16~23 */
+    uint8_t         tx_buff[13];   /* 96~108 .. transmit buffer */
+                                   /* 10~19  .. transmit buffer for BasicCAN */
+
+    uint8_t         rx_buff[SJA_RCV_BUF_LEN];  /* 32~95 .. 64bytes Rx FIFO */
+    uint32_t        rx_ptr;        /* Count by bytes. */
+    uint32_t        rx_cnt;        /* Count by bytes. */
+
+    /* PeliCAN state and registers sorted by address */
+    uint8_t         control;       /* 0 .. Control register */
+                                   /* 1 .. Command register */
+    uint8_t         status_bas;    /* 2 .. Status register */
+    uint8_t         interrupt_bas; /* 3 .. Interrupt register */
+    uint8_t         code;          /* 4 .. Acceptance code register */
+    uint8_t         mask;          /* 5 .. Acceptance mask register */
+
+    qemu_can_filter filter[4];
+
+    QemuMutex       rx_lock;
+    CanSJAIrqRaiseLower *irq_raise;
+    CanSJAIrqRaiseLower *irq_lower;
+    void            *irq_opaque;
+    CanBusClientState bus_client;
+} CanSJA1000State;
+
+/* PeliCAN mode */
+enum SJA1000_PeliCAN_regs {
+        SJA_MOD      = 0x00,
+/* Command register */
+        SJA_CMR      = 0x01,
+/* Status register */
+        SJA_SR       = 0x02,
+/* Interrupt register */
+        SJA_IR       = 0x03,
+/* Interrupt Enable */
+        SJA_IER      = 0x04,
+/* Bus Timing register 0 */
+        SJA_BTR0     = 0x06,
+/* Bus Timing register 1 */
+        SJA_BTR1     = 0x07,
+/* Output Control register */
+        SJA_OCR      = 0x08,
+/* Arbitration Lost Capture */
+        SJA_ALC      = 0x0b,
+/* Error Code Capture */
+        SJA_ECC      = 0x0c,
+/* Error Warning Limit */
+        SJA_EWLR     = 0x0d,
+/* RX Error Counter */
+        SJA_RXERR    = 0x0e,
+/* TX Error Counter */
+        SJA_TXERR0   = 0x0e,
+        SJA_TXERR1   = 0x0f,
+/* Rx Message Counter (number of msgs. in RX FIFO */
+        SJA_RMC      = 0x1d,
+/* Rx Buffer Start Addr. (address of current MSG) */
+        SJA_RBSA     = 0x1e,
+/* Transmit Buffer (write) Receive Buffer (read) Frame Information */
+        SJA_FRM      = 0x10,
+/*
+ * ID bytes (11 bits in 0 and 1 for standard message or
+ *          16 bits in 0,1 and 13 bits in 2,3 for extended message)
+ */
+        SJA_ID0      = 0x11, SJA_ID1 = 0x12,
+/* ID cont. for extended frames */
+        SJA_ID2      = 0x13, SJA_ID3 = 0x14,
+/* Data start standard frame */
+        SJA_DATS     = 0x13,
+/* Data start extended frame */
+        SJA_DATE     = 0x15,
+/* Acceptance Code (4 bytes) in RESET mode */
+        SJA_ACR0     = 0x10,
+/* Acceptance Mask (4 bytes) in RESET mode */
+        SJA_AMR0     = 0x14,
+/* 4 bytes */
+        SJA_PeliCAN_AC_LEN = 4,
+/* Clock Divider */
+        SJA_CDR      = 0x1f
+};
+
+
+/* PeliCAN mode */
+enum SJA1000_BasicCAN_regs {
+        SJA_BCAN_CTR = 0x00,
+/* Command register */
+        SJA_BCAN_CMR = 0x01,
+/* Status register */
+        SJA_BCAN_SR  = 0x02,
+/* Interrupt register */
+        SJA_BCAN_IR  = 0x03
+};
+
+void can_sja_hardware_reset(CanSJA1000State *s);
+
+void can_sja_mem_write(CanSJA1000State *s, hwaddr addr, uint64_t val,
+                       unsigned size);
+
+uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size);
+
+int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus);
+
+void can_sja_disconnect(CanSJA1000State *s);
+
+int can_sja_init(CanSJA1000State *s, CanSJAIrqRaiseLower *irq_raise,
+                 CanSJAIrqRaiseLower *irq_lower, void *irq_opaque);
+
+void can_sja_exit(CanSJA1000State *s);
+
+int can_sja_can_receive(CanBusClientState *client);
+
+ssize_t can_sja_receive(CanBusClientState *client,
+                        const qemu_can_frame *frames, size_t frames_cnt);
+
+extern const VMStateDescription vmstate_can_sja;
+
+#endif
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH V4 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
  2018-01-14 20:14 [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (2 preceding siblings ...)
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 3/7] CAN bus SJA1000 chip register level emulation for QEMU pisa
@ 2018-01-14 20:14 ` pisa
  2018-01-15  3:09   ` Philippe Mathieu-Daudé
  2018-03-06 15:29   ` Thomas Huth
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 5/7] QEMU CAN bus emulation documentation pisa
                   ` (3 subsequent siblings)
  7 siblings, 2 replies; 45+ messages in thread
From: pisa @ 2018-01-14 20:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 default-configs/pci.mak |   1 +
 hw/can/Makefile.objs    |   1 +
 hw/can/can_kvaser_pci.c | 375 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 377 insertions(+)
 create mode 100644 hw/can/can_kvaser_pci.c

diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 979b649fe5..72c0802ced 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -33,6 +33,7 @@ CONFIG_SERIAL_ISA=y
 CONFIG_SERIAL_PCI=y
 CONFIG_CAN_CORE=y
 CONFIG_CAN_SJA1000=y
+CONFIG_CAN_PCI=y
 CONFIG_IPACK=y
 CONFIG_WDT_IB6300ESB=y
 CONFIG_PCI_TESTDEV=y
diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index 3c4bf3bfc1..c9d07b9b16 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -8,4 +8,5 @@ else
 common-obj-y += can_host_stub.o
 endif
 common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
+common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
 endif
diff --git a/hw/can/can_kvaser_pci.c b/hw/can/can_kvaser_pci.c
new file mode 100644
index 0000000000..7e3f28d83c
--- /dev/null
+++ b/hw/can/can_kvaser_pci.c
@@ -0,0 +1,375 @@
+/*
+ * Kvaser PCI CAN device (SJA1000 based) emulation
+ *
+ * Copyright (c) 2013-2014 Jin Yang
+ * Copyright (c) 2014-2018 Pavel Pisa
+ *
+ * Partially based on educational PCIexpress APOHW hardware
+ * emulator used fro class A0B36APO at CTU FEE course by
+ *    Rostislav Lisovy and Pavel Pisa
+ *
+ * Initial development supported by Google GSoC 2013 from RTEMS project slot
+ *
+ * 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 "qemu/osdep.h"
+#include "qemu/event_notifier.h"
+#include "qemu/thread.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "chardev/char.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "can/can_emu.h"
+
+#include "can_sja1000.h"
+
+#define TYPE_CAN_PCI_DEV "kvaser_pci"
+
+#define KVASER_PCI_DEV(obj) \
+    OBJECT_CHECK(KvaserPCIState, (obj), TYPE_CAN_PCI_DEV)
+
+#ifndef KVASER_PCI_VENDOR_ID1
+#define KVASER_PCI_VENDOR_ID1     0x10e8    /* the PCI device and vendor IDs */
+#endif
+
+#ifndef KVASER_PCI_DEVICE_ID1
+#define KVASER_PCI_DEVICE_ID1     0x8406
+#endif
+
+#define KVASER_PCI_S5920_RANGE    0x80
+#define KVASER_PCI_SJA_RANGE      0x80
+#define KVASER_PCI_XILINX_RANGE   0x8
+
+#define KVASER_PCI_BYTES_PER_SJA  0x20
+
+#define S5920_OMB                 0x0C
+#define S5920_IMB                 0x1C
+#define S5920_MBEF                0x34
+#define S5920_INTCSR              0x38
+#define S5920_RCR                 0x3C
+#define S5920_PTCR                0x60
+
+#define S5920_INTCSR_ADDON_INTENABLE_M        0x2000
+#define S5920_INTCSR_INTERRUPT_ASSERTED_M     0x800000
+
+#define KVASER_PCI_XILINX_VERINT  7   /* Lower nibble simulate interrupts,
+                                         high nibble version number. */
+
+#define KVASER_PCI_XILINX_VERSION_NUMBER 13
+
+typedef struct KvaserPCIState {
+    /*< private >*/
+    PCIDevice       dev;
+    /*< public >*/
+    MemoryRegion    s5920_io;
+    MemoryRegion    sja_io;
+    MemoryRegion    xilinx_io;
+
+    CanSJA1000State sja_state;
+    qemu_irq        irq;
+
+    uint32_t        s5920_intcsr;
+    uint32_t        s5920_irqstate;
+
+    char            *model; /* The model that support, only SJA1000 now. */
+    char            *canbus;
+    char            *host;
+} KvaserPCIState;
+
+static void kvaser_pci_irq_raise(void *opaque)
+{
+    KvaserPCIState *d = (KvaserPCIState *)opaque;
+    d->s5920_irqstate = 1;
+
+    if (d->s5920_intcsr & S5920_INTCSR_ADDON_INTENABLE_M) {
+        qemu_irq_raise(d->irq);
+    }
+}
+
+static void kvaser_pci_irq_lower(void *opaque)
+{
+    KvaserPCIState *d = (KvaserPCIState *)opaque;
+    d->s5920_irqstate = 0;
+    qemu_irq_lower(d->irq);
+}
+
+static void
+kvaser_pci_reset(void *opaque)
+{
+    KvaserPCIState *d = (KvaserPCIState *)opaque;
+    CanSJA1000State *s = &d->sja_state;
+
+    can_sja_hardware_reset(s);
+}
+
+static uint64_t kvaser_pci_s5920_io_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    KvaserPCIState *d = opaque;
+    uint64_t val;
+
+    switch (addr) {
+    case S5920_INTCSR:
+        val = d->s5920_intcsr;
+        val &= ~S5920_INTCSR_INTERRUPT_ASSERTED_M;
+        if (d->s5920_irqstate) {
+            val |= S5920_INTCSR_INTERRUPT_ASSERTED_M;
+        }
+        return val;
+    }
+    return 0;
+}
+
+static void kvaser_pci_s5920_io_write(void *opaque, hwaddr addr, uint64_t data,
+                                      unsigned size)
+{
+    KvaserPCIState *d = opaque;
+
+    switch (addr) {
+    case S5920_INTCSR:
+        if (~d->s5920_intcsr & data & S5920_INTCSR_ADDON_INTENABLE_M) {
+            if (d->s5920_irqstate) {
+                qemu_irq_raise(d->irq);
+            }
+        }
+        d->s5920_intcsr = data;
+        break;
+    }
+}
+
+static uint64_t kvaser_pci_sja_io_read(void *opaque, hwaddr addr, unsigned size)
+{
+    KvaserPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state;
+
+    if (addr >= KVASER_PCI_BYTES_PER_SJA) {
+        return 0;
+    }
+
+    return can_sja_mem_read(s, addr, size);
+}
+
+static void kvaser_pci_sja_io_write(void *opaque, hwaddr addr, uint64_t data,
+                                    unsigned size)
+{
+    KvaserPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state;
+
+    if (addr >= KVASER_PCI_BYTES_PER_SJA) {
+        return;
+    }
+
+    can_sja_mem_write(s, addr, data, size);
+}
+
+static uint64_t kvaser_pci_xilinx_io_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    /*KvaserPCIState *d = opaque;*/
+
+    switch (addr) {
+    case KVASER_PCI_XILINX_VERINT:
+        return (KVASER_PCI_XILINX_VERSION_NUMBER << 4) | 0;
+    }
+
+    return 0;
+}
+
+static void kvaser_pci_xilinx_io_write(void *opaque, hwaddr addr, uint64_t data,
+                             unsigned size)
+{
+    /*KvaserPCIState *d = opaque;*/
+}
+
+static const MemoryRegionOps kvaser_pci_s5920_io_ops = {
+    .read = kvaser_pci_s5920_io_read,
+    .write = kvaser_pci_s5920_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps kvaser_pci_sja_io_ops = {
+    .read = kvaser_pci_sja_io_read,
+    .write = kvaser_pci_sja_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps kvaser_pci_xilinx_io_ops = {
+    .read = kvaser_pci_xilinx_io_read,
+    .write = kvaser_pci_xilinx_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int kvaser_pci_init(PCIDevice *pci_dev)
+{
+    KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
+    CanSJA1000State *s = &d->sja_state;
+    uint8_t *pci_conf;
+    CanBusState *can_bus;
+
+    if (d->model) {
+        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
+            error_report("Can't create CAN device, "
+                         "the model %s is not supported now.", d->model);
+            exit(1);
+        }
+    }
+
+    can_bus = can_bus_find_by_name(d->canbus, true);
+    if (can_bus == NULL) {
+        error_report("Cannot create can find/allocate CAN bus");
+        exit(1);
+
+    }
+
+    if (d->host != NULL) {
+        if (can_bus_connect_to_host_device(can_bus, d->host) < 0) {
+            error_report("Cannot connect CAN bus to host device \"%s\"",
+                         d->host);
+            exit(1);
+        }
+    }
+
+    pci_conf = pci_dev->config;
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
+
+    d->irq = pci_allocate_irq(&d->dev);
+
+    can_sja_init(s, kvaser_pci_irq_raise, kvaser_pci_irq_lower, d);
+
+    qemu_register_reset(kvaser_pci_reset, d);
+
+    if (can_sja_connect_to_bus(s, can_bus) < 0) {
+        error_report("can_sja_connect_to_bus failed");
+        exit(1);
+    }
+
+    memory_region_init_io(&d->s5920_io, OBJECT(d), &kvaser_pci_s5920_io_ops,
+                          d, "kvaser_pci-s5920", KVASER_PCI_S5920_RANGE);
+    memory_region_init_io(&d->sja_io, OBJECT(d), &kvaser_pci_sja_io_ops,
+                          d, "kvaser_pci-sja", KVASER_PCI_SJA_RANGE);
+    memory_region_init_io(&d->xilinx_io, OBJECT(d), &kvaser_pci_xilinx_io_ops,
+                          d, "kvaser_pci-xilinx", KVASER_PCI_XILINX_RANGE);
+
+    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
+                                            &d->s5920_io);
+    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
+                                            &d->sja_io);
+    pci_register_bar(&d->dev, /*BAR*/ 2, PCI_BASE_ADDRESS_SPACE_IO,
+                                            &d->xilinx_io);
+
+    return 0;
+}
+
+static void kvaser_pci_exit(PCIDevice *pci_dev)
+{
+    KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
+    CanSJA1000State *s = &d->sja_state;
+
+    can_sja_disconnect(s);
+
+    qemu_unregister_reset(kvaser_pci_reset, d);
+
+    /*
+     * regions d->s5920_io, d->sja_io and d->xilinx_io
+     * are destroyed by QOM now
+     */
+
+    can_sja_exit(s);
+
+    qemu_free_irq(d->irq);
+}
+
+static const VMStateDescription vmstate_kvaser_pci = {
+    .name = "kvaser_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, KvaserPCIState),
+        VMSTATE_STRUCT(sja_state, KvaserPCIState, 0, vmstate_can_sja,
+                       CanSJA1000State),
+        /*char *model,*/
+        VMSTATE_UINT32(s5920_intcsr, KvaserPCIState),
+        VMSTATE_UINT32(s5920_irqstate, KvaserPCIState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void qdev_kvaser_pci_reset(DeviceState *dev)
+{
+    KvaserPCIState *d = KVASER_PCI_DEV(dev);
+    kvaser_pci_reset(d);
+}
+
+static Property kvaser_pci_properties[] = {
+    DEFINE_PROP_STRING("canbus",   KvaserPCIState, canbus),
+    DEFINE_PROP_STRING("host",  KvaserPCIState, host),
+    DEFINE_PROP_STRING("model", KvaserPCIState, model),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void kvaser_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = kvaser_pci_init;
+    k->exit = kvaser_pci_exit;
+    k->vendor_id = KVASER_PCI_VENDOR_ID1;
+    k->device_id = KVASER_PCI_DEVICE_ID1;
+    k->revision = 0x00;
+    k->class_id = 0x00ff00;
+    dc->desc = "Kvaser PCICANx";
+    dc->props = kvaser_pci_properties;
+    dc->vmsd = &vmstate_kvaser_pci;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    dc->reset = qdev_kvaser_pci_reset;
+}
+
+static const TypeInfo kvaser_pci_info = {
+    .name          = TYPE_CAN_PCI_DEV,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(KvaserPCIState),
+    .class_init    = kvaser_pci_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void kvaser_pci_register_types(void)
+{
+    type_register_static(&kvaser_pci_info);
+}
+
+type_init(kvaser_pci_register_types)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH V4 5/7] QEMU CAN bus emulation documentation
  2018-01-14 20:14 [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (3 preceding siblings ...)
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added pisa
@ 2018-01-14 20:14 ` pisa
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 6/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added pisa
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 45+ messages in thread
From: pisa @ 2018-01-14 20:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 docs/can.txt | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)
 create mode 100644 docs/can.txt

diff --git a/docs/can.txt b/docs/can.txt
new file mode 100644
index 0000000000..ac3170e947
--- /dev/null
+++ b/docs/can.txt
@@ -0,0 +1,78 @@
+QEMU CAN bus emulation support
+==============================
+
+The CAN bus emulation provides mechanism to connect multiple
+emulated CAN controller chips together by one or multiple CAN busses
+(the controller device "canbus"  parameter). The individual busses
+can be connected to host system CAN API (at this time only Linux
+SocketCAN is supported).
+
+The concept of busses is generic and different CAN controllers
+can be implemented for it but at this time only SJA1000 chip
+controller is implemented.
+
+The PCI addon card hardware has been selected as the first CAN
+interface to implement because such device can be easily connected
+to systems with different CPU architectures (x86, PowerPC, ARM, etc.).
+
+The project has been initially started in frame of RTEMS GSoC 2013
+slot by Jin Yang under our mentoring  The initial idea was to provide generic
+CAN subsystem for RTEMS. But lack of common environment for code and RTEMS
+testing lead to goal change to provide environment which provides complete
+emulated environment for testing and RTEMS GSoC slot has been donated
+to work on CAN hardware emulation on QEMU.
+
+Examples how to use CAN emulation
+=================================
+
+When QEMU with CAN PCI support is compiled then one of the next
+CAN boards can be selected
+
+ (1) CAN bus Kvaser PCI CAN-S (single SJA1000 channel) boad. QEMU startup options
+    -device kvaser_pci,canbus=canbus0
+    Add "host" parameter to connect device to host system CAN bus
+    -device kvaser_pci,canbus=canbus0,host=can0
+
+ (2) CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation
+    -device pcm3680_pci,canbus=canbus0,host=can0
+
+ (3) CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation
+    -device mioe3680_pci,canbus=canbus0,host=can0
+
+
+The ''kvaser_pci'' board/device model is compatible with and has been tested with
+''kvaser_pci'' driver included in mainline Linux kernel.
+The tested setup was Linux 4.9 kernel on the host and guest side.
+
+Next parameters has been used for qemu-system-x86_64
+
+    qemu-system-x86_64 -enable-kvm -kernel /boot/vmlinuz-4.9.0-4-amd64 \
+      -initrd ramdisk.cpio \
+      -virtfs local,path=shareddir,security_model=none,mount_tag=shareddir \
+      -vga cirrus \
+      -device kvaser_pci,canbus=canbus0,host=can0 \
+      -nographic -append "console=ttyS0"
+
+The list of parameters for qemu-system-arm
+
+    qemu-system-arm -cpu arm1176 -m 256 -M versatilepb \
+      -kernel kernel-qemu-arm1176-versatilepb \
+      -hda rpi-wheezy-overlay \
+      -append "console=ttyAMA0 root=/dev/sda2 ro init=/sbin/init-overlay" \
+      -nographic \
+      -virtfs local,path=shareddir,security_model=none,mount_tag=shareddir \
+      -device kvaser_pci,canbus=canbus0,host=can0 \
+
+Links to other resources
+========================
+
+ (1) Repository with development branch can-pci at Czech Technical University
+     https://gitlab.fel.cvut.cz/canbus/qemu-canbus
+ (2) GitHub repository with can-pci and our other changes included
+     https://gitlab.fel.cvut.cz/canbus/qemu-canbus
+ (3) RTEMS page describing project
+     https://devel.rtems.org/wiki/Developer/Simulators/QEMU/CANEmulation
+ (4) RTLWS 2015 article about the projevt and its use with CANopen emulation
+     http://rtime.felk.cvut.cz/publications/public/rtlws2015-qemu-can.pdf
+     Slides
+     http://rtime.felk.cvut.cz/publications/public/rtlws2015-qemu-can-slides.pdf
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH V4 6/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
  2018-01-14 20:14 [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (4 preceding siblings ...)
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 5/7] QEMU CAN bus emulation documentation pisa
@ 2018-01-14 20:14 ` pisa
  2018-01-15  3:12   ` Philippe Mathieu-Daudé
  2018-01-19 13:15   ` Philippe Mathieu-Daudé
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 7/7] CAN bus MIOe-3680 " pisa
  2018-01-22 11:35 ` [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) Philippe Mathieu-Daudé
  7 siblings, 2 replies; 45+ messages in thread
From: pisa @ 2018-01-14 20:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Deniz Eren <deniz.eren@icloud.com>

Signed-off-by: Deniz Eren <deniz.eren@icloud.com>
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 hw/can/Makefile.objs     |   1 +
 hw/can/can_pcm3680_pci.c | 336 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 337 insertions(+)
 create mode 100644 hw/can/can_pcm3680_pci.c

diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index c9d07b9b16..6a328f0c3a 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -9,4 +9,5 @@ common-obj-y += can_host_stub.o
 endif
 common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
 common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
+common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
 endif
diff --git a/hw/can/can_pcm3680_pci.c b/hw/can/can_pcm3680_pci.c
new file mode 100644
index 0000000000..e85b61849a
--- /dev/null
+++ b/hw/can/can_pcm3680_pci.c
@@ -0,0 +1,336 @@
+/*
+ * PCM-3680i PCI CAN device (SJA1000 based) emulation
+ *
+ * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
+ *
+ * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
+ * Jin Yang and Pavel Pisa
+ *
+ * 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 "qemu/osdep.h"
+#include "qemu/event_notifier.h"
+#include "qemu/thread.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "chardev/char.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "can/can_emu.h"
+
+#include "can_sja1000.h"
+
+#define TYPE_CAN_PCI_DEV "pcm3680_pci"
+
+#define PCM3680i_PCI_DEV(obj) \
+    OBJECT_CHECK(Pcm3680iPCIState, (obj), TYPE_CAN_PCI_DEV)
+
+/* the PCI device and vendor IDs */
+#ifndef PCM3680i_PCI_VENDOR_ID1
+#define PCM3680i_PCI_VENDOR_ID1     0x13fe
+#endif
+
+#ifndef PCM3680i_PCI_DEVICE_ID1
+#define PCM3680i_PCI_DEVICE_ID1     0xc002
+#endif
+
+#define PCM3680i_PCI_SJA_RANGE     0x200
+
+#define PCM3680i_PCI_BYTES_PER_SJA 0x20
+
+typedef struct Pcm3680iPCIState {
+    /*< private >*/
+    PCIDevice       dev;
+    /*< public >*/
+    MemoryRegion    sja_io[2];
+
+    CanSJA1000State sja_state[2];
+    qemu_irq        irq;
+
+    char            *model; /* The model that support, only SJA1000 now. */
+    char            *canbus[2];
+    char            *host[2];
+} Pcm3680iPCIState;
+
+static void pcm3680i_pci_irq_raise(void *opaque)
+{
+    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
+
+    qemu_irq_raise(d->irq);
+}
+
+static void pcm3680i_pci_irq_lower(void *opaque)
+{
+    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
+
+    qemu_irq_lower(d->irq);
+}
+
+static void
+pcm3680i_pci_reset(void *opaque)
+{
+    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+
+    can_sja_hardware_reset(s1);
+    can_sja_hardware_reset(s2);
+}
+
+static uint64_t pcm3680i_pci_sja1_io_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    Pcm3680iPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[0];
+
+    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
+        return 0;
+    }
+
+    return can_sja_mem_read(s, addr, size);
+}
+
+static void pcm3680i_pci_sja1_io_write(void *opaque, hwaddr addr,
+                                       uint64_t data, unsigned size)
+{
+    Pcm3680iPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[0];
+
+    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
+        return;
+    }
+
+    can_sja_mem_write(s, addr, data, size);
+}
+
+static uint64_t pcm3680i_pci_sja2_io_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    Pcm3680iPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[1];
+
+    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
+        return 0;
+    }
+
+    return can_sja_mem_read(s, addr, size);
+}
+
+static void pcm3680i_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
+                             unsigned size)
+{
+    Pcm3680iPCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[1];
+
+    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
+        return;
+    }
+
+    can_sja_mem_write(s, addr, data, size);
+}
+
+static const MemoryRegionOps pcm3680i_pci_sja1_io_ops = {
+    .read = pcm3680i_pci_sja1_io_read,
+    .write = pcm3680i_pci_sja1_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps pcm3680i_pci_sja2_io_ops = {
+    .read = pcm3680i_pci_sja2_io_read,
+    .write = pcm3680i_pci_sja2_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int pcm3680i_pci_init(PCIDevice *pci_dev)
+{
+    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+    uint8_t *pci_conf;
+    CanBusState *can_bus1;
+    CanBusState *can_bus2;
+
+    if (d->model) {
+        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
+            error_report("Can't create CAN device, "
+                         "the model %s is not supported now.", d->model);
+            exit(1);
+        }
+    }
+
+    can_bus1 = can_bus_find_by_name(d->canbus[0], true);
+    if (can_bus1 == NULL) {
+        error_report("Cannot create can find/allocate CAN bus #1");
+        exit(1);
+    }
+
+    can_bus2 = can_bus_find_by_name(d->canbus[1], true);
+    if (can_bus2 == NULL) {
+        error_report("Cannot create can find/allocate CAN bus #2");
+        exit(1);
+    }
+
+    if (d->host[0] != NULL) {
+        if (can_bus_connect_to_host_device(can_bus1, d->host[0]) < 0) {
+            error_report("Cannot connect CAN bus to host #1 device \"%s\"",
+                         d->host[0]);
+            exit(1);
+        }
+    }
+
+    if (d->host[1] != NULL) {
+        if (can_bus_connect_to_host_device(can_bus2, d->host[1]) < 0) {
+            error_report("Cannot connect CAN bus to host #2 device \"%s\"",
+                         d->host[1]);
+            exit(1);
+        }
+    }
+
+    pci_conf = pci_dev->config;
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
+
+    d->irq = pci_allocate_irq(&d->dev);
+
+    can_sja_init(s1, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
+    can_sja_init(s2, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
+
+    qemu_register_reset(pcm3680i_pci_reset, d);
+
+    if (can_sja_connect_to_bus(s1, can_bus1) < 0) {
+        error_report("can_sja_connect_to_bus failed");
+        exit(1);
+    }
+
+    if (can_sja_connect_to_bus(s2, can_bus2) < 0) {
+        error_report("can_sja_connect_to_bus failed");
+        exit(1);
+    }
+
+    memory_region_init_io(&d->sja_io[0], OBJECT(d), &pcm3680i_pci_sja1_io_ops,
+                          d, "pcm3680i_pci-sja1", PCM3680i_PCI_SJA_RANGE / 2);
+    memory_region_init_io(&d->sja_io[1], OBJECT(d), &pcm3680i_pci_sja2_io_ops,
+                          d, "pcm3680i_pci-sja2", PCM3680i_PCI_SJA_RANGE / 2);
+
+    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
+                                             &d->sja_io[0]);
+    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
+                                             &d->sja_io[1]);
+
+    return 0;
+}
+
+static void pcm3680i_pci_exit(PCIDevice *pci_dev)
+{
+    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+
+    can_sja_disconnect(s1);
+    can_sja_disconnect(s2);
+
+    qemu_unregister_reset(pcm3680i_pci_reset, d);
+
+    /*
+     * region d->sja_io is destroyed by QOM now
+     */
+    /* memory_region_destroy(&d->sja_io[0]); */
+    /* memory_region_destroy(&d->sja_io[1]); */
+
+    can_sja_exit(s1);
+    can_sja_exit(s2);
+
+    qemu_free_irq(d->irq);
+}
+
+static const VMStateDescription vmstate_pcm3680i_pci = {
+    .name = "pcm3680i_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, Pcm3680iPCIState),
+        VMSTATE_STRUCT(sja_state[0], Pcm3680iPCIState, 0,
+                       vmstate_can_sja, CanSJA1000State),
+        VMSTATE_STRUCT(sja_state[1], Pcm3680iPCIState, 0,
+                       vmstate_can_sja, CanSJA1000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void qdev_pcm3680i_pci_reset(DeviceState *dev)
+{
+    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(dev);
+    pcm3680i_pci_reset(d);
+}
+
+static Property pcm3680i_pci_properties[] = {
+    DEFINE_PROP_STRING("canbus1",   Pcm3680iPCIState, canbus[0]),
+    DEFINE_PROP_STRING("canbus2",   Pcm3680iPCIState, canbus[1]),
+    DEFINE_PROP_STRING("host1",  Pcm3680iPCIState, host[0]),
+    DEFINE_PROP_STRING("host2",  Pcm3680iPCIState, host[1]),
+    DEFINE_PROP_STRING("model", Pcm3680iPCIState, model),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pcm3680i_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pcm3680i_pci_init;
+    k->exit = pcm3680i_pci_exit;
+    k->vendor_id = PCM3680i_PCI_VENDOR_ID1;
+    k->device_id = PCM3680i_PCI_DEVICE_ID1;
+    k->revision = 0x00;
+    k->class_id = 0x000c09;
+    k->subsystem_vendor_id = PCM3680i_PCI_VENDOR_ID1;
+    k->subsystem_id = PCM3680i_PCI_DEVICE_ID1;
+    dc->desc = "Pcm3680i PCICANx";
+    dc->props = pcm3680i_pci_properties;
+    dc->vmsd = &vmstate_pcm3680i_pci;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    dc->reset = qdev_pcm3680i_pci_reset;
+}
+
+static const TypeInfo pcm3680i_pci_info = {
+    .name          = TYPE_CAN_PCI_DEV,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(Pcm3680iPCIState),
+    .class_init    = pcm3680i_pci_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void pcm3680i_pci_register_types(void)
+{
+    type_register_static(&pcm3680i_pci_info);
+}
+
+type_init(pcm3680i_pci_register_types)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH V4 7/7] CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added.
  2018-01-14 20:14 [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (5 preceding siblings ...)
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 6/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added pisa
@ 2018-01-14 20:14 ` pisa
  2018-01-19 13:13   ` Philippe Mathieu-Daudé
  2018-01-22 11:35 ` [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) Philippe Mathieu-Daudé
  7 siblings, 1 reply; 45+ messages in thread
From: pisa @ 2018-01-14 20:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Konrad Frederic, Deniz Eren, Oliver Hartkopp,
	Marek Vasut, Jan Kiszka, Oleksij Rempel, Pavel Pisa

From: Deniz Eren <deniz.eren@icloud.com>

Signed-off-by: Deniz Eren <deniz.eren@icloud.com>
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
---
 hw/can/Makefile.objs      |   1 +
 hw/can/can_mioe3680_pci.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 337 insertions(+)
 create mode 100644 hw/can/can_mioe3680_pci.c

diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index 6a328f0c3a..8fcc455800 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -10,4 +10,5 @@ endif
 common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
 common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
 common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
+common-obj-$(CONFIG_CAN_PCI) += can_mioe3680_pci.o
 endif
diff --git a/hw/can/can_mioe3680_pci.c b/hw/can/can_mioe3680_pci.c
new file mode 100644
index 0000000000..7e761a838a
--- /dev/null
+++ b/hw/can/can_mioe3680_pci.c
@@ -0,0 +1,336 @@
+/*
+ * MIOe-3680 PCI CAN device (SJA1000 based) emulation
+ *
+ * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
+ *
+ * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
+ * Jin Yang and Pavel Pisa
+ *
+ * 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 "qemu/osdep.h"
+#include "qemu/event_notifier.h"
+#include "qemu/thread.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "chardev/char.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "can/can_emu.h"
+
+#include "can_sja1000.h"
+
+#define TYPE_CAN_PCI_DEV "mioe3680_pci"
+
+#define MIOe3680_PCI_DEV(obj) \
+    OBJECT_CHECK(Mioe3680PCIState, (obj), TYPE_CAN_PCI_DEV)
+
+/* the PCI device and vendor IDs */
+#ifndef MIOe3680_PCI_VENDOR_ID1
+#define MIOe3680_PCI_VENDOR_ID1     0x13fe
+#endif
+
+#ifndef MIOe3680_PCI_DEVICE_ID1
+#define MIOe3680_PCI_DEVICE_ID1     0xc302
+#endif
+
+#define MIOe3680_PCI_SJA_RANGE     0x800
+
+#define MIOe3680_PCI_BYTES_PER_SJA 0x80
+
+typedef struct Mioe3680PCIState {
+    /*< private >*/
+    PCIDevice       dev;
+    /*< public >*/
+    MemoryRegion    sja_io[2];
+
+    CanSJA1000State sja_state[2];
+    qemu_irq        irq;
+
+    char            *model; /* The model that support, only SJA1000 now. */
+    char            *canbus[2];
+    char            *host[2];
+} Mioe3680PCIState;
+
+static void mioe3680_pci_irq_raise(void *opaque)
+{
+    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
+
+    qemu_irq_raise(d->irq);
+}
+
+static void mioe3680_pci_irq_lower(void *opaque)
+{
+    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
+
+    qemu_irq_lower(d->irq);
+}
+
+static void
+mioe3680_pci_reset(void *opaque)
+{
+    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+
+    can_sja_hardware_reset(s1);
+    can_sja_hardware_reset(s2);
+}
+
+static uint64_t mioe3680_pci_sja1_io_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    Mioe3680PCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[0];
+
+    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
+        return 0;
+    }
+
+    return can_sja_mem_read(s, addr >> 2, size);
+}
+
+static void mioe3680_pci_sja1_io_write(void *opaque, hwaddr addr, uint64_t data,
+                             unsigned size)
+{
+    Mioe3680PCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[0];
+
+    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
+        return;
+    }
+
+    can_sja_mem_write(s, addr >> 2, data, size);
+}
+
+static uint64_t mioe3680_pci_sja2_io_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    Mioe3680PCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[1];
+
+    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
+        return 0;
+    }
+
+    return can_sja_mem_read(s, addr >> 2, size);
+}
+
+static void mioe3680_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
+                             unsigned size)
+{
+    Mioe3680PCIState *d = opaque;
+    CanSJA1000State *s = &d->sja_state[1];
+
+    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
+        return;
+    }
+
+    can_sja_mem_write(s, addr >> 2, data, size);
+}
+
+static const MemoryRegionOps mioe3680_pci_sja1_io_ops = {
+    .read = mioe3680_pci_sja1_io_read,
+    .write = mioe3680_pci_sja1_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps mioe3680_pci_sja2_io_ops = {
+    .read = mioe3680_pci_sja2_io_read,
+    .write = mioe3680_pci_sja2_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int mioe3680_pci_init(PCIDevice *pci_dev)
+{
+    Mioe3680PCIState *d = MIOe3680_PCI_DEV(pci_dev);
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+    uint8_t *pci_conf;
+    CanBusState *can_bus1;
+    CanBusState *can_bus2;
+
+    if (d->model) {
+        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
+            error_report("Can't create CAN device, "
+                         "the model %s is not supported now.", d->model);
+            exit(1);
+        }
+    }
+
+    can_bus1 = can_bus_find_by_name(d->canbus[0], true);
+    if (can_bus1 == NULL) {
+        error_report("Cannot create can find/allocate CAN bus #1");
+        exit(1);
+    }
+
+    can_bus2 = can_bus_find_by_name(d->canbus[1], true);
+    if (can_bus2 == NULL) {
+        error_report("Cannot create can find/allocate CAN bus #2");
+        exit(1);
+    }
+
+    if (d->host[0] != NULL) {
+        if (can_bus_connect_to_host_device(can_bus1, d->host[0]) < 0) {
+            error_report("Cannot connect CAN bus to host #1 device \"%s\"",
+                         d->host[0]);
+            exit(1);
+        }
+    }
+
+    if (d->host[1] != NULL) {
+        if (can_bus_connect_to_host_device(can_bus2, d->host[1]) < 0) {
+            error_report("Cannot connect CAN bus to host #2 device \"%s\"",
+                         d->host[1]);
+            exit(1);
+        }
+    }
+
+    pci_conf = pci_dev->config;
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
+
+    d->irq = pci_allocate_irq(&d->dev);
+
+    can_sja_init(s1, mioe3680_pci_irq_raise, mioe3680_pci_irq_lower, d);
+    can_sja_init(s2, mioe3680_pci_irq_raise, mioe3680_pci_irq_lower, d);
+
+    qemu_register_reset(mioe3680_pci_reset, d);
+
+    if (can_sja_connect_to_bus(s1, can_bus1) < 0) {
+        error_report("can_sja_connect_to_bus failed");
+        exit(1);
+    }
+
+    if (can_sja_connect_to_bus(s2, can_bus2) < 0) {
+        error_report("can_sja_connect_to_bus failed");
+        exit(1);
+    }
+
+    memory_region_init_io(&d->sja_io[0], OBJECT(d), &mioe3680_pci_sja1_io_ops,
+                          d, "mioe3680_pci-sja1", MIOe3680_PCI_SJA_RANGE / 2);
+    memory_region_init_io(&d->sja_io[1], OBJECT(d), &mioe3680_pci_sja2_io_ops,
+                          d, "mioe3680_pci-sja2", MIOe3680_PCI_SJA_RANGE / 2);
+
+    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
+                                            &d->sja_io[0]);
+    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
+                                            &d->sja_io[1]);
+
+    return 0;
+}
+
+static void mioe3680_pci_exit(PCIDevice *pci_dev)
+{
+    Mioe3680PCIState *d = MIOe3680_PCI_DEV(pci_dev);
+    CanSJA1000State *s1 = &d->sja_state[0];
+    CanSJA1000State *s2 = &d->sja_state[1];
+
+    can_sja_disconnect(s1);
+    can_sja_disconnect(s2);
+
+    qemu_unregister_reset(mioe3680_pci_reset, d);
+
+    /*
+     * region d->sja_io is destroyed by QOM now
+     */
+    /* memory_region_destroy(&d->sja_io[0]); */
+    /* memory_region_destroy(&d->sja_io[1]); */
+
+    can_sja_exit(s1);
+    can_sja_exit(s2);
+
+    qemu_free_irq(d->irq);
+}
+
+static const VMStateDescription vmstate_mioe3680_pci = {
+    .name = "mioe3680_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, Mioe3680PCIState),
+        VMSTATE_STRUCT(sja_state[0], Mioe3680PCIState, 0, vmstate_can_sja,
+                       CanSJA1000State),
+        VMSTATE_STRUCT(sja_state[1], Mioe3680PCIState, 0, vmstate_can_sja,
+                       CanSJA1000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void qdev_mioe3680_pci_reset(DeviceState *dev)
+{
+    Mioe3680PCIState *d = MIOe3680_PCI_DEV(dev);
+    mioe3680_pci_reset(d);
+}
+
+static Property mioe3680_pci_properties[] = {
+    DEFINE_PROP_STRING("canbus1",   Mioe3680PCIState, canbus[0]),
+    DEFINE_PROP_STRING("canbus2",   Mioe3680PCIState, canbus[1]),
+    DEFINE_PROP_STRING("host1",  Mioe3680PCIState, host[0]),
+    DEFINE_PROP_STRING("host2",  Mioe3680PCIState, host[1]),
+    DEFINE_PROP_STRING("model", Mioe3680PCIState, model),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mioe3680_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = mioe3680_pci_init;
+    k->exit = mioe3680_pci_exit;
+    k->vendor_id = MIOe3680_PCI_VENDOR_ID1;
+    k->device_id = MIOe3680_PCI_DEVICE_ID1;
+    k->revision = 0x00;
+    k->class_id = 0x000c09;
+    k->subsystem_vendor_id = MIOe3680_PCI_VENDOR_ID1;
+    k->subsystem_id = MIOe3680_PCI_DEVICE_ID1;
+    dc->desc = "Mioe3680 PCICANx";
+    dc->props = mioe3680_pci_properties;
+    dc->vmsd = &vmstate_mioe3680_pci;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    dc->reset = qdev_mioe3680_pci_reset;
+}
+
+static const TypeInfo mioe3680_pci_info = {
+    .name          = TYPE_CAN_PCI_DEV,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(Mioe3680PCIState),
+    .class_init    = mioe3680_pci_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void mioe3680_pci_register_types(void)
+{
+    type_register_static(&mioe3680_pci_info);
+}
+
+type_init(mioe3680_pci_register_types)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface pisa
@ 2018-01-15  2:55   ` Philippe Mathieu-Daudé
  2018-01-15 21:29     ` Pavel Pisa
  2018-01-19 12:57   ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-15  2:55 UTC (permalink / raw)
  To: pisa, Daniel P. Berrange, Gerd Hoffmann, Paolo Bonzini
  Cc: qemu-devel, Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi,
	Deniz Eren, Oleksij Rempel, Konrad Frederic, Jan Kiszka

Hi Pavel,

I'm CC'ing the QEMU Sockets maintainer to ask them a quick review of the
socket part.

On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> Connection to the real host CAN bus network through
> SocketCAN network interface is available only for Linux
> host system. Mechanism is generic, support for another
> CAN API and operating systems can be implemented in future.
> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>  hw/can/Makefile.objs   |   4 +
>  hw/can/can_socketcan.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 318 insertions(+)
>  create mode 100644 hw/can/can_socketcan.c
> 
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index 1028d7c455..f999085f7a 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -2,5 +2,9 @@
>  
>  ifeq ($(CONFIG_CAN_CORE),y)
>  common-obj-y += can_core.o
> +ifeq ($(CONFIG_LINUX),y)
> +common-obj-y += can_socketcan.o
> +else
>  common-obj-y += can_host_stub.o
>  endif
> +endif
> diff --git a/hw/can/can_socketcan.c b/hw/can/can_socketcan.c
> new file mode 100644
> index 0000000000..f6df747c5a
> --- /dev/null
> +++ b/hw/can/can_socketcan.c
> @@ -0,0 +1,314 @@
> +/*
> + * CAN socketcan support to connect to the Linux host SocketCAN interfaces
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014-2018 Pavel Pisa
> + *
> + * Initial development supported by Google GSoC 2013 from RTEMS project slot
> + *
> + * 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 "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "qemu/error-report.h"
> +#include "chardev/char.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "hw/hw.h"
> +#include "can/can_emu.h"
> +
> +#include <sys/ioctl.h>
> +#include <net/if.h>
> +#include <linux/can.h>
> +#include <linux/can/raw.h>
> +
> +#ifndef DEBUG_CAN
> +#define DEBUG_CAN 0
> +#endif /*DEBUG_CAN*/
> +
> +#define CAN_READ_BUF_LEN  5
> +typedef struct {
> +    CanBusClientState  bus_client;
> +    qemu_can_filter    *rfilter;
> +    int                rfilter_num;
> +    can_err_mask_t     err_mask;
> +
> +    qemu_can_frame     buf[CAN_READ_BUF_LEN];
> +    int                bufcnt;
> +    int                bufptr;
> +
> +    int                fd;
> +} CanBusSocketcanConnectState;
> +

Please move those checks out of the function, to call them once at build
time and not at runtime.

/* Check that QEMU and Linux kernel flags encoding matches */
QEMU_BUILD_BUG_ON(QEMU_CAN_EFF_FLAG == CAN_EFF_FLAG);
QEMU_BUILD_BUG_ON(QEMU_CAN_RTR_FLAG == CAN_RTR_FLAG);
QEMU_BUILD_BUG_ON(QEMU_CAN_ERR_FLAG == CAN_ERR_FLAG);
QEMU_BUILD_BUG_ON(QEMU_CAN_INV_FILTER == CAN_INV_FILTER);
QEMU_BUILD_BUG_ON(offsetof(qemu_can_frame, data)
                  == offsetof(struct can_frame, data));

> +static void can_bus_socketcan_display_msg(struct qemu_can_frame *msg)
> +{
> +    int i;
> +
> +    /* Check that QEMU and Linux kernel flags encoding matches */
> +    assert(QEMU_CAN_EFF_FLAG == CAN_EFF_FLAG);
> +    assert(QEMU_CAN_RTR_FLAG == CAN_RTR_FLAG);
> +    assert(QEMU_CAN_ERR_FLAG == CAN_ERR_FLAG);
> +
> +    assert(QEMU_CAN_INV_FILTER == CAN_INV_FILTER);
> +
> +    assert(offsetof(qemu_can_frame, data) == offsetof(struct can_frame, data));

^ those

> +
> +    qemu_log_lock();
> +    qemu_log("[cansocketcan]: %03X [%01d] %s %s",
> +             msg->can_id & QEMU_CAN_EFF_MASK,
> +             msg->can_dlc,
> +             msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF",
> +             msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT");
> +
> +    for (i = 0; i < msg->can_dlc; i++) {
> +        qemu_log(" %02X", msg->data[i]);
> +    }
> +    qemu_log("\n");

I'd rather use tracepoints, but since this is restricted by DEBUG_CAN
this doesn't bother the user console, so ok.

> +    qemu_log_flush();
> +    qemu_log_unlock();
> +}
> +
> +static void can_bus_socketcan_read(void *opaque)
> +{
> +    CanBusSocketcanConnectState *c;
> +    c = (CanBusSocketcanConnectState *)opaque;
> +
> +
> +
> +    /* CAN_READ_BUF_LEN for multiple messages syscall is possible for future */
> +    c->bufcnt = read(c->fd, c->buf, sizeof(qemu_can_frame));
> +    if (c->bufcnt < 0) {
> +        warn_report("CAN bus host read failed (%s)", strerror(errno));
> +        return;
> +    }
> +
> +    can_bus_client_send(&c->bus_client, c->buf, 1);
> +
> +    if (DEBUG_CAN) {
> +        can_bus_socketcan_display_msg(c->buf);
> +    }
> +}
> +
> +static int can_bus_socketcan_can_receive(CanBusClientState *client)
> +{
> +    CanBusSocketcanConnectState *c;
> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
> +
> +    if (c->fd < 0) {
> +        return -1;
> +    }
> +
> +    return 1;
> +}
> +
> +static ssize_t can_bus_socketcan_receive(CanBusClientState *client,
> +                            const qemu_can_frame *frames, size_t frames_cnt)
> +{
> +    CanBusSocketcanConnectState *c;
> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
> +    size_t len = sizeof(qemu_can_frame);
> +    int res;
> +
> +    if (c->fd < 0) {
> +        return -1;
> +    }
> +
> +    res = write(c->fd, frames, len);
> +
> +    if (!res) {
> +        warn_report("[cansocketcan]: write message to host returns zero");
> +        return -1;
> +    }
> +
> +    if (res != len) {
> +        if (res < 0) {
> +            warn_report("[cansocketcan]: write to host failed (%s)",
> +                        strerror(errno));
> +        } else {
> +            warn_report("[cansocketcan]: write to host truncated");
> +        }
> +        return -1;
> +    }
> +
> +    return 1;
> +}
> +
> +static void can_bus_socketcan_cleanup(CanBusClientState *client)
> +{
> +    CanBusSocketcanConnectState *c;
> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
> +
> +    if (c->fd >= 0) {
> +        qemu_set_fd_handler(c->fd, NULL, NULL, c);
> +        close(c->fd);
> +        c->fd = -1;
> +    }
> +
> +    c->rfilter_num = 0;
> +    if (c->rfilter != NULL) {
> +        g_free(c->rfilter);
> +    }
> +}
> +
> +static int can_bus_socketcan_set_filters(CanBusClientState *client,
> +                   const struct qemu_can_filter *filters, size_t filters_cnt)
> +{
> +    CanBusSocketcanConnectState *c;
> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
> +
> +    int i;
> +
> +    if (DEBUG_CAN) {
> +        qemu_log_lock();
> +        qemu_log("[cansocketcan]: filters set for channel\n");
> +        for (i = 0; i < filters_cnt; i++) {
> +            fprintf(stderr, "[%i]  id=0x%08x maks=0x%08x\n",
> +                   i, filters[i].can_id, filters[i].can_mask);
> +        }
> +        qemu_log("\n");
> +        qemu_log_flush();
> +        qemu_log_unlock();
> +    }
> +
> +    setsockopt(c->fd, SOL_CAN_RAW, CAN_RAW_FILTER,
> +               filters, filters_cnt * sizeof(qemu_can_filter));
> +
> +    return 0;
> +}
> +
> +static
> +void can_bus_socketcan_update_read_handler(CanBusSocketcanConnectState *c)
> +{
> +    if (c->fd >= 0) {
> +        qemu_set_fd_handler(c->fd, can_bus_socketcan_read, NULL, c);
> +    }
> +}
> +
> +static CanBusClientInfo can_bus_socketcan_bus_client_info = {
> +    .can_receive = can_bus_socketcan_can_receive,
> +    .receive = can_bus_socketcan_receive,
> +    .cleanup = can_bus_socketcan_cleanup,
> +    .poll = NULL
> +};
> +
> +static CanBusSocketcanConnectState *
> +    can_bus_socketcan_connect_new(const char *host_dev_name)
> +{
> +    int s; /* can raw socket */
> +    CanBusSocketcanConnectState    *c;
> +    struct sockaddr_can addr;
> +    struct ifreq ifr;
> +
> +    c = g_malloc0(sizeof(CanBusSocketcanConnectState));
> +    if (c == NULL) {
> +        goto fail1;
> +    }
> +
> +    c->fd = -1;
> +
> +    /* open socket */
> +    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);

I never used it, but I think QEMU uses his socket API: "qemu/sockets.h"

> +    if (s < 0) {
> +        error_report("[cansocketcan]: CAN_RAW socket create failed  (%s)",
> +                        strerror(errno));
> +        goto fail;
> +    }
> +
> +    addr.can_family = AF_CAN;
> +    memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
> +    strcpy(ifr.ifr_name, host_dev_name);
> +    if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
> +        error_report("[cansocketcan]: host interface %s not available (%s)",
> +                     host_dev_name, strerror(errno));
> +        goto fail;
> +    }
> +    addr.can_ifindex = ifr.ifr_ifindex;
> +
> +    c->err_mask = 0xffffffff; /* Receive error frame. */
> +    setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
> +                   &c->err_mask, sizeof(c->err_mask));
> +
> +    c->rfilter_num = 1;
> +    c->rfilter = g_malloc0(c->rfilter_num * sizeof(struct qemu_can_filter));
> +    if (c->rfilter == NULL) {
> +        goto fail;
> +    }
> +
> +    /* Receive all data frame. If |= CAN_INV_FILTER no data. */
> +    c->rfilter[0].can_id = 0;
> +    c->rfilter[0].can_mask = 0;
> +    c->rfilter[0].can_mask &= ~CAN_ERR_FLAG;
> +
> +    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, c->rfilter,
> +               c->rfilter_num * sizeof(struct qemu_can_filter));
> +
> +    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
> +        error_report("[cansocketcan]: bind to host interface %s failed (%s)",
> +                     host_dev_name, strerror(errno));
> +        goto fail;
> +    }
> +
> +    c->fd = s;
> +
> +    c->bus_client.info = &can_bus_socketcan_bus_client_info;
> +
> +    can_bus_socketcan_update_read_handler(c);
> +
> +    return c;
> +
> +fail:
> +    can_bus_socketcan_cleanup(&c->bus_client);
> +    g_free(c);
> +fail1:
> +
> +    return NULL;
> +}
> +
> +static int can_bus_connect_to_host_socketcan(CanBusState *bus,
> +                                             const char *host_dev_name)
> +{
> +    CanBusSocketcanConnectState *c;
> +
> +    c = can_bus_socketcan_connect_new(host_dev_name);
> +    if (c == NULL) {
> +        error_report("CAN bus setup of host connect to \"%s\" failed",
> +                      host_dev_name);
> +        exit(1);
> +    }
> +
> +    if (can_bus_insert_client(bus, &c->bus_client) < 0) {
> +        error_report("CAN host device \"%s\" connect to bus \"%s\" failed",
> +                      host_dev_name, bus->name);
> +        exit(1);
> +    }
> +
> +    if (0) {
> +        /*
> +         * Not used there or as a CanBusSocketcanConnectState method
> +         * for now but included there for documentation purposes
> +         * and to suppress warning.
> +         */
> +        can_bus_socketcan_set_filters(&c->bus_client, NULL, 0);
> +    }
> +
> +    return 0;
> +}
> +
> +int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
> +        can_bus_connect_to_host_socketcan;
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 3/7] CAN bus SJA1000 chip register level emulation for QEMU
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 3/7] CAN bus SJA1000 chip register level emulation for QEMU pisa
@ 2018-01-15  3:03   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-15  3:03 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> The core SJA1000 support is independent of following
> patches which map SJA1000 chip to PCI boards.
> 
> The work is based on Jin Yang GSoC 2013 work funded
> by Google and mentored in frame of RTEMS project GSoC
> slot donated to QEMU.
> 
> Rewritten for QEMU-2.0+ versions and architecture cleanup
> by Pavel Pisa (Czech Technical University in Prague).
> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>  default-configs/pci.mak |    1 +
>  hw/can/Makefile.objs    |    1 +
>  hw/can/can_sja1000.c    | 1013 +++++++++++++++++++++++++++++++++++++++++++++++
>  hw/can/can_sja1000.h    |  167 ++++++++
>  4 files changed, 1182 insertions(+)
>  create mode 100644 hw/can/can_sja1000.c
>  create mode 100644 hw/can/can_sja1000.h
> 
> diff --git a/default-configs/pci.mak b/default-configs/pci.mak
> index bbe11887a1..979b649fe5 100644
> --- a/default-configs/pci.mak
> +++ b/default-configs/pci.mak
> @@ -32,6 +32,7 @@ CONFIG_SERIAL=y
>  CONFIG_SERIAL_ISA=y
>  CONFIG_SERIAL_PCI=y
>  CONFIG_CAN_CORE=y
> +CONFIG_CAN_SJA1000=y
>  CONFIG_IPACK=y
>  CONFIG_WDT_IB6300ESB=y
>  CONFIG_PCI_TESTDEV=y
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index f999085f7a..3c4bf3bfc1 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -7,4 +7,5 @@ common-obj-y += can_socketcan.o
>  else
>  common-obj-y += can_host_stub.o
>  endif
> +common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
>  endif
> diff --git a/hw/can/can_sja1000.c b/hw/can/can_sja1000.c
> new file mode 100644
> index 0000000000..7f7a6ea244
> --- /dev/null
> +++ b/hw/can/can_sja1000.c
> @@ -0,0 +1,1013 @@
> +/*
> + * CAN device - SJA1000 chip emulation for QEMU
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014-2018 Pavel Pisa
> + *
> + * Initial development supported by Google GSoC 2013 from RTEMS project slot
> + *
> + * 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 "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "chardev/char.h"
> +#include "hw/hw.h"
> +#include "can/can_emu.h"
> +
> +#include "can_sja1000.h"
> +
> +#ifndef DEBUG_FILTER
> +#define DEBUG_FILTER 0
> +#endif /*DEBUG_FILTER*/
> +
> +#ifndef DEBUG_CAN
> +#define DEBUG_CAN 0
> +#endif /*DEBUG_CAN*/
> +
> +#define DPRINTF(fmt, ...) \
> +    do { \
> +        if (DEBUG_CAN) { \
> +            qemu_log("[cansja]: " fmt , ## __VA_ARGS__); \
> +        } \
> +    } while (0)
> +
> +static void can_sja_software_reset(CanSJA1000State *s)
> +{
> +    s->mode        &= ~0x31;
> +    s->mode        |= 0x01;
> +    s->status_pel  &= ~0x37;
> +    s->status_pel  |= 0x34;
> +
> +    s->rxbuf_start = 0x00;
> +    s->rxmsg_cnt   = 0x00;
> +    s->rx_cnt      = 0x00;
> +}
> +
> +void can_sja_hardware_reset(CanSJA1000State *s)
> +{
> +    /* Reset by hardware, p10 */
> +    s->mode        = 0x01;
> +    s->status_pel  = 0x3c;
> +    s->interrupt_pel = 0x00;
> +    s->clock       = 0x00;
> +    s->rxbuf_start = 0x00;
> +    s->rxmsg_cnt   = 0x00;
> +    s->rx_cnt      = 0x00;
> +
> +    s->control     = 0x01;
> +    s->status_bas  = 0x0c;
> +    s->interrupt_bas = 0x00;
> +
> +    s->irq_lower(s->irq_opaque);
> +}
> +
> +static
> +void can_sja_single_filter(struct qemu_can_filter *filter,
> +            const uint8_t *acr,  const uint8_t *amr, int extended)
> +{
> +    if (extended) {
> +        filter->can_id = (uint32_t)acr[0] << 21;
> +        filter->can_id |= (uint32_t)acr[1] << 13;
> +        filter->can_id |= (uint32_t)acr[2] << 5;
> +        filter->can_id |= (uint32_t)acr[3] >> 3;
> +        if (acr[3] & 4) {
> +            filter->can_id |= QEMU_CAN_RTR_FLAG;
> +        }

I hope we inline that later...

> +
> +        filter->can_mask = (uint32_t)amr[0] << 21;
> +        filter->can_mask |= (uint32_t)amr[1] << 13;
> +        filter->can_mask |= (uint32_t)amr[2] << 5;
> +        filter->can_mask |= (uint32_t)amr[3] >> 3;
> +        filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK;
> +        if (!(amr[3] & 4)) {
> +            filter->can_mask |= QEMU_CAN_RTR_FLAG;
> +        }
> +    } else {
> +        filter->can_id = (uint32_t)acr[0] << 3;
> +        filter->can_id |= (uint32_t)acr[1] >> 5;
> +        if (acr[1] & 0x10) {
> +            filter->can_id |= QEMU_CAN_RTR_FLAG;
> +        }

ditto.

> +
> +        filter->can_mask = (uint32_t)amr[0] << 3;
> +        filter->can_mask |= (uint32_t)amr[1] << 5;
> +        filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK;
> +        if (!(amr[1] & 4)) {
> +            filter->can_mask |= QEMU_CAN_RTR_FLAG;
> +        }
> +    }
> +}
> +
> +static
> +void can_sja_dual_filter(struct qemu_can_filter *filter,
> +            const uint8_t *acr,  const uint8_t *amr, int extended)
> +{
> +    if (extended) {
> +        filter->can_id = (uint32_t)acr[0] << 21;
> +        filter->can_id |= (uint32_t)acr[1] << 13;
> +
> +        filter->can_mask = (uint32_t)amr[0] << 21;
> +        filter->can_mask |= (uint32_t)amr[1] << 13;
> +        filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK & ~0x1fff;
> +    } else {
> +        filter->can_id = (uint32_t)acr[0] << 3;
> +        filter->can_id |= (uint32_t)acr[1] >> 5;
> +        if (acr[1] & 0x10) {
> +            filter->can_id |= QEMU_CAN_RTR_FLAG;
> +        }
> +
> +        filter->can_mask = (uint32_t)amr[0] << 3;
> +        filter->can_mask |= (uint32_t)amr[1] >> 5;
> +        filter->can_mask = ~filter->can_mask & QEMU_CAN_SFF_MASK;
> +        if (!(amr[1] & 0x10)) {
> +            filter->can_mask |= QEMU_CAN_RTR_FLAG;
> +        }
> +    }
> +}
> +
> +/* Details in DS-p22, what we need to do here is to test the data. */
> +static
> +int can_sja_accept_filter(CanSJA1000State *s,
> +                                 const qemu_can_frame *frame)
> +{
> +
> +    struct qemu_can_filter filter;
> +
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +        if (s->mode & (1 << 3)) { /* Single mode. */
> +            if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
> +                can_sja_single_filter(&filter,
> +                    s->code_mask + 0, s->code_mask + 4, 1);
> +
> +                if (!can_bus_filter_match(&filter, frame->can_id)) {
> +                    return 0;
> +                }
> +            } else { /* SFF */
> +                can_sja_single_filter(&filter,
> +                    s->code_mask + 0, s->code_mask + 4, 0);
> +
> +                if (!can_bus_filter_match(&filter, frame->can_id)) {
> +                    return 0;
> +                }
> +
> +                if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
> +                    return 1;
> +                }
> +
> +                if (frame->can_dlc == 0) {
> +                    return 1;
> +                }
> +
> +                if ((frame->data[0] & ~(s->code_mask[6])) !=
> +                   (s->code_mask[2] & ~(s->code_mask[6]))) {
> +                    return 0;
> +                }
> +
> +                if (frame->can_dlc < 2) {
> +                    return 1;
> +                }
> +
> +                if ((frame->data[1] & ~(s->code_mask[7])) ==
> +                    (s->code_mask[3] & ~(s->code_mask[7]))) {
> +                    return 1;
> +                }
> +
> +                return 0;
> +            }
> +        } else { /* Dual mode */
> +            if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
> +                can_sja_dual_filter(&filter,
> +                    s->code_mask + 0, s->code_mask + 4, 1);
> +
> +                if (can_bus_filter_match(&filter, frame->can_id)) {
> +                    return 1;
> +                }
> +
> +                can_sja_dual_filter(&filter,
> +                    s->code_mask + 2, s->code_mask + 6, 1);
> +
> +                if (can_bus_filter_match(&filter, frame->can_id)) {
> +                    return 1;
> +                }
> +
> +                return 0;
> +            } else {
> +                can_sja_dual_filter(&filter,
> +                    s->code_mask + 0, s->code_mask + 4, 0);
> +
> +                if (can_bus_filter_match(&filter, frame->can_id)) {
> +                    uint8_t expect;
> +                    uint8_t mask;
> +                    expect = s->code_mask[1] << 4;
> +                    expect |= s->code_mask[3] & 0x0f;
> +
> +                    mask = s->code_mask[5] << 4;
> +                    mask |= s->code_mask[7] & 0x0f;
> +                        mask = ~mask & 0xff;
> +
> +                    if ((frame->data[0] & mask) ==
> +                        (expect & mask)) {
> +                        return 1;
> +                    }
> +                }
> +
> +                can_sja_dual_filter(&filter,
> +                    s->code_mask + 2, s->code_mask + 6, 0);
> +
> +                if (can_bus_filter_match(&filter, frame->can_id)) {
> +                    return 1;
> +                }
> +
> +                return 0;
> +            }
> +        }
> +    }
> +
> +    return 1;
> +}
> +
> +static void can_display_msg(const char *prefix, const qemu_can_frame *msg)
> +{
> +    int i;
> +
> +    qemu_log_lock();
> +    qemu_log("%s%03X [%01d] %s %s",
> +             prefix,
> +             msg->can_id & QEMU_CAN_EFF_MASK,
> +             msg->can_dlc,
> +             msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF",
> +             msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT");
> +
> +    for (i = 0; i < msg->can_dlc; i++) {
> +        qemu_log(" %02X", msg->data[i]);
> +    }
> +    qemu_log("\n");
> +    qemu_log_flush();
> +    qemu_log_unlock();
> +}
> +
> +static void buff2frame_pel(const uint8_t *buff, qemu_can_frame *frame)
> +{
> +    uint8_t i;
> +
> +    frame->can_id = 0;
> +    if (buff[0] & 0x40) { /* RTR */
> +        frame->can_id = QEMU_CAN_RTR_FLAG;
> +    }
> +    frame->can_dlc = buff[0] & 0x0f;
> +
> +    if (buff[0] & 0x80) { /* Extended */
> +        frame->can_id |= QEMU_CAN_EFF_FLAG;
> +        frame->can_id |= buff[1] << 21; /* ID.28~ID.21 */
> +        frame->can_id |= buff[2] << 13; /* ID.20~ID.13 */
> +        frame->can_id |= buff[3] <<  5;
> +        frame->can_id |= buff[4] >>  3;
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            frame->data[i] = buff[5 + i];
> +        }
> +        for (; i < 8; i++) {
> +            frame->data[i] = 0;
> +        }
> +    } else {
> +        frame->can_id |= buff[1] <<  3;
> +        frame->can_id |= buff[2] >>  5;
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            frame->data[i] = buff[3 + i];
> +        }
> +        for (; i < 8; i++) {
> +            frame->data[i] = 0;
> +        }
> +    }
> +}
> +
> +
> +static void buff2frame_bas(const uint8_t *buff, qemu_can_frame *frame)
> +{
> +    uint8_t i;
> +
> +    frame->can_id = ((buff[0] << 3) & (0xff << 3)) + ((buff[1] >> 5) & 0x07);
> +    if (buff[1] & 0x10) { /* RTR */
> +        frame->can_id = QEMU_CAN_RTR_FLAG;
> +    }
> +    frame->can_dlc = buff[1] & 0x0f;
> +
> +    for (i = 0; i < frame->can_dlc; i++) {
> +        frame->data[i] = buff[2 + i];
> +    }
> +    for (; i < 8; i++) {
> +        frame->data[i] = 0;
> +    }
> +}
> +
> +
> +static int frame2buff_pel(const qemu_can_frame *frame, uint8_t *buff)
> +{
> +    int i;
> +
> +    if (frame->can_id & QEMU_CAN_ERR_FLAG) { /* error frame, NOT support now. */
> +        return -1;
> +    }
> +
> +    buff[0] = 0x0f & frame->can_dlc; /* DLC */
> +    if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
> +        buff[0] |= (1 << 6);
> +    }
> +    if (frame->can_id & QEMU_CAN_EFF_FLAG) { /* EFF */
> +        buff[0] |= (1 << 7);
> +        buff[1] = extract32(frame->can_id, 21, 8); /* ID.28~ID.21 */
> +        buff[2] = extract32(frame->can_id, 13, 8); /* ID.20~ID.13 */
> +        buff[3] = extract32(frame->can_id, 5, 8);  /* ID.12~ID.05 */
> +        buff[4] = extract32(frame->can_id, 0, 5) << 3; /* ID.04~ID.00,xxx */
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            buff[5 + i] = frame->data[i];
> +        }
> +        return frame->can_dlc + 5;
> +    } else { /* SFF */
> +        buff[1] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */
> +        buff[2] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,xxxxx */
> +        for (i = 0; i < frame->can_dlc; i++) {
> +            buff[3 + i] = frame->data[i];
> +        }
> +
> +        return frame->can_dlc + 3;
> +    }
> +
> +    return -1;
> +}
> +
> +static int frame2buff_bas(const qemu_can_frame *frame, uint8_t *buff)
> +{
> +    int i;
> +
> +     /*
> +      * EFF, no support for BasicMode
> +      * No use for Error frames now,
> +      * they could be used in future to update SJA1000 error state
> +      */
> +    if ((frame->can_id & QEMU_CAN_EFF_FLAG) ||
> +       (frame->can_id & QEMU_CAN_ERR_FLAG)) {
> +        return -1;
> +    }
> +
> +    buff[0] = extract32(frame->can_id, 3, 8); /* ID.10~ID.03 */
> +    buff[1] = extract32(frame->can_id, 0, 3) << 5; /* ID.02~ID.00,xxxxx */
> +    if (frame->can_id & QEMU_CAN_RTR_FLAG) { /* RTR */
> +        buff[1] |= (1 << 4);
> +    }
> +    buff[1] |= frame->can_dlc & 0x0f;
> +    for (i = 0; i < frame->can_dlc; i++) {
> +        buff[2 + i] = frame->data[i];
> +    }
> +
> +    return frame->can_dlc + 2;
> +}
> +
> +void can_sja_mem_write(CanSJA1000State *s, hwaddr addr, uint64_t val,
> +                       unsigned size)
> +{
> +    qemu_can_frame   frame;
> +    uint32_t         tmp;
> +    uint8_t          tmp8, count;
> +
> +
> +    DPRINTF("write 0x%02llx addr 0x%02x\n",
> +            (unsigned long long)val, (unsigned int)addr);
> +
> +    if (addr > CAN_SJA_MEM_SIZE) {
> +        return ;
> +    }
> +
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +        switch (addr) {
> +        case SJA_MOD: /* Mode register */
> +            s->mode = 0x1f & val;
> +            if ((s->mode & 0x01) && ((val & 0x01) == 0)) {
> +                /* Go to operation mode from reset mode. */
> +                if (s->mode & (1 << 3)) { /* Single mode. */
> +                    /* For EFF */
> +                    can_sja_single_filter(&s->filter[0],
> +                        s->code_mask + 0, s->code_mask + 4, 1);
> +
> +                    /* For SFF */
> +                    can_sja_single_filter(&s->filter[1],
> +                        s->code_mask + 0, s->code_mask + 4, 0);
> +
> +                    can_bus_client_set_filters(&s->bus_client, s->filter, 2);
> +                } else { /* Dual mode */
> +                    /* For EFF */
> +                    can_sja_dual_filter(&s->filter[0],
> +                        s->code_mask + 0, s->code_mask + 4, 1);
> +
> +                    can_sja_dual_filter(&s->filter[1],
> +                        s->code_mask + 2, s->code_mask + 6, 1);
> +
> +                    /* For SFF */
> +                    can_sja_dual_filter(&s->filter[2],
> +                        s->code_mask + 0, s->code_mask + 4, 0);
> +
> +                    can_sja_dual_filter(&s->filter[3],
> +                        s->code_mask + 2, s->code_mask + 6, 0);
> +
> +                    can_bus_client_set_filters(&s->bus_client, s->filter, 4);
> +                }
> +
> +                s->rxmsg_cnt = 0;
> +                s->rx_cnt = 0;
> +            }
> +            break;
> +
> +        case SJA_CMR: /* Command register. */
> +            if (0x01 & val) { /* Send transmission request. */
> +                buff2frame_pel(s->tx_buff, &frame);
> +                if (DEBUG_FILTER) {
> +                    can_display_msg("[cansja]: Tx request " , &frame);
> +                }
> +
> +                /*
> +                 * Clear transmission complete status,
> +                 * and Transmit Buffer Status.
> +                 * write to the backends.
> +                 */
> +                s->status_pel &= ~(3 << 2);
> +
> +                can_bus_client_send(&s->bus_client, &frame, 1);
> +
> +                /*
> +                 * Set transmission complete status
> +                 * and Transmit Buffer Status.
> +                 */
> +                s->status_pel |= (3 << 2);
> +
> +                /* Clear transmit status. */
> +                s->status_pel &= ~(1 << 5);
> +                s->interrupt_pel |= 0x02;
> +                if (s->interrupt_en & 0x02) {
> +                    s->irq_raise(s->irq_opaque);
> +                }
> +            }
> +            if (0x04 & val) { /* Release Receive Buffer */
> +                if (s->rxmsg_cnt <= 0) {
> +                    break;
> +                }
> +
> +                tmp8 = s->rx_buff[s->rxbuf_start]; count = 0;
> +                if (tmp8 & (1 << 7)) { /* EFF */
> +                    count += 2;
> +                }
> +                count += 3;
> +                if (!(tmp8 & (1 << 6))) { /* DATA */
> +                    count += (tmp8 & 0x0f);
> +                }
> +
> +                if (DEBUG_FILTER) {
> +                    qemu_log("[cansja]: message released from "
> +                             "Rx FIFO cnt=%d, count=%d\n", s->rx_cnt, count);
> +                }
> +
> +                s->rxbuf_start += count;
> +                s->rxbuf_start %= SJA_RCV_BUF_LEN;
> +
> +                s->rx_cnt -= count;
> +                s->rxmsg_cnt--;
> +                if (s->rxmsg_cnt == 0) {
> +                    s->status_pel &= ~(1 << 0);
> +                    s->interrupt_pel &= ~(1 << 0);
> +                }
> +                if ((s->interrupt_en & 0x01) && (s->interrupt_pel == 0)) {
> +                    /* no other interrupts. */
> +                    s->irq_lower(s->irq_opaque);
> +                }
> +            }
> +            if (0x08 & val) { /* Clear data overrun */
> +                s->status_pel &= ~(1 << 1);
> +                s->interrupt_pel &= ~(1 << 3);
> +                if ((s->interrupt_en & 0x80) && (s->interrupt_pel == 0)) {
> +                    /* no other interrupts. */
> +                    s->irq_lower(s->irq_opaque);
> +                }
> +            }
> +            break;
> +        case SJA_SR: /* Status register */
> +        case SJA_IR: /* Interrupt register */
> +            break; /* Do nothing */
> +        case SJA_IER: /* Interrupt enable register */
> +            s->interrupt_en = val;
> +            break;
> +        case 16: /* RX frame information addr16-28. */
> +            s->status_pel |= (1 << 5); /* Set transmit status. */
> +        case 17:
> +        case 18:
> +        case 19:
> +        case 20:
> +        case 21:
> +        case 22:
> +        case 23:
> +        case 24:
> +        case 25:
> +        case 26:
> +        case 27:
> +        case 28:

           case 17 ... 28:

> +            if (s->mode & 0x01) { /* Reset mode */
> +                if (addr < 24) {
> +                    s->code_mask[addr - 16] = val;
> +                }
> +            } else { /* Operation mode */
> +                s->tx_buff[addr - 16] = val; /* Store to TX buffer directly. */
> +            }
> +            break;
> +        case SJA_CDR:
> +            s->clock = val;
> +            break;
> +        }
> +    } else { /* Basic Mode */
> +        switch (addr) {
> +        case SJA_BCAN_CTR: /* Control register, addr 0 */
> +            if ((s->control & 0x01) && ((val & 0x01) == 0)) {
> +                /* Go to operation mode from reset mode. */
> +                s->filter[0].can_id = (s->code << 3) & (0xff << 3);
> +                tmp = (~(s->mask << 3)) & (0xff << 3);
> +                tmp |= QEMU_CAN_EFF_FLAG; /* Only Basic CAN Frame. */
> +                s->filter[0].can_mask = tmp;
> +                can_bus_client_set_filters(&s->bus_client, s->filter, 1);
> +
> +                s->rxmsg_cnt = 0;
> +                s->rx_cnt = 0;
> +            } else if (!(s->control & 0x01) && !(val & 0x01)) {
> +                can_sja_software_reset(s);
> +            }
> +
> +            s->control = 0x1f & val;
> +            break;
> +        case SJA_BCAN_CMR: /* Command register, addr 1 */
> +            if (0x01 & val) { /* Send transmission request. */
> +                buff2frame_bas(s->tx_buff, &frame);
> +                if (DEBUG_FILTER) {
> +                    can_display_msg("[cansja]: Tx request " , &frame);
> +                }
> +
> +                /*
> +                 * Clear transmission complete status,
> +                 * and Transmit Buffer Status.
> +                 */
> +                s->status_bas &= ~(3 << 2);
> +
> +                /* write to the backends. */
> +                can_bus_client_send(&s->bus_client, &frame, 1);
> +
> +                /*
> +                 * Set transmission complete status,
> +                 * and Transmit Buffer Status.
> +                 */
> +                s->status_bas |= (3 << 2);
> +
> +                /* Clear transmit status. */
> +                s->status_bas &= ~(1 << 5);
> +                s->interrupt_bas |= 0x02;
> +                if (s->control & 0x04) {
> +                    s->irq_raise(s->irq_opaque);
> +                }
> +            }
> +            if (0x04 & val) { /* Release Receive Buffer */
> +                if (s->rxmsg_cnt <= 0) {
> +                    break;
> +                }
> +
> +                qemu_mutex_lock(&s->rx_lock);
> +                tmp8 = s->rx_buff[(s->rxbuf_start + 1) % SJA_RCV_BUF_LEN];
> +                count = 2 + (tmp8 & 0x0f);
> +
> +                if (DEBUG_FILTER) {
> +                    qemu_log("[cansja]: message released from "
> +                             "Rx FIFO cnt=%d, count=%d\n", s->rx_cnt, count);
> +                }
> +
> +                s->rxbuf_start += count;
> +                s->rxbuf_start %= SJA_RCV_BUF_LEN;
> +                s->rx_cnt -= count;
> +                s->rxmsg_cnt--;
> +                qemu_mutex_unlock(&s->rx_lock);
> +
> +                if (s->rxmsg_cnt == 0) {
> +                    s->status_bas &= ~(1 << 0);
> +                    s->interrupt_bas &= ~(1 << 0);
> +                }
> +                if ((s->control & 0x02) && (s->interrupt_bas == 0)) {
> +                    /* no other interrupts. */
> +                    s->irq_lower(s->irq_opaque);
> +                }
> +            }
> +            if (0x08 & val) { /* Clear data overrun */
> +                s->status_bas &= ~(1 << 1);
> +                s->interrupt_bas &= ~(1 << 3);
> +                if ((s->control & 0x10) && (s->interrupt_bas == 0)) {
> +                    /* no other interrupts. */
> +                    s->irq_lower(s->irq_opaque);
> +                }
> +            }
> +            break;
> +        case 4:
> +            s->code = val;
> +            break;
> +        case 5:
> +            s->mask = val;
> +            break;
> +        case 10:
> +            s->status_bas |= (1 << 5); /* Set transmit status. */
> +        case 11:
> +        case 12:
> +        case 13:
> +        case 14:
> +        case 15:
> +        case 16:
> +        case 17:
> +        case 18:
> +        case 19:

           case 11 ... 19:

> +            if ((s->control & 0x01) == 0) { /* Operation mode */
> +                s->tx_buff[addr - 10] = val; /* Store to TX buffer directly. */
> +            }
> +            break;
> +        case SJA_CDR:
> +            s->clock = val;
> +            break;
> +        }
> +    }
> +}
> +
> +uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size)
> +{
> +    uint64_t temp = 0;
> +
> +    DPRINTF("read addr 0x%02x ...\n", (unsigned int)addr);
> +
> +    if (addr > CAN_SJA_MEM_SIZE) {
> +        return 0;
> +    }
> +
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +        switch (addr) {
> +        case SJA_MOD: /* Mode register, addr 0 */
> +            temp = s->mode;
> +            break;
> +        case SJA_CMR: /* Command register, addr 1 */
> +            temp = 0x00; /* Command register, cannot be read. */
> +            break;
> +        case SJA_SR: /* Status register, addr 2 */
> +            temp = s->status_pel;
> +            break;
> +        case SJA_IR: /* Interrupt register, addr 3 */
> +            temp = s->interrupt_pel;
> +            s->interrupt_pel = 0;
> +            if (s->rxmsg_cnt) {
> +                s->interrupt_pel |= (1 << 0); /* Receive interrupt. */
> +                break;
> +            }
> +            s->irq_lower(s->irq_opaque);
> +            break;
> +        case SJA_IER: /* Interrupt enable register, addr 4 */
> +            temp = s->interrupt_en;
> +            break;
> +        case 5: /* Reserved */
> +        case 6: /* Bus timing 0, hardware related, not support now. */
> +        case 7: /* Bus timing 1, hardware related, not support now. */
> +        case 8: /*
> +                 * Output control register, hardware related,
> +                 * not supported for now.
> +                 */
> +        case 9: /* Test. */
> +        case 10: /* Reserved */
> +        case 11:
> +        case 12:
> +        case 13:
> +        case 14:
> +        case 15:
> +            temp = 0x00;
> +            break;
> +
> +        case 16:
> +        case 17:
> +        case 18:
> +        case 19:
> +        case 20:
> +        case 21:
> +        case 22:
> +        case 23:
> +        case 24:
> +        case 25:
> +        case 26:
> +        case 27:
> +        case 28:
> +            if (s->mode & 0x01) { /* Reset mode */
> +                if (addr < 24) {
> +                    temp = s->code_mask[addr - 16];
> +                } else {
> +                    temp = 0x00;
> +                }
> +            } else { /* Operation mode */
> +                temp = s->rx_buff[(s->rxbuf_start + addr - 16) %
> +                       SJA_RCV_BUF_LEN];
> +            }
> +            break;
> +        case SJA_CDR:
> +            temp = s->clock;
> +            break;
> +        default:
> +            temp = 0xff;
> +        }
> +    } else { /* Basic Mode */
> +        switch (addr) {
> +        case SJA_BCAN_CTR: /* Control register, addr 0 */
> +            temp = s->control;
> +            break;
> +        case SJA_BCAN_SR: /* Status register, addr 2 */
> +            temp = s->status_bas;
> +            break;
> +        case SJA_BCAN_IR: /* Interrupt register, addr 3 */
> +            temp = s->interrupt_bas;
> +            s->interrupt_bas = 0;
> +            if (s->rxmsg_cnt) {
> +                s->interrupt_bas |= (1 << 0); /* Receive interrupt. */
> +                break;
> +            }
> +            s->irq_lower(s->irq_opaque);
> +            break;
> +        case 4:
> +            temp = s->code;
> +            break;
> +        case 5:
> +            temp = s->mask;
> +            break;
> +        case 20:
> +        case 21:
> +        case 22:
> +        case 23:
> +        case 24:
> +        case 25:
> +        case 26:
> +        case 27:
> +        case 28:
> +        case 29:
> +            temp = s->rx_buff[(s->rxbuf_start + addr - 20) % SJA_RCV_BUF_LEN];
> +            break;
> +        case 31:
> +            temp = s->clock;
> +            break;
> +        default:
> +            temp = 0xff;
> +            break;
> +        }
> +    }
> +    DPRINTF("read addr 0x%02x, %d bytes, content 0x%02lx\n",
> +            (int)addr, size, (long unsigned int)temp);
> +
> +    return temp;
> +}
> +
> +int can_sja_can_receive(CanBusClientState *client)
> +{
> +    CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client);
> +
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +        if (s->mode & 0x01) { /* reset mode. */
> +            return 0;
> +        }
> +    } else { /* BasicCAN mode */
> +        if (s->control & 0x01) {
> +            return 0;
> +        }
> +    }
> +
> +    return 1; /* always return 1, when operation mode */
> +}
> +
> +ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames,
> +                        size_t frames_cnt)
> +{
> +    CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client);
> +    static uint8_t rcv[SJA_MSG_MAX_LEN];
> +    int i;
> +    int ret = -1;
> +    const qemu_can_frame *frame = frames;
> +
> +    if (frames_cnt <= 0) {
> +        return 0;
> +    }
> +    if (DEBUG_FILTER) {
> +        can_display_msg("[cansja]: receive ", frame);
> +    }
> +
> +    qemu_mutex_lock(&s->rx_lock); /* Just do it quickly :) */
> +    if (s->clock & 0x80) { /* PeliCAN Mode */
> +
> +        /* the CAN controller is receiving a message */
> +        s->status_pel |= (1 << 4);
> +
> +        if (can_sja_accept_filter(s, frame) == 0) {
> +            s->status_pel &= ~(1 << 4);
> +            if (DEBUG_FILTER) {
> +                qemu_log("[cansja]: filter rejects message\n");
> +            }
> +            goto fail;
> +        }
> +
> +        ret = frame2buff_pel(frame, rcv);
> +        if (ret < 0) {
> +            s->status_pel &= ~(1 << 4);
> +            if (DEBUG_FILTER) {
> +                qemu_log("[cansja]: message store failed\n");
> +            }
> +            goto fail; /* maybe not support now. */
> +        }
> +
> +        if (s->rx_cnt + ret > SJA_RCV_BUF_LEN) { /* Data overrun. */
> +            s->status_pel |= (1 << 1); /* Overrun status */
> +            s->interrupt_pel |= (1 << 3);
> +            if (s->interrupt_en & (1 << 3)) { /* Overrun interrupt enable */
> +                s->irq_raise(s->irq_opaque);
> +            }
> +            s->status_pel &= ~(1 << 4);
> +            if (DEBUG_FILTER) {
> +                qemu_log("[cansja]: receive FIFO overrun\n");
> +            }
> +            goto fail;
> +        }
> +        s->rx_cnt += ret;
> +        s->rxmsg_cnt++;
> +        if (DEBUG_FILTER) {
> +            qemu_log("[cansja]: message stored in receive FIFO\n");
> +        }
> +
> +        for (i = 0; i < ret; i++) {
> +            s->rx_buff[(s->rx_ptr++) % SJA_RCV_BUF_LEN] = rcv[i];
> +        }
> +        s->rx_ptr %= SJA_RCV_BUF_LEN; /* update the pointer. */
> +
> +        s->status_pel |= 0x01; /* Set the Receive Buffer Status. DS-p23 */
> +        s->interrupt_pel |= 0x01;
> +        s->status_pel &= ~(1 << 4);
> +        s->status_pel |= (1 << 0);
> +        if (s->interrupt_en & 0x01) { /* Receive Interrupt enable. */
> +            s->irq_raise(s->irq_opaque);
> +        }
> +    } else { /* BasicCAN mode */
> +
> +        /* the CAN controller is receiving a message */
> +        s->status_bas |= (1 << 4);
> +
> +        ret = frame2buff_bas(frame, rcv);
> +        if (ret < 0) {
> +            s->status_bas &= ~(1 << 4);
> +            if (DEBUG_FILTER) {
> +                qemu_log("[cansja]: message store failed\n");
> +            }
> +            goto fail; /* maybe not support now. */
> +        }
> +
> +        if (s->rx_cnt + ret > SJA_RCV_BUF_LEN) { /* Data overrun. */
> +            s->status_bas |= (1 << 1); /* Overrun status */
> +            s->status_bas &= ~(1 << 4);
> +            s->interrupt_bas |= (1 << 3);
> +            if (s->control & (1 << 4)) { /* Overrun interrupt enable */
> +                s->irq_raise(s->irq_opaque);
> +            }
> +            if (DEBUG_FILTER) {
> +                qemu_log("[cansja]: receive FIFO overrun\n");
> +            }
> +            goto fail;
> +        }
> +        s->rx_cnt += ret;
> +        s->rxmsg_cnt++;
> +
> +        if (DEBUG_FILTER) {
> +            qemu_log("[cansja]: message stored\n");
> +        }
> +
> +        for (i = 0; i < ret; i++) {
> +            s->rx_buff[(s->rx_ptr++) % SJA_RCV_BUF_LEN] = rcv[i];
> +        }
> +        s->rx_ptr %= SJA_RCV_BUF_LEN; /* update the pointer. */
> +
> +        s->status_bas |= 0x01; /* Set the Receive Buffer Status. DS-p15 */
> +        s->status_bas &= ~(1 << 4);
> +        s->interrupt_bas |= 0x01;
> +        if (s->control & 0x02) { /* Receive Interrupt enable. */
> +            s->irq_raise(s->irq_opaque);
> +        }
> +    }
> +    ret = 1;
> +fail:
> +    qemu_mutex_unlock(&s->rx_lock);
> +
> +    return ret;
> +}
> +
> +static CanBusClientInfo can_sja_bus_client_info = {
> +    .can_receive = can_sja_can_receive,
> +    .receive = can_sja_receive,
> +    .cleanup = NULL,
> +    .poll = NULL
> +};
> +
> +
> +int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus)
> +{
> +    s->bus_client.info = &can_sja_bus_client_info;
> +
> +    if (can_bus_insert_client(bus, &s->bus_client) < 0) {
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +void can_sja_disconnect(CanSJA1000State *s)
> +{
> +    can_bus_remove_client(&s->bus_client);
> +}
> +
> +int can_sja_init(CanSJA1000State *s, CanSJAIrqRaiseLower *irq_raise,
> +                 CanSJAIrqRaiseLower *irq_lower, void *irq_opaque)
> +{
> +    qemu_mutex_init(&s->rx_lock);
> +
> +    s->irq_raise = irq_raise;
> +    s->irq_lower = irq_lower;
> +    s->irq_opaque = irq_opaque;
> +
> +    s->irq_lower(s->irq_opaque);
> +
> +    can_sja_hardware_reset(s);
> +
> +    return 0;
> +}
> +
> +void can_sja_exit(CanSJA1000State *s)
> +{
> +    qemu_mutex_destroy(&s->rx_lock);
> +}
> +
> +const VMStateDescription vmstate_qemu_can_filter = {
> +    .name = "qemu_can_filter",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(can_id, qemu_can_filter),
> +        VMSTATE_UINT32(can_mask, qemu_can_filter),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +/* VMState is needed for live migration of QEMU images */
> +const VMStateDescription vmstate_can_sja = {
> +    .name = "can_sja",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8(mode, CanSJA1000State),
> +
> +        VMSTATE_UINT8(status_pel, CanSJA1000State),
> +        VMSTATE_UINT8(interrupt_pel, CanSJA1000State),
> +        VMSTATE_UINT8(interrupt_en, CanSJA1000State),
> +        VMSTATE_UINT8(rxmsg_cnt, CanSJA1000State),
> +        VMSTATE_UINT8(rxbuf_start, CanSJA1000State),
> +        VMSTATE_UINT8(clock, CanSJA1000State),
> +
> +        VMSTATE_BUFFER(code_mask, CanSJA1000State),
> +        VMSTATE_BUFFER(tx_buff, CanSJA1000State),
> +
> +        VMSTATE_BUFFER(rx_buff, CanSJA1000State),
> +
> +        VMSTATE_UINT32(rx_ptr, CanSJA1000State),
> +        VMSTATE_UINT32(rx_cnt, CanSJA1000State),
> +
> +        VMSTATE_UINT8(control, CanSJA1000State),
> +
> +        VMSTATE_UINT8(status_bas, CanSJA1000State),
> +        VMSTATE_UINT8(interrupt_bas, CanSJA1000State),
> +        VMSTATE_UINT8(code, CanSJA1000State),
> +        VMSTATE_UINT8(mask, CanSJA1000State),
> +
> +        VMSTATE_STRUCT_ARRAY(filter, CanSJA1000State, 4, 0,
> +                             vmstate_qemu_can_filter, qemu_can_filter),
> +
> +
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> diff --git a/hw/can/can_sja1000.h b/hw/can/can_sja1000.h
> new file mode 100644
> index 0000000000..6f2cfbcb72
> --- /dev/null
> +++ b/hw/can/can_sja1000.h
> @@ -0,0 +1,167 @@
> +/*
> + * CAN device - SJA1000 chip emulation for QEMU
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014-2018 Pavel Pisa
> + *
> + * Initial development supported by Google GSoC 2013 from RTEMS project slot
> + *
> + * 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.
> + */
> +#ifndef HW_CAN_SJA1000_H
> +#define HW_CAN_SJA1000_H
> +
> +#include "can/can_emu.h"
> +
> +#define CAN_SJA_MEM_SIZE      128
> +
> +/* The max size for a message buffer, EFF and DLC=8, DS-p39 */
> +#define SJA_MSG_MAX_LEN       13
> +/* The receive buffer size. */
> +#define SJA_RCV_BUF_LEN       64
> +
> +typedef void (CanSJAIrqRaiseLower)(void *opaque);
> +
> +typedef struct CanSJA1000State {
> +    /* PeliCAN state and registers sorted by address */
> +    uint8_t         mode;          /* 0  .. Mode register, DS-p26 */
> +                                   /* 1  .. Command register */
> +    uint8_t         status_pel;    /* 2  .. Status register, p15 */
> +    uint8_t         interrupt_pel; /* 3  .. Interrupt register */
> +    uint8_t         interrupt_en;  /* 4  .. Interrupt Enable register */
> +    uint8_t         rxmsg_cnt;     /* 29 .. RX message counter. DS-p49 */
> +    uint8_t         rxbuf_start;   /* 30 .. RX buffer start address, DS-p49 */
> +    uint8_t         clock;         /* 31 .. Clock Divider register, DS-p55 */
> +
> +    uint8_t         code_mask[8];  /* 16~23 */
> +    uint8_t         tx_buff[13];   /* 96~108 .. transmit buffer */
> +                                   /* 10~19  .. transmit buffer for BasicCAN */
> +
> +    uint8_t         rx_buff[SJA_RCV_BUF_LEN];  /* 32~95 .. 64bytes Rx FIFO */
> +    uint32_t        rx_ptr;        /* Count by bytes. */
> +    uint32_t        rx_cnt;        /* Count by bytes. */
> +
> +    /* PeliCAN state and registers sorted by address */
> +    uint8_t         control;       /* 0 .. Control register */
> +                                   /* 1 .. Command register */
> +    uint8_t         status_bas;    /* 2 .. Status register */
> +    uint8_t         interrupt_bas; /* 3 .. Interrupt register */
> +    uint8_t         code;          /* 4 .. Acceptance code register */
> +    uint8_t         mask;          /* 5 .. Acceptance mask register */
> +
> +    qemu_can_filter filter[4];
> +
> +    QemuMutex       rx_lock;
> +    CanSJAIrqRaiseLower *irq_raise;
> +    CanSJAIrqRaiseLower *irq_lower;
> +    void            *irq_opaque;
> +    CanBusClientState bus_client;
> +} CanSJA1000State;
> +
> +/* PeliCAN mode */
> +enum SJA1000_PeliCAN_regs {
> +        SJA_MOD      = 0x00,
> +/* Command register */

why not keep in one line?

           SJA_MOD      = 0x00, /* Command */
           SJA_CMR      = 0x01, /* Status */

> +        SJA_CMR      = 0x01,
> +/* Status register */
> +        SJA_SR       = 0x02,
> +/* Interrupt register */
> +        SJA_IR       = 0x03,
> +/* Interrupt Enable */
> +        SJA_IER      = 0x04,
> +/* Bus Timing register 0 */
> +        SJA_BTR0     = 0x06,
> +/* Bus Timing register 1 */
> +        SJA_BTR1     = 0x07,
> +/* Output Control register */
> +        SJA_OCR      = 0x08,
> +/* Arbitration Lost Capture */
> +        SJA_ALC      = 0x0b,
> +/* Error Code Capture */
> +        SJA_ECC      = 0x0c,
> +/* Error Warning Limit */
> +        SJA_EWLR     = 0x0d,
> +/* RX Error Counter */
> +        SJA_RXERR    = 0x0e,
> +/* TX Error Counter */
> +        SJA_TXERR0   = 0x0e,
> +        SJA_TXERR1   = 0x0f,
> +/* Rx Message Counter (number of msgs. in RX FIFO */
> +        SJA_RMC      = 0x1d,
> +/* Rx Buffer Start Addr. (address of current MSG) */
> +        SJA_RBSA     = 0x1e,
> +/* Transmit Buffer (write) Receive Buffer (read) Frame Information */
> +        SJA_FRM      = 0x10,
> +/*
> + * ID bytes (11 bits in 0 and 1 for standard message or
> + *          16 bits in 0,1 and 13 bits in 2,3 for extended message)
> + */
> +        SJA_ID0      = 0x11, SJA_ID1 = 0x12,
> +/* ID cont. for extended frames */
> +        SJA_ID2      = 0x13, SJA_ID3 = 0x14,
> +/* Data start standard frame */
> +        SJA_DATS     = 0x13,
> +/* Data start extended frame */
> +        SJA_DATE     = 0x15,
> +/* Acceptance Code (4 bytes) in RESET mode */
> +        SJA_ACR0     = 0x10,
> +/* Acceptance Mask (4 bytes) in RESET mode */
> +        SJA_AMR0     = 0x14,
> +/* 4 bytes */
> +        SJA_PeliCAN_AC_LEN = 4,
> +/* Clock Divider */
> +        SJA_CDR      = 0x1f
> +};
> +
> +
> +/* PeliCAN mode */
> +enum SJA1000_BasicCAN_regs {
> +        SJA_BCAN_CTR = 0x00,
> +/* Command register */
> +        SJA_BCAN_CMR = 0x01,
> +/* Status register */
> +        SJA_BCAN_SR  = 0x02,
> +/* Interrupt register */
> +        SJA_BCAN_IR  = 0x03
> +};
> +
> +void can_sja_hardware_reset(CanSJA1000State *s);
> +
> +void can_sja_mem_write(CanSJA1000State *s, hwaddr addr, uint64_t val,
> +                       unsigned size);
> +
> +uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size);
> +
> +int can_sja_connect_to_bus(CanSJA1000State *s, CanBusState *bus);
> +
> +void can_sja_disconnect(CanSJA1000State *s);
> +
> +int can_sja_init(CanSJA1000State *s, CanSJAIrqRaiseLower *irq_raise,
> +                 CanSJAIrqRaiseLower *irq_lower, void *irq_opaque);
> +
> +void can_sja_exit(CanSJA1000State *s);
> +
> +int can_sja_can_receive(CanBusClientState *client);
> +
> +ssize_t can_sja_receive(CanBusClientState *client,
> +                        const qemu_can_frame *frames, size_t frames_cnt);
> +
> +extern const VMStateDescription vmstate_can_sja;
> +
> +#endif
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added pisa
@ 2018-01-15  3:09   ` Philippe Mathieu-Daudé
  2018-03-06 15:29   ` Thomas Huth
  1 sibling, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-15  3:09 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>  default-configs/pci.mak |   1 +
>  hw/can/Makefile.objs    |   1 +
>  hw/can/can_kvaser_pci.c | 375 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 377 insertions(+)
>  create mode 100644 hw/can/can_kvaser_pci.c
> 
> diff --git a/default-configs/pci.mak b/default-configs/pci.mak
> index 979b649fe5..72c0802ced 100644
> --- a/default-configs/pci.mak
> +++ b/default-configs/pci.mak
> @@ -33,6 +33,7 @@ CONFIG_SERIAL_ISA=y
>  CONFIG_SERIAL_PCI=y
>  CONFIG_CAN_CORE=y
>  CONFIG_CAN_SJA1000=y
> +CONFIG_CAN_PCI=y
>  CONFIG_IPACK=y
>  CONFIG_WDT_IB6300ESB=y
>  CONFIG_PCI_TESTDEV=y
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index 3c4bf3bfc1..c9d07b9b16 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -8,4 +8,5 @@ else
>  common-obj-y += can_host_stub.o
>  endif
>  common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
> +common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
>  endif
> diff --git a/hw/can/can_kvaser_pci.c b/hw/can/can_kvaser_pci.c
> new file mode 100644
> index 0000000000..7e3f28d83c
> --- /dev/null
> +++ b/hw/can/can_kvaser_pci.c
> @@ -0,0 +1,375 @@
> +/*
> + * Kvaser PCI CAN device (SJA1000 based) emulation
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014-2018 Pavel Pisa
> + *
> + * Partially based on educational PCIexpress APOHW hardware
> + * emulator used fro class A0B36APO at CTU FEE course by
> + *    Rostislav Lisovy and Pavel Pisa
> + *
> + * Initial development supported by Google GSoC 2013 from RTEMS project slot
> + *
> + * 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 "qemu/osdep.h"
> +#include "qemu/event_notifier.h"
> +#include "qemu/thread.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "chardev/char.h"
> +#include "hw/hw.h"
> +#include "hw/pci/pci.h"
> +#include "can/can_emu.h"
> +
> +#include "can_sja1000.h"
> +
> +#define TYPE_CAN_PCI_DEV "kvaser_pci"
> +
> +#define KVASER_PCI_DEV(obj) \
> +    OBJECT_CHECK(KvaserPCIState, (obj), TYPE_CAN_PCI_DEV)
> +
> +#ifndef KVASER_PCI_VENDOR_ID1
> +#define KVASER_PCI_VENDOR_ID1     0x10e8    /* the PCI device and vendor IDs */
> +#endif
> +
> +#ifndef KVASER_PCI_DEVICE_ID1
> +#define KVASER_PCI_DEVICE_ID1     0x8406
> +#endif
> +
> +#define KVASER_PCI_S5920_RANGE    0x80
> +#define KVASER_PCI_SJA_RANGE      0x80
> +#define KVASER_PCI_XILINX_RANGE   0x8
> +
> +#define KVASER_PCI_BYTES_PER_SJA  0x20
> +
> +#define S5920_OMB                 0x0C
> +#define S5920_IMB                 0x1C
> +#define S5920_MBEF                0x34
> +#define S5920_INTCSR              0x38
> +#define S5920_RCR                 0x3C
> +#define S5920_PTCR                0x60
> +
> +#define S5920_INTCSR_ADDON_INTENABLE_M        0x2000
> +#define S5920_INTCSR_INTERRUPT_ASSERTED_M     0x800000
> +
> +#define KVASER_PCI_XILINX_VERINT  7   /* Lower nibble simulate interrupts,
> +                                         high nibble version number. */
> +
> +#define KVASER_PCI_XILINX_VERSION_NUMBER 13
> +
> +typedef struct KvaserPCIState {
> +    /*< private >*/
> +    PCIDevice       dev;
> +    /*< public >*/
> +    MemoryRegion    s5920_io;
> +    MemoryRegion    sja_io;
> +    MemoryRegion    xilinx_io;
> +
> +    CanSJA1000State sja_state;
> +    qemu_irq        irq;
> +
> +    uint32_t        s5920_intcsr;
> +    uint32_t        s5920_irqstate;
> +
> +    char            *model; /* The model that support, only SJA1000 now. */
> +    char            *canbus;
> +    char            *host;
> +} KvaserPCIState;
> +
> +static void kvaser_pci_irq_raise(void *opaque)
> +{
> +    KvaserPCIState *d = (KvaserPCIState *)opaque;
> +    d->s5920_irqstate = 1;
> +
> +    if (d->s5920_intcsr & S5920_INTCSR_ADDON_INTENABLE_M) {
> +        qemu_irq_raise(d->irq);
> +    }
> +}
> +
> +static void kvaser_pci_irq_lower(void *opaque)
> +{
> +    KvaserPCIState *d = (KvaserPCIState *)opaque;
> +    d->s5920_irqstate = 0;
> +    qemu_irq_lower(d->irq);
> +}
> +
> +static void
> +kvaser_pci_reset(void *opaque)

static void kvaser_pci_reset(void *opaque)

> +{
> +    KvaserPCIState *d = (KvaserPCIState *)opaque;
> +    CanSJA1000State *s = &d->sja_state;
> +
> +    can_sja_hardware_reset(s);
> +}
> +
> +static uint64_t kvaser_pci_s5920_io_read(void *opaque, hwaddr addr,
> +                             unsigned size)

weird align

> +{
> +    KvaserPCIState *d = opaque;
> +    uint64_t val;
> +
> +    switch (addr) {
> +    case S5920_INTCSR:
> +        val = d->s5920_intcsr;
> +        val &= ~S5920_INTCSR_INTERRUPT_ASSERTED_M;
> +        if (d->s5920_irqstate) {
> +            val |= S5920_INTCSR_INTERRUPT_ASSERTED_M;
> +        }
> +        return val;
> +    }
> +    return 0;
> +}
> +
> +static void kvaser_pci_s5920_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                                      unsigned size)
> +{
> +    KvaserPCIState *d = opaque;
> +
> +    switch (addr) {
> +    case S5920_INTCSR:
> +        if (~d->s5920_intcsr & data & S5920_INTCSR_ADDON_INTENABLE_M) {
> +            if (d->s5920_irqstate) {
> +                qemu_irq_raise(d->irq);
> +            }
> +        }
> +        d->s5920_intcsr = data;
> +        break;
> +    }
> +}
> +
> +static uint64_t kvaser_pci_sja_io_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    KvaserPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state;
> +
> +    if (addr >= KVASER_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr, size);
> +}
> +
> +static void kvaser_pci_sja_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                                    unsigned size)
> +{
> +    KvaserPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state;
> +
> +    if (addr >= KVASER_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr, data, size);
> +}
> +
> +static uint64_t kvaser_pci_xilinx_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    /*KvaserPCIState *d = opaque;*/

remove?

it would be nice to have trace events here (later).

> +
> +    switch (addr) {
> +    case KVASER_PCI_XILINX_VERINT:
> +        return (KVASER_PCI_XILINX_VERSION_NUMBER << 4) | 0;
> +    }
> +
> +    return 0;
> +}
> +
> +static void kvaser_pci_xilinx_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                             unsigned size)
> +{
> +    /*KvaserPCIState *d = opaque;*/

also trace events.

> +}
> +
> +static const MemoryRegionOps kvaser_pci_s5920_io_ops = {
> +    .read = kvaser_pci_s5920_io_read,
> +    .write = kvaser_pci_s5920_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
> +};
> +
> +static const MemoryRegionOps kvaser_pci_sja_io_ops = {
> +    .read = kvaser_pci_sja_io_read,
> +    .write = kvaser_pci_sja_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,

superfluous ^

> +        .max_access_size = 1,
> +    },
> +};
> +
> +static const MemoryRegionOps kvaser_pci_xilinx_io_ops = {
> +    .read = kvaser_pci_xilinx_io_read,
> +    .write = kvaser_pci_xilinx_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,

ditto

> +        .max_access_size = 1,
> +    },
> +};
> +
> +static int kvaser_pci_init(PCIDevice *pci_dev)
> +{
> +    KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
> +    CanSJA1000State *s = &d->sja_state;
> +    uint8_t *pci_conf;
> +    CanBusState *can_bus;
> +
> +    if (d->model) {
> +        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */

Why 256?

> +            error_report("Can't create CAN device, "
> +                         "the model %s is not supported now.", d->model);
> +            exit(1);
> +        }
> +    }
> +
> +    can_bus = can_bus_find_by_name(d->canbus, true);
> +    if (can_bus == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus");
> +        exit(1);
> +
> +    }
> +
> +    if (d->host != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus, d->host) < 0) {
> +            error_report("Cannot connect CAN bus to host device \"%s\"",
> +                         d->host);
> +            exit(1);
> +        }
> +    }
> +
> +    pci_conf = pci_dev->config;
> +    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
> +
> +    d->irq = pci_allocate_irq(&d->dev);
> +
> +    can_sja_init(s, kvaser_pci_irq_raise, kvaser_pci_irq_lower, d);
> +
> +    qemu_register_reset(kvaser_pci_reset, d);
> +
> +    if (can_sja_connect_to_bus(s, can_bus) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    memory_region_init_io(&d->s5920_io, OBJECT(d), &kvaser_pci_s5920_io_ops,
> +                          d, "kvaser_pci-s5920", KVASER_PCI_S5920_RANGE);
> +    memory_region_init_io(&d->sja_io, OBJECT(d), &kvaser_pci_sja_io_ops,
> +                          d, "kvaser_pci-sja", KVASER_PCI_SJA_RANGE);
> +    memory_region_init_io(&d->xilinx_io, OBJECT(d), &kvaser_pci_xilinx_io_ops,
> +                          d, "kvaser_pci-xilinx", KVASER_PCI_XILINX_RANGE);
> +
> +    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
> +                                            &d->s5920_io);
> +    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
> +                                            &d->sja_io);
> +    pci_register_bar(&d->dev, /*BAR*/ 2, PCI_BASE_ADDRESS_SPACE_IO,
> +                                            &d->xilinx_io);
> +
> +    return 0;
> +}
> +
> +static void kvaser_pci_exit(PCIDevice *pci_dev)
> +{
> +    KvaserPCIState *d = KVASER_PCI_DEV(pci_dev);
> +    CanSJA1000State *s = &d->sja_state;
> +
> +    can_sja_disconnect(s);
> +
> +    qemu_unregister_reset(kvaser_pci_reset, d);
> +
> +    /*
> +     * regions d->s5920_io, d->sja_io and d->xilinx_io
> +     * are destroyed by QOM now
> +     */
> +
> +    can_sja_exit(s);
> +
> +    qemu_free_irq(d->irq);
> +}
> +
> +static const VMStateDescription vmstate_kvaser_pci = {
> +    .name = "kvaser_pci",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(dev, KvaserPCIState),
> +        VMSTATE_STRUCT(sja_state, KvaserPCIState, 0, vmstate_can_sja,
> +                       CanSJA1000State),
> +        /*char *model,*/
> +        VMSTATE_UINT32(s5920_intcsr, KvaserPCIState),
> +        VMSTATE_UINT32(s5920_irqstate, KvaserPCIState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void qdev_kvaser_pci_reset(DeviceState *dev)
> +{
> +    KvaserPCIState *d = KVASER_PCI_DEV(dev);
> +    kvaser_pci_reset(d);
> +}
> +
> +static Property kvaser_pci_properties[] = {
> +    DEFINE_PROP_STRING("canbus",   KvaserPCIState, canbus),
> +    DEFINE_PROP_STRING("host",  KvaserPCIState, host),
> +    DEFINE_PROP_STRING("model", KvaserPCIState, model),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void kvaser_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    k->init = kvaser_pci_init;
> +    k->exit = kvaser_pci_exit;
> +    k->vendor_id = KVASER_PCI_VENDOR_ID1;
> +    k->device_id = KVASER_PCI_DEVICE_ID1;
> +    k->revision = 0x00;
> +    k->class_id = 0x00ff00;
> +    dc->desc = "Kvaser PCICANx";
> +    dc->props = kvaser_pci_properties;
> +    dc->vmsd = &vmstate_kvaser_pci;
> +    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +    dc->reset = qdev_kvaser_pci_reset;
> +}
> +
> +static const TypeInfo kvaser_pci_info = {
> +    .name          = TYPE_CAN_PCI_DEV,
> +    .parent        = TYPE_PCI_DEVICE,
> +    .instance_size = sizeof(KvaserPCIState),
> +    .class_init    = kvaser_pci_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> +        { },
> +    },
> +};
> +
> +static void kvaser_pci_register_types(void)
> +{
> +    type_register_static(&kvaser_pci_info);
> +}
> +
> +type_init(kvaser_pci_register_types)
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 6/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 6/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added pisa
@ 2018-01-15  3:12   ` Philippe Mathieu-Daudé
  2018-01-19 13:15   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-15  3:12 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Deniz Eren <deniz.eren@icloud.com>
> 
> Signed-off-by: Deniz Eren <deniz.eren@icloud.com>
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>  hw/can/Makefile.objs     |   1 +
>  hw/can/can_pcm3680_pci.c | 336 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 337 insertions(+)
>  create mode 100644 hw/can/can_pcm3680_pci.c
> 
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index c9d07b9b16..6a328f0c3a 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -9,4 +9,5 @@ common-obj-y += can_host_stub.o
>  endif
>  common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
>  common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
> +common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
>  endif
> diff --git a/hw/can/can_pcm3680_pci.c b/hw/can/can_pcm3680_pci.c
> new file mode 100644
> index 0000000000..e85b61849a
> --- /dev/null
> +++ b/hw/can/can_pcm3680_pci.c
> @@ -0,0 +1,336 @@
> +/*
> + * PCM-3680i PCI CAN device (SJA1000 based) emulation
> + *
> + * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
> + *
> + * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
> + * Jin Yang and Pavel Pisa
> + *
> + * 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 "qemu/osdep.h"
> +#include "qemu/event_notifier.h"
> +#include "qemu/thread.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "chardev/char.h"
> +#include "hw/hw.h"
> +#include "hw/pci/pci.h"
> +#include "can/can_emu.h"
> +
> +#include "can_sja1000.h"
> +
> +#define TYPE_CAN_PCI_DEV "pcm3680_pci"
> +
> +#define PCM3680i_PCI_DEV(obj) \
> +    OBJECT_CHECK(Pcm3680iPCIState, (obj), TYPE_CAN_PCI_DEV)
> +
> +/* the PCI device and vendor IDs */
> +#ifndef PCM3680i_PCI_VENDOR_ID1
> +#define PCM3680i_PCI_VENDOR_ID1     0x13fe
> +#endif
> +
> +#ifndef PCM3680i_PCI_DEVICE_ID1
> +#define PCM3680i_PCI_DEVICE_ID1     0xc002
> +#endif
> +
> +#define PCM3680i_PCI_SJA_RANGE     0x200
> +
> +#define PCM3680i_PCI_BYTES_PER_SJA 0x20
> +
> +typedef struct Pcm3680iPCIState {
> +    /*< private >*/
> +    PCIDevice       dev;
> +    /*< public >*/
> +    MemoryRegion    sja_io[2];
> +
> +    CanSJA1000State sja_state[2];
> +    qemu_irq        irq;
> +
> +    char            *model; /* The model that support, only SJA1000 now. */
> +    char            *canbus[2];
> +    char            *host[2];
> +} Pcm3680iPCIState;
> +
> +static void pcm3680i_pci_irq_raise(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +
> +    qemu_irq_raise(d->irq);
> +}
> +
> +static void pcm3680i_pci_irq_lower(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +
> +    qemu_irq_lower(d->irq);
> +}
> +
> +static void
> +pcm3680i_pci_reset(void *opaque)

static void pcm3680i_pci_reset(void *opaque)

> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_hardware_reset(s1);
> +    can_sja_hardware_reset(s2);
> +}
> +
> +static uint64_t pcm3680i_pci_sja1_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr, size);
> +}
> +
> +static void pcm3680i_pci_sja1_io_write(void *opaque, hwaddr addr,
> +                                       uint64_t data, unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr, data, size);
> +}
> +
> +static uint64_t pcm3680i_pci_sja2_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr, size);
> +}
> +
> +static void pcm3680i_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                             unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr, data, size);
> +}
> +
> +static const MemoryRegionOps pcm3680i_pci_sja1_io_ops = {
> +    .read = pcm3680i_pci_sja1_io_read,
> +    .write = pcm3680i_pci_sja1_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,

superfluous ^

> +        .max_access_size = 1,
> +    },
> +};
> +
> +static const MemoryRegionOps pcm3680i_pci_sja2_io_ops = {
> +    .read = pcm3680i_pci_sja2_io_read,
> +    .write = pcm3680i_pci_sja2_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,

ditto

> +        .max_access_size = 1,
> +    },
> +};
> +
> +static int pcm3680i_pci_init(PCIDevice *pci_dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +    uint8_t *pci_conf;
> +    CanBusState *can_bus1;
> +    CanBusState *can_bus2;

why not use CanBusState *can_bus[2]?

> +
> +    if (d->model) {
> +        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
> +            error_report("Can't create CAN device, "
> +                         "the model %s is not supported now.", d->model);
> +            exit(1);
> +        }
> +    }
> +
> +    can_bus1 = can_bus_find_by_name(d->canbus[0], true);
> +    if (can_bus1 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #1");
> +        exit(1);
> +    }
> +
> +    can_bus2 = can_bus_find_by_name(d->canbus[1], true);
> +    if (can_bus2 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #2");
> +        exit(1);
> +    }
> +
> +    if (d->host[0] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus1, d->host[0]) < 0) {
> +            error_report("Cannot connect CAN bus to host #1 device \"%s\"",
> +                         d->host[0]);
> +            exit(1);
> +        }
> +    }
> +
> +    if (d->host[1] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus2, d->host[1]) < 0) {
> +            error_report("Cannot connect CAN bus to host #2 device \"%s\"",
> +                         d->host[1]);
> +            exit(1);
> +        }
> +    }
> +
> +    pci_conf = pci_dev->config;
> +    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
> +
> +    d->irq = pci_allocate_irq(&d->dev);
> +
> +    can_sja_init(s1, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
> +    can_sja_init(s2, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
> +
> +    qemu_register_reset(pcm3680i_pci_reset, d);
> +
> +    if (can_sja_connect_to_bus(s1, can_bus1) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    if (can_sja_connect_to_bus(s2, can_bus2) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    memory_region_init_io(&d->sja_io[0], OBJECT(d), &pcm3680i_pci_sja1_io_ops,
> +                          d, "pcm3680i_pci-sja1", PCM3680i_PCI_SJA_RANGE / 2);
> +    memory_region_init_io(&d->sja_io[1], OBJECT(d), &pcm3680i_pci_sja2_io_ops,
> +                          d, "pcm3680i_pci-sja2", PCM3680i_PCI_SJA_RANGE / 2);
> +
> +    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
> +                                             &d->sja_io[0]);
> +    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
> +                                             &d->sja_io[1]);
> +
> +    return 0;
> +}
> +
> +static void pcm3680i_pci_exit(PCIDevice *pci_dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_disconnect(s1);
> +    can_sja_disconnect(s2);
> +
> +    qemu_unregister_reset(pcm3680i_pci_reset, d);
> +
> +    /*
> +     * region d->sja_io is destroyed by QOM now
> +     */
> +    /* memory_region_destroy(&d->sja_io[0]); */
> +    /* memory_region_destroy(&d->sja_io[1]); */
> +
> +    can_sja_exit(s1);
> +    can_sja_exit(s2);
> +
> +    qemu_free_irq(d->irq);
> +}
> +
> +static const VMStateDescription vmstate_pcm3680i_pci = {
> +    .name = "pcm3680i_pci",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(dev, Pcm3680iPCIState),
> +        VMSTATE_STRUCT(sja_state[0], Pcm3680iPCIState, 0,
> +                       vmstate_can_sja, CanSJA1000State),
> +        VMSTATE_STRUCT(sja_state[1], Pcm3680iPCIState, 0,
> +                       vmstate_can_sja, CanSJA1000State),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void qdev_pcm3680i_pci_reset(DeviceState *dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(dev);
> +    pcm3680i_pci_reset(d);
> +}
> +
> +static Property pcm3680i_pci_properties[] = {
> +    DEFINE_PROP_STRING("canbus1",   Pcm3680iPCIState, canbus[0]),
> +    DEFINE_PROP_STRING("canbus2",   Pcm3680iPCIState, canbus[1]),
> +    DEFINE_PROP_STRING("host1",  Pcm3680iPCIState, host[0]),
> +    DEFINE_PROP_STRING("host2",  Pcm3680iPCIState, host[1]),
> +    DEFINE_PROP_STRING("model", Pcm3680iPCIState, model),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void pcm3680i_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    k->init = pcm3680i_pci_init;
> +    k->exit = pcm3680i_pci_exit;
> +    k->vendor_id = PCM3680i_PCI_VENDOR_ID1;
> +    k->device_id = PCM3680i_PCI_DEVICE_ID1;
> +    k->revision = 0x00;
> +    k->class_id = 0x000c09;
> +    k->subsystem_vendor_id = PCM3680i_PCI_VENDOR_ID1;
> +    k->subsystem_id = PCM3680i_PCI_DEVICE_ID1;
> +    dc->desc = "Pcm3680i PCICANx";
> +    dc->props = pcm3680i_pci_properties;
> +    dc->vmsd = &vmstate_pcm3680i_pci;
> +    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +    dc->reset = qdev_pcm3680i_pci_reset;
> +}
> +
> +static const TypeInfo pcm3680i_pci_info = {
> +    .name          = TYPE_CAN_PCI_DEV,
> +    .parent        = TYPE_PCI_DEVICE,
> +    .instance_size = sizeof(Pcm3680iPCIState),
> +    .class_init    = pcm3680i_pci_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> +        { },
> +    },
> +};
> +
> +static void pcm3680i_pci_register_types(void)
> +{
> +    type_register_static(&pcm3680i_pci_info);
> +}
> +
> +type_init(pcm3680i_pci_register_types)
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-15  2:55   ` Philippe Mathieu-Daudé
@ 2018-01-15 21:29     ` Pavel Pisa
  2018-01-16  0:12       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 45+ messages in thread
From: Pavel Pisa @ 2018-01-15 21:29 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Daniel P. Berrange, Gerd Hoffmann, Paolo Bonzini, qemu-devel,
	Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

Hello Philippe,

thanks for review.

I have updated patch series in can-pci branch in

  https://gitlab.fel.cvut.cz/canbus/qemu-canbus

I would wait some day if there is some remark
from other developers and socket ones especially.

On Monday 15 of January 2018 03:55:00 Philippe Mathieu-Daudé wrote:
> Hi Pavel,
>
> I'm CC'ing the QEMU Sockets maintainer to ask them a quick review of the
> socket part.
>
> On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> > From: Pavel Pisa <pisa@cmp.felk.cvut.cz>

> Please move those checks out of the function, to call them once at build
> time and not at runtime.
>
> /* Check that QEMU and Linux kernel flags encoding matches */
> QEMU_BUILD_BUG_ON(QEMU_CAN_EFF_FLAG == CAN_EFF_FLAG);
> QEMU_BUILD_BUG_ON(QEMU_CAN_RTR_FLAG == CAN_RTR_FLAG);
> QEMU_BUILD_BUG_ON(QEMU_CAN_ERR_FLAG == CAN_ERR_FLAG);
> QEMU_BUILD_BUG_ON(QEMU_CAN_INV_FILTER == CAN_INV_FILTER);
> QEMU_BUILD_BUG_ON(offsetof(qemu_can_frame, data)
>                   == offsetof(struct can_frame, data));

moved

> > +
> > +    qemu_log_lock();
> > +    qemu_log("[cansocketcan]: %03X [%01d] %s %s",
> > +             msg->can_id & QEMU_CAN_EFF_MASK,
> > +             msg->can_dlc,
> > +             msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF",
> > +             msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT");
> > +
> > +    for (i = 0; i < msg->can_dlc; i++) {
> > +        qemu_log(" %02X", msg->data[i]);
> > +    }
> > +    qemu_log("\n");
>
> I'd rather use tracepoints, but since this is restricted by DEBUG_CAN
> this doesn't bother the user console, so ok.
>
> > +    qemu_log_flush();
> > +    qemu_log_unlock();
> > +}

Trace events seems as nice feature. But simple text printf
like output has been enough till now for CAN testing.
There is no debugging output in production build.
So I would add tracing infrastructure later if needed.

> > +    /* open socket */
> > +    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
>
> I never used it, but I think QEMU uses his socket API: "qemu/sockets.h"

The SocketCAN host connection code is Linux specific,
but I can switch to qemu_socket() if it is preferred.
But address family has to be from Linux header file anyway.

Best wishes,

Pavel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-15 21:29     ` Pavel Pisa
@ 2018-01-16  0:12       ` Philippe Mathieu-Daudé
  2018-01-19  8:51         ` Pavel Pisa
  2018-01-19 13:37         ` Daniel P. Berrange
  0 siblings, 2 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-16  0:12 UTC (permalink / raw)
  To: Pavel Pisa
  Cc: Daniel P. Berrange, Gerd Hoffmann, Paolo Bonzini, qemu-devel,
	Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

On 01/15/2018 06:29 PM, Pavel Pisa wrote:
> Hello Philippe,
> 
> thanks for review.
> 
> I have updated patch series in can-pci branch in
> 
>   https://gitlab.fel.cvut.cz/canbus/qemu-canbus
> 
> I would wait some day if there is some remark
> from other developers and socket ones especially.

I'll have a look.

> 
> On Monday 15 of January 2018 03:55:00 Philippe Mathieu-Daudé wrote:
>> Hi Pavel,
>>
>> I'm CC'ing the QEMU Sockets maintainer to ask them a quick review of the
>> socket part.
>>
>> On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
>>> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
>> Please move those checks out of the function, to call them once at build
>> time and not at runtime.
>>
>> /* Check that QEMU and Linux kernel flags encoding matches */
>> QEMU_BUILD_BUG_ON(QEMU_CAN_EFF_FLAG == CAN_EFF_FLAG);
>> QEMU_BUILD_BUG_ON(QEMU_CAN_RTR_FLAG == CAN_RTR_FLAG);
>> QEMU_BUILD_BUG_ON(QEMU_CAN_ERR_FLAG == CAN_ERR_FLAG);
>> QEMU_BUILD_BUG_ON(QEMU_CAN_INV_FILTER == CAN_INV_FILTER);
>> QEMU_BUILD_BUG_ON(offsetof(qemu_can_frame, data)
>>                   == offsetof(struct can_frame, data));
> 
> moved
> 
>>> +
>>> +    qemu_log_lock();
>>> +    qemu_log("[cansocketcan]: %03X [%01d] %s %s",
>>> +             msg->can_id & QEMU_CAN_EFF_MASK,
>>> +             msg->can_dlc,
>>> +             msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF",
>>> +             msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT");
>>> +
>>> +    for (i = 0; i < msg->can_dlc; i++) {
>>> +        qemu_log(" %02X", msg->data[i]);
>>> +    }
>>> +    qemu_log("\n");
>>
>> I'd rather use tracepoints, but since this is restricted by DEBUG_CAN
>> this doesn't bother the user console, so ok.
>>
>>> +    qemu_log_flush();
>>> +    qemu_log_unlock();
>>> +}
> 
> Trace events seems as nice feature. But simple text printf
> like output has been enough till now for CAN testing.
> There is no debugging output in production build.
> So I would add tracing infrastructure later if needed.

They are as useful as console printf, but less invasive and more
powerful: you can use a much precise timing, select which set of events
to display without having to recompile.
The default backend behaves as console printf.

You should try them :)

>>> +    /* open socket */
>>> +    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
>>
>> I never used it, but I think QEMU uses his socket API: "qemu/sockets.h"
> 
> The SocketCAN host connection code is Linux specific,
> but I can switch to qemu_socket() if it is preferred.
> But address family has to be from Linux header file anyway.

qemu_socket() sockets are heavily tested and already solve many things,
like async I/O and error handling.

Regards,

Phil.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-16  0:12       ` Philippe Mathieu-Daudé
@ 2018-01-19  8:51         ` Pavel Pisa
  2018-01-19 13:37           ` Philippe Mathieu-Daudé
  2018-01-19 13:37         ` Daniel P. Berrange
  1 sibling, 1 reply; 45+ messages in thread
From: Pavel Pisa @ 2018-01-19  8:51 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Daniel P. Berrange, Gerd Hoffmann, Paolo Bonzini, qemu-devel,
	Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

Hello Philippe,

On Tuesday 16 of January 2018 01:12:09 Philippe Mathieu-Daudé wrote:
> On 01/15/2018 06:29 PM, Pavel Pisa wrote:
> > Hello Philippe,
> >
> > thanks for review.
> >
> > I have updated patch series in can-pci branch in
> >
> >   https://gitlab.fel.cvut.cz/canbus/qemu-canbus
> >
> > I would wait some day if there is some remark
> > from other developers and socket ones especially.
>
> I'll have a look.

if there are no more comments, I prepare version 5
of the patches at start of the next week.

Already implemented changes for version 5:

Assertions to check match to Linux struct can_frame
has been moved out of the function.
The case statements use ranges.
min_access_size=1 removed.
"for loops" are used to process operations
for the first and the second chip where
appropriate in PCM-3680I and MIOe-3680 patches.
Deniz Eren reported that updated version
works correctly.

I have not proceed with next two remarks yet:

Inlining in can_sja_single_filter and can_sja_dual_filter
functions. There is only single group of repeated four lines
of code which could be inlined, others are groups of two
lines each. 

>     if (extended) {
vvvvvvvvvvvvvvv
>         filter->can_id = (uint32_t)acr[0] << 21;
>         filter->can_id |= (uint32_t)acr[1] << 13;
>         filter->can_id |= (uint32_t)acr[2] << 5;
>         filter->can_id |= (uint32_t)acr[3] >> 3;
^^^^^^^^^^^^^^^
>         if (acr[3] & 4) {
>             filter->can_id |= QEMU_CAN_RTR_FLAG;
>         }
>
vvvvvvvvvvvvvvv
>         filter->can_mask = (uint32_t)amr[0] << 21;
>         filter->can_mask |= (uint32_t)amr[1] << 13;
>         filter->can_mask |= (uint32_t)amr[2] << 5;
>         filter->can_mask |= (uint32_t)amr[3] >> 3;
^^^^^^^^^^^^^^^
>         filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK;
>         if (!(amr[3] & 4)) {
>             filter->can_mask |= QEMU_CAN_RTR_FLAG;
>         }

Only these marked parts repeats.
Rest is similar but not material for simple inline.
Same for others two line sequences.
All these bit level manipulations are moved from frame
processing and another more top level functions into these
short can_sja_{single,dual}_filter functions.

> /* PeliCAN mode */
> enum SJA1000_PeliCAN_regs {
>         SJA_MOD      = 0x00,
> /* Command register */
>         SJA_CMR      = 0x01,
....
> /* TX Error Counter */
>         SJA_TXERR0   = 0x0e,
>         SJA_TXERR1   = 0x0f,
> /* Rx Message Counter (number of msgs. in RX FIFO */
>         SJA_RMC      = 0x1d,
> /* Rx Buffer Start Addr. (address of current MSG) */
>         SJA_RBSA     = 0x1e,
> /* Transmit Buffer (write) Receive Buffer (read) Frame Information */
>         SJA_FRM      = 0x10,
> /*
>  * ID bytes (11 bits in 0 and 1 for standard message or
>  *          16 bits in 0,1 and 13 bits in 2,3 for extended message)
>  */
>         SJA_ID0      = 0x11, SJA_ID1 = 0x12,
> /* ID cont. for extended frames */
>         SJA_ID2      = 0x13, SJA_ID3 = 0x14,

Proposed formating

           SJA_MOD      = 0x00, /* Command */
           SJA_CMR      = 0x01, /* Status */

this is really better for short comments.
But how format long ones then to keep lines max 80 characters

           SJA_FRM      = 0x10, /* Transmit Buffer (write) Receive Buffer
                                 * (read) Frame Information
                                 */

The SJA_ID0 is would look even worse.

But if the second format is preferred then I update the patch.

> > Trace events seems as nice feature. But simple text printf
> > like output has been enough till now for CAN testing.
> > There is no debugging output in production build.
> > So I would add tracing infrastructure later if needed.
>
> They are as useful as console printf, but less invasive and more
> powerful: you can use a much precise timing, select which set of events
> to display without having to recompile.
> The default backend behaves as console printf.
>
> You should try them :)

I have tried them on 

  pci_update_mappings_del
  pci_update_mappings_add
  pci_cfg_write

and they work great. They would be nice for SJA1000
register accesses, PCI boards configuration etc.
I am not sure how to use them for CAN messages
which has a variable length data field.
Any of debugging outputs is active (all is optimized out)
in regular build.

> >>> +    /* open socket */
> >>> +    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
> >>
> >> I never used it, but I think QEMU uses his socket API: "qemu/sockets.h"
> >
> > The SocketCAN host connection code is Linux specific,
> > but I can switch to qemu_socket() if it is preferred.
> > But address family has to be from Linux header file anyway.
>
> qemu_socket() sockets are heavily tested and already solve many things,
> like async I/O and error handling.

The CAN socket works with RAW packets read and written as 16 bytes.
So some higher level of optimizations used for stream or larger packets
have no significant effect there and SocketCAN API is Linux kernel
specific so generic abstraction layers has no effect there as well.

I have question about reporting fatal error.

Our code uses error_report() and exit(1) for now.

        error_report("CAN host device \"%s\" connect to bus \"%s\" failed",
                      host_dev_name, bus->name);
        exit(1);

Is that correct or there is better solution/function instead of exit?
I have seen this combination in many other places of QEMU code
in past but may it be there is some proposed change already.

Best wishes,

Pavel Pisa

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 1/7] CAN bus simple messages transport implementation for QEMU
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 1/7] CAN bus simple messages transport implementation for QEMU pisa
@ 2018-01-19 12:38   ` Philippe Mathieu-Daudé
  2018-01-19 13:28     ` Pavel Pisa
  2018-01-19 17:04     ` Pavel Pisa
  0 siblings, 2 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-19 12:38 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> The CanBusState state structure is created for each
> emulated CAN channel. Individual clients/emulated
> CAN interfaces or host interface connection registers
> to the bus by CanBusClientState structure.
> 
> The CAN core is prepared to support connection to the
> real host CAN bus network. The commit with such support
> for Linux SocketCAN follows.
> 
> Implementation is as simple as possible, no migration,
> messages prioritization and queuing considered for now.
> But it is intended to be extended when need arises.
> 
> Development repository and more documentation at
> 
> https://gitlab.fel.cvut.cz/canbus/qemu-canbus
> 
> The work is based on Jin Yang GSoC 2013 work funded
> by Google and mentored in frame of RTEMS project GSoC
> slot donated to QEMU.
> 
> Rewritten for QEMU-2.0+ versions and architecture cleanup
> by Pavel Pisa (Czech Technical University in Prague).
> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>  default-configs/pci.mak |   1 +
>  hw/Makefile.objs        |   1 +
>  hw/can/Makefile.objs    |   6 +++
>  hw/can/can_core.c       | 136 ++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/can/can_host_stub.c  |  36 +++++++++++++
>  include/can/can_emu.h   | 131 ++++++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 311 insertions(+)
>  create mode 100644 hw/can/Makefile.objs
>  create mode 100644 hw/can/can_core.c
>  create mode 100644 hw/can/can_host_stub.c
>  create mode 100644 include/can/can_emu.h
> 
> diff --git a/default-configs/pci.mak b/default-configs/pci.mak
> index e514bdef42..bbe11887a1 100644
> --- a/default-configs/pci.mak
> +++ b/default-configs/pci.mak
> @@ -31,6 +31,7 @@ CONFIG_ESP_PCI=y
>  CONFIG_SERIAL=y
>  CONFIG_SERIAL_ISA=y
>  CONFIG_SERIAL_PCI=y
> +CONFIG_CAN_CORE=y

please use CONFIG_CAN_BUS for the 'core' part.
(we also have CONFIG_ISA_BUS)

>  CONFIG_IPACK=y
>  CONFIG_WDT_IB6300ESB=y
>  CONFIG_PCI_TESTDEV=y
> diff --git a/hw/Makefile.objs b/hw/Makefile.objs
> index cf4cb2010b..9d84b8faaa 100644
> --- a/hw/Makefile.objs
> +++ b/hw/Makefile.objs
> @@ -6,6 +6,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += block/
>  devices-dirs-$(CONFIG_SOFTMMU) += bt/
>  devices-dirs-$(CONFIG_SOFTMMU) += char/
>  devices-dirs-$(CONFIG_SOFTMMU) += cpu/
> +devices-dirs-$(CONFIG_SOFTMMU) += can/
>  devices-dirs-$(CONFIG_SOFTMMU) += display/
>  devices-dirs-$(CONFIG_SOFTMMU) += dma/
>  devices-dirs-$(CONFIG_SOFTMMU) += gpio/
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> new file mode 100644
> index 0000000000..1028d7c455
> --- /dev/null
> +++ b/hw/can/Makefile.objs
> @@ -0,0 +1,6 @@
> +# CAN bus interfaces emulation and infrastructure
> +
> +ifeq ($(CONFIG_CAN_CORE),y)
> +common-obj-y += can_core.o

Please follow QEMU style:

common-obj-$(CONFIG_CAN_BUS) += can_core.o

> +common-obj-y += can_host_stub.o
> +endif
> diff --git a/hw/can/can_core.c b/hw/can/can_core.c
> new file mode 100644
> index 0000000000..41c458c792
> --- /dev/null
> +++ b/hw/can/can_core.c
> @@ -0,0 +1,136 @@
> +/*
> + * CAN common CAN bus emulation support
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014-2018 Pavel Pisa
> + *
> + * Initial development supported by Google GSoC 2013 from RTEMS project slot
> + *
> + * 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 "qemu/osdep.h"
> +#include "chardev/char.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "hw/hw.h"
> +#include "can/can_emu.h"
> +
> +static QTAILQ_HEAD(, CanBusState) can_buses =
> +    QTAILQ_HEAD_INITIALIZER(can_buses);
> +
> +CanBusState *can_bus_find_by_name(const char *name, bool create_missing)
> +{
> +    CanBusState *bus;
> +
> +    if (name == NULL) {
> +        name = "canbus0";
> +    }
> +
> +    QTAILQ_FOREACH(bus, &can_buses, next) {
> +        if (!strcmp(bus->name, name)) {
> +            return bus;
> +        }
> +    }
> +
> +    if (!create_missing) {
> +        return 0;
> +    }
> +
> +    bus = g_malloc0(sizeof(*bus));
> +    if (bus == NULL) {
> +        return NULL;
> +    }
> +
> +    QTAILQ_INIT(&bus->clients);
> +
> +    bus->name = g_strdup(name);
> +
> +    QTAILQ_INSERT_TAIL(&can_buses, bus, next);
> +    return bus;
> +}
> +
> +int can_bus_insert_client(CanBusState *bus, CanBusClientState *client)
> +{
> +    client->bus = bus;
> +    QTAILQ_INSERT_TAIL(&bus->clients, client, next);
> +    return 0;
> +}
> +
> +int can_bus_remove_client(CanBusClientState *client)
> +{
> +    CanBusState *bus = client->bus;
> +    if (bus == NULL) {
> +        return 0;
> +    }
> +
> +    QTAILQ_REMOVE(&bus->clients, client, next);
> +    client->bus = NULL;
> +    return 1;
> +}
> +
> +ssize_t can_bus_client_send(CanBusClientState *client,
> +             const struct qemu_can_frame *frames, size_t frames_cnt)
> +{
> +    int ret = 0;
> +    CanBusState *bus = client->bus;
> +    CanBusClientState *peer;
> +    if (bus == NULL) {
> +        return -1;
> +    }
> +
> +    QTAILQ_FOREACH(peer, &bus->clients, next) {
> +        if (peer->info->can_receive(peer)) {
> +            if (peer == client) {
> +                /* No loopback support for now */
> +                continue;
> +            }
> +            if (peer->info->receive(peer, frames, frames_cnt) > 0) {
> +                ret = 1;
> +            }
> +        }
> +    }
> +
> +    return ret;
> +}
> +
> +int can_bus_filter_match(struct qemu_can_filter *filter, qemu_canid_t can_id)
> +{
> +    int m;
> +    if (((can_id | filter->can_mask) & QEMU_CAN_ERR_FLAG)) {
> +        return (filter->can_mask & QEMU_CAN_ERR_FLAG) != 0;
> +    }
> +    m = (can_id & filter->can_mask) == (filter->can_id & filter->can_mask);
> +    return filter->can_id & QEMU_CAN_INV_FILTER ? !m : m;
> +}
> +
> +int can_bus_client_set_filters(CanBusClientState *client,
> +             const struct qemu_can_filter *filters, size_t filters_cnt)
> +{
> +    return 0;
> +}
> +
> +int can_bus_connect_to_host_device(CanBusState *bus, const char *name)
> +{
> +    if (can_bus_connect_to_host_variant == NULL) {
> +        error_report("CAN bus connect to host device is not "
> +                     "supported on this system");
> +        exit(1);
> +    }
> +    return can_bus_connect_to_host_variant(bus, name);
> +}
> diff --git a/hw/can/can_host_stub.c b/hw/can/can_host_stub.c
> new file mode 100644
> index 0000000000..748d25f995
> --- /dev/null
> +++ b/hw/can/can_host_stub.c
> @@ -0,0 +1,36 @@
> +/*
> + * CAN stub to connect to host system CAN interface
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014-2018 Pavel Pisa
> + *
> + * Initial development supported by Google GSoC 2013 from RTEMS project slot
> + *
> + * 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 "qemu/osdep.h"
> +#include "chardev/char.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "hw/hw.h"
> +#include "can/can_emu.h"
> +
> +
> +int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
> +        NULL;
> diff --git a/include/can/can_emu.h b/include/can/can_emu.h
> new file mode 100644
> index 0000000000..85237ee3c9
> --- /dev/null
> +++ b/include/can/can_emu.h
> @@ -0,0 +1,131 @@
> +/*
> + * CAN common CAN bus emulation support
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014-2018 Pavel Pisa
> + *
> + * Initial development supported by Google GSoC 2013 from RTEMS project slot
> + *
> + * 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.
> + */
> +
> +#ifndef NET_CAN_EMU_H
> +#define NET_CAN_EMU_H
> +
> +#include "qemu/queue.h"
> +
> +/* NOTE: the following two structures is copied from <linux/can.h>. */
> +
> +/*
> + * Controller Area Network Identifier structure
> + *
> + * bit 0-28    : CAN identifier (11/29 bit)
> + * bit 29      : error frame flag (0 = data frame, 1 = error frame)
> + * bit 30      : remote transmission request flag (1 = rtr frame)
> + * bit 31      : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
> + */
> +typedef uint32_t qemu_canid_t;
> +
> +typedef struct qemu_can_frame {
> +    qemu_canid_t    can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */
> +    uint8_t         can_dlc; /* data length code: 0 .. 8 */
> +    uint8_t         data[8] QEMU_ALIGNED(8);
> +} qemu_can_frame;
> +
> +/* Keep defines for QEMU separate from Linux ones for now */
> +
> +#define QEMU_CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
> +#define QEMU_CAN_RTR_FLAG 0x40000000U /* remote transmission request */
> +#define QEMU_CAN_ERR_FLAG 0x20000000U /* error message frame */
> +
> +#define QEMU_CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
> +#define QEMU_CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
> +
> +/**
> + * struct qemu_can_filter - CAN ID based filter in can_register().
> + * @can_id:   relevant bits of CAN ID which are not masked out.
> + * @can_mask: CAN mask (see description)
> + *
> + * Description:
> + * A filter matches, when
> + *
> + *          <received_can_id> & mask == can_id & mask
> + *
> + * The filter can be inverted (QEMU_CAN_INV_FILTER bit set in can_id) or it can
> + * filter for error message frames (QEMU_CAN_ERR_FLAG bit set in mask).
> + */
> +typedef struct qemu_can_filter {
> +    qemu_canid_t    can_id;
> +    qemu_canid_t    can_mask;
> +} qemu_can_filter;
> +
> +/* QEMU_CAN_INV_FILTER can be set in qemu_can_filter.can_id */
> +#define QEMU_CAN_INV_FILTER 0x20000000U
> +
> +typedef struct CanBusClientState CanBusClientState;
> +typedef struct CanBusState CanBusState;
> +
> +typedef struct CanBusClientInfo {
> +    size_t size;
> +    int (*can_receive)(CanBusClientState *);
> +    ssize_t (*receive)(CanBusClientState *,
> +        const struct qemu_can_frame *frames, size_t frames_cnt);
> +    void (*cleanup) (CanBusClientState *);
> +    void (*poll)(CanBusClientState *, bool enable);
> +} CanBusClientInfo;
> +
> +struct CanBusClientState {
> +    CanBusClientInfo *info;
> +    CanBusState *bus;
> +    int link_down;
> +    QTAILQ_ENTRY(CanBusClientState) next;
> +    CanBusClientState *peer;
> +    char *model;
> +    char *name;
> +    void (*destructor)(CanBusClientState *);
> +};
> +
> +struct CanBusState {
> +    char *name;
> +    QTAILQ_HEAD(, CanBusClientState) clients;
> +    QTAILQ_ENTRY(CanBusState) next;
> +};
> +
> +extern int (*can_bus_connect_to_host_variant)(CanBusState *bus,
> +                                              const char *name);

Isn't extern (*func) an anti-pattern?
One might be tempted to call it without checking it is non-NULL...

Please declare it as a function, and using a static pointer, i.e.:

typedef int (*can_bus_connect_to_host_variant_t)(CanBusState *bus,
                                       const char *name);


static can_bus_connect_to_host_variant_t
can_bus_connect_to_host_variant_handler;

void
set_can_bus_connect_to_host_variant(can_bus_connect_to_host_variant_t
handler)
{
    can_bus_connect_to_host_variant_handler = handler;
}

int can_bus_connect_to_host_variant(CanBusState *bus,
                          const char *name)
{
    if (!can_bus_connect_to_host_variant_handler) {
        return ERROR;
    }
    return can_bus_connect_to_host_variant_handler(bus, name);
}

I'm sure we can find nicer/shorter function names ;)

> +
> +int can_bus_filter_match(struct qemu_can_filter *filter, qemu_canid_t can_id);
> +
> +CanBusState *can_bus_find_by_name(const char *name, bool create_missing);
> +
> +int can_bus_insert_client(CanBusState *bus, CanBusClientState *client);
> +
> +int can_bus_remove_client(CanBusClientState *client);
> +
> +ssize_t can_bus_client_send(CanBusClientState *,
> +                            const struct qemu_can_frame *frames,
> +                            size_t frames_cnt);
> +
> +int can_bus_client_set_filters(CanBusClientState *,
> +                               const struct qemu_can_filter *filters,
> +                               size_t filters_cnt);
> +
> +int can_bus_connect_to_host_device(CanBusState *bus, const char *host_dev_name);
> +
> +#endif
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface pisa
  2018-01-15  2:55   ` Philippe Mathieu-Daudé
@ 2018-01-19 12:57   ` Philippe Mathieu-Daudé
  2018-01-19 13:01     ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-19 12:57 UTC (permalink / raw)
  To: pisa, qemu-devel, Paolo Bonzini, Marc-André Lureau
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

Cc'ing Paolo and Marc-André, the "Character device backends" maintainers.

On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> Connection to the real host CAN bus network through
> SocketCAN network interface is available only for Linux
> host system. Mechanism is generic, support for another
> CAN API and operating systems can be implemented in future.
> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>  hw/can/Makefile.objs   |   4 +
>  hw/can/can_socketcan.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 318 insertions(+)
>  create mode 100644 hw/can/can_socketcan.c
> 
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index 1028d7c455..f999085f7a 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -2,5 +2,9 @@
>  
>  ifeq ($(CONFIG_CAN_CORE),y)
>  common-obj-y += can_core.o
> +ifeq ($(CONFIG_LINUX),y)
> +common-obj-y += can_socketcan.o
> +else
>  common-obj-y += can_host_stub.o

I'd just throw this stub in stubs/can_host.c

>  endif
> +endif
> diff --git a/hw/can/can_socketcan.c b/hw/can/can_socketcan.c
> new file mode 100644
> index 0000000000..f6df747c5a
> --- /dev/null
> +++ b/hw/can/can_socketcan.c

I think this is not the correct place to put this file, this is not a
modeled hardware, but a chardev backend.

This would be chardev/can-socketcan.c.

> @@ -0,0 +1,314 @@
> +/*
> + * CAN socketcan support to connect to the Linux host SocketCAN interfaces
> + *
> + * Copyright (c) 2013-2014 Jin Yang
> + * Copyright (c) 2014-2018 Pavel Pisa
> + *
> + * Initial development supported by Google GSoC 2013 from RTEMS project slot
> + *
> + * 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 "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "qemu/error-report.h"
> +#include "chardev/char.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "hw/hw.h"
> +#include "can/can_emu.h"
> +
> +#include <sys/ioctl.h>
> +#include <net/if.h>
> +#include <linux/can.h>
> +#include <linux/can/raw.h>
> +
> +#ifndef DEBUG_CAN
> +#define DEBUG_CAN 0
> +#endif /*DEBUG_CAN*/
> +
> +#define CAN_READ_BUF_LEN  5
> +typedef struct {
> +    CanBusClientState  bus_client;
> +    qemu_can_filter    *rfilter;
> +    int                rfilter_num;
> +    can_err_mask_t     err_mask;
> +
> +    qemu_can_frame     buf[CAN_READ_BUF_LEN];
> +    int                bufcnt;
> +    int                bufptr;
> +
> +    int                fd;
> +} CanBusSocketcanConnectState;
> +
> +static void can_bus_socketcan_display_msg(struct qemu_can_frame *msg)
> +{
> +    int i;
> +
> +    /* Check that QEMU and Linux kernel flags encoding matches */
> +    assert(QEMU_CAN_EFF_FLAG == CAN_EFF_FLAG);
> +    assert(QEMU_CAN_RTR_FLAG == CAN_RTR_FLAG);
> +    assert(QEMU_CAN_ERR_FLAG == CAN_ERR_FLAG);
> +
> +    assert(QEMU_CAN_INV_FILTER == CAN_INV_FILTER);
> +
> +    assert(offsetof(qemu_can_frame, data) == offsetof(struct can_frame, data));
> +
> +    qemu_log_lock();
> +    qemu_log("[cansocketcan]: %03X [%01d] %s %s",
> +             msg->can_id & QEMU_CAN_EFF_MASK,
> +             msg->can_dlc,
> +             msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF",
> +             msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT");
> +
> +    for (i = 0; i < msg->can_dlc; i++) {
> +        qemu_log(" %02X", msg->data[i]);
> +    }
> +    qemu_log("\n");
> +    qemu_log_flush();
> +    qemu_log_unlock();
> +}
> +
> +static void can_bus_socketcan_read(void *opaque)
> +{
> +    CanBusSocketcanConnectState *c;
> +    c = (CanBusSocketcanConnectState *)opaque;
> +
> +
> +
> +    /* CAN_READ_BUF_LEN for multiple messages syscall is possible for future */
> +    c->bufcnt = read(c->fd, c->buf, sizeof(qemu_can_frame));
> +    if (c->bufcnt < 0) {
> +        warn_report("CAN bus host read failed (%s)", strerror(errno));
> +        return;
> +    }
> +
> +    can_bus_client_send(&c->bus_client, c->buf, 1);
> +
> +    if (DEBUG_CAN) {
> +        can_bus_socketcan_display_msg(c->buf);
> +    }
> +}
> +
> +static int can_bus_socketcan_can_receive(CanBusClientState *client)
> +{
> +    CanBusSocketcanConnectState *c;
> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
> +
> +    if (c->fd < 0) {
> +        return -1;
> +    }
> +
> +    return 1;
> +}
> +
> +static ssize_t can_bus_socketcan_receive(CanBusClientState *client,
> +                            const qemu_can_frame *frames, size_t frames_cnt)
> +{
> +    CanBusSocketcanConnectState *c;
> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
> +    size_t len = sizeof(qemu_can_frame);
> +    int res;
> +
> +    if (c->fd < 0) {
> +        return -1;
> +    }
> +
> +    res = write(c->fd, frames, len);
> +
> +    if (!res) {
> +        warn_report("[cansocketcan]: write message to host returns zero");
> +        return -1;
> +    }
> +
> +    if (res != len) {
> +        if (res < 0) {
> +            warn_report("[cansocketcan]: write to host failed (%s)",
> +                        strerror(errno));
> +        } else {
> +            warn_report("[cansocketcan]: write to host truncated");
> +        }
> +        return -1;
> +    }
> +
> +    return 1;
> +}
> +
> +static void can_bus_socketcan_cleanup(CanBusClientState *client)
> +{
> +    CanBusSocketcanConnectState *c;
> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
> +
> +    if (c->fd >= 0) {
> +        qemu_set_fd_handler(c->fd, NULL, NULL, c);
> +        close(c->fd);
> +        c->fd = -1;
> +    }
> +
> +    c->rfilter_num = 0;
> +    if (c->rfilter != NULL) {
> +        g_free(c->rfilter);
> +    }
> +}
> +
> +static int can_bus_socketcan_set_filters(CanBusClientState *client,
> +                   const struct qemu_can_filter *filters, size_t filters_cnt)
> +{
> +    CanBusSocketcanConnectState *c;
> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
> +
> +    int i;
> +
> +    if (DEBUG_CAN) {
> +        qemu_log_lock();
> +        qemu_log("[cansocketcan]: filters set for channel\n");
> +        for (i = 0; i < filters_cnt; i++) {
> +            fprintf(stderr, "[%i]  id=0x%08x maks=0x%08x\n",
> +                   i, filters[i].can_id, filters[i].can_mask);
> +        }
> +        qemu_log("\n");
> +        qemu_log_flush();
> +        qemu_log_unlock();
> +    }
> +
> +    setsockopt(c->fd, SOL_CAN_RAW, CAN_RAW_FILTER,
> +               filters, filters_cnt * sizeof(qemu_can_filter));

Good than you don't do the filtering in userland :)

> +
> +    return 0;
> +}
> +
> +static
> +void can_bus_socketcan_update_read_handler(CanBusSocketcanConnectState *c)
> +{
> +    if (c->fd >= 0) {
> +        qemu_set_fd_handler(c->fd, can_bus_socketcan_read, NULL, c);
> +    }
> +}
> +
> +static CanBusClientInfo can_bus_socketcan_bus_client_info = {
> +    .can_receive = can_bus_socketcan_can_receive,
> +    .receive = can_bus_socketcan_receive,
> +    .cleanup = can_bus_socketcan_cleanup,
> +    .poll = NULL
> +};
> +
> +static CanBusSocketcanConnectState *
> +    can_bus_socketcan_connect_new(const char *host_dev_name)
> +{
> +    int s; /* can raw socket */
> +    CanBusSocketcanConnectState    *c;
> +    struct sockaddr_can addr;
> +    struct ifreq ifr;
> +
> +    c = g_malloc0(sizeof(CanBusSocketcanConnectState));
> +    if (c == NULL) {
> +        goto fail1;
> +    }
> +
> +    c->fd = -1;
> +
> +    /* open socket */
> +    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
> +    if (s < 0) {
> +        error_report("[cansocketcan]: CAN_RAW socket create failed  (%s)",
> +                        strerror(errno));
> +        goto fail;
> +    }
> +
> +    addr.can_family = AF_CAN;
> +    memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
> +    strcpy(ifr.ifr_name, host_dev_name);
> +    if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
> +        error_report("[cansocketcan]: host interface %s not available (%s)",
> +                     host_dev_name, strerror(errno));
> +        goto fail;
> +    }
> +    addr.can_ifindex = ifr.ifr_ifindex;
> +
> +    c->err_mask = 0xffffffff; /* Receive error frame. */
> +    setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
> +                   &c->err_mask, sizeof(c->err_mask));
> +
> +    c->rfilter_num = 1;
> +    c->rfilter = g_malloc0(c->rfilter_num * sizeof(struct qemu_can_filter));
> +    if (c->rfilter == NULL) {
> +        goto fail;
> +    }
> +
> +    /* Receive all data frame. If |= CAN_INV_FILTER no data. */
> +    c->rfilter[0].can_id = 0;
> +    c->rfilter[0].can_mask = 0;
> +    c->rfilter[0].can_mask &= ~CAN_ERR_FLAG;
> +

I'd extract this in a more explicit explicit function like
promisc_filter() and use

       can_bus_socketcan_set_filters(c, promisc_filter);

maybe clever would be to use NULL for promisc?

#define CANBUS_PROMISC_FILTER NULL /* why... */

       can_bus_socketcan_set_filters(c, CANBUS_PROMISC_FILTER);

can_bus_socketcan_set_filters( ..., *filters, rfilter_num )
{
    static const qemu_can_filter promisc_filter = {
        .can_id = 0,
        .can_mask = 0,
        .can_mask &= ~CAN_ERR_FLAG
    };

    if (!filters) {
        filters = &promisc_filter;
        rfilter_num = 1;
    }
    setsockopt(c->fd, SOL_CAN_RAW, CAN_RAW_FILTER,
               filters, rfilter_num * sizeof(struct qemu_can_filter));
    ...

> +    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, c->rfilter,
> +               c->

don't forget to g_free(c->rfilter);

> +
> +    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
> +        error_report("[cansocketcan]: bind to host interface %s failed (%s)",
> +                     host_dev_name, strerror(errno));
> +        goto fail;
> +    }
> +
> +    c->fd = s;
> +
> +    c->bus_client.info = &can_bus_socketcan_bus_client_info;
> +
> +    can_bus_socketcan_update_read_handler(c);
> +
> +    return c;
> +
> +fail:
> +    can_bus_socketcan_cleanup(&c->bus_client);
> +    g_free(c);
> +fail1:
> +
> +    return NULL;
> +}
> +
> +static int can_bus_connect_to_host_socketcan(CanBusState *bus,
> +                                             const char *host_dev_name)
> +{
> +    CanBusSocketcanConnectState *c;
> +
> +    c = can_bus_socketcan_connect_new(host_dev_name);
> +    if (c == NULL) {
> +        error_report("CAN bus setup of host connect to \"%s\" failed",
> +                      host_dev_name);
> +        exit(1);
> +    }
> +
> +    if (can_bus_insert_client(bus, &c->bus_client) < 0) {
> +        error_report("CAN host device \"%s\" connect to bus \"%s\" failed",
> +                      host_dev_name, bus->name);
> +        exit(1);
> +    }
> +
> +    if (0) {
> +        /*
> +         * Not used there or as a CanBusSocketcanConnectState method
> +         * for now but included there for documentation purposes
> +         * and to suppress warning.

So this can be avoided using PROMISC = NULL as suggested.

> +         */
> +        can_bus_socketcan_set_filters(&c->bus_client, NULL, 0);
> +    }
> +
> +    return 0;
> +}
> +
> +int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
> +        can_bus_connect_to_host_socketcan;
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-19 12:57   ` Philippe Mathieu-Daudé
@ 2018-01-19 13:01     ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-19 13:01 UTC (permalink / raw)
  To: pisa, qemu-devel, Paolo Bonzini, Marc-André Lureau
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

On 01/19/2018 09:57 AM, Philippe Mathieu-Daudé wrote:
> Cc'ing Paolo and Marc-André, the "Character device backends" maintainers.
> 
> On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
>> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
>>
>> Connection to the real host CAN bus network through
>> SocketCAN network interface is available only for Linux
>> host system. Mechanism is generic, support for another
>> CAN API and operating systems can be implemented in future.
>>
>> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
>> ---
>>  hw/can/Makefile.objs   |   4 +
>>  hw/can/can_socketcan.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 318 insertions(+)
>>  create mode 100644 hw/can/can_socketcan.c
>>
>> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
>> index 1028d7c455..f999085f7a 100644
>> --- a/hw/can/Makefile.objs
>> +++ b/hw/can/Makefile.objs
>> @@ -2,5 +2,9 @@
>>  
>>  ifeq ($(CONFIG_CAN_CORE),y)
>>  common-obj-y += can_core.o
>> +ifeq ($(CONFIG_LINUX),y)
>> +common-obj-y += can_socketcan.o
>> +else
>>  common-obj-y += can_host_stub.o
> 
> I'd just throw this stub in stubs/can_host.c
> 
>>  endif
>> +endif
>> diff --git a/hw/can/can_socketcan.c b/hw/can/can_socketcan.c
>> new file mode 100644
>> index 0000000000..f6df747c5a
>> --- /dev/null
>> +++ b/hw/can/can_socketcan.c
> 
> I think this is not the correct place to put this file, this is not a
> modeled hardware, but a chardev backend.

I meant 'socketcan is a frontend for the canbus char backend'.

> 
> This would be chardev/can-socketcan.c.
> 
>> @@ -0,0 +1,314 @@
>> +/*
>> + * CAN socketcan support to connect to the Linux host SocketCAN interfaces
>> + *
>> + * Copyright (c) 2013-2014 Jin Yang
>> + * Copyright (c) 2014-2018 Pavel Pisa
>> + *
>> + * Initial development supported by Google GSoC 2013 from RTEMS project slot
>> + *
>> + * 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 "qemu/osdep.h"
>> +#include "qemu/log.h"
>> +#include "qemu/error-report.h"
>> +#include "chardev/char.h"
>> +#include "qemu/sockets.h"
>> +#include "qemu/error-report.h"
>> +#include "hw/hw.h"
>> +#include "can/can_emu.h"
>> +
>> +#include <sys/ioctl.h>
>> +#include <net/if.h>
>> +#include <linux/can.h>
>> +#include <linux/can/raw.h>
>> +
>> +#ifndef DEBUG_CAN
>> +#define DEBUG_CAN 0
>> +#endif /*DEBUG_CAN*/
>> +
>> +#define CAN_READ_BUF_LEN  5
>> +typedef struct {
>> +    CanBusClientState  bus_client;
>> +    qemu_can_filter    *rfilter;
>> +    int                rfilter_num;
>> +    can_err_mask_t     err_mask;
>> +
>> +    qemu_can_frame     buf[CAN_READ_BUF_LEN];
>> +    int                bufcnt;
>> +    int                bufptr;
>> +
>> +    int                fd;
>> +} CanBusSocketcanConnectState;
>> +
>> +static void can_bus_socketcan_display_msg(struct qemu_can_frame *msg)
>> +{
>> +    int i;
>> +
>> +    /* Check that QEMU and Linux kernel flags encoding matches */
>> +    assert(QEMU_CAN_EFF_FLAG == CAN_EFF_FLAG);
>> +    assert(QEMU_CAN_RTR_FLAG == CAN_RTR_FLAG);
>> +    assert(QEMU_CAN_ERR_FLAG == CAN_ERR_FLAG);
>> +
>> +    assert(QEMU_CAN_INV_FILTER == CAN_INV_FILTER);
>> +
>> +    assert(offsetof(qemu_can_frame, data) == offsetof(struct can_frame, data));
>> +
>> +    qemu_log_lock();
>> +    qemu_log("[cansocketcan]: %03X [%01d] %s %s",
>> +             msg->can_id & QEMU_CAN_EFF_MASK,
>> +             msg->can_dlc,
>> +             msg->can_id & QEMU_CAN_EFF_FLAG ? "EFF" : "SFF",
>> +             msg->can_id & QEMU_CAN_RTR_FLAG ? "RTR" : "DAT");
>> +
>> +    for (i = 0; i < msg->can_dlc; i++) {
>> +        qemu_log(" %02X", msg->data[i]);
>> +    }
>> +    qemu_log("\n");
>> +    qemu_log_flush();
>> +    qemu_log_unlock();
>> +}
>> +
>> +static void can_bus_socketcan_read(void *opaque)
>> +{
>> +    CanBusSocketcanConnectState *c;
>> +    c = (CanBusSocketcanConnectState *)opaque;
>> +
>> +
>> +
>> +    /* CAN_READ_BUF_LEN for multiple messages syscall is possible for future */
>> +    c->bufcnt = read(c->fd, c->buf, sizeof(qemu_can_frame));
>> +    if (c->bufcnt < 0) {
>> +        warn_report("CAN bus host read failed (%s)", strerror(errno));
>> +        return;
>> +    }
>> +
>> +    can_bus_client_send(&c->bus_client, c->buf, 1);
>> +
>> +    if (DEBUG_CAN) {
>> +        can_bus_socketcan_display_msg(c->buf);
>> +    }
>> +}
>> +
>> +static int can_bus_socketcan_can_receive(CanBusClientState *client)
>> +{
>> +    CanBusSocketcanConnectState *c;
>> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
>> +
>> +    if (c->fd < 0) {
>> +        return -1;
>> +    }
>> +
>> +    return 1;
>> +}
>> +
>> +static ssize_t can_bus_socketcan_receive(CanBusClientState *client,
>> +                            const qemu_can_frame *frames, size_t frames_cnt)
>> +{
>> +    CanBusSocketcanConnectState *c;
>> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
>> +    size_t len = sizeof(qemu_can_frame);
>> +    int res;
>> +
>> +    if (c->fd < 0) {
>> +        return -1;
>> +    }
>> +
>> +    res = write(c->fd, frames, len);
>> +
>> +    if (!res) {
>> +        warn_report("[cansocketcan]: write message to host returns zero");
>> +        return -1;
>> +    }
>> +
>> +    if (res != len) {
>> +        if (res < 0) {
>> +            warn_report("[cansocketcan]: write to host failed (%s)",
>> +                        strerror(errno));
>> +        } else {
>> +            warn_report("[cansocketcan]: write to host truncated");
>> +        }
>> +        return -1;
>> +    }
>> +
>> +    return 1;
>> +}
>> +
>> +static void can_bus_socketcan_cleanup(CanBusClientState *client)
>> +{
>> +    CanBusSocketcanConnectState *c;
>> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
>> +
>> +    if (c->fd >= 0) {
>> +        qemu_set_fd_handler(c->fd, NULL, NULL, c);
>> +        close(c->fd);
>> +        c->fd = -1;
>> +    }
>> +
>> +    c->rfilter_num = 0;
>> +    if (c->rfilter != NULL) {
>> +        g_free(c->rfilter);
>> +    }
>> +}
>> +
>> +static int can_bus_socketcan_set_filters(CanBusClientState *client,
>> +                   const struct qemu_can_filter *filters, size_t filters_cnt)
>> +{
>> +    CanBusSocketcanConnectState *c;
>> +    c = container_of(client, CanBusSocketcanConnectState, bus_client);
>> +
>> +    int i;
>> +
>> +    if (DEBUG_CAN) {
>> +        qemu_log_lock();
>> +        qemu_log("[cansocketcan]: filters set for channel\n");
>> +        for (i = 0; i < filters_cnt; i++) {
>> +            fprintf(stderr, "[%i]  id=0x%08x maks=0x%08x\n",
>> +                   i, filters[i].can_id, filters[i].can_mask);
>> +        }
>> +        qemu_log("\n");
>> +        qemu_log_flush();
>> +        qemu_log_unlock();
>> +    }
>> +
>> +    setsockopt(c->fd, SOL_CAN_RAW, CAN_RAW_FILTER,
>> +               filters, filters_cnt * sizeof(qemu_can_filter));
> 
> Good than you don't do the filtering in userland :)
> 
>> +
>> +    return 0;
>> +}
>> +
>> +static
>> +void can_bus_socketcan_update_read_handler(CanBusSocketcanConnectState *c)
>> +{
>> +    if (c->fd >= 0) {
>> +        qemu_set_fd_handler(c->fd, can_bus_socketcan_read, NULL, c);
>> +    }
>> +}
>> +
>> +static CanBusClientInfo can_bus_socketcan_bus_client_info = {
>> +    .can_receive = can_bus_socketcan_can_receive,
>> +    .receive = can_bus_socketcan_receive,
>> +    .cleanup = can_bus_socketcan_cleanup,
>> +    .poll = NULL
>> +};
>> +
>> +static CanBusSocketcanConnectState *
>> +    can_bus_socketcan_connect_new(const char *host_dev_name)
>> +{
>> +    int s; /* can raw socket */
>> +    CanBusSocketcanConnectState    *c;
>> +    struct sockaddr_can addr;
>> +    struct ifreq ifr;
>> +
>> +    c = g_malloc0(sizeof(CanBusSocketcanConnectState));
>> +    if (c == NULL) {
>> +        goto fail1;
>> +    }
>> +
>> +    c->fd = -1;
>> +
>> +    /* open socket */
>> +    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
>> +    if (s < 0) {
>> +        error_report("[cansocketcan]: CAN_RAW socket create failed  (%s)",
>> +                        strerror(errno));
>> +        goto fail;
>> +    }
>> +
>> +    addr.can_family = AF_CAN;
>> +    memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
>> +    strcpy(ifr.ifr_name, host_dev_name);
>> +    if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
>> +        error_report("[cansocketcan]: host interface %s not available (%s)",
>> +                     host_dev_name, strerror(errno));
>> +        goto fail;
>> +    }
>> +    addr.can_ifindex = ifr.ifr_ifindex;
>> +
>> +    c->err_mask = 0xffffffff; /* Receive error frame. */
>> +    setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
>> +                   &c->err_mask, sizeof(c->err_mask));
>> +
>> +    c->rfilter_num = 1;
>> +    c->rfilter = g_malloc0(c->rfilter_num * sizeof(struct qemu_can_filter));
>> +    if (c->rfilter == NULL) {
>> +        goto fail;
>> +    }
>> +
>> +    /* Receive all data frame. If |= CAN_INV_FILTER no data. */
>> +    c->rfilter[0].can_id = 0;
>> +    c->rfilter[0].can_mask = 0;
>> +    c->rfilter[0].can_mask &= ~CAN_ERR_FLAG;
>> +
> 
> I'd extract this in a more explicit explicit function like
> promisc_filter() and use
> 
>        can_bus_socketcan_set_filters(c, promisc_filter);
> 
> maybe clever would be to use NULL for promisc?
> 
> #define CANBUS_PROMISC_FILTER NULL /* why... */
> 
>        can_bus_socketcan_set_filters(c, CANBUS_PROMISC_FILTER);
> 
> can_bus_socketcan_set_filters( ..., *filters, rfilter_num )
> {
>     static const qemu_can_filter promisc_filter = {
>         .can_id = 0,
>         .can_mask = 0,
>         .can_mask &= ~CAN_ERR_FLAG
>     };
> 
>     if (!filters) {
>         filters = &promisc_filter;
>         rfilter_num = 1;
>     }
>     setsockopt(c->fd, SOL_CAN_RAW, CAN_RAW_FILTER,
>                filters, rfilter_num * sizeof(struct qemu_can_filter));
>     ...
> 
>> +    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, c->rfilter,
>> +               c->
> 
> don't forget to g_free(c->rfilter);
> 
>> +
>> +    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
>> +        error_report("[cansocketcan]: bind to host interface %s failed (%s)",
>> +                     host_dev_name, strerror(errno));
>> +        goto fail;
>> +    }
>> +
>> +    c->fd = s;
>> +
>> +    c->bus_client.info = &can_bus_socketcan_bus_client_info;
>> +
>> +    can_bus_socketcan_update_read_handler(c);
>> +
>> +    return c;
>> +
>> +fail:
>> +    can_bus_socketcan_cleanup(&c->bus_client);
>> +    g_free(c);
>> +fail1:
>> +
>> +    return NULL;
>> +}
>> +
>> +static int can_bus_connect_to_host_socketcan(CanBusState *bus,
>> +                                             const char *host_dev_name)
>> +{
>> +    CanBusSocketcanConnectState *c;
>> +
>> +    c = can_bus_socketcan_connect_new(host_dev_name);
>> +    if (c == NULL) {
>> +        error_report("CAN bus setup of host connect to \"%s\" failed",
>> +                      host_dev_name);
>> +        exit(1);
>> +    }
>> +
>> +    if (can_bus_insert_client(bus, &c->bus_client) < 0) {
>> +        error_report("CAN host device \"%s\" connect to bus \"%s\" failed",
>> +                      host_dev_name, bus->name);
>> +        exit(1);
>> +    }
>> +
>> +    if (0) {
>> +        /*
>> +         * Not used there or as a CanBusSocketcanConnectState method
>> +         * for now but included there for documentation purposes
>> +         * and to suppress warning.
> 
> So this can be avoided using PROMISC = NULL as suggested.
> 
>> +         */
>> +        can_bus_socketcan_set_filters(&c->bus_client, NULL, 0);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
>> +        can_bus_connect_to_host_socketcan;
>>

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 7/7] CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added.
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 7/7] CAN bus MIOe-3680 " pisa
@ 2018-01-19 13:13   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-19 13:13 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Deniz Eren <deniz.eren@icloud.com>
> 
> Signed-off-by: Deniz Eren <deniz.eren@icloud.com>
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>  hw/can/Makefile.objs      |   1 +
>  hw/can/can_mioe3680_pci.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 337 insertions(+)
>  create mode 100644 hw/can/can_mioe3680_pci.c
> 
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index 6a328f0c3a..8fcc455800 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -10,4 +10,5 @@ endif
>  common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
>  common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
>  common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
> +common-obj-$(CONFIG_CAN_PCI) += can_mioe3680_pci.o
>  endif
> diff --git a/hw/can/can_mioe3680_pci.c b/hw/can/can_mioe3680_pci.c
> new file mode 100644
> index 0000000000..7e761a838a
> --- /dev/null
> +++ b/hw/can/can_mioe3680_pci.c
> @@ -0,0 +1,336 @@
> +/*
> + * MIOe-3680 PCI CAN device (SJA1000 based) emulation

You are adding 3 SJA1000 based devices, sharing many common code.

Can we have the SJA1000 based devices inherit from a CanSJA1000Class
(this class supporting a dynamic number of channels).

> + *
> + * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
> + *
> + * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
> + * Jin Yang and Pavel Pisa
> + *
> + * 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 "qemu/osdep.h"
> +#include "qemu/event_notifier.h"
> +#include "qemu/thread.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "chardev/char.h"
> +#include "hw/hw.h"
> +#include "hw/pci/pci.h"
> +#include "can/can_emu.h"
> +
> +#include "can_sja1000.h"
> +
> +#define TYPE_CAN_PCI_DEV "mioe3680_pci"
> +
> +#define MIOe3680_PCI_DEV(obj) \
> +    OBJECT_CHECK(Mioe3680PCIState, (obj), TYPE_CAN_PCI_DEV)
> +
> +/* the PCI device and vendor IDs */
> +#ifndef MIOe3680_PCI_VENDOR_ID1
> +#define MIOe3680_PCI_VENDOR_ID1     0x13fe
> +#endif
> +
> +#ifndef MIOe3680_PCI_DEVICE_ID1
> +#define MIOe3680_PCI_DEVICE_ID1     0xc302
> +#endif
> +
> +#define MIOe3680_PCI_SJA_RANGE     0x800
> +
> +#define MIOe3680_PCI_BYTES_PER_SJA 0x80
> +
> +typedef struct Mioe3680PCIState {
> +    /*< private >*/
> +    PCIDevice       dev;
> +    /*< public >*/
> +    MemoryRegion    sja_io[2];
> +
> +    CanSJA1000State sja_state[2];
> +    qemu_irq        irq;
> +
> +    char            *model; /* The model that support, only SJA1000 now. */
> +    char            *canbus[2];
> +    char            *host[2];
> +} Mioe3680PCIState;
> +
> +static void mioe3680_pci_irq_raise(void *opaque)
> +{
> +    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
> +
> +    qemu_irq_raise(d->irq);
> +}
> +
> +static void mioe3680_pci_irq_lower(void *opaque)
> +{
> +    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
> +
> +    qemu_irq_lower(d->irq);
> +}
> +
> +static void
> +mioe3680_pci_reset(void *opaque)
> +{
> +    Mioe3680PCIState *d = (Mioe3680PCIState *)opaque;
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_hardware_reset(s1);
> +    can_sja_hardware_reset(s2);
> +}
> +
> +static uint64_t mioe3680_pci_sja1_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Mioe3680PCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr >> 2, size);
> +}
> +
> +static void mioe3680_pci_sja1_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                             unsigned size)
> +{
> +    Mioe3680PCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr >> 2, data, size);
> +}
> +
> +static uint64_t mioe3680_pci_sja2_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Mioe3680PCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr >> 2, size);
> +}
> +
> +static void mioe3680_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                             unsigned size)
> +{
> +    Mioe3680PCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= MIOe3680_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr >> 2, data, size);
> +}
> +
> +static const MemoryRegionOps mioe3680_pci_sja1_io_ops = {
> +    .read = mioe3680_pci_sja1_io_read,
> +    .write = mioe3680_pci_sja1_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static const MemoryRegionOps mioe3680_pci_sja2_io_ops = {
> +    .read = mioe3680_pci_sja2_io_read,
> +    .write = mioe3680_pci_sja2_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +

Using an abstract CanSJA1000Class, you don't need anything except this
init().

> +static int mioe3680_pci_init(PCIDevice *pci_dev)
> +{
> +    Mioe3680PCIState *d = MIOe3680_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +    uint8_t *pci_conf;
> +    CanBusState *can_bus1;
> +    CanBusState *can_bus2;
> +
> +    if (d->model) {
> +        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
> +            error_report("Can't create CAN device, "
> +                         "the model %s is not supported now.", d->model);
> +            exit(1);
> +        }
> +    }
> +
> +    can_bus1 = can_bus_find_by_name(d->canbus[0], true);
> +    if (can_bus1 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #1");
> +        exit(1);
> +    }
> +
> +    can_bus2 = can_bus_find_by_name(d->canbus[1], true);
> +    if (can_bus2 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #2");
> +        exit(1);
> +    }
> +
> +    if (d->host[0] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus1, d->host[0]) < 0) {
> +            error_report("Cannot connect CAN bus to host #1 device \"%s\"",
> +                         d->host[0]);
> +            exit(1);
> +        }
> +    }
> +
> +    if (d->host[1] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus2, d->host[1]) < 0) {
> +            error_report("Cannot connect CAN bus to host #2 device \"%s\"",
> +                         d->host[1]);
> +            exit(1);
> +        }
> +    }
> +
> +    pci_conf = pci_dev->config;
> +    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
> +
> +    d->irq = pci_allocate_irq(&d->dev);
> +
> +    can_sja_init(s1, mioe3680_pci_irq_raise, mioe3680_pci_irq_lower, d);
> +    can_sja_init(s2, mioe3680_pci_irq_raise, mioe3680_pci_irq_lower, d);
> +
> +    qemu_register_reset(mioe3680_pci_reset, d);
> +
> +    if (can_sja_connect_to_bus(s1, can_bus1) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    if (can_sja_connect_to_bus(s2, can_bus2) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    memory_region_init_io(&d->sja_io[0], OBJECT(d), &mioe3680_pci_sja1_io_ops,
> +                          d, "mioe3680_pci-sja1", MIOe3680_PCI_SJA_RANGE / 2);
> +    memory_region_init_io(&d->sja_io[1], OBJECT(d), &mioe3680_pci_sja2_io_ops,
> +                          d, "mioe3680_pci-sja2", MIOe3680_PCI_SJA_RANGE / 2);
> +
> +    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
> +                                            &d->sja_io[0]);
> +    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
> +                                            &d->sja_io[1]);
> +
> +    return 0;
> +}
> +
> +static void mioe3680_pci_exit(PCIDevice *pci_dev)
> +{
> +    Mioe3680PCIState *d = MIOe3680_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_disconnect(s1);
> +    can_sja_disconnect(s2);
> +
> +    qemu_unregister_reset(mioe3680_pci_reset, d);
> +
> +    /*
> +     * region d->sja_io is destroyed by QOM now
> +     */
> +    /* memory_region_destroy(&d->sja_io[0]); */
> +    /* memory_region_destroy(&d->sja_io[1]); */
> +
> +    can_sja_exit(s1);
> +    can_sja_exit(s2);
> +
> +    qemu_free_irq(d->irq);
> +}
> +
> +static const VMStateDescription vmstate_mioe3680_pci = {
> +    .name = "mioe3680_pci",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(dev, Mioe3680PCIState),
> +        VMSTATE_STRUCT(sja_state[0], Mioe3680PCIState, 0, vmstate_can_sja,
> +                       CanSJA1000State),
> +        VMSTATE_STRUCT(sja_state[1], Mioe3680PCIState, 0, vmstate_can_sja,
> +                       CanSJA1000State),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void qdev_mioe3680_pci_reset(DeviceState *dev)
> +{
> +    Mioe3680PCIState *d = MIOe3680_PCI_DEV(dev);
> +    mioe3680_pci_reset(d);
> +}
> +
> +static Property mioe3680_pci_properties[] = {
> +    DEFINE_PROP_STRING("canbus1",   Mioe3680PCIState, canbus[0]),
> +    DEFINE_PROP_STRING("canbus2",   Mioe3680PCIState, canbus[1]),
> +    DEFINE_PROP_STRING("host1",  Mioe3680PCIState, host[0]),
> +    DEFINE_PROP_STRING("host2",  Mioe3680PCIState, host[1]),
> +    DEFINE_PROP_STRING("model", Mioe3680PCIState, model),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void mioe3680_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    k->init = mioe3680_pci_init;
> +    k->exit = mioe3680_pci_exit;
> +    k->vendor_id = MIOe3680_PCI_VENDOR_ID1;
> +    k->device_id = MIOe3680_PCI_DEVICE_ID1;
> +    k->revision = 0x00;
> +    k->class_id = 0x000c09;
> +    k->subsystem_vendor_id = MIOe3680_PCI_VENDOR_ID1;
> +    k->subsystem_id = MIOe3680_PCI_DEVICE_ID1;
> +    dc->desc = "Mioe3680 PCICANx";
> +    dc->props = mioe3680_pci_properties;
> +    dc->vmsd = &vmstate_mioe3680_pci;
> +    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +    dc->reset = qdev_mioe3680_pci_reset;
> +}
> +
> +static const TypeInfo mioe3680_pci_info = {
> +    .name          = TYPE_CAN_PCI_DEV,

This name clashes with kvaser_pci...

> +    .parent        = TYPE_PCI_DEVICE,

Here you'd use TYPE_CAN_SJA_PCI_DEVICE

> +    .instance_size = sizeof(Mioe3680PCIState),
> +    .class_init    = mioe3680_pci_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> +        { },
> +    },
> +};
> +
> +static void mioe3680_pci_register_types(void)
> +{
> +    type_register_static(&mioe3680_pci_info);
> +}
> +
> +type_init(mioe3680_pci_register_types)
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 6/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 6/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added pisa
  2018-01-15  3:12   ` Philippe Mathieu-Daudé
@ 2018-01-19 13:15   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-19 13:15 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Deniz Eren <deniz.eren@icloud.com>
> 
> Signed-off-by: Deniz Eren <deniz.eren@icloud.com>
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>  hw/can/Makefile.objs     |   1 +
>  hw/can/can_pcm3680_pci.c | 336 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 337 insertions(+)
>  create mode 100644 hw/can/can_pcm3680_pci.c
> 
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index c9d07b9b16..6a328f0c3a 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -9,4 +9,5 @@ common-obj-y += can_host_stub.o
>  endif
>  common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
>  common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
> +common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
>  endif
> diff --git a/hw/can/can_pcm3680_pci.c b/hw/can/can_pcm3680_pci.c
> new file mode 100644
> index 0000000000..e85b61849a
> --- /dev/null
> +++ b/hw/can/can_pcm3680_pci.c
> @@ -0,0 +1,336 @@
> +/*
> + * PCM-3680i PCI CAN device (SJA1000 based) emulation
> + *
> + * Copyright (c) 2016 Deniz Eren (deniz.eren@icloud.com)
> + *
> + * Based on Kvaser PCI CAN device (SJA1000 based) emulation implemented by
> + * Jin Yang and Pavel Pisa
> + *
> + * 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 "qemu/osdep.h"
> +#include "qemu/event_notifier.h"
> +#include "qemu/thread.h"
> +#include "qemu/sockets.h"
> +#include "qemu/error-report.h"
> +#include "chardev/char.h"
> +#include "hw/hw.h"
> +#include "hw/pci/pci.h"
> +#include "can/can_emu.h"
> +
> +#include "can_sja1000.h"
> +
> +#define TYPE_CAN_PCI_DEV "pcm3680_pci"
> +
> +#define PCM3680i_PCI_DEV(obj) \
> +    OBJECT_CHECK(Pcm3680iPCIState, (obj), TYPE_CAN_PCI_DEV)
> +
> +/* the PCI device and vendor IDs */
> +#ifndef PCM3680i_PCI_VENDOR_ID1
> +#define PCM3680i_PCI_VENDOR_ID1     0x13fe
> +#endif
> +
> +#ifndef PCM3680i_PCI_DEVICE_ID1
> +#define PCM3680i_PCI_DEVICE_ID1     0xc002
> +#endif
> +
> +#define PCM3680i_PCI_SJA_RANGE     0x200
> +
> +#define PCM3680i_PCI_BYTES_PER_SJA 0x20
> +
> +typedef struct Pcm3680iPCIState {
> +    /*< private >*/
> +    PCIDevice       dev;
> +    /*< public >*/
> +    MemoryRegion    sja_io[2];
> +
> +    CanSJA1000State sja_state[2];
> +    qemu_irq        irq;
> +
> +    char            *model; /* The model that support, only SJA1000 now. */
> +    char            *canbus[2];
> +    char            *host[2];
> +} Pcm3680iPCIState;
> +
> +static void pcm3680i_pci_irq_raise(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +
> +    qemu_irq_raise(d->irq);
> +}
> +
> +static void pcm3680i_pci_irq_lower(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +
> +    qemu_irq_lower(d->irq);
> +}
> +
> +static void
> +pcm3680i_pci_reset(void *opaque)
> +{
> +    Pcm3680iPCIState *d = (Pcm3680iPCIState *)opaque;
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_hardware_reset(s1);
> +    can_sja_hardware_reset(s2);
> +}
> +
> +static uint64_t pcm3680i_pci_sja1_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr, size);
> +}
> +
> +static void pcm3680i_pci_sja1_io_write(void *opaque, hwaddr addr,
> +                                       uint64_t data, unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[0];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr, data, size);
> +}
> +
> +static uint64_t pcm3680i_pci_sja2_io_read(void *opaque, hwaddr addr,
> +                                          unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return 0;
> +    }
> +
> +    return can_sja_mem_read(s, addr, size);
> +}
> +
> +static void pcm3680i_pci_sja2_io_write(void *opaque, hwaddr addr, uint64_t data,
> +                             unsigned size)
> +{
> +    Pcm3680iPCIState *d = opaque;
> +    CanSJA1000State *s = &d->sja_state[1];
> +
> +    if (addr >= PCM3680i_PCI_BYTES_PER_SJA) {
> +        return;
> +    }
> +
> +    can_sja_mem_write(s, addr, data, size);
> +}
> +
> +static const MemoryRegionOps pcm3680i_pci_sja1_io_ops = {
> +    .read = pcm3680i_pci_sja1_io_read,
> +    .write = pcm3680i_pci_sja1_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static const MemoryRegionOps pcm3680i_pci_sja2_io_ops = {
> +    .read = pcm3680i_pci_sja2_io_read,
> +    .write = pcm3680i_pci_sja2_io_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .impl = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +static int pcm3680i_pci_init(PCIDevice *pci_dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +    uint8_t *pci_conf;
> +    CanBusState *can_bus1;
> +    CanBusState *can_bus2;
> +
> +    if (d->model) {
> +        if (strncmp(d->model, "pcican-s", 256)) { /* for security reason */
> +            error_report("Can't create CAN device, "
> +                         "the model %s is not supported now.", d->model);
> +            exit(1);
> +        }
> +    }
> +
> +    can_bus1 = can_bus_find_by_name(d->canbus[0], true);
> +    if (can_bus1 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #1");
> +        exit(1);
> +    }
> +
> +    can_bus2 = can_bus_find_by_name(d->canbus[1], true);
> +    if (can_bus2 == NULL) {
> +        error_report("Cannot create can find/allocate CAN bus #2");
> +        exit(1);
> +    }
> +
> +    if (d->host[0] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus1, d->host[0]) < 0) {
> +            error_report("Cannot connect CAN bus to host #1 device \"%s\"",
> +                         d->host[0]);
> +            exit(1);
> +        }
> +    }
> +
> +    if (d->host[1] != NULL) {
> +        if (can_bus_connect_to_host_device(can_bus2, d->host[1]) < 0) {
> +            error_report("Cannot connect CAN bus to host #2 device \"%s\"",
> +                         d->host[1]);
> +            exit(1);
> +        }
> +    }
> +
> +    pci_conf = pci_dev->config;
> +    pci_conf[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
> +
> +    d->irq = pci_allocate_irq(&d->dev);
> +
> +    can_sja_init(s1, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
> +    can_sja_init(s2, pcm3680i_pci_irq_raise, pcm3680i_pci_irq_lower, d);
> +
> +    qemu_register_reset(pcm3680i_pci_reset, d);
> +
> +    if (can_sja_connect_to_bus(s1, can_bus1) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    if (can_sja_connect_to_bus(s2, can_bus2) < 0) {
> +        error_report("can_sja_connect_to_bus failed");
> +        exit(1);
> +    }
> +
> +    memory_region_init_io(&d->sja_io[0], OBJECT(d), &pcm3680i_pci_sja1_io_ops,
> +                          d, "pcm3680i_pci-sja1", PCM3680i_PCI_SJA_RANGE / 2);
> +    memory_region_init_io(&d->sja_io[1], OBJECT(d), &pcm3680i_pci_sja2_io_ops,
> +                          d, "pcm3680i_pci-sja2", PCM3680i_PCI_SJA_RANGE / 2);
> +
> +    pci_register_bar(&d->dev, /*BAR*/ 0, PCI_BASE_ADDRESS_SPACE_IO,
> +                                             &d->sja_io[0]);
> +    pci_register_bar(&d->dev, /*BAR*/ 1, PCI_BASE_ADDRESS_SPACE_IO,
> +                                             &d->sja_io[1]);
> +
> +    return 0;
> +}
> +
> +static void pcm3680i_pci_exit(PCIDevice *pci_dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(pci_dev);
> +    CanSJA1000State *s1 = &d->sja_state[0];
> +    CanSJA1000State *s2 = &d->sja_state[1];
> +
> +    can_sja_disconnect(s1);
> +    can_sja_disconnect(s2);
> +
> +    qemu_unregister_reset(pcm3680i_pci_reset, d);
> +
> +    /*
> +     * region d->sja_io is destroyed by QOM now
> +     */
> +    /* memory_region_destroy(&d->sja_io[0]); */
> +    /* memory_region_destroy(&d->sja_io[1]); */
> +
> +    can_sja_exit(s1);
> +    can_sja_exit(s2);
> +
> +    qemu_free_irq(d->irq);
> +}
> +
> +static const VMStateDescription vmstate_pcm3680i_pci = {
> +    .name = "pcm3680i_pci",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(dev, Pcm3680iPCIState),
> +        VMSTATE_STRUCT(sja_state[0], Pcm3680iPCIState, 0,
> +                       vmstate_can_sja, CanSJA1000State),
> +        VMSTATE_STRUCT(sja_state[1], Pcm3680iPCIState, 0,
> +                       vmstate_can_sja, CanSJA1000State),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void qdev_pcm3680i_pci_reset(DeviceState *dev)
> +{
> +    Pcm3680iPCIState *d = PCM3680i_PCI_DEV(dev);
> +    pcm3680i_pci_reset(d);
> +}
> +
> +static Property pcm3680i_pci_properties[] = {
> +    DEFINE_PROP_STRING("canbus1",   Pcm3680iPCIState, canbus[0]),
> +    DEFINE_PROP_STRING("canbus2",   Pcm3680iPCIState, canbus[1]),
> +    DEFINE_PROP_STRING("host1",  Pcm3680iPCIState, host[0]),
> +    DEFINE_PROP_STRING("host2",  Pcm3680iPCIState, host[1]),
> +    DEFINE_PROP_STRING("model", Pcm3680iPCIState, model),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void pcm3680i_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    k->init = pcm3680i_pci_init;
> +    k->exit = pcm3680i_pci_exit;
> +    k->vendor_id = PCM3680i_PCI_VENDOR_ID1;
> +    k->device_id = PCM3680i_PCI_DEVICE_ID1;
> +    k->revision = 0x00;
> +    k->class_id = 0x000c09;
> +    k->subsystem_vendor_id = PCM3680i_PCI_VENDOR_ID1;
> +    k->subsystem_id = PCM3680i_PCI_DEVICE_ID1;
> +    dc->desc = "Pcm3680i PCICANx";
> +    dc->props = pcm3680i_pci_properties;
> +    dc->vmsd = &vmstate_pcm3680i_pci;
> +    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +    dc->reset = qdev_pcm3680i_pci_reset;
> +}
> +
> +static const TypeInfo pcm3680i_pci_info = {
> +    .name          = TYPE_CAN_PCI_DEV,

Clashing with "kvaser_pci"

> +    .parent        = TYPE_PCI_DEVICE,

Same comments here, this class should inherit from CanSJA1000Class.

> +    .instance_size = sizeof(Pcm3680iPCIState),
> +    .class_init    = pcm3680i_pci_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> +        { },
> +    },
> +};
> +
> +static void pcm3680i_pci_register_types(void)
> +{
> +    type_register_static(&pcm3680i_pci_info);
> +}
> +
> +type_init(pcm3680i_pci_register_types)
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 1/7] CAN bus simple messages transport implementation for QEMU
  2018-01-19 12:38   ` Philippe Mathieu-Daudé
@ 2018-01-19 13:28     ` Pavel Pisa
  2018-01-19 17:04     ` Pavel Pisa
  1 sibling, 0 replies; 45+ messages in thread
From: Pavel Pisa @ 2018-01-19 13:28 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: qemu-devel, Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi,
	Deniz Eren, Oleksij Rempel, Konrad Frederic, Jan Kiszka

Hello Philippe,

On Friday 19 of January 2018 13:38:11 Philippe Mathieu-Daudé wrote:
> On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> > From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> >
> > +extern int (*can_bus_connect_to_host_variant)(CanBusState *bus,
> > +                                              const char *name);
>
> Isn't extern (*func) an anti-pattern?
> One might be tempted to call it without checking it is non-NULL...
>
> Please declare it as a function, and using a static pointer, i.e.:
>
> typedef int (*can_bus_connect_to_host_variant_t)(CanBusState *bus,
>                                        const char *name);
>
>
> static can_bus_connect_to_host_variant_t
> can_bus_connect_to_host_variant_handler;
>
> void
> set_can_bus_connect_to_host_variant(can_bus_connect_to_host_variant_t
> handler)
> {
>     can_bus_connect_to_host_variant_handler = handler;
> }
>
> int can_bus_connect_to_host_variant(CanBusState *bus,
>                           const char *name)
> {
>     if (!can_bus_connect_to_host_variant_handler) {
>         return ERROR;
>     }
>     return can_bus_connect_to_host_variant_handler(bus, name);
> }


Yes, that has been my initial idea but then I need
some way how to setup variant from can_socketcan.c
when it is linked in

Something like

static void __attribute__((constructor)) can_socketcan_setup_variant(void)
{

}

or

module_init()

or

in can_socketcan.c or have there some QOM object which
type initialization setups pointer early before
individual instances of kvaser_pci

Thanks for suggestion in advance,

Pavel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-16  0:12       ` Philippe Mathieu-Daudé
  2018-01-19  8:51         ` Pavel Pisa
@ 2018-01-19 13:37         ` Daniel P. Berrange
  1 sibling, 0 replies; 45+ messages in thread
From: Daniel P. Berrange @ 2018-01-19 13:37 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Pavel Pisa, Gerd Hoffmann, Paolo Bonzini, qemu-devel,
	Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

On Mon, Jan 15, 2018 at 09:12:09PM -0300, Philippe Mathieu-Daudé wrote:
> On 01/15/2018 06:29 PM, Pavel Pisa wrote:
> >>> +    /* open socket */
> >>> +    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
> >>
> >> I never used it, but I think QEMU uses his socket API: "qemu/sockets.h"
> > 
> > The SocketCAN host connection code is Linux specific,
> > but I can switch to qemu_socket() if it is preferred.
> > But address family has to be from Linux header file anyway.
> 
> qemu_socket() sockets are heavily tested and already solve many things,
> like async I/O and error handling.

NB that's just the low level system call wrapper. All it really does is
ensure O_CLOSEXEC is set for all sockets. It should defintely be used
just for that reason alone though. 

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-19  8:51         ` Pavel Pisa
@ 2018-01-19 13:37           ` Philippe Mathieu-Daudé
  2018-01-22 10:28             ` Stefan Hajnoczi
  0 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-19 13:37 UTC (permalink / raw)
  To: Pavel Pisa, Stefan Hajnoczi, Paolo Bonzini, Marc-André Lureau
  Cc: Daniel P. Berrange, Gerd Hoffmann, qemu-devel, Marek Vasut,
	Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren, Oleksij Rempel,
	Konrad Frederic, Jan Kiszka

On 01/19/2018 05:51 AM, Pavel Pisa wrote:
> Hello Philippe,
> 
> On Tuesday 16 of January 2018 01:12:09 Philippe Mathieu-Daudé wrote:
>> On 01/15/2018 06:29 PM, Pavel Pisa wrote:
>>> Hello Philippe,
>>>
>>> thanks for review.
>>>
>>> I have updated patch series in can-pci branch in
>>>
>>>   https://gitlab.fel.cvut.cz/canbus/qemu-canbus
>>>
>>> I would wait some day if there is some remark
>>> from other developers and socket ones especially.
>>
>> I'll have a look.
> 
> if there are no more comments, I prepare version 5
> of the patches at start of the next week.
> 
> Already implemented changes for version 5:
> 
> Assertions to check match to Linux struct can_frame
> has been moved out of the function.
> The case statements use ranges.
> min_access_size=1 removed.
> "for loops" are used to process operations
> for the first and the second chip where
> appropriate in PCM-3680I and MIOe-3680 patches.
> Deniz Eren reported that updated version
> works correctly.
> 
> I have not proceed with next two remarks yet:
> 
> Inlining in can_sja_single_filter and can_sja_dual_filter
> functions. There is only single group of repeated four lines
> of code which could be inlined, others are groups of two
> lines each. 
> 
>>     if (extended) {
> vvvvvvvvvvvvvvv
>>         filter->can_id = (uint32_t)acr[0] << 21;
>>         filter->can_id |= (uint32_t)acr[1] << 13;
>>         filter->can_id |= (uint32_t)acr[2] << 5;
>>         filter->can_id |= (uint32_t)acr[3] >> 3;
> ^^^^^^^^^^^^^^^
>>         if (acr[3] & 4) {
>>             filter->can_id |= QEMU_CAN_RTR_FLAG;
>>         }
>>
> vvvvvvvvvvvvvvv
>>         filter->can_mask = (uint32_t)amr[0] << 21;
>>         filter->can_mask |= (uint32_t)amr[1] << 13;
>>         filter->can_mask |= (uint32_t)amr[2] << 5;
>>         filter->can_mask |= (uint32_t)amr[3] >> 3;
> ^^^^^^^^^^^^^^^
>>         filter->can_mask = ~filter->can_mask & QEMU_CAN_EFF_MASK;
>>         if (!(amr[3] & 4)) {
>>             filter->can_mask |= QEMU_CAN_RTR_FLAG;
>>         }
> 
> Only these marked parts repeats.
> Rest is similar but not material for simple inline.
> Same for others two line sequences.
> All these bit level manipulations are moved from frame
> processing and another more top level functions into these
> short can_sja_{single,dual}_filter functions.

fine.

> 
>> /* PeliCAN mode */
>> enum SJA1000_PeliCAN_regs {
>>         SJA_MOD      = 0x00,
>> /* Command register */
>>         SJA_CMR      = 0x01,
> ....
>> /* TX Error Counter */
>>         SJA_TXERR0   = 0x0e,
>>         SJA_TXERR1   = 0x0f,
>> /* Rx Message Counter (number of msgs. in RX FIFO */
>>         SJA_RMC      = 0x1d,
>> /* Rx Buffer Start Addr. (address of current MSG) */
>>         SJA_RBSA     = 0x1e,
>> /* Transmit Buffer (write) Receive Buffer (read) Frame Information */
>>         SJA_FRM      = 0x10,
>> /*
>>  * ID bytes (11 bits in 0 and 1 for standard message or
>>  *          16 bits in 0,1 and 13 bits in 2,3 for extended message)
>>  */
>>         SJA_ID0      = 0x11, SJA_ID1 = 0x12,
>> /* ID cont. for extended frames */
>>         SJA_ID2      = 0x13, SJA_ID3 = 0x14,
> 
> Proposed formating
> 
>            SJA_MOD      = 0x00, /* Command */
>            SJA_CMR      = 0x01, /* Status */
> 
> this is really better for short comments.
> But how format long ones then to keep lines max 80 characters
> 
>            SJA_FRM      = 0x10, /* Transmit Buffer (write) Receive Buffer
>                                  * (read) Frame Information
>                                  */

            SJA_FRM      = 0x10, /* Frame Information              */
                                 /* on write: Transmit Buffer used */
                                 /* on read: Receive Buffer used   */

but I'd keep it as:

            SJA_FRM      = 0x10, /* Frame Information */

> 
> The SJA_ID0 is would look even worse.

As you prefer, comments are good if useful, too much redundant comments
are counter productive IMHO.

> 
> But if the second format is preferred then I update the patch.
> 
>>> Trace events seems as nice feature. But simple text printf
>>> like output has been enough till now for CAN testing.
>>> There is no debugging output in production build.
>>> So I would add tracing infrastructure later if needed.
>>
>> They are as useful as console printf, but less invasive and more
>> powerful: you can use a much precise timing, select which set of events
>> to display without having to recompile.
>> The default backend behaves as console printf.
>>
>> You should try them :)
> 
> I have tried them on 
> 
>   pci_update_mappings_del
>   pci_update_mappings_add
>   pci_cfg_write
> 
> and they work great. They would be nice for SJA1000
> register accesses, PCI boards configuration etc.
> I am not sure how to use them for CAN messages
> which has a variable length data field.

Yes, I hit this problem with variable length data in the SD Bus.

Let's ask Stefan what is the best approach (he said "Tracing is not
great for dumping large amounts of data")

> Any of debugging outputs is active (all is optimized out)
> in regular build.
> 
>>>>> +    /* open socket */
>>>>> +    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
>>>>
>>>> I never used it, but I think QEMU uses his socket API: "qemu/sockets.h"
>>>
>>> The SocketCAN host connection code is Linux specific,
>>> but I can switch to qemu_socket() if it is preferred.
>>> But address family has to be from Linux header file anyway.

I'll let the Chardev maintainers suggest what's best.

>>
>> qemu_socket() sockets are heavily tested and already solve many things,
>> like async I/O and error handling.
> 
> The CAN socket works with RAW packets read and written as 16 bytes.
> So some higher level of optimizations used for stream or larger packets
> have no significant effect there and SocketCAN API is Linux kernel
> specific so generic abstraction layers has no effect there as well.
> 
> I have question about reporting fatal error.
> 
> Our code uses error_report() and exit(1) for now.
> 
>         error_report("CAN host device \"%s\" connect to bus \"%s\" failed",
>                       host_dev_name, bus->name);
>         exit(1);
> 
> Is that correct or there is better solution/function instead of exit?
> I have seen this combination in many other places of QEMU code
> in past but may it be there is some proposed change already.

I think QEMU codebase now try to unify this using
"include/qapi/error.h", so your can_bus_connect_to_host_socketcan()
function would take an extra 'Error *errp' parameter.

> 
> Best wishes,
> 
> Pavel Pisa
> 
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 1/7] CAN bus simple messages transport implementation for QEMU
  2018-01-19 12:38   ` Philippe Mathieu-Daudé
  2018-01-19 13:28     ` Pavel Pisa
@ 2018-01-19 17:04     ` Pavel Pisa
  1 sibling, 0 replies; 45+ messages in thread
From: Pavel Pisa @ 2018-01-19 17:04 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: qemu-devel, Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi,
	Deniz Eren, Oleksij Rempel, Konrad Frederic, Jan Kiszka

Hello Philippe,

On Friday 19 of January 2018 13:38:11 Philippe Mathieu-Daudé wrote:
> > diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> > new file mode 100644
> > index 0000000000..1028d7c455
> > --- /dev/null
> > +++ b/hw/can/Makefile.objs
> > @@ -0,0 +1,6 @@
> > +# CAN bus interfaces emulation and infrastructure
> > +
> > +ifeq ($(CONFIG_CAN_CORE),y)
> > +common-obj-y += can_core.o
>
> Please follow QEMU style:
>
> common-obj-$(CONFIG_CAN_BUS) += can_core.o

I agree that in the first patch it is not logical
to use if but problem is that final Makefile.objs
needs to resolve operating system logic and other
conditions.

ifeq ($(CONFIG_CAN_BUS),y)
common-obj-y += can_core.o
ifeq ($(CONFIG_LINUX),y)
common-obj-y += can_socketcan.o
else
common-obj-y += can_host_stub.o
endif
common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
common-obj-$(CONFIG_CAN_PCI) += can_mioe3680_pci.o
endif

If there is Kconfig style system
controlling mutual options combination then plain
common-obj-$(CONFIG_*) would work but it is not
the case and I have followed seen in another QEMU 

I have followed style found in another subsystems

qemu-git/hw/smbios/Makefile.objs

ifeq ($(CONFIG_SMBIOS),y)
common-obj-y += smbios.o
common-obj-$(CONFIG_IPMI) += smbios_type_38.o
common-obj-$(call lnot,$(CONFIG_IPMI)) += smbios_type_38-stub.o
else
common-obj-y += smbios-stub.o
endif

common-obj-$(CONFIG_ALL) += smbios-stub.o
common-obj-$(CONFIG_ALL) += smbios_type_38-stub.o

qemu-git/hw/timer/Makefile.objs

...
...
qemu-git/hw/vfio/Makefile.objs

I am not sure how to resolve these conditions better way.

Best wishes,

Pavel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface.
  2018-01-19 13:37           ` Philippe Mathieu-Daudé
@ 2018-01-22 10:28             ` Stefan Hajnoczi
  0 siblings, 0 replies; 45+ messages in thread
From: Stefan Hajnoczi @ 2018-01-22 10:28 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Pavel Pisa, Paolo Bonzini, Marc-André Lureau,
	Daniel P. Berrange, Gerd Hoffmann, qemu-devel, Marek Vasut,
	Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren, Oleksij Rempel,
	Konrad Frederic, Jan Kiszka

[-- Attachment #1: Type: text/plain, Size: 1647 bytes --]

On Fri, Jan 19, 2018 at 10:37:22AM -0300, Philippe Mathieu-Daudé wrote:
> On 01/19/2018 05:51 AM, Pavel Pisa wrote:
> > On Tuesday 16 of January 2018 01:12:09 Philippe Mathieu-Daudé wrote:
> >> On 01/15/2018 06:29 PM, Pavel Pisa wrote:
> > But if the second format is preferred then I update the patch.
> > 
> >>> Trace events seems as nice feature. But simple text printf
> >>> like output has been enough till now for CAN testing.
> >>> There is no debugging output in production build.
> >>> So I would add tracing infrastructure later if needed.
> >>
> >> They are as useful as console printf, but less invasive and more
> >> powerful: you can use a much precise timing, select which set of events
> >> to display without having to recompile.
> >> The default backend behaves as console printf.
> >>
> >> You should try them :)
> > 
> > I have tried them on 
> > 
> >   pci_update_mappings_del
> >   pci_update_mappings_add
> >   pci_cfg_write
> > 
> > and they work great. They would be nice for SJA1000
> > register accesses, PCI boards configuration etc.
> > I am not sure how to use them for CAN messages
> > which has a variable length data field.
> 
> Yes, I hit this problem with variable length data in the SD Bus.
> 
> Let's ask Stefan what is the best approach (he said "Tracing is not
> great for dumping large amounts of data")

Yes, tracing isn't pcap.  It's not designed for dumping payloads -
especially when the length is more than 64 bytes or so.

I suggest writing out a pcap file so wireshark or tcpdump can be used to
analyze it.  The code is pretty simple, see net/dump.c.

Stefan

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 455 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-14 20:14 [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
                   ` (6 preceding siblings ...)
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 7/7] CAN bus MIOe-3680 " pisa
@ 2018-01-22 11:35 ` Philippe Mathieu-Daudé
  2018-01-23 21:42   ` Pavel Pisa
  7 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-22 11:35 UTC (permalink / raw)
  To: pisa, qemu-devel, Marc-André Lureau, Paolo Bonzini
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

[-- Attachment #1: Type: text/plain, Size: 6422 bytes --]

Hi Pavel,

On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> Basic emulation of CAN bus controller and interconnection for QEMU.
> 
> Patches version 4:
> Resolve comments longer than 80 characters to suppress
> all warnings reported by scripts/checkpatch.pl.
> Follow all suggestions from Frederic Konrad review.
> Replace all printf and perror calls by QEMU equivalents.
> Include Deniz Eren signed-off confimation.
> 
> Patches version 3:
> Support to connect to host SocketCAN interface has been
> separated from the core bus implementation. Only simple
> statically initialize pointer to the connection function
> is used, no QOM concept for now.
> SJA1000 message filters redone and code unified where
> possible.
> Basic documentation added.
> QEMU_ALIGNED used in definition of CAN frame structure,
> structure and defines are separated from Linux/SocketCAN
> API defined ones to allow to keep QEMU message format
> independed from host system one. Check for correspondence
> to socketcan defines added.
> 
> Patches version 2:
> The bus emulation and the SJA1000 chip emulation introduced
> by individual patches as suggested by Frederic Konrad.
> Simple example board to test SJA1000 as single memory-mapped BAR
> has been omitted in a new series because emulation of real
> existing boards can provide same functions now.
> Conditionalized debug printfs changed to be exposed to compiler
> syntax check as suggested in review.
> 
> The work has been started by Jin Yang in the frame of GSoC 2013 slot
> contributed by RTEMS project which has been looking for environment
> to allow develop and test CAN drivers for multiple CPU architectures.
> 
> I have menthored the project and then done substantial code cleanup
> and update to QOM. Deniz Eren then used emulation for SJA1000 base card
> driver development for other operating system and contributed
> PCM-3680I and MIOe-3680 support.
> 
> Some page about the project
> 
>   https://gitlab.fel.cvut.cz/canbus/qemu-canbus/wikis/home
> 
> FEE CTU GitLab repository with can-pci branch for 2.3, 2.4, 2.7, 2.8, 2.10
> and 2.11 QEMU version is available in the repository
> 
>   https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci
> 
> mirror at GitHub
> 
>   https://github.com/CTU-IIG/qemu
> 
> There are many areas for improvement and extension of the code still
> (for example freeze and migration is not implemented. CAN controllers
> use proper QOM model but bus/interconnection emulation uses simple broadcast
> connection which is required for CAN, but it is not based on QEMU bus model).
> I have tried to look into QEMU VLANs implementation but it
> does not map straightforward to CAN and I would need some help/opinion
> from more advanced developers to decide what is their right
> mapping to CAN.

I think your series is quite ready to get accepted, although I'm not
sure through with tree it will goes.

Most of my review comments are not blocking issues and might get
addressed later (like having an abstract sja1000).

The principal issue I'd like to discuss with Paolo/Marc-André is the
chardev backend, they might say it's OK to accept it in this current
state and refactor the CANBus backend later.

I'd still avoid using directly the socket() syscall and use the QEMU
socket API instead (also suggested by Daniel).

> 
> CAN-FD support would be interesting requires other developers/
> companies contributions or setup of some project to allow invite
> some students and colleagues from my university into project.
> 
> But I believe that (even in its actual state) provided solution
> is great help for embedded systems developers when they can connect
> SocketCAN from one or more embedded systems running in virtual
> environment together or with Linux host SocketCAN virtual
> or real bus interfaces.
> 
> We have even tested our generic CANopen device configured
> for CANopen 401 profile for generic I/O running in the virtual
> system which can control GPIO inputs/outputs through virtual
> industrial I/O card.
> 
> Generally QEMU can be interesting setup which allows
> to test complete industrial and automotive applications
> in virtual environment even before real hardware is availabe.

I have been thinking a bit about how to test some frame operations
(rather than the PCI devices) and the Linux vcan driver might be a good
option (Virtual Local CAN Interface). This is also useful to test this
series without having CAN hardware. How to use vcan might be worth his
own paragraph in docs/can.txt.

Do you think some of your tests can be added in the QEMU test suite
(qtests)?

Regards,

Phil.

> 
> Deniz Eren (2):
>   CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added.
>   CAN bus MIOe-3680 PCI (dual SJA1000 channel) emulation added.
> 
> Pavel Pisa (5):
>   CAN bus simple messages transport implementation for QEMU
>   CAN bus support to connect bust to Linux host SocketCAN interface.
>   CAN bus SJA1000 chip register level emulation for QEMU
>   CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
>   QEMU CAN bus emulation documentation
> 
>  default-configs/pci.mak   |    3 +
>  docs/can.txt              |   78 ++++
>  hw/Makefile.objs          |    1 +
>  hw/can/Makefile.objs      |   14 +
>  hw/can/can_core.c         |  136 ++++++
>  hw/can/can_host_stub.c    |   36 ++
>  hw/can/can_kvaser_pci.c   |  375 +++++++++++++++++
>  hw/can/can_mioe3680_pci.c |  336 +++++++++++++++
>  hw/can/can_pcm3680_pci.c  |  336 +++++++++++++++
>  hw/can/can_sja1000.c      | 1013 +++++++++++++++++++++++++++++++++++++++++++++
>  hw/can/can_sja1000.h      |  167 ++++++++
>  hw/can/can_socketcan.c    |  314 ++++++++++++++
>  include/can/can_emu.h     |  131 ++++++
>  13 files changed, 2940 insertions(+)
>  create mode 100644 docs/can.txt
>  create mode 100644 hw/can/Makefile.objs
>  create mode 100644 hw/can/can_core.c
>  create mode 100644 hw/can/can_host_stub.c
>  create mode 100644 hw/can/can_kvaser_pci.c
>  create mode 100644 hw/can/can_mioe3680_pci.c
>  create mode 100644 hw/can/can_pcm3680_pci.c
>  create mode 100644 hw/can/can_sja1000.c
>  create mode 100644 hw/can/can_sja1000.h
>  create mode 100644 hw/can/can_socketcan.c
>  create mode 100644 include/can/can_emu.h
> 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-22 11:35 ` [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) Philippe Mathieu-Daudé
@ 2018-01-23 21:42   ` Pavel Pisa
  2018-01-24 20:22     ` Pavel Pisa
  2018-01-25 13:58     ` Paolo Bonzini
  0 siblings, 2 replies; 45+ messages in thread
From: Pavel Pisa @ 2018-01-23 21:42 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: qemu-devel, Marc-André Lureau, Paolo Bonzini, Marek Vasut,
	Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren, Oleksij Rempel,
	Konrad Frederic, Jan Kiszka

Hello Philippe,

On Monday 22 of January 2018 12:35:33 Philippe Mathieu-Daudé wrote:
> Hi Pavel,
>
> On 01/14/2018 05:14 PM, pisa@cmp.felk.cvut.cz wrote:
>
> I think your series is quite ready to get accepted, although I'm not
> sure through with tree it will goes.
>
> Most of my review comments are not blocking issues and might get
> addressed later (like having an abstract sja1000).

Great, I would be happy to reach acceptable state when development
can switch to incremental mode as time allows. I hope than even
actual state is usable from reports (at least for some usescases).

> The principal issue I'd like to discuss with Paolo/Marc-André is the
> chardev backend, they might say it's OK to accept it in this current
> state and refactor the CANBus backend later.

Do you think QOM based? I would like it to be implemented
that way but I need some assistance where to look how this
object kind should be implemented and from which base object
inherit from. But I prefer to left that for later work.

I would definitely like to use some mechanism which allows
to get rid of externally visible pointer and need to assign
it in the stub. It has been my initial idea and your review
sumbled across this hack as well. But I need suggestion what
is the preferred way for QEMU.

When Linux specific object file is linked in then some local
function needs to be called before QOM instances population.
I know how to do that GCC specific/non-portable way

static void __attribute__((constructor)) can_socketcan_setup_variant(void)
{

}

but I expect that something like

module_init()

in can_socketcan.c should be used.

Problem is that there is not module_init
type for plain function in include/qemu/module.h

    MODULE_INIT_BLOCK,
    MODULE_INIT_OPTS,
    MODULE_INIT_QOM,
    MODULE_INIT_TRACE,
    MODULE_INIT_MAX

I expect that QOM object would solve that in future
but I would be happy to left it simple for now.

What is preferred solution there?

> I'd still avoid using directly the socket() syscall and use the QEMU
> socket API instead (also suggested by Daniel).

I have already switched to qemu_socket(), implementation
looks fine and I have tested that it works.
I have tested functionality and updated can-pci branch.

> I have been thinking a bit about how to test some frame operations
> (rather than the PCI devices) and the Linux vcan driver might be a good
> option (Virtual Local CAN Interface). This is also useful to test this
> series without having CAN hardware. How to use vcan might be worth his
> own paragraph in docs/can.txt.
>
> Do you think some of your tests can be added in the QEMU test suite
> (qtests)?

I have added some more infomation into docs file

+ The CAN interface of the host system has to be configured for proper
+ bitrate and set up. Configuration is not propagated from emulated
+ devices through bus to the physical host device. Example configuration
+ for 1 Mbit/s
+
+   ip link set can0 type can bitrate 1000000
+   ip link set can0 up
+
+ Virtual (host local only) can interface can be used on the host
+ side instead of physical interface
+
+   ip link add dev can0 type vcan
+
+ The CAN interface on the host side can be used to analyze CAN
+ traffic with "candump" command which is included in "can-utils".
+
+   candump can0

As for the automatic testing, iproute2 tools are required
on host and guest side (considering use of Linux)
and kernel with CAN drivers support.
Root access is required on the host side to setup CAN
interface. Some simple tool is required. It can be based
on can-utils code or our older canping code for example.

Best wishes,

Pavel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-23 21:42   ` Pavel Pisa
@ 2018-01-24 20:22     ` Pavel Pisa
  2018-01-24 21:41       ` Philippe Mathieu-Daudé
  2018-01-25 13:58     ` Paolo Bonzini
  1 sibling, 1 reply; 45+ messages in thread
From: Pavel Pisa @ 2018-01-24 20:22 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: qemu-devel, Marc-André Lureau, Paolo Bonzini, Marek Vasut,
	Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren, Oleksij Rempel,
	Konrad Frederic, Jan Kiszka

Hello everybody,

On Tuesday 23 of January 2018 22:42:31 Pavel Pisa wrote:
> When Linux specific object file is linked in then some local
> function needs to be called before QOM instances population.
> I know how to do that GCC specific/non-portable way
>
> static void __attribute__((constructor)) can_socketcan_setup_variant(void)
> {
>
> }
>
> but I expect that something like
>
> module_init()
>
> in can_socketcan.c should be used.


I have experimented with code changes to get rid of stub for
non Linux systems. type_init() is used because it is more
portable than constructor attribute.

I have seen that a few other type_init-s do more
than simple sequence of type_register_static().
Is it acceptable to use type_init for registration
to CAN core by function call for now? Conversion simplifies
makefiles and unnecessary stub file is removed.

But I would use attribute if that solution is preferred because
it is allways present on Linux where SocketCAN is used anyway
and it is used in other Qemu subsystems as well.

----------------------------------------------------------------
Solution with attribute

#ifdef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
static void __attribute__((constructor))
can_bus_socketcan_setup(void)
{
    can_bus_set_connect_to_host(can_bus_connect_to_host_socketcan);
}
#endif

----------------------------------------------------------------
Solution with type_init
branch https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci-socketcan-init

diff --git a/hw/can/can_socketcan.c b/hw/can/can_socketcan.c
index 42099fb696..fb41853c2b 100644
--- a/hw/can/can_socketcan.c
+++ b/hw/can/can_socketcan.c
@@ -309,5 +309,14 @@ static int can_bus_connect_to_host_socketcan(CanBusState *bus,
     return 0;
 }
 
-int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
-        can_bus_connect_to_host_socketcan;
+static void can_bus_socketcan_type_init(void)
+{
+    /*
+     * There should be object registration when CanBusSocketcanConnectState
+     * is converted into QOM object. Use for registration of host
+     * can bus access for now.
+     */
+    can_bus_set_connect_to_host(can_bus_connect_to_host_socketcan);
+}
+
+type_init(can_bus_socketcan_type_init);


diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
index 1ce9950de0..14c2369718 100644
--- a/hw/can/Makefile.objs
+++ b/hw/can/Makefile.objs
@@ -2,11 +2,7 @@
 
 ifeq ($(CONFIG_CAN_BUS),y)
 common-obj-y += can_core.o
-ifeq ($(CONFIG_LINUX),y)
-common-obj-y += can_socketcan.o
-else
-common-obj-y += can_host_stub.o
-endif
+common-obj-$(CONFIG_LINUX) += can_socketcan.o
 common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
 common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
 common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
diff --git a/hw/can/can_core.c b/hw/can/can_core.c
index 41c458c792..c14807b188 100644
--- a/hw/can/can_core.c
+++ b/hw/can/can_core.c
@@ -34,6 +34,8 @@
 static QTAILQ_HEAD(, CanBusState) can_buses =
     QTAILQ_HEAD_INITIALIZER(can_buses);
 
+static can_bus_connect_to_host_t can_bus_connect_to_host_fnc;
+
 CanBusState *can_bus_find_by_name(const char *name, bool create_missing)
 {
     CanBusState *bus;
@@ -127,10 +129,15 @@ int can_bus_client_set_filters(CanBusClientState *client,
 
 int can_bus_connect_to_host_device(CanBusState *bus, const char *name)
 {
-    if (can_bus_connect_to_host_variant == NULL) {
+    if (can_bus_connect_to_host_fnc == NULL) {
         error_report("CAN bus connect to host device is not "
                      "supported on this system");
         exit(1);
     }
-    return can_bus_connect_to_host_variant(bus, name);
+    return can_bus_connect_to_host_fnc(bus, name);
+}
+
+void can_bus_set_connect_to_host(can_bus_connect_to_host_t connect_fnc)
+{
+    can_bus_connect_to_host_fnc = connect_fnc;
 }
diff --git a/hw/can/can_host_stub.c b/hw/can/can_host_stub.c
deleted file mode 100644
index 748d25f995..0000000000
--- a/hw/can/can_host_stub.c
+++ /dev/null
@@ -1,36 +0,0 @@
....
....
....
-
-
-int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
-        NULL;

diff --git a/include/can/can_emu.h b/include/can/can_emu.h
index 85237ee3c9..7f0705e49f 100644
--- a/include/can/can_emu.h
+++ b/include/can/can_emu.h
@@ -107,8 +107,9 @@ struct CanBusState {
     QTAILQ_ENTRY(CanBusState) next;
 };
 
-extern int (*can_bus_connect_to_host_variant)(CanBusState *bus,
-                                              const char *name);
+typedef int (*can_bus_connect_to_host_t)(CanBusState *bus, const char *name);
+
+void can_bus_set_connect_to_host(can_bus_connect_to_host_t connect_fnc);
 
 int can_bus_filter_match(struct qemu_can_filter *filter, qemu_canid_t can_id);
----------------------------------------------------------------

Best wishes,

Pavel

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-24 20:22     ` Pavel Pisa
@ 2018-01-24 21:41       ` Philippe Mathieu-Daudé
  2018-01-25  8:24         ` Pavel Pisa
  0 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-01-24 21:41 UTC (permalink / raw)
  To: Pavel Pisa
  Cc: qemu-devel, Marc-André Lureau, Paolo Bonzini, Marek Vasut,
	Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren, Oleksij Rempel,
	Konrad Frederic, Jan Kiszka

Hi Pavel,

On 01/24/2018 05:22 PM, Pavel Pisa wrote:
> Hello everybody,
> 
> On Tuesday 23 of January 2018 22:42:31 Pavel Pisa wrote:
>> When Linux specific object file is linked in then some local
>> function needs to be called before QOM instances population.
>> I know how to do that GCC specific/non-portable way
>>
>> static void __attribute__((constructor)) can_socketcan_setup_variant(void)
>> {
>>
>> }
>>
>> but I expect that something like
>>
>> module_init()
>>
>> in can_socketcan.c should be used.
> 
> 
> I have experimented with code changes to get rid of stub for
> non Linux systems. type_init() is used because it is more
> portable than constructor attribute.
> 
> I have seen that a few other type_init-s do more
> than simple sequence of type_register_static().
> Is it acceptable to use type_init for registration
> to CAN core by function call for now? Conversion simplifies
> makefiles and unnecessary stub file is removed.
> 
> But I would use attribute if that solution is preferred because
> it is allways present on Linux where SocketCAN is used anyway
> and it is used in other Qemu subsystems as well.

using stubs/monitor.c as a template for stubs/can_host_variant.c doesn't
work?

> 
> ----------------------------------------------------------------
> Solution with attribute
> 
> #ifdef TOOLCHAIN_SUPPORTS_ATTRIBUTE_CONSTRUCTOR
> static void __attribute__((constructor))
> can_bus_socketcan_setup(void)
> {
>     can_bus_set_connect_to_host(can_bus_connect_to_host_socketcan);
> }
> #endif
> 
> ----------------------------------------------------------------
> Solution with type_init
> branch https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci-socketcan-init
> 
> diff --git a/hw/can/can_socketcan.c b/hw/can/can_socketcan.c
> index 42099fb696..fb41853c2b 100644
> --- a/hw/can/can_socketcan.c
> +++ b/hw/can/can_socketcan.c
> @@ -309,5 +309,14 @@ static int can_bus_connect_to_host_socketcan(CanBusState *bus,
>      return 0;
>  }
>  
> -int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
> -        can_bus_connect_to_host_socketcan;
> +static void can_bus_socketcan_type_init(void)
> +{
> +    /*
> +     * There should be object registration when CanBusSocketcanConnectState
> +     * is converted into QOM object. Use for registration of host
> +     * can bus access for now.
> +     */
> +    can_bus_set_connect_to_host(can_bus_connect_to_host_socketcan);
> +}
> +
> +type_init(can_bus_socketcan_type_init);
> 
> 
> diff --git a/hw/can/Makefile.objs b/hw/can/Makefile.objs
> index 1ce9950de0..14c2369718 100644
> --- a/hw/can/Makefile.objs
> +++ b/hw/can/Makefile.objs
> @@ -2,11 +2,7 @@
>  
>  ifeq ($(CONFIG_CAN_BUS),y)
>  common-obj-y += can_core.o
> -ifeq ($(CONFIG_LINUX),y)
> -common-obj-y += can_socketcan.o
> -else
> -common-obj-y += can_host_stub.o
> -endif
> +common-obj-$(CONFIG_LINUX) += can_socketcan.o
>  common-obj-$(CONFIG_CAN_SJA1000) += can_sja1000.o
>  common-obj-$(CONFIG_CAN_PCI) += can_kvaser_pci.o
>  common-obj-$(CONFIG_CAN_PCI) += can_pcm3680_pci.o
> diff --git a/hw/can/can_core.c b/hw/can/can_core.c
> index 41c458c792..c14807b188 100644
> --- a/hw/can/can_core.c
> +++ b/hw/can/can_core.c
> @@ -34,6 +34,8 @@
>  static QTAILQ_HEAD(, CanBusState) can_buses =
>      QTAILQ_HEAD_INITIALIZER(can_buses);
>  
> +static can_bus_connect_to_host_t can_bus_connect_to_host_fnc;
> +
>  CanBusState *can_bus_find_by_name(const char *name, bool create_missing)
>  {
>      CanBusState *bus;
> @@ -127,10 +129,15 @@ int can_bus_client_set_filters(CanBusClientState *client,
>  
>  int can_bus_connect_to_host_device(CanBusState *bus, const char *name)
>  {
> -    if (can_bus_connect_to_host_variant == NULL) {
> +    if (can_bus_connect_to_host_fnc == NULL) {
>          error_report("CAN bus connect to host device is not "
>                       "supported on this system");
>          exit(1);
>      }
> -    return can_bus_connect_to_host_variant(bus, name);
> +    return can_bus_connect_to_host_fnc(bus, name);
> +}
> +
> +void can_bus_set_connect_to_host(can_bus_connect_to_host_t connect_fnc)
> +{
> +    can_bus_connect_to_host_fnc = connect_fnc;
>  }
> diff --git a/hw/can/can_host_stub.c b/hw/can/can_host_stub.c
> deleted file mode 100644
> index 748d25f995..0000000000
> --- a/hw/can/can_host_stub.c
> +++ /dev/null
> @@ -1,36 +0,0 @@
> ....
> ....
> ....
> -
> -
> -int (*can_bus_connect_to_host_variant)(CanBusState *bus, const char *name) =
> -        NULL;
> 
> diff --git a/include/can/can_emu.h b/include/can/can_emu.h
> index 85237ee3c9..7f0705e49f 100644
> --- a/include/can/can_emu.h
> +++ b/include/can/can_emu.h
> @@ -107,8 +107,9 @@ struct CanBusState {
>      QTAILQ_ENTRY(CanBusState) next;
>  };
>  
> -extern int (*can_bus_connect_to_host_variant)(CanBusState *bus,
> -                                              const char *name);
> +typedef int (*can_bus_connect_to_host_t)(CanBusState *bus, const char *name);
> +
> +void can_bus_set_connect_to_host(can_bus_connect_to_host_t connect_fnc);
>  
>  int can_bus_filter_match(struct qemu_can_filter *filter, qemu_canid_t can_id);
> ----------------------------------------------------------------
> 
> Best wishes,
> 
> Pavel
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-24 21:41       ` Philippe Mathieu-Daudé
@ 2018-01-25  8:24         ` Pavel Pisa
  2018-01-25 13:50           ` Deniz Eren
  0 siblings, 1 reply; 45+ messages in thread
From: Pavel Pisa @ 2018-01-25  8:24 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: qemu-devel, Marc-André Lureau, Paolo Bonzini, Marek Vasut,
	Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren, Oleksij Rempel,
	Konrad Frederic, Jan Kiszka

Hello Philippe,

On Wednesday 24 of January 2018 22:41:16 Philippe Mathieu-Daudé wrote:
> Hi Pavel,
> > I have seen that a few other type_init-s do more
> > than simple sequence of type_register_static().
> > Is it acceptable to use type_init for registration
> > to CAN core by function call for now? Conversion simplifies
> > makefiles and unnecessary stub file is removed.
> >
> > But I would use attribute if that solution is preferred because
> > it is allways present on Linux where SocketCAN is used anyway
> > and it is used in other Qemu subsystems as well.
>
> using stubs/monitor.c as a template for stubs/can_host_variant.c doesn't
> work?

If that is preferred then I implement the stub this way.
As for the location, can I add

  stub-obj-y += can_host_stub.o

into hw/can/Makefile.objs same as it is in crypto/Makefile.objs
to keep CAN stuff together at least for now or it should go
to stubs directory?

  stub-obj-$(CONFIG_CAN_BUS) += can_host_variant.o

As for connection to host, again I have weak preference
to keep it in hw/can to keep CAN related code together
but if you think that it should go t chardev, I would prepare
patch that way

  chardev/can-socketcan.c

As for the rest of the remarks

You are right that there is some code duplication
in the SJA1000 CAN PCI cards support but problem
is that KVASER single uses S5920 PCI local bus bridge
which requires additional BARs and additional bridge
specific interrupt enable support. There are more KVASER
variants which combine multiple SJA1000 in a single BAR.
pcm3680 and mioe3680 have different BAR structure,
each SJA1000 uses one BAR. The first uses I/O mapped
SJA1000 and another memory mapped with stride 4.
Yes, it all can be combined into one C file.
But it would require to to add more more fields
into CardX_PCIState structure and some mechanisms
and code to select right combination of the BARs,
handlers etc for each card. It all can be done,
but I am not sure if I find time for such changes now.
I expect to have time again in summer when my teaching
semester ends.
Another disadvantage is that if somebody else wants
to implement other card emulation then actual simple
can_kvaser_pci.c is easily readable. Code gets much
more complex with all variants selection logic and
we have already abandoned that simple PCI example
(can_pci.c) with dummy PCI ID which as been included
in the past.

If the code duplication is a problem for now then
I vote to include only can_kvaser_pci.c for now.
But Deniz Eren would be sad because he uses the
cards (which he has contributed) in his test environment.

Anyway, I would follow what is proposed.

Thanks for your review and time,

Pavel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-25  8:24         ` Pavel Pisa
@ 2018-01-25 13:50           ` Deniz Eren
  0 siblings, 0 replies; 45+ messages in thread
From: Deniz Eren @ 2018-01-25 13:50 UTC (permalink / raw)
  To: Pavel Pisa
  Cc: Philippe Mathieu-Daudé,
	qemu-devel, Marc-André Lureau, Paolo Bonzini, Marek Vasut,
	Oliver Hartkopp, Stefan Hajnoczi, Oleksij Rempel,
	Konrad Frederic, Jan Kiszka

Hi Pavel, Philippe,

I’m happy with whatever way is best for the project.

However I would personally think merging the different drivers into one C file would not be a very modular way of handling the problem. As you can see from the Advantech drivers for example, the card supplier end can pose difficult Bar allocation logic, which I would think is best isolated within the particular driver model C file. Trying to come up with mechanisms to handle these could prove difficult.

Also keep in mind there should be more driver support added in future, which could pose other driver model specific difficulties that are best isolated to their own C files.

Having said all that, there might be a nice way of merging them all generically which I fail to see currently.



Best regards,
Deniz

Sent from my iPhone

Deniz Eren
+61 400 307 762

> On 25 Jan 2018, at 7:24 pm, Pavel Pisa <pisa@cmp.felk.cvut.cz> wrote:
> 
> Hello Philippe,
> 
>> On Wednesday 24 of January 2018 22:41:16 Philippe Mathieu-Daudé wrote:
>> Hi Pavel,
>>> I have seen that a few other type_init-s do more
>>> than simple sequence of type_register_static().
>>> Is it acceptable to use type_init for registration
>>> to CAN core by function call for now? Conversion simplifies
>>> makefiles and unnecessary stub file is removed.
>>> 
>>> But I would use attribute if that solution is preferred because
>>> it is allways present on Linux where SocketCAN is used anyway
>>> and it is used in other Qemu subsystems as well.
>> 
>> using stubs/monitor.c as a template for stubs/can_host_variant.c doesn't
>> work?
> 
> If that is preferred then I implement the stub this way.
> As for the location, can I add
> 
>  stub-obj-y += can_host_stub.o
> 
> into hw/can/Makefile.objs same as it is in crypto/Makefile.objs
> to keep CAN stuff together at least for now or it should go
> to stubs directory?
> 
>  stub-obj-$(CONFIG_CAN_BUS) += can_host_variant.o
> 
> As for connection to host, again I have weak preference
> to keep it in hw/can to keep CAN related code together
> but if you think that it should go t chardev, I would prepare
> patch that way
> 
>  chardev/can-socketcan.c
> 
> As for the rest of the remarks
> 
> You are right that there is some code duplication
> in the SJA1000 CAN PCI cards support but problem
> is that KVASER single uses S5920 PCI local bus bridge
> which requires additional BARs and additional bridge
> specific interrupt enable support. There are more KVASER
> variants which combine multiple SJA1000 in a single BAR.
> pcm3680 and mioe3680 have different BAR structure,
> each SJA1000 uses one BAR. The first uses I/O mapped
> SJA1000 and another memory mapped with stride 4.
> Yes, it all can be combined into one C file.
> But it would require to to add more more fields
> into CardX_PCIState structure and some mechanisms
> and code to select right combination of the BARs,
> handlers etc for each card. It all can be done,
> but I am not sure if I find time for such changes now.
> I expect to have time again in summer when my teaching
> semester ends.
> Another disadvantage is that if somebody else wants
> to implement other card emulation then actual simple
> can_kvaser_pci.c is easily readable. Code gets much
> more complex with all variants selection logic and
> we have already abandoned that simple PCI example
> (can_pci.c) with dummy PCI ID which as been included
> in the past.
> 
> If the code duplication is a problem for now then
> I vote to include only can_kvaser_pci.c for now.
> But Deniz Eren would be sad because he uses the
> cards (which he has contributed) in his test environment.
> 
> Anyway, I would follow what is proposed.
> 
> Thanks for your review and time,
> 
> Pavel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-23 21:42   ` Pavel Pisa
  2018-01-24 20:22     ` Pavel Pisa
@ 2018-01-25 13:58     ` Paolo Bonzini
  2018-01-25 21:33       ` Pavel Pisa
  1 sibling, 1 reply; 45+ messages in thread
From: Paolo Bonzini @ 2018-01-25 13:58 UTC (permalink / raw)
  To: Pavel Pisa, Philippe Mathieu-Daudé
  Cc: Marek Vasut, Stefan Hajnoczi, Deniz Eren, qemu-devel,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka, Oliver Hartkopp,
	Marc-André Lureau

On 23/01/2018 22:42, Pavel Pisa wrote:
> Do you think QOM based? I would like it to be implemented
> that way but I need some assistance where to look how this
> object kind should be implemented and from which base object
> inherit from. But I prefer to left that for later work.
> 
> I would definitely like to use some mechanism which allows
> to get rid of externally visible pointer and need to assign
> it in the stub. It has been my initial idea and your review
> sumbled across this hack as well. But I need suggestion what
> is the preferred way for QEMU.

The best way would be a QOM object.  That is, you would do

   -object can-bus,id=canbus0
   -object can-host-socketcan,id=can0-host,canbus=canbus0,if=can0
   -device kvaser_pci,canbus=canbus0

In the current version, it's not clear to me:

* what it means if multiple controllers have the same canbus

* what it means if multiple controllers with the same canbus have
different host interfaces

Separating the QOM objects is a bit more work, but it makes the
semantics clearer.  The classes would be:

- can-bus and an abstract class can-host, which would inherit directly
from TYPE_OBJECT and implement TYPE_USER_CREATABLE

- can-host-socketcan, which would inherit from can-host (and take the
TYPE_USER_CREATABLE implementation from there)

while CanBusClientState and CanBusClientInfo need not be QOMified.

can-host's class structure would define a function pointer corresponding
to what you have now for the function pointer, more or less---except
that allocation is handled by QOM and the method only has to do the
connection.  You would have something like this:

static void can_host_disconnect(CANHost *ch, Error **errp)
{
    CANHostClass *chc = CAN_HOST_GET_CLASS(ch);

    chc->disconnect(ch);
}

static void can_host_connect(CANHost *ch, Error **errp)
{
    CANHostClass *chc = CAN_HOST_GET_CLASS(ch);
    Error *local_err = NULL;

    chc->connect(ch, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }

    can_bus_insert_client(ch->bus, &ch->bus_client, local_err);
    if (local_err) {
        can_host_disconnect(ch);
        error_propagate(errp, local_err);
        return;
    }
}

and TYPE_USER_CREATABLE's "complete" method would simply invoke
can_host_connect.  For can-host-socketcan, chc->connect would be
assigned something like this:

static void can_host_socketcan_connect(CANHost *ch, Error **errp)
{
    CANHostSocketCAN *chs = CAN_HOST_SOCKETCAN(ch);

    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (s < 0) {
        error_setg_errno(errp, errno "CAN_RAW socket create failed");
        return;
    }

    addr.can_family = AF_CAN;
    memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
    strcpy(ifr.ifr_name, chs->host_dev_name);
    if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
        error_setg_errno(errp, "host interface %s not available",
                         chs->host_dev_name);
        goto fail;
    }
    addr.can_ifindex = ifr.ifr_ifindex;
    ....
}

In particular, note the difference in error reporting with
error_report/exit vs. error_setg/error_propagate.  Any call to "exit" is
probably grounds for instant rejection of your patch. :)  This also
means that you have to check for leaks in the failure paths, such as
forgetting to close the PF_CAN socket.

Thanks,

Paolo

> When Linux specific object file is linked in then some local
> function needs to be called before QOM instances population.
> I know how to do that GCC specific/non-portable way
> 
> static void __attribute__((constructor)) can_socketcan_setup_variant(void)
> {
> 
> }
> 
> but I expect that something like
> 
> module_init()
> 
> in can_socketcan.c should be used.
> 
> Problem is that there is not module_init
> type for plain function in include/qemu/module.h
> 
>     MODULE_INIT_BLOCK,
>     MODULE_INIT_OPTS,
>     MODULE_INIT_QOM,
>     MODULE_INIT_TRACE,
>     MODULE_INIT_MAX
> 
> I expect that QOM object would solve that in future
> but I would be happy to left it simple for now.
> 
> What is preferred solution there?
> 
>> I'd still avoid using directly the socket() syscall and use the QEMU
>> socket API instead (also suggested by Daniel).
> 
> I have already switched to qemu_socket(), implementation
> looks fine and I have tested that it works.
> I have tested functionality and updated can-pci branch.
> 
>> I have been thinking a bit about how to test some frame operations
>> (rather than the PCI devices) and the Linux vcan driver might be a good
>> option (Virtual Local CAN Interface). This is also useful to test this
>> series without having CAN hardware. How to use vcan might be worth his
>> own paragraph in docs/can.txt.
>>
>> Do you think some of your tests can be added in the QEMU test suite
>> (qtests)?
> 
> I have added some more infomation into docs file
> 
> + The CAN interface of the host system has to be configured for proper
> + bitrate and set up. Configuration is not propagated from emulated
> + devices through bus to the physical host device. Example configuration
> + for 1 Mbit/s
> +
> +   ip link set can0 type can bitrate 1000000
> +   ip link set can0 up
> +
> + Virtual (host local only) can interface can be used on the host
> + side instead of physical interface
> +
> +   ip link add dev can0 type vcan
> +
> + The CAN interface on the host side can be used to analyze CAN
> + traffic with "candump" command which is included in "can-utils".
> +
> +   candump can0
> 
> As for the automatic testing, iproute2 tools are required
> on host and guest side (considering use of Linux)
> and kernel with CAN drivers support.
> Root access is required on the host side to setup CAN
> interface. Some simple tool is required. It can be based
> on can-utils code or our older canping code for example.
> 
> Best wishes,
> 
> Pavel
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-25 13:58     ` Paolo Bonzini
@ 2018-01-25 21:33       ` Pavel Pisa
  2018-01-26 11:12         ` Paolo Bonzini
  2018-01-30 14:15         ` Paolo Bonzini
  0 siblings, 2 replies; 45+ messages in thread
From: Pavel Pisa @ 2018-01-25 21:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Philippe Mathieu-Daudé,
	Marek Vasut, Stefan Hajnoczi, Deniz Eren, qemu-devel,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka, Oliver Hartkopp,
	Marc-André Lureau

Hello Paolo,

thanks for suggestions. I understand and fully agree with your
request to switch to QOM. I have succeed with that for CAN devices
some time ago. It worth to be done for the rest of the objects
but I fear that I do not find time to complete QOMification
in reasonable future. Contributions/suggestions from other
are welcomed. I can look for students for GSoC at our university
or under other funding.

On Thursday 25 of January 2018 14:58:41 Paolo Bonzini wrote:
> On 23/01/2018 22:42, Pavel Pisa wrote:
> > Do you think QOM based? I would like it to be implemented
> > that way but I need some assistance where to look how this
> > object kind should be implemented and from which base object
> > inherit from. But I prefer to left that for later work.
> >
> > I would definitely like to use some mechanism which allows
> > to get rid of externally visible pointer and need to assign
> > it in the stub. It has been my initial idea and your review
> > sumbled across this hack as well. But I need suggestion what
> > is the preferred way for QEMU.
>
> The best way would be a QOM object.  That is, you would do
>
>    -object can-bus,id=canbus0
>    -object can-host-socketcan,id=can0-host,canbus=canbus0,if=can0
>    -device kvaser_pci,canbus=canbus0

I would prefer to allow CAN emulation to be used without
explicit can-bus object creation specified on the command line.
The bus object could be created when requested by
can-host-socketcan or device (kvaser_pci) automatically.

When multiple QOM object are put on the list then the list content
should be preserved over save+restore (mostly hypothetical question
for now). There should be probably used some other construct instead
of

  QTAILQ_HEAD(, CanBusClientState) clients;
  QTAILQ_ENTRY(CanBusState) next;

> In the current version, it's not clear to me:
>
> * what it means if multiple controllers have the same canbus

That is fully supported and sane configuration.
CAN is publis/subscribe network in principle
so sending message from one controller to another
one on the host side is intended and can be used
to test drivers even if host connection is
not available/supported on given OS/setup.
Interconnection of multiple controllers with
host CAN bus is functional as well.

> * what it means if multiple controllers with the same canbus have
> different host interfaces

It is legitimate but probably not much usesfull/intended setup.
It would result is bridging two host CAN busses
together. It would work because SocketCAN does not
deliver message back to the socket which has been used to send
it by default. Connecting twice to the same SocketCAN bus
would lead to infinite message loop.

Connection of given can bus to the host twice can be prevented
if host connection flag is included in CanBusState and if it is
already set then next host connection attempt would be reported
as error.

> Separating the QOM objects is a bit more work, but it makes the
> semantics clearer.  The classes would be:
>
> - can-bus and an abstract class can-host, which would inherit directly
> from TYPE_OBJECT and implement TYPE_USER_CREATABLE
>
> - can-host-socketcan, which would inherit from can-host (and take the
> TYPE_USER_CREATABLE implementation from there)
>
> while CanBusClientState and CanBusClientInfo need not be QOMified.

May it be, can-host-socketcan can be based directly on TYPE_OBJECT,
because only QEMU CAN bus specific part is CanBusClientState which
allows it to connect to the CAN bus same way as other CAN controllers
connect to the bus.

> can-host's class structure would define a function pointer corresponding
> to what you have now for the function pointer, more or less---except
> that allocation is handled by QOM and the method only has to do the
> connection.  You would have something like this:
>
> static void can_host_disconnect(CANHost *ch, Error **errp)
> {
>     CANHostClass *chc = CAN_HOST_GET_CLASS(ch);
>
>     chc->disconnect(ch);
> }
>
> static void can_host_connect(CANHost *ch, Error **errp)
> {
>     CANHostClass *chc = CAN_HOST_GET_CLASS(ch);
>     Error *local_err = NULL;
>
>     chc->connect(ch, &local_err);
>     if (local_err) {
>         error_propagate(errp, local_err);
>         return;
>     }
>
>     can_bus_insert_client(ch->bus, &ch->bus_client, local_err);
>     if (local_err) {
>         can_host_disconnect(ch);
>         error_propagate(errp, local_err);
>         return;
>     }
> }
>
> and TYPE_USER_CREATABLE's "complete" method would simply invoke
> can_host_connect.  For can-host-socketcan, chc->connect would be
> assigned something like this:
>
> static void can_host_socketcan_connect(CANHost *ch, Error **errp)
> {
>     CANHostSocketCAN *chs = CAN_HOST_SOCKETCAN(ch);
>
>     s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
>     if (s < 0) {
>         error_setg_errno(errp, errno "CAN_RAW socket create failed");
>         return;
>     }
>
>     addr.can_family = AF_CAN;
>     memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
>     strcpy(ifr.ifr_name, chs->host_dev_name);
>     if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
>         error_setg_errno(errp, "host interface %s not available",
>                          chs->host_dev_name);
>         goto fail;
>     }
>     addr.can_ifindex = ifr.ifr_ifindex;
>     ....
> }

Thanks for providing ideas for future development directions.

> In particular, note the difference in error reporting with
> error_report/exit vs. error_setg/error_propagate.  Any call to "exit" is
> probably grounds for instant rejection of your patch. :)

It seems that it is necessary to switch to use realize()
method instead of init() to have initial **errp pointer
in the call chain.

> This also means that you have to check for leaks in the failure paths,
> such as  forgetting to close the PF_CAN socket.

The socket is closed in can_bus_socketcan_cleanup()
in the failure case. g_free(c->rfilter); is there
as well.

Thanks for ideas and review,

Pavel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-25 21:33       ` Pavel Pisa
@ 2018-01-26 11:12         ` Paolo Bonzini
  2018-01-28  9:02           ` Pavel Pisa
  2018-01-30 14:15         ` Paolo Bonzini
  1 sibling, 1 reply; 45+ messages in thread
From: Paolo Bonzini @ 2018-01-26 11:12 UTC (permalink / raw)
  To: Pavel Pisa
  Cc: Philippe Mathieu-Daudé,
	Marek Vasut, Stefan Hajnoczi, Deniz Eren, qemu-devel,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka, Oliver Hartkopp,
	Marc-André Lureau

On 25/01/2018 22:33, Pavel Pisa wrote:
> Hello Paolo,
> 
> thanks for suggestions. I understand and fully agree with your
> request to switch to QOM. I have succeed with that for CAN devices
> some time ago. It worth to be done for the rest of the objects
> but I fear that I do not find time to complete QOMification
> in reasonable future. Contributions/suggestions from other
> are welcomed. I can look for students for GSoC at our university
> or under other funding.

Coincidentially, I have some time on a flight next Monday. :)  I
obviously cannot really _test_ anything, but I can at least do the
changes below and set up all the QOM boilerplate.

> On Thursday 25 of January 2018 14:58:41 Paolo Bonzini wrote:
>> On 23/01/2018 22:42, Pavel Pisa wrote:
>>> Do you think QOM based? I would like it to be implemented
>>> that way but I need some assistance where to look how this
>>> object kind should be implemented and from which base object
>>> inherit from. But I prefer to left that for later work.
>>>
>>> I would definitely like to use some mechanism which allows
>>> to get rid of externally visible pointer and need to assign
>>> it in the stub. It has been my initial idea and your review
>>> sumbled across this hack as well. But I need suggestion what
>>> is the preferred way for QEMU.
>>
>> The best way would be a QOM object.  That is, you would do
>>
>>    -object can-bus,id=canbus0
>>    -object can-host-socketcan,id=can0-host,canbus=canbus0,if=can0
>>    -device kvaser_pci,canbus=canbus0
> 
> I would prefer to allow CAN emulation to be used without
> explicit can-bus object creation specified on the command line.
> The bus object could be created when requested by
> can-host-socketcan or device (kvaser_pci) automatically.

It could be fine to allow "-device kvaser_pci" to automatically create a
private bus.  However, IMO it's better to be explicit in the case where
multiple objects (e.g. can-host-socketcan and the kvaser_pci device, or
two controllers) want to connect to the same object.

>> Separating the QOM objects is a bit more work, but it makes the
>> semantics clearer.  The classes would be:
>>
>> - can-bus and an abstract class can-host, which would inherit directly
>> from TYPE_OBJECT and implement TYPE_USER_CREATABLE
>>
>> - can-host-socketcan, which would inherit from can-host (and take the
>> TYPE_USER_CREATABLE implementation from there)
>>
>> while CanBusClientState and CanBusClientInfo need not be QOMified.
> 
> May it be, can-host-socketcan can be based directly on TYPE_OBJECT,
> because only QEMU CAN bus specific part is CanBusClientState which
> allows it to connect to the CAN bus same way as other CAN controllers
> connect to the bus.

The abstract class "can-host" is useful to keep can-host-socketcan free
of things that are not specific to SocketCAN, but it's just a small detail.

Paolo

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-26 11:12         ` Paolo Bonzini
@ 2018-01-28  9:02           ` Pavel Pisa
  2018-01-29  7:43             ` Oleksij Rempel
  0 siblings, 1 reply; 45+ messages in thread
From: Pavel Pisa @ 2018-01-28  9:02 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Philippe Mathieu-Daudé,
	Marek Vasut, Stefan Hajnoczi, Deniz Eren, qemu-devel,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka, Oliver Hartkopp,
	Marc-André Lureau

Hello Paolo,

On Friday 26 of January 2018 12:12:32 Paolo Bonzini wrote:
> Coincidentially, I have some time on a flight next Monday. :)  I
> obviously cannot really _test_ anything, but I can at least do the
> changes below and set up all the QOM boilerplate.

thanks much for offer to help.

Deniz Eren or Oleksij Rempel can test your changes as well.

I have prepared branch "can-pci-qom" in GitLab repository

  https://gitlab.fel.cvut.cz/canbus/qemu-canbus

  https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci-qom

and I have updated all PCI devices to use realize() instead of init(),
eliminated all uses of exit() and changed error reporting to use
error_setg() and error_setg_errno(). So I think that there is
no fatal blocker in these files. Problematic is setup
of connect_to_host variant

 can_bus_set_connect_to_host(can_bus_connect_to_host_socketcan);

in "hw/can/can_socketcan.c" and location of this file
in HW. I keep it there to have all CAN support *.c
files in single place for now.

I have studied "tests/check-qom-proplist.c" for while
but I expect that you will be much more successfull
and efficient to define mainline acceptable object model.

Thanks again,

Pavel

> >> The best way would be a QOM object.  That is, you would do
> >>
> >>    -object can-bus,id=canbus0
> >>    -object can-host-socketcan,id=can0-host,canbus=canbus0,if=can0
> >>    -device kvaser_pci,canbus=canbus0
> >
> > I would prefer to allow CAN emulation to be used without
> > explicit can-bus object creation specified on the command line.
> > The bus object could be created when requested by
> > can-host-socketcan or device (kvaser_pci) automatically.
>
> It could be fine to allow "-device kvaser_pci" to automatically create a
> private bus.  However, IMO it's better to be explicit in the case where
> multiple objects (e.g. can-host-socketcan and the kvaser_pci device, or
> two controllers) want to connect to the same object.
>
> >> Separating the QOM objects is a bit more work, but it makes the
> >> semantics clearer.  The classes would be:
> >>
> >> - can-bus and an abstract class can-host, which would inherit directly
> >> from TYPE_OBJECT and implement TYPE_USER_CREATABLE
> >>
> >> - can-host-socketcan, which would inherit from can-host (and take the
> >> TYPE_USER_CREATABLE implementation from there)
> >>
> >> while CanBusClientState and CanBusClientInfo need not be QOMified.
> >
> > May it be, can-host-socketcan can be based directly on TYPE_OBJECT,
> > because only QEMU CAN bus specific part is CanBusClientState which
> > allows it to connect to the CAN bus same way as other CAN controllers
> > connect to the bus.
>
> The abstract class "can-host" is useful to keep can-host-socketcan free
> of things that are not specific to SocketCAN, but it's just a small detail.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-28  9:02           ` Pavel Pisa
@ 2018-01-29  7:43             ` Oleksij Rempel
  0 siblings, 0 replies; 45+ messages in thread
From: Oleksij Rempel @ 2018-01-29  7:43 UTC (permalink / raw)
  To: Pavel Pisa, Paolo Bonzini
  Cc: Philippe Mathieu-Daudé,
	Marek Vasut, Stefan Hajnoczi, Deniz Eren, qemu-devel,
	Konrad Frederic, Jan Kiszka, Oliver Hartkopp,
	Marc-André Lureau

Hi,

On 28.01.2018 10:02, Pavel Pisa wrote:
> Hello Paolo,
> 
> On Friday 26 of January 2018 12:12:32 Paolo Bonzini wrote:
>> Coincidentially, I have some time on a flight next Monday. :)  I
>> obviously cannot really _test_ anything, but I can at least do the
>> changes below and set up all the QOM boilerplate.
> 
> thanks much for offer to help.
> 
> Deniz Eren or Oleksij Rempel can test your changes as well.

just tell me wen and what should i test :)

> I have prepared branch "can-pci-qom" in GitLab repository
> 
>   https://gitlab.fel.cvut.cz/canbus/qemu-canbus
> 
>   https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci-qom
> 
> and I have updated all PCI devices to use realize() instead of init(),
> eliminated all uses of exit() and changed error reporting to use
> error_setg() and error_setg_errno(). So I think that there is
> no fatal blocker in these files. Problematic is setup
> of connect_to_host variant
> 
>  can_bus_set_connect_to_host(can_bus_connect_to_host_socketcan);
> 
> in "hw/can/can_socketcan.c" and location of this file
> in HW. I keep it there to have all CAN support *.c
> files in single place for now.
> 
> I have studied "tests/check-qom-proplist.c" for while
> but I expect that you will be much more successfull
> and efficient to define mainline acceptable object model.
> 
> Thanks again,
> 
> Pavel
> 
>>>> The best way would be a QOM object.  That is, you would do
>>>>
>>>>    -object can-bus,id=canbus0
>>>>    -object can-host-socketcan,id=can0-host,canbus=canbus0,if=can0
>>>>    -device kvaser_pci,canbus=canbus0
>>>
>>> I would prefer to allow CAN emulation to be used without
>>> explicit can-bus object creation specified on the command line.
>>> The bus object could be created when requested by
>>> can-host-socketcan or device (kvaser_pci) automatically.
>>
>> It could be fine to allow "-device kvaser_pci" to automatically create a
>> private bus.  However, IMO it's better to be explicit in the case where
>> multiple objects (e.g. can-host-socketcan and the kvaser_pci device, or
>> two controllers) want to connect to the same object.
>>
>>>> Separating the QOM objects is a bit more work, but it makes the
>>>> semantics clearer.  The classes would be:
>>>>
>>>> - can-bus and an abstract class can-host, which would inherit directly
>>>> from TYPE_OBJECT and implement TYPE_USER_CREATABLE
>>>>
>>>> - can-host-socketcan, which would inherit from can-host (and take the
>>>> TYPE_USER_CREATABLE implementation from there)
>>>>
>>>> while CanBusClientState and CanBusClientInfo need not be QOMified.
>>>
>>> May it be, can-host-socketcan can be based directly on TYPE_OBJECT,
>>> because only QEMU CAN bus specific part is CanBusClientState which
>>> allows it to connect to the CAN bus same way as other CAN controllers
>>> connect to the bus.
>>
>> The abstract class "can-host" is useful to keep can-host-socketcan free
>> of things that are not specific to SocketCAN, but it's just a small detail.
> 
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-25 21:33       ` Pavel Pisa
  2018-01-26 11:12         ` Paolo Bonzini
@ 2018-01-30 14:15         ` Paolo Bonzini
  2018-01-30 22:12           ` Pavel Pisa
  1 sibling, 1 reply; 45+ messages in thread
From: Paolo Bonzini @ 2018-01-30 14:15 UTC (permalink / raw)
  To: Pavel Pisa
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Philippe Mathieu-Daudé,
	qemu-devel, Oleksij Rempel, Konrad Frederic, Jan Kiszka,
	Marc-André Lureau

On 25/01/2018 22:33, Pavel Pisa wrote:
> Hello Paolo,
> 
> thanks for suggestions. I understand and fully agree with your
> request to switch to QOM. I have succeed with that for CAN devices
> some time ago. It worth to be done for the rest of the objects
> but I fear that I do not find time to complete QOMification
> in reasonable future. Contributions/suggestions from other
> are welcomed. I can look for students for GSoC at our university
> or under other funding.

Please take a look at branch can-pci-qom of github.com/bonzini/qemu.git.
 Apart from QOMification of the backend include, I simplified the IRQ
handling in can_kvaser_pci (fixing bugs too I think), and removed an
unnecessary mutex.  I also moved the files to net/can and hw/net/can so
that in the future Jason (networking maintainer) can take care of pull
requests.

I might have broken something, and the top commit in particular is
completely untested.

Paolo

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-30 14:15         ` Paolo Bonzini
@ 2018-01-30 22:12           ` Pavel Pisa
  2018-01-31  0:13             ` Deniz Eren
  0 siblings, 1 reply; 45+ messages in thread
From: Pavel Pisa @ 2018-01-30 22:12 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Philippe Mathieu-Daudé,
	qemu-devel, Oleksij Rempel, Konrad Frederic, Jan Kiszka,
	Marc-André Lureau

Hello Paolo,

thanks much for conversion to acceptable QOM model.

On Tuesday 30 of January 2018 15:15:22 Paolo Bonzini wrote:
> On 25/01/2018 22:33, Pavel Pisa wrote:
> > Hello Paolo,
> >
> > thanks for suggestions. I understand and fully agree with your
> > request to switch to QOM. I have succeed with that for CAN devices
> > some time ago. It worth to be done for the rest of the objects
> > but I fear that I do not find time to complete QOMification
> > in reasonable future. Contributions/suggestions from other
> > are welcomed. I can look for students for GSoC at our university
> > or under other funding.
>
> Please take a look at branch can-pci-qom of github.com/bonzini/qemu.git.
>  Apart from QOMification of the backend include, I simplified the IRQ
> handling in can_kvaser_pci (fixing bugs too I think), and removed an
> unnecessary mutex.  I also moved the files to net/can and hw/net/can so
> that in the future Jason (networking maintainer) can take care of pull
> requests.
>
> I might have broken something, and the top commit in particular is
> completely untested.

I have run basic test with Linux kernel on both sides
for one kavser_pci card on guest side and vcan (no real interface)
on host side.

Mesages exchange tests passed and looks OK.

I have used next parameters

      -object can-bus,id=canbus0 \
      -device kvaser_pci,canbus=canbus0 \
      -object can-host-socketcan,if=can0,canbus=canbus0,id=canbus0-socketcan

The id parameter is required for "can-host-socketcan" object.
Else next error is printed

  qemu-system-x86_64: -object can-host-socketcan,if=can0,canbus=canbus0: Parameter 'id' is missing

If "-object can-bus,id=canbus0" is missing then next error is reported

  qemu-system-x86_64: -object can-host-socketcan,if=can0,canbus=canbus0,id=canbus0-socketcan: Device 'canbus0' not found

I have inspected through monitor the state of objects

  (qemu) qom-list /objects
  canbus0-socketcan (child<can-host-socketcan>)
  type (string)
  canbus0 (child<can-bus>)

  (qemu) info qom-tree
  /machine (pc-i440fx-2.12-machine)
    ...
    /peripheral-anon (container)
      /device[1] (kvaser_pci)
        /bus master[0] (qemu:memory-region)
        /kvaser_pci-xilinx[0] (qemu:memory-region)
        /kvaser_pci-s5920[0] (qemu:memory-region)
        /kvaser_pci-sja[0] (qemu:memory-region)
        /bus master container[0] (qemu:memory-region)
    ...


  (qemu) qom-list /objects
  canbus0-socketcan (child<can-host-socketcan>)
  type (string)
  canbus0 (child<can-bus>)

  (qemu) qom-list /machine/peripheral-anon/device[1]
  bus master container[0] (child<qemu:memory-region>)
  canbus (link<can-bus>)
  rombar (uint32)
  hotpluggable (bool)
  x-pcie-lnksta-dllla (bool)
  kvaser_pci-sja[0] (child<qemu:memory-region>)
  multifunction (bool)
  hotplugged (bool)
  parent_bus (link<bus>)
  romfile (str)
  kvaser_pci-s5920[0] (child<qemu:memory-region>)
  x-pcie-extcap-init (bool)
  command_serr_enable (bool)
  addr (int32)
  type (string)
  legacy-addr (str)
  kvaser_pci-xilinx[0] (child<qemu:memory-region>)
  realized (bool)
  bus master[0] (child<qemu:memory-region>)

From the user point of view, it would be nice if "can-bus"
can be populated when required automatically.

I am not sure, but may it be that it would worth to
push can-bus objects under some category/specific
container. The path /objects is quite wide.
Into something like /object/can-bus or /net/can.

But generally thanks much, the progress you have made
in one day is really great. I hope that others check
your branch. I have pushed your unmodified version into
"can-pci-qom" branch of my repo

  https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci-qom

It would be great if others can check that everything
works in their setup. I think that then it can be pushed
into mainline and some usability improvements can be
done/experiment with later.

Thanks much,


                Pavel Pisa

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-30 22:12           ` Pavel Pisa
@ 2018-01-31  0:13             ` Deniz Eren
  2018-01-31  1:08               ` Paolo Bonzini
  0 siblings, 1 reply; 45+ messages in thread
From: Deniz Eren @ 2018-01-31  0:13 UTC (permalink / raw)
  To: Pavel Pisa
  Cc: Paolo Bonzini, Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi,
	Philippe Mathieu-Daudé,
	qemu-devel, Oleksij Rempel, Konrad Frederic, Jan Kiszka,
	Marc-André Lureau

Hi Pavel, Paolo,

I tried to rerun my environment to test however it seems the interface has changed a little and my standard program options cause complaints. Unfortunately I don’t have too much time to dig through at the moment.

My standard startup command is:

$ ./qemu-local/bin/qemu-system-i386 -hda sdd2gb-uno1483-16.04-2.0-dev.img -boot d -k en-us -device mioe3680_pci,canbus1=canbus0,host1=vcan0,canbus2=canbus1,host2=vcan1 -m size=2048 -netdev user,id=user.0 -device e1000,netdev=user.0 -redir tcp:5022::22 -enable-kvm &



Best regards,
Deniz

Sent from my iPhone

Deniz Eren
+61 400 307 762

> On 31 Jan 2018, at 9:12 am, Pavel Pisa <pisa@cmp.felk.cvut.cz> wrote:
> 
> Hello Paolo,
> 
> thanks much for conversion to acceptable QOM model.
> 
>> On Tuesday 30 of January 2018 15:15:22 Paolo Bonzini wrote:
>>> On 25/01/2018 22:33, Pavel Pisa wrote:
>>> Hello Paolo,
>>> 
>>> thanks for suggestions. I understand and fully agree with your
>>> request to switch to QOM. I have succeed with that for CAN devices
>>> some time ago. It worth to be done for the rest of the objects
>>> but I fear that I do not find time to complete QOMification
>>> in reasonable future. Contributions/suggestions from other
>>> are welcomed. I can look for students for GSoC at our university
>>> or under other funding.
>> 
>> Please take a look at branch can-pci-qom of github.com/bonzini/qemu.git.
>> Apart from QOMification of the backend include, I simplified the IRQ
>> handling in can_kvaser_pci (fixing bugs too I think), and removed an
>> unnecessary mutex.  I also moved the files to net/can and hw/net/can so
>> that in the future Jason (networking maintainer) can take care of pull
>> requests.
>> 
>> I might have broken something, and the top commit in particular is
>> completely untested.
> 
> I have run basic test with Linux kernel on both sides
> for one kavser_pci card on guest side and vcan (no real interface)
> on host side.
> 
> Mesages exchange tests passed and looks OK.
> 
> I have used next parameters
> 
>      -object can-bus,id=canbus0 \
>      -device kvaser_pci,canbus=canbus0 \
>      -object can-host-socketcan,if=can0,canbus=canbus0,id=canbus0-socketcan
> 
> The id parameter is required for "can-host-socketcan" object.
> Else next error is printed
> 
>  qemu-system-x86_64: -object can-host-socketcan,if=can0,canbus=canbus0: Parameter 'id' is missing
> 
> If "-object can-bus,id=canbus0" is missing then next error is reported
> 
>  qemu-system-x86_64: -object can-host-socketcan,if=can0,canbus=canbus0,id=canbus0-socketcan: Device 'canbus0' not found
> 
> I have inspected through monitor the state of objects
> 
>  (qemu) qom-list /objects
>  canbus0-socketcan (child<can-host-socketcan>)
>  type (string)
>  canbus0 (child<can-bus>)
> 
>  (qemu) info qom-tree
>  /machine (pc-i440fx-2.12-machine)
>    ...
>    /peripheral-anon (container)
>      /device[1] (kvaser_pci)
>        /bus master[0] (qemu:memory-region)
>        /kvaser_pci-xilinx[0] (qemu:memory-region)
>        /kvaser_pci-s5920[0] (qemu:memory-region)
>        /kvaser_pci-sja[0] (qemu:memory-region)
>        /bus master container[0] (qemu:memory-region)
>    ...
> 
> 
>  (qemu) qom-list /objects
>  canbus0-socketcan (child<can-host-socketcan>)
>  type (string)
>  canbus0 (child<can-bus>)
> 
>  (qemu) qom-list /machine/peripheral-anon/device[1]
>  bus master container[0] (child<qemu:memory-region>)
>  canbus (link<can-bus>)
>  rombar (uint32)
>  hotpluggable (bool)
>  x-pcie-lnksta-dllla (bool)
>  kvaser_pci-sja[0] (child<qemu:memory-region>)
>  multifunction (bool)
>  hotplugged (bool)
>  parent_bus (link<bus>)
>  romfile (str)
>  kvaser_pci-s5920[0] (child<qemu:memory-region>)
>  x-pcie-extcap-init (bool)
>  command_serr_enable (bool)
>  addr (int32)
>  type (string)
>  legacy-addr (str)
>  kvaser_pci-xilinx[0] (child<qemu:memory-region>)
>  realized (bool)
>  bus master[0] (child<qemu:memory-region>)
> 
> From the user point of view, it would be nice if "can-bus"
> can be populated when required automatically.
> 
> I am not sure, but may it be that it would worth to
> push can-bus objects under some category/specific
> container. The path /objects is quite wide.
> Into something like /object/can-bus or /net/can.
> 
> But generally thanks much, the progress you have made
> in one day is really great. I hope that others check
> your branch. I have pushed your unmodified version into
> "can-pci-qom" branch of my repo
> 
>  https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci-qom
> 
> It would be great if others can check that everything
> works in their setup. I think that then it can be pushed
> into mainline and some usability improvements can be
> done/experiment with later.
> 
> Thanks much,
> 
> 
>                Pavel Pisa

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-31  0:13             ` Deniz Eren
@ 2018-01-31  1:08               ` Paolo Bonzini
  2018-01-31  1:10                 ` Paolo Bonzini
  0 siblings, 1 reply; 45+ messages in thread
From: Paolo Bonzini @ 2018-01-31  1:08 UTC (permalink / raw)
  To: Deniz Eren, Pavel Pisa
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi,
	Philippe Mathieu-Daudé,
	qemu-devel, Oleksij Rempel, Konrad Frederic, Jan Kiszka,
	Marc-André Lureau

On 30/01/2018 19:13, Deniz Eren wrote:
> Hi Pavel, Paolo,
> 
> I tried to rerun my environment to test however it seems the interface has changed a little and my standard program options cause complaints. Unfortunately I don’t have too much time to dig through at the moment.
> 
> My standard startup command is:
> 
> $ ./qemu-local/bin/qemu-system-i386 -hda sdd2gb-uno1483-16.04-2.0-dev.img -boot d -k en-us -device mioe3680_pci,canbus1=canbus0,host1=vcan0,canbus2=canbus1,host2=vcan1 -m size=2048 -netdev user,id=user.0 -device e1000,netdev=user.0 -redir tcp:5022::22 -enable-kvm &

Yep, it's now like this:

./qemu-local/bin/qemu-system-i386 \
  -hda sdd2gb-uno1483-16.04-2.0-dev.img -boot d -k en-us \
  -object can-bus,id=canbus0 \
  -object can-bus,id=canbus1 \
  -object can-host-socketcan,id=canhost0,canbus=canbus0,ifname=vcan0 \
  -object can-host-socketcan,id=canhost1,canbus=canbus1,ifname=vcan1 \
  -device mioe3680_pci,canbus0=canbus0,canbus1=canbus1 \
  -m size=2048 -netdev user,id=user.0 -device e1000,netdev=user.0 \
  -redir tcp:5022::22 -enable-kvm

Thanks,

Paolo

> 
> 
> 
> Best regards,
> Deniz
> 
> Sent from my iPhone
> 
> Deniz Eren
> +61 400 307 762
> 
>> On 31 Jan 2018, at 9:12 am, Pavel Pisa <pisa@cmp.felk.cvut.cz> wrote:
>>
>> Hello Paolo,
>>
>> thanks much for conversion to acceptable QOM model.
>>
>>> On Tuesday 30 of January 2018 15:15:22 Paolo Bonzini wrote:
>>>> On 25/01/2018 22:33, Pavel Pisa wrote:
>>>> Hello Paolo,
>>>>
>>>> thanks for suggestions. I understand and fully agree with your
>>>> request to switch to QOM. I have succeed with that for CAN devices
>>>> some time ago. It worth to be done for the rest of the objects
>>>> but I fear that I do not find time to complete QOMification
>>>> in reasonable future. Contributions/suggestions from other
>>>> are welcomed. I can look for students for GSoC at our university
>>>> or under other funding.
>>>
>>> Please take a look at branch can-pci-qom of github.com/bonzini/qemu.git.
>>> Apart from QOMification of the backend include, I simplified the IRQ
>>> handling in can_kvaser_pci (fixing bugs too I think), and removed an
>>> unnecessary mutex.  I also moved the files to net/can and hw/net/can so
>>> that in the future Jason (networking maintainer) can take care of pull
>>> requests.
>>>
>>> I might have broken something, and the top commit in particular is
>>> completely untested.
>>
>> I have run basic test with Linux kernel on both sides
>> for one kavser_pci card on guest side and vcan (no real interface)
>> on host side.
>>
>> Mesages exchange tests passed and looks OK.
>>
>> I have used next parameters
>>
>>      -object can-bus,id=canbus0 \
>>      -device kvaser_pci,canbus=canbus0 \
>>      -object can-host-socketcan,if=can0,canbus=canbus0,id=canbus0-socketcan
>>
>> The id parameter is required for "can-host-socketcan" object.
>> Else next error is printed
>>
>>  qemu-system-x86_64: -object can-host-socketcan,if=can0,canbus=canbus0: Parameter 'id' is missing
>>
>> If "-object can-bus,id=canbus0" is missing then next error is reported
>>
>>  qemu-system-x86_64: -object can-host-socketcan,if=can0,canbus=canbus0,id=canbus0-socketcan: Device 'canbus0' not found
>>
>> I have inspected through monitor the state of objects
>>
>>  (qemu) qom-list /objects
>>  canbus0-socketcan (child<can-host-socketcan>)
>>  type (string)
>>  canbus0 (child<can-bus>)
>>
>>  (qemu) info qom-tree
>>  /machine (pc-i440fx-2.12-machine)
>>    ...
>>    /peripheral-anon (container)
>>      /device[1] (kvaser_pci)
>>        /bus master[0] (qemu:memory-region)
>>        /kvaser_pci-xilinx[0] (qemu:memory-region)
>>        /kvaser_pci-s5920[0] (qemu:memory-region)
>>        /kvaser_pci-sja[0] (qemu:memory-region)
>>        /bus master container[0] (qemu:memory-region)
>>    ...
>>
>>
>>  (qemu) qom-list /objects
>>  canbus0-socketcan (child<can-host-socketcan>)
>>  type (string)
>>  canbus0 (child<can-bus>)
>>
>>  (qemu) qom-list /machine/peripheral-anon/device[1]
>>  bus master container[0] (child<qemu:memory-region>)
>>  canbus (link<can-bus>)
>>  rombar (uint32)
>>  hotpluggable (bool)
>>  x-pcie-lnksta-dllla (bool)
>>  kvaser_pci-sja[0] (child<qemu:memory-region>)
>>  multifunction (bool)
>>  hotplugged (bool)
>>  parent_bus (link<bus>)
>>  romfile (str)
>>  kvaser_pci-s5920[0] (child<qemu:memory-region>)
>>  x-pcie-extcap-init (bool)
>>  command_serr_enable (bool)
>>  addr (int32)
>>  type (string)
>>  legacy-addr (str)
>>  kvaser_pci-xilinx[0] (child<qemu:memory-region>)
>>  realized (bool)
>>  bus master[0] (child<qemu:memory-region>)
>>
>> From the user point of view, it would be nice if "can-bus"
>> can be populated when required automatically.
>>
>> I am not sure, but may it be that it would worth to
>> push can-bus objects under some category/specific
>> container. The path /objects is quite wide.
>> Into something like /object/can-bus or /net/can.
>>
>> But generally thanks much, the progress you have made
>> in one day is really great. I hope that others check
>> your branch. I have pushed your unmodified version into
>> "can-pci-qom" branch of my repo
>>
>>  https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci-qom
>>
>> It would be great if others can check that everything
>> works in their setup. I think that then it can be pushed
>> into mainline and some usability improvements can be
>> done/experiment with later.
>>
>> Thanks much,
>>
>>
>>                Pavel Pisa

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
  2018-01-31  1:08               ` Paolo Bonzini
@ 2018-01-31  1:10                 ` Paolo Bonzini
  0 siblings, 0 replies; 45+ messages in thread
From: Paolo Bonzini @ 2018-01-31  1:10 UTC (permalink / raw)
  To: Deniz Eren, Pavel Pisa
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi,
	Philippe Mathieu-Daudé,
	qemu-devel, Oleksij Rempel, Konrad Frederic, Jan Kiszka,
	Marc-André Lureau

On 30/01/2018 20:08, Paolo Bonzini wrote:
> On 30/01/2018 19:13, Deniz Eren wrote:
>> Hi Pavel, Paolo,
>>
>> I tried to rerun my environment to test however it seems the interface has changed a little and my standard program options cause complaints. Unfortunately I don’t have too much time to dig through at the moment.
>>
>> My standard startup command is:
>>
>> $ ./qemu-local/bin/qemu-system-i386 -hda sdd2gb-uno1483-16.04-2.0-dev.img -boot d -k en-us -device mioe3680_pci,canbus1=canbus0,host1=vcan0,canbus2=canbus1,host2=vcan1 -m size=2048 -netdev user,id=user.0 -device e1000,netdev=user.0 -redir tcp:5022::22 -enable-kvm &
> 
> Yep, it's now like this:
> 
> ./qemu-local/bin/qemu-system-i386 \
>   -hda sdd2gb-uno1483-16.04-2.0-dev.img -boot d -k en-us \
>   -object can-bus,id=canbus0 \
>   -object can-bus,id=canbus1 \
>   -object can-host-socketcan,id=canhost0,canbus=canbus0,ifname=vcan0 \
>   -object can-host-socketcan,id=canhost1,canbus=canbus1,ifname=vcan1 \
>   -device mioe3680_pci,canbus0=canbus0,canbus1=canbus1 \
>   -m size=2048 -netdev user,id=user.0 -device e1000,netdev=user.0 \
>   -redir tcp:5022::22 -enable-kvm

Sorry, all "ifname" are "if".

Paolo

> Thanks,
> 
> Paolo
> 
>>
>>
>>
>> Best regards,
>> Deniz
>>
>> Sent from my iPhone
>>
>> Deniz Eren
>> +61 400 307 762
>>
>>> On 31 Jan 2018, at 9:12 am, Pavel Pisa <pisa@cmp.felk.cvut.cz> wrote:
>>>
>>> Hello Paolo,
>>>
>>> thanks much for conversion to acceptable QOM model.
>>>
>>>> On Tuesday 30 of January 2018 15:15:22 Paolo Bonzini wrote:
>>>>> On 25/01/2018 22:33, Pavel Pisa wrote:
>>>>> Hello Paolo,
>>>>>
>>>>> thanks for suggestions. I understand and fully agree with your
>>>>> request to switch to QOM. I have succeed with that for CAN devices
>>>>> some time ago. It worth to be done for the rest of the objects
>>>>> but I fear that I do not find time to complete QOMification
>>>>> in reasonable future. Contributions/suggestions from other
>>>>> are welcomed. I can look for students for GSoC at our university
>>>>> or under other funding.
>>>>
>>>> Please take a look at branch can-pci-qom of github.com/bonzini/qemu.git.
>>>> Apart from QOMification of the backend include, I simplified the IRQ
>>>> handling in can_kvaser_pci (fixing bugs too I think), and removed an
>>>> unnecessary mutex.  I also moved the files to net/can and hw/net/can so
>>>> that in the future Jason (networking maintainer) can take care of pull
>>>> requests.
>>>>
>>>> I might have broken something, and the top commit in particular is
>>>> completely untested.
>>>
>>> I have run basic test with Linux kernel on both sides
>>> for one kavser_pci card on guest side and vcan (no real interface)
>>> on host side.
>>>
>>> Mesages exchange tests passed and looks OK.
>>>
>>> I have used next parameters
>>>
>>>      -object can-bus,id=canbus0 \
>>>      -device kvaser_pci,canbus=canbus0 \
>>>      -object can-host-socketcan,if=can0,canbus=canbus0,id=canbus0-socketcan
>>>
>>> The id parameter is required for "can-host-socketcan" object.
>>> Else next error is printed
>>>
>>>  qemu-system-x86_64: -object can-host-socketcan,if=can0,canbus=canbus0: Parameter 'id' is missing
>>>
>>> If "-object can-bus,id=canbus0" is missing then next error is reported
>>>
>>>  qemu-system-x86_64: -object can-host-socketcan,if=can0,canbus=canbus0,id=canbus0-socketcan: Device 'canbus0' not found
>>>
>>> I have inspected through monitor the state of objects
>>>
>>>  (qemu) qom-list /objects
>>>  canbus0-socketcan (child<can-host-socketcan>)
>>>  type (string)
>>>  canbus0 (child<can-bus>)
>>>
>>>  (qemu) info qom-tree
>>>  /machine (pc-i440fx-2.12-machine)
>>>    ...
>>>    /peripheral-anon (container)
>>>      /device[1] (kvaser_pci)
>>>        /bus master[0] (qemu:memory-region)
>>>        /kvaser_pci-xilinx[0] (qemu:memory-region)
>>>        /kvaser_pci-s5920[0] (qemu:memory-region)
>>>        /kvaser_pci-sja[0] (qemu:memory-region)
>>>        /bus master container[0] (qemu:memory-region)
>>>    ...
>>>
>>>
>>>  (qemu) qom-list /objects
>>>  canbus0-socketcan (child<can-host-socketcan>)
>>>  type (string)
>>>  canbus0 (child<can-bus>)
>>>
>>>  (qemu) qom-list /machine/peripheral-anon/device[1]
>>>  bus master container[0] (child<qemu:memory-region>)
>>>  canbus (link<can-bus>)
>>>  rombar (uint32)
>>>  hotpluggable (bool)
>>>  x-pcie-lnksta-dllla (bool)
>>>  kvaser_pci-sja[0] (child<qemu:memory-region>)
>>>  multifunction (bool)
>>>  hotplugged (bool)
>>>  parent_bus (link<bus>)
>>>  romfile (str)
>>>  kvaser_pci-s5920[0] (child<qemu:memory-region>)
>>>  x-pcie-extcap-init (bool)
>>>  command_serr_enable (bool)
>>>  addr (int32)
>>>  type (string)
>>>  legacy-addr (str)
>>>  kvaser_pci-xilinx[0] (child<qemu:memory-region>)
>>>  realized (bool)
>>>  bus master[0] (child<qemu:memory-region>)
>>>
>>> From the user point of view, it would be nice if "can-bus"
>>> can be populated when required automatically.
>>>
>>> I am not sure, but may it be that it would worth to
>>> push can-bus objects under some category/specific
>>> container. The path /objects is quite wide.
>>> Into something like /object/can-bus or /net/can.
>>>
>>> But generally thanks much, the progress you have made
>>> in one day is really great. I hope that others check
>>> your branch. I have pushed your unmodified version into
>>> "can-pci-qom" branch of my repo
>>>
>>>  https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci-qom
>>>
>>> It would be great if others can check that everything
>>> works in their setup. I think that then it can be pushed
>>> into mainline and some usability improvements can be
>>> done/experiment with later.
>>>
>>> Thanks much,
>>>
>>>
>>>                Pavel Pisa
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
  2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added pisa
  2018-01-15  3:09   ` Philippe Mathieu-Daudé
@ 2018-03-06 15:29   ` Thomas Huth
  2018-03-06 20:52     ` Pavel Pisa
  1 sibling, 1 reply; 45+ messages in thread
From: Thomas Huth @ 2018-03-06 15:29 UTC (permalink / raw)
  To: pisa, qemu-devel
  Cc: Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi, Deniz Eren,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka, Paolo Bonzini

On 14.01.2018 21:14, pisa@cmp.felk.cvut.cz wrote:
> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> 
> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> ---
>  default-configs/pci.mak |   1 +
>  hw/can/Makefile.objs    |   1 +
>  hw/can/can_kvaser_pci.c | 375 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 377 insertions(+)
>  create mode 100644 hw/can/can_kvaser_pci.c

 Hi,

the kvaser_pci device introduced a new way to crash QEMU, e.g.:

mips64el-softmmu/qemu-system-mips64el -M malta,accel=qtest \
                                      -device kvaser_pci

Program received signal SIGSEGV, Segmentation fault.
0x0000555555a6e2ec in can_bus_insert_client (bus=0x0, client=client@entry=0x5555570c4018)
    at /home/thuth/devel/qemu/net/can/can_core.c:50
50	    QTAILQ_INSERT_TAIL(&bus->clients, client, next);
(gdb) bt
#0  0x0000555555a6e2ec in can_bus_insert_client (bus=0x0, client=client@entry=0x5555570c4018)
    at /home/thuth/devel/qemu/net/can/can_core.c:50
#1  0x00005555559d7364 in can_sja_connect_to_bus (s=s@entry=0x5555570c3f80, bus=<optimized out>)
    at /home/thuth/devel/qemu/hw/net/can/can_sja1000.c:869
#2  0x00005555559d75a4 in kvaser_pci_realize (pci_dev=0x5555570c33d0, errp=0x7fffffffd8e0)
    at /home/thuth/devel/qemu/hw/net/can/can_kvaser_pci.c:230
#3  0x00005555559e12f1 in pci_qdev_realize (qdev=0x5555570c33d0, errp=0x7fffffffd980)
    at /home/thuth/devel/qemu/hw/pci/pci.c:2029
#4  0x0000555555963c3a in device_set_realized (obj=<optimized out>, value=<optimized out>, errp=0x7fffffffdab8)
    at /home/thuth/devel/qemu/hw/core/qdev.c:852
#5  0x0000555555aa7a7e in property_set_bool (obj=0x5555570c33d0, v=<optimized out>, name=<optimized out>, opaque=0x555556f6d220, errp=0x7fffffffdab8) at /home/thuth/devel/qemu/qom/object.c:1906
#6  0x0000555555aabbef in object_property_set_qobject (obj=obj@entry=0x5555570c33d0, value=value@entry=0x5555570c4a60, name=name@entry=0x555555c7079f "realized", errp=errp@entry=0x7fffffffdab8)
    at /home/thuth/devel/qemu/qom/qom-qobject.c:27
#7  0x0000555555aa9860 in object_property_set_bool (obj=0x5555570c33d0, value=<optimized out>, name=0x555555c7079f "realized", errp=0x7fffffffdab8) at /home/thuth/devel/qemu/qom/object.c:1171
#8  0x00005555558eb1d9 in qdev_device_add (opts=0x55555689ff40, errp=errp@entry=0x7fffffffdb90)
    at /home/thuth/devel/qemu/qdev-monitor.c:634
#9  0x00005555558ed547 in device_init_func (opaque=<optimized out>, opts=<optimized out>, errp=<optimized out>)
    at /home/thuth/devel/qemu/vl.c:2350
#10 0x0000555555b8d75a in qemu_opts_foreach (list=<optimized out>, func=func@entry=
    0x5555558ed520 <device_init_func>, opaque=opaque@entry=0x0, errp=errp@entry=0x0)
    at /home/thuth/devel/qemu/util/qemu-option.c:1073
#11 0x00005555557b8f64 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>)
    at /home/thuth/devel/qemu/vl.c:4618

Could you please fix this?

 Thanks,
  Thomas

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
  2018-03-06 15:29   ` Thomas Huth
@ 2018-03-06 20:52     ` Pavel Pisa
  2018-03-07 11:40       ` Paolo Bonzini
  0 siblings, 1 reply; 45+ messages in thread
From: Pavel Pisa @ 2018-03-06 20:52 UTC (permalink / raw)
  To: Thomas Huth, Deniz Eren, Paolo Bonzini
  Cc: qemu-devel, Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

Hello Thomas,

thanks for report but I at this time I am and
can be some time in condition which does not allow
me to access e-mail and normal work

On Tuesday 06 of March 2018 16:29:19 Thomas Huth wrote:
> On 14.01.2018 21:14, pisa@cmp.felk.cvut.cz wrote:
> > From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> >
> > Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
> > ---
> >  default-configs/pci.mak |   1 +
> >  hw/can/Makefile.objs    |   1 +
> >  hw/can/can_kvaser_pci.c | 375
> > ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 377
> > insertions(+)
> >  create mode 100644 hw/can/can_kvaser_pci.c
>
>  Hi,
>
> the kvaser_pci device introduced a new way to crash QEMU, e.g.:
>
> mips64el-softmmu/qemu-system-mips64el -M malta,accel=qtest \
>                                       -device kvaser_pci
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x0000555555a6e2ec in can_bus_insert_client (bus=0x0,
> client=client@entry=0x5555570c4018) at
> /home/thuth/devel/qemu/net/can/can_core.c:50
> 50	    QTAILQ_INSERT_TAIL(&bus->clients, client, next);

The reason is that parameters canbus0 and canbus1 are required.

  -object can-bus,id=canbus0 \
  -device kvaser_pci,canbus0=canbus0

This could be be fast fix but plead somebody else to send regular
patch.

--- a/net/can/can_host.c
+++ b/net/can/can_host.c
@@ -57,6 +57,10 @@ static void can_host_connect(CanHostState *ch, Error **errp)
         return;
     }

+    if (ch->bus_client == NULL) {
+        error_setg(errp, "bus is not specified for given device.");
+        return;
+    }
     can_bus_insert_client(ch->bus, &ch->bus_client);
 }


My personal opinion is to create bus on 

Best wishes,

Pavel Pisa

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added.
  2018-03-06 20:52     ` Pavel Pisa
@ 2018-03-07 11:40       ` Paolo Bonzini
  0 siblings, 0 replies; 45+ messages in thread
From: Paolo Bonzini @ 2018-03-07 11:40 UTC (permalink / raw)
  To: Pavel Pisa, Thomas Huth, Deniz Eren
  Cc: qemu-devel, Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi,
	Oleksij Rempel, Konrad Frederic, Jan Kiszka

On 06/03/2018 21:52, Pavel Pisa wrote:
> Hello Thomas,
> 
> thanks for report but I at this time I am and
> can be some time in condition which does not allow
> me to access e-mail and normal work
> 
> On Tuesday 06 of March 2018 16:29:19 Thomas Huth wrote:
>> On 14.01.2018 21:14, pisa@cmp.felk.cvut.cz wrote:
>>> From: Pavel Pisa <pisa@cmp.felk.cvut.cz>
>>>
>>> Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
>>> ---
>>>  default-configs/pci.mak |   1 +
>>>  hw/can/Makefile.objs    |   1 +
>>>  hw/can/can_kvaser_pci.c | 375
>>> ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 377
>>> insertions(+)
>>>  create mode 100644 hw/can/can_kvaser_pci.c
>>
>>  Hi,
>>
>> the kvaser_pci device introduced a new way to crash QEMU, e.g.:
>>
>> mips64el-softmmu/qemu-system-mips64el -M malta,accel=qtest \
>>                                       -device kvaser_pci
>>
>> Program received signal SIGSEGV, Segmentation fault.
>> 0x0000555555a6e2ec in can_bus_insert_client (bus=0x0,
>> client=client@entry=0x5555570c4018) at
>> /home/thuth/devel/qemu/net/can/can_core.c:50
>> 50	    QTAILQ_INSERT_TAIL(&bus->clients, client, next);
> 
> The reason is that parameters canbus0 and canbus1 are required.
> 
>   -object can-bus,id=canbus0 \
>   -device kvaser_pci,canbus0=canbus0
> 
> This could be be fast fix but plead somebody else to send regular
> patch.
> 
> --- a/net/can/can_host.c
> +++ b/net/can/can_host.c
> @@ -57,6 +57,10 @@ static void can_host_connect(CanHostState *ch, Error **errp)
>          return;
>      }
> 
> +    if (ch->bus_client == NULL) {
> +        error_setg(errp, "bus is not specified for given device.");
> +        return;
> +    }
>      can_bus_insert_client(ch->bus, &ch->bus_client);
>  }

Ok, I'll check it out.

Thanks Thomas for the report!

Paolo

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
@ 2018-01-31  4:07 Deniz Eren
  0 siblings, 0 replies; 45+ messages in thread
From: Deniz Eren @ 2018-01-31  4:07 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Pavel Pisa, Marek Vasut, Oliver Hartkopp, Stefan Hajnoczi,
	Philippe Mathieu-Daudé,
	qemu-devel, Oleksij Rempel, Konrad Frederic, Jan Kiszka,
	Marc-André Lureau

Hi Paolo,



Thank you for the correction! Greatly appreciated and it worked.



I tested all combinations of Linux host using virtual Socket-CAN and pcm3680 and mioe3680 client QEmu Linux environments using Linux Socket-CAN drivers, sending and receiving from each-other (all combinations; host-to-client, client-to-client, etc).


All tests passed!



Details:



Setup virtual Socket-CAN from host Linux system:

    $ sudo ip link add dev vcan0 type vcan
    $ sudo ip link set up vcan0
    $ sudo ip link add dev vcan1 type vcan
    $ sudo ip link set up vcan1

    $ sudo ip link set vcan0 txqueuelen 15
    $ sudo ip link set vcan1 txqueuelen 15


Starting 2 x QEmu sessions from host Linux; one for pcm3680 and other for mioe3680:

    $ ./qemu-local/bin/qemu-system-i386 -hda sdd2gb-uno1483-16.04-2.0-dev.img -boot d -k en-us -object can-bus,id=canbus0 -object can-bus,id=canbus1 -object can-host-socketcan,id=canhost0,canbus=canbus0,if=vcan0 -object can-host-socketcan,id=canhost1,canbus=canbus1,if=vcan1 -device mioe3680_pci,canbus0=canbus0,canbus1=canbus1 -m size=2048 -netdev user,id=user.0 -device e1000,netdev=user.0 -redir tcp:5022::22 -enable-kvm &

    $ ./qemu-local/bin/qemu-system-i386 -hda sdd2gb-uno1483-16.04-2.0-dev-copy.img -boot d -k en-us -object can-bus,id=canbus0 -object can-bus,id=canbus1 -object can-host-socketcan,id=canhost0,canbus=canbus0,if=vcan0 -object can-host-socketcan,id=canhost1,canbus=canbus1,if=vcan1 -device pcm3680_pci,canbus0=canbus0,canbus1=canbus1 -m size=2048 -netdev user,id=user.0 -device e1000,netdev=user.0 -redir tcp:6022::22 -enable-kvm &

    
Login to client QEmu instances and setup CAN networks:

    $ ssh -Yp5022 user@localhost

    $ sudo ip link set can0 type can bitrate 250000
    $ sudo ip link set can1 type can bitrate 250000
    $ sudo ip link set up can0
    $ sudo ip link set up can1
    $ sudo ip link set can0 txqueuelen 15
    $ sudo ip link set can1 txqueuelen 15

    $ ssh -Yp6022 user@localhost

    $ ... similarly ...

Then tried all combinations of "candump vcan0/1" from host and "candump can0/1" from clients for transmission and reception to and from host to client and client to client.

user@:~$ candump can1
  can1  123   [8]  11 22 33 44 55 66 77 88
  can1  123   [8]  11 22 33 44 55 66 77 88
  can1  123   [8]  11 22 33 44 55 66 77 88

host:$ candump vcan0
  vcan0  123   [8]  11 22 33 44 55 66 77 88
  vcan0  123   [8]  11 22 33 44 55 66 77 88
  vcan0  123   [8]  11 22 33 44 55 66 77 88
  vcan0  123   [8]  11 22 33 44 55 66 77 88

All successful.







Best regards,
Deniz

On Jan 31, 2018, at 12:10 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:


On 30/01/2018 20:08, Paolo Bonzini wrote:

On 30/01/2018 19:13, Deniz Eren wrote:
Hi Pavel, Paolo,


I tried to rerun my environment to test however it seems the interface has changed a little and my standard program options cause complaints. Unfortunately I don’t have too much time to dig through at the moment.


My standard startup command is:


$ ./qemu-local/bin/qemu-system-i386 -hda sdd2gb-uno1483-16.04-2.0-dev.img -boot d -k en-us -device mioe3680_pci,canbus1=canbus0,host1=vcan0,canbus2=canbus1,host2=vcan1 -m size=2048 -netdev user,id=user.0 -device e1000,netdev=user.0 -redir tcp:5022::22 -enable-kvm &


Yep, it's now like this:


./qemu-local/bin/qemu-system-i386 \
-hda sdd2gb-uno1483-16.04-2.0-dev.img -boot d -k en-us \
-object can-bus,id=canbus0 \
-object can-bus,id=canbus1 \
-object can-host-socketcan,id=canhost0,canbus=canbus0,ifname=vcan0 \
-object can-host-socketcan,id=canhost1,canbus=canbus1,ifname=vcan1 \
-device mioe3680_pci,canbus0=canbus0,canbus1=canbus1 \
-m size=2048 -netdev user,id=user.0 -device e1000,netdev=user.0 \
-redir tcp:5022::22 -enable-kvm

Sorry, all "ifname" are "if".

Paolo


Thanks,


Paolo








Best regards,
Deniz


Sent from my iPhone


Deniz Eren
+61 400 307 762


On 31 Jan 2018, at 9:12 am, Pavel Pisa <pisa@cmp.felk.cvut.cz> wrote:


Hello Paolo,


thanks much for conversion to acceptable QOM model.


On Tuesday 30 of January 2018 15:15:22 Paolo Bonzini wrote:
On 25/01/2018 22:33, Pavel Pisa wrote:
Hello Paolo,


thanks for suggestions. I understand and fully agree with your
request to switch to QOM. I have succeed with that for CAN devices
some time ago. It worth to be done for the rest of the objects
but I fear that I do not find time to complete QOMification
in reasonable future. Contributions/suggestions from other
are welcomed. I can look for students for GSoC at our university
or under other funding.


Please take a look at branch can-pci-qom of github.com/bonzini/qemu.git.
Apart from QOMification of the backend include, I simplified the IRQ
handling in can_kvaser_pci (fixing bugs too I think), and removed an
unnecessary mutex. I also moved the files to net/can and hw/net/can so
that in the future Jason (networking maintainer) can take care of pull
requests.


I might have broken something, and the top commit in particular is
completely untested.


I have run basic test with Linux kernel on both sides
for one kavser_pci card on guest side and vcan (no real interface)
on host side.


Mesages exchange tests passed and looks OK.


I have used next parameters


-object can-bus,id=canbus0 \
-device kvaser_pci,canbus=canbus0 \
-object can-host-socketcan,if=can0,canbus=canbus0,id=canbus0-socketcan


The id parameter is required for "can-host-socketcan" object.
Else next error is printed


qemu-system-x86_64: -object can-host-socketcan,if=can0,canbus=canbus0: Parameter 'id' is missing


If "-object can-bus,id=canbus0" is missing then next error is reported


qemu-system-x86_64: -object can-host-socketcan,if=can0,canbus=canbus0,id=canbus0-socketcan: Device 'canbus0' not found


I have inspected through monitor the state of objects


(qemu) qom-list /objects
canbus0-socketcan (child<can-host-socketcan>)
type (string)
canbus0 (child<can-bus>)


(qemu) info qom-tree
/machine (pc-i440fx-2.12-machine)
...
/peripheral-anon (container)
/device[1] (kvaser_pci)
/bus master[0] (qemu:memory-region)
/kvaser_pci-xilinx[0] (qemu:memory-region)
/kvaser_pci-s5920[0] (qemu:memory-region)
/kvaser_pci-sja[0] (qemu:memory-region)
/bus master container[0] (qemu:memory-region)
...




(qemu) qom-list /objects
canbus0-socketcan (child<can-host-socketcan>)
type (string)
canbus0 (child<can-bus>)


(qemu) qom-list /machine/peripheral-anon/device[1]
bus master container[0] (child<qemu:memory-region>)
canbus (link<can-bus>)
rombar (uint32)
hotpluggable (bool)
x-pcie-lnksta-dllla (bool)
kvaser_pci-sja[0] (child<qemu:memory-region>)
multifunction (bool)
hotplugged (bool)
parent_bus (link<bus>)
romfile (str)
kvaser_pci-s5920[0] (child<qemu:memory-region>)
x-pcie-extcap-init (bool)
command_serr_enable (bool)
addr (int32)
type (string)
legacy-addr (str)
kvaser_pci-xilinx[0] (child<qemu:memory-region>)
realized (bool)
bus master[0] (child<qemu:memory-region>)


From the user point of view, it would be nice if "can-bus"
can be populated when required automatically.


I am not sure, but may it be that it would worth to
push can-bus objects under some category/specific
container. The path /objects is quite wide.
Into something like /object/can-bus or /net/can.


But generally thanks much, the progress you have made
in one day is really great. I hope that others check
your branch. I have pushed your unmodified version into
"can-pci-qom" branch of my repo


https://gitlab.fel.cvut.cz/canbus/qemu-canbus/tree/can-pci-qom



It would be great if others can check that everything
works in their setup. I think that then it can be pushed
into mainline and some usability improvements can be
done/experiment with later.


Thanks much,




Pavel Pisa





^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2018-03-07 11:40 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-14 20:14 [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) pisa
2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 1/7] CAN bus simple messages transport implementation for QEMU pisa
2018-01-19 12:38   ` Philippe Mathieu-Daudé
2018-01-19 13:28     ` Pavel Pisa
2018-01-19 17:04     ` Pavel Pisa
2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 2/7] CAN bus support to connect bust to Linux host SocketCAN interface pisa
2018-01-15  2:55   ` Philippe Mathieu-Daudé
2018-01-15 21:29     ` Pavel Pisa
2018-01-16  0:12       ` Philippe Mathieu-Daudé
2018-01-19  8:51         ` Pavel Pisa
2018-01-19 13:37           ` Philippe Mathieu-Daudé
2018-01-22 10:28             ` Stefan Hajnoczi
2018-01-19 13:37         ` Daniel P. Berrange
2018-01-19 12:57   ` Philippe Mathieu-Daudé
2018-01-19 13:01     ` Philippe Mathieu-Daudé
2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 3/7] CAN bus SJA1000 chip register level emulation for QEMU pisa
2018-01-15  3:03   ` Philippe Mathieu-Daudé
2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 4/7] CAN bus Kvaser PCI CAN-S (single SJA1000 channel) emulation added pisa
2018-01-15  3:09   ` Philippe Mathieu-Daudé
2018-03-06 15:29   ` Thomas Huth
2018-03-06 20:52     ` Pavel Pisa
2018-03-07 11:40       ` Paolo Bonzini
2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 5/7] QEMU CAN bus emulation documentation pisa
2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 6/7] CAN bus PCM-3680I PCI (dual SJA1000 channel) emulation added pisa
2018-01-15  3:12   ` Philippe Mathieu-Daudé
2018-01-19 13:15   ` Philippe Mathieu-Daudé
2018-01-14 20:14 ` [Qemu-devel] [PATCH V4 7/7] CAN bus MIOe-3680 " pisa
2018-01-19 13:13   ` Philippe Mathieu-Daudé
2018-01-22 11:35 ` [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far) Philippe Mathieu-Daudé
2018-01-23 21:42   ` Pavel Pisa
2018-01-24 20:22     ` Pavel Pisa
2018-01-24 21:41       ` Philippe Mathieu-Daudé
2018-01-25  8:24         ` Pavel Pisa
2018-01-25 13:50           ` Deniz Eren
2018-01-25 13:58     ` Paolo Bonzini
2018-01-25 21:33       ` Pavel Pisa
2018-01-26 11:12         ` Paolo Bonzini
2018-01-28  9:02           ` Pavel Pisa
2018-01-29  7:43             ` Oleksij Rempel
2018-01-30 14:15         ` Paolo Bonzini
2018-01-30 22:12           ` Pavel Pisa
2018-01-31  0:13             ` Deniz Eren
2018-01-31  1:08               ` Paolo Bonzini
2018-01-31  1:10                 ` Paolo Bonzini
2018-01-31  4:07 Deniz Eren

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.