xref: /kvmtool/include/kvm/pci.h (revision 2f6384f924d709196a7c25f10eb097dd888e84bf)
160742802SPekka Enberg #ifndef KVM__PCI_H
260742802SPekka Enberg #define KVM__PCI_H
360742802SPekka Enberg 
43fdf659dSSasha Levin #include <linux/types.h>
51de74957SSasha Levin #include <linux/kvm.h>
620c64ecaSPekka Enberg #include <linux/pci_regs.h>
7aa73be70SMatt Evans #include <endian.h>
8*2f6384f9SAlexandru Elisei #include <stdbool.h>
976f9c841SCyrill Gorcunov 
10b5981636SWill Deacon #include "kvm/devices.h"
11f7c17d7cSPekka Enberg #include "kvm/msi.h"
12ff01b5dbSJean-Philippe Brucker #include "kvm/fdt.h"
13d0297a59SMatt Evans 
144402a581SPekka Enberg /*
154402a581SPekka Enberg  * PCI Configuration Mechanism #1 I/O ports. See Section 3.7.4.1.
164402a581SPekka Enberg  * ("Configuration Mechanism #1") of the PCI Local Bus Specification 2.1 for
174402a581SPekka Enberg  * details.
184402a581SPekka Enberg  */
19305b72ceSCyrill Gorcunov #define PCI_CONFIG_ADDRESS	0xcf8
20305b72ceSCyrill Gorcunov #define PCI_CONFIG_DATA		0xcfc
212b9e4709SCyrill Gorcunov #define PCI_CONFIG_BUS_FORWARD	0xcfa
2295d13a52SSasha Levin #define PCI_IO_SIZE		0x100
23854aa2efSJulien Thierry #define PCI_IOPORT_START	0x6200
24b403f2f7SWill Deacon #define PCI_CFG_SIZE		(1ULL << 24)
25305b72ceSCyrill Gorcunov 
266078a454SJean-Philippe Brucker struct kvm;
276078a454SJean-Philippe Brucker 
28aa73be70SMatt Evans union pci_config_address {
29aa73be70SMatt Evans 	struct {
30aa73be70SMatt Evans #if __BYTE_ORDER == __LITTLE_ENDIAN
31d0297a59SMatt Evans 		unsigned	reg_offset	: 2;		/* 1  .. 0  */
324402a581SPekka Enberg 		unsigned	register_number	: 6;		/* 7  .. 2  */
334402a581SPekka Enberg 		unsigned	function_number	: 3;		/* 10 .. 8  */
344402a581SPekka Enberg 		unsigned	device_number	: 5;		/* 15 .. 11 */
354402a581SPekka Enberg 		unsigned	bus_number	: 8;		/* 23 .. 16 */
364402a581SPekka Enberg 		unsigned	reserved	: 7;		/* 30 .. 24 */
374402a581SPekka Enberg 		unsigned	enable_bit	: 1;		/* 31       */
38aa73be70SMatt Evans #else
39aa73be70SMatt Evans 		unsigned	enable_bit	: 1;		/* 31       */
40aa73be70SMatt Evans 		unsigned	reserved	: 7;		/* 30 .. 24 */
41aa73be70SMatt Evans 		unsigned	bus_number	: 8;		/* 23 .. 16 */
42aa73be70SMatt Evans 		unsigned	device_number	: 5;		/* 15 .. 11 */
43aa73be70SMatt Evans 		unsigned	function_number	: 3;		/* 10 .. 8  */
44aa73be70SMatt Evans 		unsigned	register_number	: 6;		/* 7  .. 2  */
45d0297a59SMatt Evans 		unsigned	reg_offset	: 2;		/* 1  .. 0  */
46aa73be70SMatt Evans #endif
47aa73be70SMatt Evans 	};
48aa73be70SMatt Evans 	u32 w;
494402a581SPekka Enberg };
504402a581SPekka Enberg 
51bc485053SSasha Levin struct msix_table {
521de74957SSasha Levin 	struct msi_msg msg;
53bc485053SSasha Levin 	u32 ctrl;
54bc485053SSasha Levin };
55bc485053SSasha Levin 
56bc485053SSasha Levin struct msix_cap {
57bc485053SSasha Levin 	u8 cap;
58bc485053SSasha Levin 	u8 next;
5906f48103SSasha Levin 	u16 ctrl;
60bc485053SSasha Levin 	u32 table_offset;
6106f48103SSasha Levin 	u32 pba_offset;
62bc485053SSasha Levin };
63bc485053SSasha Levin 
648dd28afeSJean-Philippe Brucker struct msi_cap_64 {
658dd28afeSJean-Philippe Brucker 	u8 cap;
668dd28afeSJean-Philippe Brucker 	u8 next;
678dd28afeSJean-Philippe Brucker 	u16 ctrl;
688dd28afeSJean-Philippe Brucker 	u32 address_lo;
698dd28afeSJean-Philippe Brucker 	u32 address_hi;
708dd28afeSJean-Philippe Brucker 	u16 data;
718dd28afeSJean-Philippe Brucker 	u16 _align;
728dd28afeSJean-Philippe Brucker 	u32 mask_bits;
738dd28afeSJean-Philippe Brucker 	u32 pend_bits;
748dd28afeSJean-Philippe Brucker };
758dd28afeSJean-Philippe Brucker 
768dd28afeSJean-Philippe Brucker struct msi_cap_32 {
778dd28afeSJean-Philippe Brucker 	u8 cap;
788dd28afeSJean-Philippe Brucker 	u8 next;
798dd28afeSJean-Philippe Brucker 	u16 ctrl;
808dd28afeSJean-Philippe Brucker 	u32 address_lo;
818dd28afeSJean-Philippe Brucker 	u16 data;
828dd28afeSJean-Philippe Brucker 	u16 _align;
838dd28afeSJean-Philippe Brucker 	u32 mask_bits;
848dd28afeSJean-Philippe Brucker 	u32 pend_bits;
858dd28afeSJean-Philippe Brucker };
868dd28afeSJean-Philippe Brucker 
871a51c93dSJean-Philippe Brucker struct pci_cap_hdr {
881a51c93dSJean-Philippe Brucker 	u8	type;
891a51c93dSJean-Philippe Brucker 	u8	next;
901a51c93dSJean-Philippe Brucker };
911a51c93dSJean-Philippe Brucker 
92023fdaaeSJean-Philippe Brucker #define PCI_BAR_OFFSET(b)	(offsetof(struct pci_device_header, bar[b]))
93023fdaaeSJean-Philippe Brucker #define PCI_DEV_CFG_SIZE	256
94023fdaaeSJean-Philippe Brucker #define PCI_DEV_CFG_MASK	(PCI_DEV_CFG_SIZE - 1)
95023fdaaeSJean-Philippe Brucker 
96023fdaaeSJean-Philippe Brucker struct pci_device_header;
97023fdaaeSJean-Philippe Brucker 
98023fdaaeSJean-Philippe Brucker struct pci_config_operations {
99023fdaaeSJean-Philippe Brucker 	void (*write)(struct kvm *kvm, struct pci_device_header *pci_hdr,
100023fdaaeSJean-Philippe Brucker 		      u8 offset, void *data, int sz);
101023fdaaeSJean-Philippe Brucker 	void (*read)(struct kvm *kvm, struct pci_device_header *pci_hdr,
102023fdaaeSJean-Philippe Brucker 		     u8 offset, void *data, int sz);
103023fdaaeSJean-Philippe Brucker };
104023fdaaeSJean-Philippe Brucker 
10576f9c841SCyrill Gorcunov struct pci_device_header {
106023fdaaeSJean-Philippe Brucker 	/* Configuration space, as seen by the guest */
107023fdaaeSJean-Philippe Brucker 	union {
108023fdaaeSJean-Philippe Brucker 		struct {
1093fdf659dSSasha Levin 			u16		vendor_id;
1103fdf659dSSasha Levin 			u16		device_id;
1113fdf659dSSasha Levin 			u16		command;
1123fdf659dSSasha Levin 			u16		status;
113aa73be70SMatt Evans 			u8		revision_id;
114aa73be70SMatt Evans 			u8		class[3];
1153fdf659dSSasha Levin 			u8		cacheline_size;
1163fdf659dSSasha Levin 			u8		latency_timer;
1173fdf659dSSasha Levin 			u8		header_type;
1183fdf659dSSasha Levin 			u8		bist;
1193fdf659dSSasha Levin 			u32		bar[6];
1203fdf659dSSasha Levin 			u32		card_bus;
1213fdf659dSSasha Levin 			u16		subsys_vendor_id;
1223fdf659dSSasha Levin 			u16		subsys_id;
1233fdf659dSSasha Levin 			u32		exp_rom_bar;
124aa73be70SMatt Evans 			u8		capabilities;
125aa73be70SMatt Evans 			u8		reserved1[3];
1263fdf659dSSasha Levin 			u32		reserved2;
1273fdf659dSSasha Levin 			u8		irq_line;
1283fdf659dSSasha Levin 			u8		irq_pin;
1293fdf659dSSasha Levin 			u8		min_gnt;
1303fdf659dSSasha Levin 			u8		max_lat;
131bc485053SSasha Levin 			struct msix_cap msix;
132aa73be70SMatt Evans 		} __attribute__((packed));
133023fdaaeSJean-Philippe Brucker 		/* Pad to PCI config space size */
134023fdaaeSJean-Philippe Brucker 		u8	__pad[PCI_DEV_CFG_SIZE];
135023fdaaeSJean-Philippe Brucker 	};
136023fdaaeSJean-Philippe Brucker 
137023fdaaeSJean-Philippe Brucker 	/* Private to lkvm */
138023fdaaeSJean-Philippe Brucker 	u32		bar_size[6];
139023fdaaeSJean-Philippe Brucker 	struct pci_config_operations	cfg_ops;
140ff01b5dbSJean-Philippe Brucker 	/*
141ff01b5dbSJean-Philippe Brucker 	 * PCI INTx# are level-triggered, but virtual device often feature
142ff01b5dbSJean-Philippe Brucker 	 * edge-triggered INTx# for convenience.
143ff01b5dbSJean-Philippe Brucker 	 */
144ff01b5dbSJean-Philippe Brucker 	enum irq_type	irq_type;
145023fdaaeSJean-Philippe Brucker };
14676f9c841SCyrill Gorcunov 
1471a51c93dSJean-Philippe Brucker #define PCI_CAP(pci_hdr, pos) ((void *)(pci_hdr) + (pos))
1481a51c93dSJean-Philippe Brucker 
1491a51c93dSJean-Philippe Brucker #define pci_for_each_cap(pos, cap, hdr)				\
1501a51c93dSJean-Philippe Brucker 	for ((pos) = (hdr)->capabilities & ~3;			\
1511a51c93dSJean-Philippe Brucker 	     (cap) = PCI_CAP(hdr, pos), (pos) != 0;		\
1521a51c93dSJean-Philippe Brucker 	     (pos) = ((struct pci_cap_hdr *)(cap))->next & ~3)
1531a51c93dSJean-Philippe Brucker 
1546d987703SSasha Levin int pci__init(struct kvm *kvm);
1556d987703SSasha Levin int pci__exit(struct kvm *kvm);
156d0297a59SMatt Evans struct pci_device_header *pci__find_dev(u8 dev_num);
157854aa2efSJulien Thierry u32 pci_get_mmio_block(u32 size);
158854aa2efSJulien Thierry u16 pci_get_io_port_block(u32 size);
159c0c45eedSAndre Przywara int pci__assign_irq(struct pci_device_header *pci_hdr);
160d0297a59SMatt Evans void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data, int size);
161d0297a59SMatt Evans void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data, int size);
16260742802SPekka Enberg 
1631a51c93dSJean-Philippe Brucker void *pci_find_cap(struct pci_device_header *hdr, u8 cap_type);
1641a51c93dSJean-Philippe Brucker 
165*2f6384f9SAlexandru Elisei static inline bool __pci__memory_space_enabled(u16 command)
166*2f6384f9SAlexandru Elisei {
167*2f6384f9SAlexandru Elisei 	return command & PCI_COMMAND_MEMORY;
168*2f6384f9SAlexandru Elisei }
169*2f6384f9SAlexandru Elisei 
170*2f6384f9SAlexandru Elisei static inline bool pci__memory_space_enabled(struct pci_device_header *pci_hdr)
171*2f6384f9SAlexandru Elisei {
172*2f6384f9SAlexandru Elisei 	return __pci__memory_space_enabled(pci_hdr->command);
173*2f6384f9SAlexandru Elisei }
174*2f6384f9SAlexandru Elisei 
175*2f6384f9SAlexandru Elisei static inline bool __pci__io_space_enabled(u16 command)
176*2f6384f9SAlexandru Elisei {
177*2f6384f9SAlexandru Elisei 	return command & PCI_COMMAND_IO;
178*2f6384f9SAlexandru Elisei }
179*2f6384f9SAlexandru Elisei 
180*2f6384f9SAlexandru Elisei static inline bool pci__io_space_enabled(struct pci_device_header *pci_hdr)
181*2f6384f9SAlexandru Elisei {
182*2f6384f9SAlexandru Elisei 	return __pci__io_space_enabled(pci_hdr->command);
183*2f6384f9SAlexandru Elisei }
184*2f6384f9SAlexandru Elisei 
185*2f6384f9SAlexandru Elisei static inline bool __pci__bar_is_io(u32 bar)
186*2f6384f9SAlexandru Elisei {
187*2f6384f9SAlexandru Elisei 	return bar & PCI_BASE_ADDRESS_SPACE_IO;
188*2f6384f9SAlexandru Elisei }
189*2f6384f9SAlexandru Elisei 
190*2f6384f9SAlexandru Elisei static inline bool pci__bar_is_io(struct pci_device_header *pci_hdr, int bar_num)
191*2f6384f9SAlexandru Elisei {
192*2f6384f9SAlexandru Elisei 	return __pci__bar_is_io(pci_hdr->bar[bar_num]);
193*2f6384f9SAlexandru Elisei }
194*2f6384f9SAlexandru Elisei 
195*2f6384f9SAlexandru Elisei static inline bool pci__bar_is_memory(struct pci_device_header *pci_hdr, int bar_num)
196*2f6384f9SAlexandru Elisei {
197*2f6384f9SAlexandru Elisei 	return !pci__bar_is_io(pci_hdr, bar_num);
198*2f6384f9SAlexandru Elisei }
199*2f6384f9SAlexandru Elisei 
200*2f6384f9SAlexandru Elisei static inline u32 __pci__bar_address(u32 bar)
201*2f6384f9SAlexandru Elisei {
202*2f6384f9SAlexandru Elisei 	if (__pci__bar_is_io(bar))
203*2f6384f9SAlexandru Elisei 		return bar & PCI_BASE_ADDRESS_IO_MASK;
204*2f6384f9SAlexandru Elisei 	return bar & PCI_BASE_ADDRESS_MEM_MASK;
205*2f6384f9SAlexandru Elisei }
206*2f6384f9SAlexandru Elisei 
207*2f6384f9SAlexandru Elisei static inline u32 pci__bar_address(struct pci_device_header *pci_hdr, int bar_num)
208*2f6384f9SAlexandru Elisei {
209*2f6384f9SAlexandru Elisei 	return __pci__bar_address(pci_hdr->bar[bar_num]);
210*2f6384f9SAlexandru Elisei }
211*2f6384f9SAlexandru Elisei 
212*2f6384f9SAlexandru Elisei static inline u32 pci__bar_size(struct pci_device_header *pci_hdr, int bar_num)
213*2f6384f9SAlexandru Elisei {
214*2f6384f9SAlexandru Elisei 	return pci_hdr->bar_size[bar_num];
215*2f6384f9SAlexandru Elisei }
216*2f6384f9SAlexandru Elisei 
21760742802SPekka Enberg #endif /* KVM__PCI_H */
218