vdpa.h 12.3 KB
Newer Older
J
Jason Wang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_VDPA_H
#define _LINUX_VDPA_H

#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/vhost_iotlb.h>

/**
 * vDPA callback definition.
 * @callback: interrupt callback function
 * @private: the data passed to the callback function
 */
struct vdpa_callback {
	irqreturn_t (*callback)(void *data);
	void *private;
};

20 21 22 23 24 25 26 27 28 29
/**
 * vDPA notification area
 * @addr: base address of the notification area
 * @size: size of the notification area
 */
struct vdpa_notification_area {
	resource_size_t addr;
	resource_size_t size;
};

30 31 32 33 34 35 36 37
/**
 * vDPA vq_state definition
 * @avail_index: available index
 */
struct vdpa_vq_state {
	u16	avail_index;
};

38 39
struct vdpa_mgmt_dev;

J
Jason Wang 已提交
40 41 42 43 44 45
/**
 * vDPA device - representation of a vDPA device
 * @dev: underlying device
 * @dma_dev: the actual device that is performing DMA
 * @config: the configuration ops for this device.
 * @index: device index
46
 * @features_valid: were features initialized? for legacy guests
47
 * @nvqs: maximum number of supported virtqueues
48 49
 * @mdev: management device pointer; caller must setup when registering device as part
 *	  of dev_add() mgmtdev ops callback before invoking _vdpa_register_device().
J
Jason Wang 已提交
50 51 52 53 54 55
 */
struct vdpa_device {
	struct device dev;
	struct device *dma_dev;
	const struct vdpa_config_ops *config;
	unsigned int index;
56
	bool features_valid;
M
Max Gurtovoy 已提交
57
	int nvqs;
58
	struct vdpa_mgmt_dev *mdev;
J
Jason Wang 已提交
59 60
};

61 62 63 64 65 66 67 68 69 70
/**
 * vDPA IOVA range - the IOVA range support by the device
 * @first: start of the IOVA range
 * @last: end of the IOVA range
 */
struct vdpa_iova_range {
	u64 first;
	u64 last;
};

J
Jason Wang 已提交
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
/**
 * vDPA_config_ops - operations for configuring a vDPA device.
 * Note: vDPA device drivers are required to implement all of the
 * operations unless it is mentioned to be optional in the following
 * list.
 *
 * @set_vq_address:		Set the address of virtqueue
 *				@vdev: vdpa device
 *				@idx: virtqueue index
 *				@desc_area: address of desc area
 *				@driver_area: address of driver area
 *				@device_area: address of device area
 *				Returns integer: success (0) or error (< 0)
 * @set_vq_num:			Set the size of virtqueue
 *				@vdev: vdpa device
 *				@idx: virtqueue index
 *				@num: the size of virtqueue
 * @kick_vq:			Kick the virtqueue
 *				@vdev: vdpa device
 *				@idx: virtqueue index
 * @set_vq_cb:			Set the interrupt callback function for
 *				a virtqueue
 *				@vdev: vdpa device
 *				@idx: virtqueue index
 *				@cb: virtio-vdev interrupt callback structure
 * @set_vq_ready:		Set ready status for a virtqueue
 *				@vdev: vdpa device
 *				@idx: virtqueue index
 *				@ready: ready (true) not ready(false)
 * @get_vq_ready:		Get ready status for a virtqueue
 *				@vdev: vdpa device
 *				@idx: virtqueue index
 *				Returns boolean: ready (true) or not (false)
 * @set_vq_state:		Set the state for a virtqueue
 *				@vdev: vdpa device
 *				@idx: virtqueue index
107
 *				@state: pointer to set virtqueue state (last_avail_idx)
J
Jason Wang 已提交
108 109 110 111
 *				Returns integer: success (0) or error (< 0)
 * @get_vq_state:		Get the state for a virtqueue
 *				@vdev: vdpa device
 *				@idx: virtqueue index
112
 *				@state: pointer to returned state (last_avail_idx)
113 114 115 116
 * @get_vq_notification: 	Get the notification area for a virtqueue
 *				@vdev: vdpa device
 *				@idx: virtqueue index
 *				Returns the notifcation area
117 118 119 120 121 122
 * @get_vq_irq:			Get the irq number of a virtqueue (optional,
 *				but must implemented if require vq irq offloading)
 *				@vdev: vdpa device
 *				@idx: virtqueue index
 *				Returns int: irq number of a virtqueue,
 *				negative number if no irq assigned.
J
Jason Wang 已提交
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
 * @get_vq_align:		Get the virtqueue align requirement
 *				for the device
 *				@vdev: vdpa device
 *				Returns virtqueue algin requirement
 * @get_features:		Get virtio features supported by the device
 *				@vdev: vdpa device
 *				Returns the virtio features support by the
 *				device
 * @set_features:		Set virtio features supported by the driver
 *				@vdev: vdpa device
 *				@features: feature support by the driver
 *				Returns integer: success (0) or error (< 0)
 * @set_config_cb:		Set the config interrupt callback
 *				@vdev: vdpa device
 *				@cb: virtio-vdev interrupt callback structure
 * @get_vq_num_max:		Get the max size of virtqueue
 *				@vdev: vdpa device
 *				Returns u16: max size of virtqueue
 * @get_device_id:		Get virtio device id
 *				@vdev: vdpa device
 *				Returns u32: virtio device id
 * @get_vendor_id:		Get id for the vendor that provides this device
 *				@vdev: vdpa device
 *				Returns u32: virtio vendor id
 * @get_status:			Get the device status
 *				@vdev: vdpa device
 *				Returns u8: virtio device status
 * @set_status:			Set the device status
 *				@vdev: vdpa device
 *				@status: virtio device status
 * @get_config:			Read from device specific configuration space
 *				@vdev: vdpa device
 *				@offset: offset from the beginning of
 *				configuration space
 *				@buf: buffer used to read to
 *				@len: the length to read from
 *				configuration space
 * @set_config:			Write to device specific configuration space
 *				@vdev: vdpa device
 *				@offset: offset from the beginning of
 *				configuration space
 *				@buf: buffer used to write from
 *				@len: the length to write to
 *				configuration space
 * @get_generation:		Get device config generation (optional)
 *				@vdev: vdpa device
 *				Returns u32: device generation
170 171 172 173
 * @get_iova_range:		Get supported iova range (optional)
 *				@vdev: vdpa device
 *				Returns the iova range supported by
 *				the device.
J
Jason Wang 已提交
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
 * @set_map:			Set device memory mapping (optional)
 *				Needed for device that using device
 *				specific DMA translation (on-chip IOMMU)
 *				@vdev: vdpa device
 *				@iotlb: vhost memory mapping to be
 *				used by the vDPA
 *				Returns integer: success (0) or error (< 0)
 * @dma_map:			Map an area of PA to IOVA (optional)
 *				Needed for device that using device
 *				specific DMA translation (on-chip IOMMU)
 *				and preferring incremental map.
 *				@vdev: vdpa device
 *				@iova: iova to be mapped
 *				@size: size of the area
 *				@pa: physical address for the map
 *				@perm: device access permission (VHOST_MAP_XX)
 *				Returns integer: success (0) or error (< 0)
 * @dma_unmap:			Unmap an area of IOVA (optional but
 *				must be implemented with dma_map)
 *				Needed for device that using device
 *				specific DMA translation (on-chip IOMMU)
 *				and preferring incremental unmap.
 *				@vdev: vdpa device
 *				@iova: iova to be unmapped
 *				@size: size of the area
 *				Returns integer: success (0) or error (< 0)
 * @free:			Free resources that belongs to vDPA (optional)
 *				@vdev: vdpa device
 */
struct vdpa_config_ops {
	/* Virtqueue ops */
	int (*set_vq_address)(struct vdpa_device *vdev,
			      u16 idx, u64 desc_area, u64 driver_area,
			      u64 device_area);
	void (*set_vq_num)(struct vdpa_device *vdev, u16 idx, u32 num);
	void (*kick_vq)(struct vdpa_device *vdev, u16 idx);
	void (*set_vq_cb)(struct vdpa_device *vdev, u16 idx,
			  struct vdpa_callback *cb);
	void (*set_vq_ready)(struct vdpa_device *vdev, u16 idx, bool ready);
	bool (*get_vq_ready)(struct vdpa_device *vdev, u16 idx);
214 215
	int (*set_vq_state)(struct vdpa_device *vdev, u16 idx,
			    const struct vdpa_vq_state *state);
216 217
	int (*get_vq_state)(struct vdpa_device *vdev, u16 idx,
			    struct vdpa_vq_state *state);
218 219
	struct vdpa_notification_area
	(*get_vq_notification)(struct vdpa_device *vdev, u16 idx);
220
	/* vq irq is not expected to be changed once DRIVER_OK is set */
221
	int (*get_vq_irq)(struct vdpa_device *vdv, u16 idx);
J
Jason Wang 已提交
222 223

	/* Device ops */
224
	u32 (*get_vq_align)(struct vdpa_device *vdev);
J
Jason Wang 已提交
225 226 227 228 229 230 231 232 233 234 235 236 237 238
	u64 (*get_features)(struct vdpa_device *vdev);
	int (*set_features)(struct vdpa_device *vdev, u64 features);
	void (*set_config_cb)(struct vdpa_device *vdev,
			      struct vdpa_callback *cb);
	u16 (*get_vq_num_max)(struct vdpa_device *vdev);
	u32 (*get_device_id)(struct vdpa_device *vdev);
	u32 (*get_vendor_id)(struct vdpa_device *vdev);
	u8 (*get_status)(struct vdpa_device *vdev);
	void (*set_status)(struct vdpa_device *vdev, u8 status);
	void (*get_config)(struct vdpa_device *vdev, unsigned int offset,
			   void *buf, unsigned int len);
	void (*set_config)(struct vdpa_device *vdev, unsigned int offset,
			   const void *buf, unsigned int len);
	u32 (*get_generation)(struct vdpa_device *vdev);
239
	struct vdpa_iova_range (*get_iova_range)(struct vdpa_device *vdev);
J
Jason Wang 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252

	/* DMA ops */
	int (*set_map)(struct vdpa_device *vdev, struct vhost_iotlb *iotlb);
	int (*dma_map)(struct vdpa_device *vdev, u64 iova, u64 size,
		       u64 pa, u32 perm);
	int (*dma_unmap)(struct vdpa_device *vdev, u64 iova, u64 size);

	/* Free device resources */
	void (*free)(struct vdpa_device *vdev);
};

struct vdpa_device *__vdpa_alloc_device(struct device *parent,
					const struct vdpa_config_ops *config,
253
					int nvqs, size_t size, const char *name);
J
Jason Wang 已提交
254

255
#define vdpa_alloc_device(dev_struct, member, parent, config, nvqs, name)   \
J
Jason Wang 已提交
256
			  container_of(__vdpa_alloc_device( \
M
Max Gurtovoy 已提交
257
				       parent, config, nvqs, \
J
Jason Wang 已提交
258 259
				       sizeof(dev_struct) + \
				       BUILD_BUG_ON_ZERO(offsetof( \
260
				       dev_struct, member)), name), \
J
Jason Wang 已提交
261 262 263 264 265
				       dev_struct, member)

int vdpa_register_device(struct vdpa_device *vdev);
void vdpa_unregister_device(struct vdpa_device *vdev);

266 267 268
int _vdpa_register_device(struct vdpa_device *vdev);
void _vdpa_unregister_device(struct vdpa_device *vdev);

J
Jason Wang 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
/**
 * vdpa_driver - operations for a vDPA driver
 * @driver: underlying device driver
 * @probe: the function to call when a device is found.  Returns 0 or -errno.
 * @remove: the function to call when a device is removed.
 */
struct vdpa_driver {
	struct device_driver driver;
	int (*probe)(struct vdpa_device *vdev);
	void (*remove)(struct vdpa_device *vdev);
};

#define vdpa_register_driver(drv) \
	__vdpa_register_driver(drv, THIS_MODULE)
int __vdpa_register_driver(struct vdpa_driver *drv, struct module *owner);
void vdpa_unregister_driver(struct vdpa_driver *drv);

#define module_vdpa_driver(__vdpa_driver) \
	module_driver(__vdpa_driver, vdpa_register_driver,	\
		      vdpa_unregister_driver)

static inline struct vdpa_driver *drv_to_vdpa(struct device_driver *driver)
{
	return container_of(driver, struct vdpa_driver, driver);
}

static inline struct vdpa_device *dev_to_vdpa(struct device *_dev)
{
	return container_of(_dev, struct vdpa_device, dev);
}

static inline void *vdpa_get_drvdata(const struct vdpa_device *vdev)
{
	return dev_get_drvdata(&vdev->dev);
}

static inline void vdpa_set_drvdata(struct vdpa_device *vdev, void *data)
{
	dev_set_drvdata(&vdev->dev, data);
}

static inline struct device *vdpa_get_dma_dev(struct vdpa_device *vdev)
{
	return vdev->dma_dev;
}
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345

static inline void vdpa_reset(struct vdpa_device *vdev)
{
        const struct vdpa_config_ops *ops = vdev->config;

	vdev->features_valid = false;
        ops->set_status(vdev, 0);
}

static inline int vdpa_set_features(struct vdpa_device *vdev, u64 features)
{
        const struct vdpa_config_ops *ops = vdev->config;

	vdev->features_valid = true;
        return ops->set_features(vdev, features);
}


static inline void vdpa_get_config(struct vdpa_device *vdev, unsigned offset,
				   void *buf, unsigned int len)
{
        const struct vdpa_config_ops *ops = vdev->config;

	/*
	 * Config accesses aren't supposed to trigger before features are set.
	 * If it does happen we assume a legacy guest.
	 */
	if (!vdev->features_valid)
		vdpa_set_features(vdev, 0);
	ops->get_config(vdev, offset, buf, len);
}

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
/**
 * vdpa_mgmtdev_ops - vdpa device ops
 * @dev_add:	Add a vdpa device using alloc and register
 *		@mdev: parent device to use for device addition
 *		@name: name of the new vdpa device
 *		Driver need to add a new device using _vdpa_register_device()
 *		after fully initializing the vdpa device. Driver must return 0
 *		on success or appropriate error code.
 * @dev_del:	Remove a vdpa device using unregister
 *		@mdev: parent device to use for device removal
 *		@dev: vdpa device to remove
 *		Driver need to remove the specified device by calling
 *		_vdpa_unregister_device().
 */
struct vdpa_mgmtdev_ops {
	int (*dev_add)(struct vdpa_mgmt_dev *mdev, const char *name);
	void (*dev_del)(struct vdpa_mgmt_dev *mdev, struct vdpa_device *dev);
};

struct vdpa_mgmt_dev {
	struct device *device;
	const struct vdpa_mgmtdev_ops *ops;
	const struct virtio_device_id *id_table; /* supported ids */
	struct list_head list;
};

int vdpa_mgmtdev_register(struct vdpa_mgmt_dev *mdev);
void vdpa_mgmtdev_unregister(struct vdpa_mgmt_dev *mdev);

J
Jason Wang 已提交
375
#endif /* _LINUX_VDPA_H */