2 * libqos virtio PCI driver
4 * Copyright (c) 2014 Marc MarĂ
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
13 #include "libqos/virtio.h"
14 #include "libqos/virtio-pci.h"
15 #include "libqos/pci.h"
16 #include "libqos/pci-pc.h"
18 #include "hw/pci/pci_regs.h"
20 typedef struct QVirtioPCIForeachData
{
21 void (*func
)(QVirtioDevice
*d
, void *data
);
24 } QVirtioPCIForeachData
;
26 static QVirtioPCIDevice
*qpcidevice_to_qvirtiodevice(QPCIDevice
*pdev
)
28 QVirtioPCIDevice
*vpcidev
;
29 vpcidev
= g_malloc0(sizeof(*vpcidev
));
33 vpcidev
->vdev
.device_type
=
34 qpci_config_readw(vpcidev
->pdev
, PCI_SUBSYSTEM_ID
);
40 static void qvirtio_pci_foreach_callback(
41 QPCIDevice
*dev
, int devfn
, void *data
)
43 QVirtioPCIForeachData
*d
= data
;
44 QVirtioPCIDevice
*vpcidev
= qpcidevice_to_qvirtiodevice(dev
);
46 if (vpcidev
->vdev
.device_type
== d
->device_type
) {
47 d
->func(&vpcidev
->vdev
, d
->user_data
);
53 static void qvirtio_pci_assign_device(QVirtioDevice
*d
, void *data
)
55 QVirtioPCIDevice
**vpcidev
= data
;
56 *vpcidev
= (QVirtioPCIDevice
*)d
;
59 static uint8_t qvirtio_pci_config_readb(QVirtioDevice
*d
, void *addr
)
61 QVirtioPCIDevice
*dev
= (QVirtioPCIDevice
*)d
;
62 return qpci_io_readb(dev
->pdev
, addr
);
65 static uint16_t qvirtio_pci_config_readw(QVirtioDevice
*d
, void *addr
)
67 QVirtioPCIDevice
*dev
= (QVirtioPCIDevice
*)d
;
68 return qpci_io_readw(dev
->pdev
, addr
);
71 static uint32_t qvirtio_pci_config_readl(QVirtioDevice
*d
, void *addr
)
73 QVirtioPCIDevice
*dev
= (QVirtioPCIDevice
*)d
;
74 return qpci_io_readl(dev
->pdev
, addr
);
77 static uint64_t qvirtio_pci_config_readq(QVirtioDevice
*d
, void *addr
)
79 QVirtioPCIDevice
*dev
= (QVirtioPCIDevice
*)d
;
83 if (qtest_big_endian()) {
84 for (i
= 0; i
< 8; ++i
) {
85 u64
|= (uint64_t)qpci_io_readb(dev
->pdev
, addr
+ i
) << (7 - i
) * 8;
88 for (i
= 0; i
< 8; ++i
) {
89 u64
|= (uint64_t)qpci_io_readb(dev
->pdev
, addr
+ i
) << i
* 8;
96 static uint8_t qvirtio_pci_get_status(QVirtioDevice
*d
)
98 QVirtioPCIDevice
*dev
= (QVirtioPCIDevice
*)d
;
99 return qpci_io_readb(dev
->pdev
, dev
->addr
+ QVIRTIO_DEVICE_STATUS
);
102 static void qvirtio_pci_set_status(QVirtioDevice
*d
, uint8_t status
)
104 QVirtioPCIDevice
*dev
= (QVirtioPCIDevice
*)d
;
105 qpci_io_writeb(dev
->pdev
, dev
->addr
+ QVIRTIO_DEVICE_STATUS
, status
);
108 const QVirtioBus qvirtio_pci
= {
109 .config_readb
= qvirtio_pci_config_readb
,
110 .config_readw
= qvirtio_pci_config_readw
,
111 .config_readl
= qvirtio_pci_config_readl
,
112 .config_readq
= qvirtio_pci_config_readq
,
113 .get_status
= qvirtio_pci_get_status
,
114 .set_status
= qvirtio_pci_set_status
,
117 void qvirtio_pci_foreach(QPCIBus
*bus
, uint16_t device_type
,
118 void (*func
)(QVirtioDevice
*d
, void *data
), void *data
)
120 QVirtioPCIForeachData d
= { .func
= func
,
121 .device_type
= device_type
,
124 qpci_device_foreach(bus
, QVIRTIO_VENDOR_ID
, -1,
125 qvirtio_pci_foreach_callback
, &d
);
128 QVirtioPCIDevice
*qvirtio_pci_device_find(QPCIBus
*bus
, uint16_t device_type
)
130 QVirtioPCIDevice
*dev
= NULL
;
131 qvirtio_pci_foreach(bus
, device_type
, qvirtio_pci_assign_device
, &dev
);
136 void qvirtio_pci_device_enable(QVirtioPCIDevice
*d
)
138 qpci_device_enable(d
->pdev
);
139 d
->addr
= qpci_iomap(d
->pdev
, 0, NULL
);
140 g_assert(d
->addr
!= NULL
);
143 void qvirtio_pci_device_disable(QVirtioPCIDevice
*d
)
145 qpci_iounmap(d
->pdev
, d
->addr
);