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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
|
/* SPDX-License-Identifier: GPL-2.0
*
* CDX bus public interface
*
* Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
*
*/
#ifndef _CDX_BUS_H_
#define _CDX_BUS_H_
#include <linux/device.h>
#include <linux/list.h>
#include <linux/mod_devicetable.h>
#include <linux/msi.h>
#define MAX_CDX_DEV_RESOURCES 4
#define CDX_CONTROLLER_ID_SHIFT 4
#define CDX_BUS_NUM_MASK 0xF
/* Forward declaration for CDX controller */
struct cdx_controller;
enum {
CDX_DEV_MSI_CONF,
CDX_DEV_BUS_MASTER_CONF,
CDX_DEV_RESET_CONF,
CDX_DEV_MSI_ENABLE,
};
struct cdx_msi_config {
u64 addr;
u32 data;
u16 msi_index;
};
struct cdx_device_config {
u8 type;
union {
struct cdx_msi_config msi;
bool bus_master_enable;
bool msi_enable;
};
};
typedef int (*cdx_bus_enable_cb)(struct cdx_controller *cdx, u8 bus_num);
typedef int (*cdx_bus_disable_cb)(struct cdx_controller *cdx, u8 bus_num);
typedef int (*cdx_scan_cb)(struct cdx_controller *cdx);
typedef int (*cdx_dev_configure_cb)(struct cdx_controller *cdx,
u8 bus_num, u8 dev_num,
struct cdx_device_config *dev_config);
/**
* CDX_DEVICE - macro used to describe a specific CDX device
* @vend: the 16 bit CDX Vendor ID
* @dev: the 16 bit CDX Device ID
*
* This macro is used to create a struct cdx_device_id that matches a
* specific device. The subvendor and subdevice fields will be set to
* CDX_ANY_ID.
*/
#define CDX_DEVICE(vend, dev) \
.vendor = (vend), .device = (dev), \
.subvendor = CDX_ANY_ID, .subdevice = CDX_ANY_ID
/**
* CDX_DEVICE_DRIVER_OVERRIDE - macro used to describe a CDX device with
* override_only flags.
* @vend: the 16 bit CDX Vendor ID
* @dev: the 16 bit CDX Device ID
* @driver_override: the 32 bit CDX Device override_only
*
* This macro is used to create a struct cdx_device_id that matches only a
* driver_override device. The subvendor and subdevice fields will be set to
* CDX_ANY_ID.
*/
#define CDX_DEVICE_DRIVER_OVERRIDE(vend, dev, driver_override) \
.vendor = (vend), .device = (dev), .subvendor = CDX_ANY_ID,\
.subdevice = CDX_ANY_ID, .override_only = (driver_override)
/**
* struct cdx_ops - Callbacks supported by CDX controller.
* @bus_enable: enable bus on the controller
* @bus_disable: disable bus on the controller
* @scan: scan the devices on the controller
* @dev_configure: configuration like reset, master_enable,
* msi_config etc for a CDX device
*/
struct cdx_ops {
cdx_bus_enable_cb bus_enable;
cdx_bus_disable_cb bus_disable;
cdx_scan_cb scan;
cdx_dev_configure_cb dev_configure;
};
/**
* struct cdx_controller: CDX controller object
* @dev: Linux device associated with the CDX controller.
* @priv: private data
* @msi_domain: MSI domain
* @id: Controller ID
* @controller_registered: controller registered with bus
* @ops: CDX controller ops
*/
struct cdx_controller {
struct device *dev;
void *priv;
struct irq_domain *msi_domain;
u32 id;
bool controller_registered;
struct cdx_ops *ops;
};
/**
* struct cdx_device - CDX device object
* @dev: Linux driver model device object
* @cdx: CDX controller associated with the device
* @vendor: Vendor ID for CDX device
* @device: Device ID for CDX device
* @subsystem_vendor: Subsystem Vendor ID for CDX device
* @subsystem_device: Subsystem Device ID for CDX device
* @class: Class for the CDX device
* @revision: Revision of the CDX device
* @bus_num: Bus number for this CDX device
* @dev_num: Device number for this device
* @res: array of MMIO region entries
* @res_attr: resource binary attribute
* @debugfs_dir: debugfs directory for this device
* @res_count: number of valid MMIO regions
* @dma_mask: Default DMA mask
* @flags: CDX device flags
* @req_id: Requestor ID associated with CDX device
* @is_bus: Is this bus device
* @enabled: is this bus enabled
* @msi_dev_id: MSI Device ID associated with CDX device
* @num_msi: Number of MSI's supported by the device
* @driver_override: driver name to force a match; do not set directly,
* because core frees it; use driver_set_override() to
* set or clear it.
* @irqchip_lock: lock to synchronize irq/msi configuration
* @msi_write_pending: MSI write pending for this device
*/
struct cdx_device {
struct device dev;
struct cdx_controller *cdx;
u16 vendor;
u16 device;
u16 subsystem_vendor;
u16 subsystem_device;
u32 class;
u8 revision;
u8 bus_num;
u8 dev_num;
struct resource res[MAX_CDX_DEV_RESOURCES];
struct bin_attribute *res_attr[MAX_CDX_DEV_RESOURCES];
struct dentry *debugfs_dir;
u8 res_count;
u64 dma_mask;
u16 flags;
u32 req_id;
bool is_bus;
bool enabled;
u32 msi_dev_id;
u32 num_msi;
const char *driver_override;
struct mutex irqchip_lock;
bool msi_write_pending;
};
#define to_cdx_device(_dev) \
container_of(_dev, struct cdx_device, dev)
#define cdx_resource_start(dev, num) ((dev)->res[(num)].start)
#define cdx_resource_end(dev, num) ((dev)->res[(num)].end)
#define cdx_resource_flags(dev, num) ((dev)->res[(num)].flags)
#define cdx_resource_len(dev, num) \
((cdx_resource_start((dev), (num)) == 0 && \
cdx_resource_end((dev), (num)) == \
cdx_resource_start((dev), (num))) ? 0 : \
(cdx_resource_end((dev), (num)) - \
cdx_resource_start((dev), (num)) + 1))
/**
* struct cdx_driver - CDX device driver
* @driver: Generic device driver
* @match_id_table: table of supported device matching Ids
* @probe: Function called when a device is added
* @remove: Function called when a device is removed
* @shutdown: Function called at shutdown time to quiesce the device
* @reset_prepare: Function called before is reset to notify driver
* @reset_done: Function called after reset is complete to notify driver
* @driver_managed_dma: Device driver doesn't use kernel DMA API for DMA.
* For most device drivers, no need to care about this flag
* as long as all DMAs are handled through the kernel DMA API.
* For some special ones, for example VFIO drivers, they know
* how to manage the DMA themselves and set this flag so that
* the IOMMU layer will allow them to setup and manage their
* own I/O address space.
*/
struct cdx_driver {
struct device_driver driver;
const struct cdx_device_id *match_id_table;
int (*probe)(struct cdx_device *dev);
int (*remove)(struct cdx_device *dev);
void (*shutdown)(struct cdx_device *dev);
void (*reset_prepare)(struct cdx_device *dev);
void (*reset_done)(struct cdx_device *dev);
bool driver_managed_dma;
};
#define to_cdx_driver(_drv) \
container_of_const(_drv, struct cdx_driver, driver)
/* Macro to avoid include chaining to get THIS_MODULE */
#define cdx_driver_register(drv) \
__cdx_driver_register(drv, THIS_MODULE)
/**
* __cdx_driver_register - registers a CDX device driver
* @cdx_driver: CDX driver to register
* @owner: module owner
*
* Return: -errno on failure, 0 on success.
*/
int __must_check __cdx_driver_register(struct cdx_driver *cdx_driver,
struct module *owner);
/**
* cdx_driver_unregister - unregisters a device driver from the
* CDX bus.
* @cdx_driver: CDX driver to register
*/
void cdx_driver_unregister(struct cdx_driver *cdx_driver);
extern struct bus_type cdx_bus_type;
/**
* cdx_dev_reset - Reset CDX device
* @dev: device pointer
*
* Return: 0 for success, -errno on failure
*/
int cdx_dev_reset(struct device *dev);
/**
* cdx_set_master - enables bus-mastering for CDX device
* @cdx_dev: the CDX device to enable
*
* Return: 0 for success, -errno on failure
*/
int cdx_set_master(struct cdx_device *cdx_dev);
/**
* cdx_clear_master - disables bus-mastering for CDX device
* @cdx_dev: the CDX device to disable
*
* Return: 0 for success, -errno on failure
*/
int cdx_clear_master(struct cdx_device *cdx_dev);
#ifdef CONFIG_GENERIC_MSI_IRQ
/**
* cdx_enable_msi - Enable MSI for the CDX device.
* @cdx_dev: device pointer
*
* Return: 0 for success, -errno on failure
*/
int cdx_enable_msi(struct cdx_device *cdx_dev);
/**
* cdx_disable_msi - Disable MSI for the CDX device.
* @cdx_dev: device pointer
*/
void cdx_disable_msi(struct cdx_device *cdx_dev);
#else /* CONFIG_GENERIC_MSI_IRQ */
static inline int cdx_enable_msi(struct cdx_device *cdx_dev)
{
return -ENODEV;
}
static inline void cdx_disable_msi(struct cdx_device *cdx_dev)
{
}
#endif /* CONFIG_GENERIC_MSI_IRQ */
#endif /* _CDX_BUS_H_ */
|