summaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci-bridge-emul.h
blob: 71392b67471da45a5234f77ea9cafc5a3cd7995b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PCI_BRIDGE_EMUL_H__
#define __PCI_BRIDGE_EMUL_H__

#include <linux/kernel.h>

/* PCI configuration space of a PCI-to-PCI bridge. */
struct pci_bridge_emul_conf {
	__le16 vendor;
	__le16 device;
	__le16 command;
	__le16 status;
	__le32 class_revision;
	u8 cache_line_size;
	u8 latency_timer;
	u8 header_type;
	u8 bist;
	__le32 bar[2];
	u8 primary_bus;
	u8 secondary_bus;
	u8 subordinate_bus;
	u8 secondary_latency_timer;
	u8 iobase;
	u8 iolimit;
	__le16 secondary_status;
	__le16 membase;
	__le16 memlimit;
	__le16 pref_mem_base;
	__le16 pref_mem_limit;
	__le32 prefbaseupper;
	__le32 preflimitupper;
	__le16 iobaseupper;
	__le16 iolimitupper;
	u8 capabilities_pointer;
	u8 reserve[3];
	__le32 romaddr;
	u8 intline;
	u8 intpin;
	__le16 bridgectrl;
};

/* PCI configuration space of the PCIe capabilities */
struct pci_bridge_emul_pcie_conf {
	u8 cap_id;
	u8 next;
	__le16 cap;
	__le32 devcap;
	__le16 devctl;
	__le16 devsta;
	__le32 lnkcap;
	__le16 lnkctl;
	__le16 lnksta;
	__le32 slotcap;
	__le16 slotctl;
	__le16 slotsta;
	__le16 rootctl;
	__le16 rootcap;
	__le32 rootsta;
	__le32 devcap2;
	__le16 devctl2;
	__le16 devsta2;
	__le32 lnkcap2;
	__le16 lnkctl2;
	__le16 lnksta2;
	__le32 slotcap2;
	__le16 slotctl2;
	__le16 slotsta2;
};

struct pci_bridge_emul;

typedef enum { PCI_BRIDGE_EMUL_HANDLED,
	       PCI_BRIDGE_EMUL_NOT_HANDLED } pci_bridge_emul_read_status_t;

struct pci_bridge_emul_ops {
	/*
	 * Called when reading from the regular PCI bridge
	 * configuration space. Return PCI_BRIDGE_EMUL_HANDLED when the
	 * operation has handled the read operation and filled in the
	 * *value, or PCI_BRIDGE_EMUL_NOT_HANDLED when the read should
	 * be emulated by the common code by reading from the
	 * in-memory copy of the configuration space.
	 */
	pci_bridge_emul_read_status_t (*read_base)(struct pci_bridge_emul *bridge,
						   int reg, u32 *value);

	/*
	 * Same as ->read_base(), except it is for reading from the
	 * PCIe capability configuration space.
	 */
	pci_bridge_emul_read_status_t (*read_pcie)(struct pci_bridge_emul *bridge,
						   int reg, u32 *value);

	/*
	 * Same as ->read_base(), except it is for reading from the
	 * PCIe extended capability configuration space.
	 */
	pci_bridge_emul_read_status_t (*read_ext)(struct pci_bridge_emul *bridge,
						  int reg, u32 *value);

	/*
	 * Called when writing to the regular PCI bridge configuration
	 * space. old is the current value, new is the new value being
	 * written, and mask indicates which parts of the value are
	 * being changed.
	 */
	void (*write_base)(struct pci_bridge_emul *bridge, int reg,
			   u32 old, u32 new, u32 mask);

	/*
	 * Same as ->write_base(), except it is for writing from the
	 * PCIe capability configuration space.
	 */
	void (*write_pcie)(struct pci_bridge_emul *bridge, int reg,
			   u32 old, u32 new, u32 mask);

	/*
	 * Same as ->write_base(), except it is for writing from the
	 * PCIe extended capability configuration space.
	 */
	void (*write_ext)(struct pci_bridge_emul *bridge, int reg,
			  u32 old, u32 new, u32 mask);
};

struct pci_bridge_reg_behavior;

struct pci_bridge_emul {
	struct pci_bridge_emul_conf conf;
	struct pci_bridge_emul_pcie_conf pcie_conf;
	const struct pci_bridge_emul_ops *ops;
	struct pci_bridge_reg_behavior *pci_regs_behavior;
	struct pci_bridge_reg_behavior *pcie_cap_regs_behavior;
	void *data;
	bool has_pcie;
	u16 subsystem_vendor_id;
	u16 subsystem_id;
};

enum {
	/*
	 * PCI bridge does not support forwarding of prefetchable memory
	 * requests between primary and secondary buses.
	 */
	PCI_BRIDGE_EMUL_NO_PREFMEM_FORWARD = BIT(0),

	/*
	 * PCI bridge does not support forwarding of IO requests between
	 * primary and secondary buses.
	 */
	PCI_BRIDGE_EMUL_NO_IO_FORWARD = BIT(1),
};

int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
			 unsigned int flags);
void pci_bridge_emul_cleanup(struct pci_bridge_emul *bridge);

int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
			      int size, u32 *value);
int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
			       int size, u32 value);

#endif /* __PCI_BRIDGE_EMUL_H__ */