Skip to content

Commit 5915dbb

Browse files
committed
virtio_mmio: Add SW_IMPL and SEL_GENERATION for 2-way locking
Implements the SW_IMPL register and SEL_GENERATION register for synchronization between the driver and device. This includes 2-way locking where the driver updates the register when the value is ready, and the device updates the value again when it's acknowledged the driver's write Signed-off-by: Anirudh Srinivasan <asrinivasan@tenstorrent.com>
1 parent 40f14e8 commit 5915dbb

2 files changed

Lines changed: 79 additions & 0 deletions

File tree

drivers/virtio/virtio_mmio.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#include <linux/virtio_config.h>
7070
#include <uapi/linux/virtio_mmio.h>
7171
#include <linux/virtio_ring.h>
72+
#include <linux/delay.h>
7273

7374

7475

@@ -87,27 +88,58 @@ struct virtio_mmio_device {
8788

8889
void __iomem *base;
8990
unsigned long version;
91+
unsigned long sw_impl;
9092
};
9193

9294
/* Configuration interface */
9395

96+
static int wait_sel_generation_update(struct virtio_device *vdev, u32 prev_sel_generation){
97+
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
98+
unsigned long timeout = jiffies + msecs_to_jiffies(1000); // 1 second timeout
99+
writel(prev_sel_generation + 1, vm_dev->base + VIRTIO_MMIO_SEL_GENERATION);
100+
101+
while (readl(vm_dev->base + VIRTIO_MMIO_SEL_GENERATION) == prev_sel_generation + 1) {
102+
if (time_after(jiffies, timeout)) {
103+
dev_err(&vdev->dev, "Timeout waiting for sel_generation value to update\n");
104+
return -ETIMEDOUT;
105+
}
106+
cpu_relax(); // or udelay(1), or cond_resched() if appropriate
107+
}
108+
return 0;
109+
}
110+
94111
static int vm_get_features(struct virtio_device *vdev, u64 *features_out)
95112
{
96113
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
114+
u32 sel_generation;
97115

116+
if (vm_dev->sw_impl) {
117+
sel_generation = readl(vm_dev->base + VIRTIO_MMIO_SEL_GENERATION);
118+
}
98119
writel(1, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
120+
if (vm_dev->sw_impl && wait_sel_generation_update(vdev, sel_generation)) {
121+
return -ETIMEDOUT;
122+
}
99123
*features_out = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES);
100124
*features_out <<= 32;
101125

126+
if (vm_dev->sw_impl) {
127+
sel_generation = readl(vm_dev->base + VIRTIO_MMIO_SEL_GENERATION);
128+
}
102129
writel(0, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
130+
if (vm_dev->sw_impl && wait_sel_generation_update(vdev, sel_generation)) {
131+
return -ETIMEDOUT;
132+
}
103133
*features_out |= readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES);
134+
pr_err("Device Features %llx", *features_out);
104135

105136
return 0;
106137
}
107138

108139
static int vm_finalize_features(struct virtio_device *vdev)
109140
{
110141
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
142+
u32 sel_generation;
111143

112144
/* Give virtio_ring a chance to accept features. */
113145
vring_transport_features(vdev);
@@ -119,13 +151,38 @@ static int vm_finalize_features(struct virtio_device *vdev)
119151
return -EINVAL;
120152
}
121153

154+
if (vm_dev->sw_impl) {
155+
sel_generation = readl(vm_dev->base + VIRTIO_MMIO_SEL_GENERATION);
156+
}
122157
writel(1, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
158+
if (vm_dev->sw_impl && wait_sel_generation_update(vdev, sel_generation)) {
159+
return -ETIMEDOUT;
160+
}
161+
if (vm_dev->sw_impl) {
162+
sel_generation = readl(vm_dev->base + VIRTIO_MMIO_SEL_GENERATION);
163+
}
123164
writel((u32)(vdev->features >> 32),
124165
vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES);
166+
if (vm_dev->sw_impl && wait_sel_generation_update(vdev, sel_generation)) {
167+
return -ETIMEDOUT;
168+
}
125169

170+
if (vm_dev->sw_impl) {
171+
sel_generation = readl(vm_dev->base + VIRTIO_MMIO_SEL_GENERATION);
172+
}
126173
writel(0, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
174+
if (vm_dev->sw_impl && wait_sel_generation_update(vdev, sel_generation)) {
175+
return -ETIMEDOUT;
176+
}
177+
if (vm_dev->sw_impl) {
178+
sel_generation = readl(vm_dev->base + VIRTIO_MMIO_SEL_GENERATION);
179+
}
127180
writel((u32)vdev->features,
128181
vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES);
182+
if (vm_dev->sw_impl && wait_sel_generation_update(vdev, sel_generation)) {
183+
return -ETIMEDOUT;
184+
}
185+
pr_err("Driver Features %llx", vdev->features);
129186

130187
return 0;
131188
}
@@ -351,6 +408,7 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
351408
struct virtqueue *vq;
352409
unsigned int num;
353410
int err;
411+
u32 sel_generation;
354412

355413
if (__virtio_test_bit(vdev, VIRTIO_F_NOTIFICATION_DATA))
356414
notify = vm_notify_with_data;
@@ -386,6 +444,9 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
386444

387445
vq->num_max = num;
388446

447+
if (vm_dev->sw_impl) {
448+
sel_generation = readl(vm_dev->base + VIRTIO_MMIO_SEL_GENERATION);
449+
}
389450
/* Activate the queue */
390451
writel(virtqueue_get_vring_size(vq), vm_dev->base + VIRTIO_MMIO_QUEUE_NUM);
391452
if (vm_dev->version == 1) {
@@ -426,6 +487,10 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
426487

427488
writel(1, vm_dev->base + VIRTIO_MMIO_QUEUE_READY);
428489
}
490+
if (vm_dev->sw_impl && wait_sel_generation_update(vdev, sel_generation)) {
491+
err = -ETIMEDOUT;
492+
goto error_new_virtqueue;
493+
}
429494

430495
return vq;
431496

@@ -606,6 +671,14 @@ static int virtio_mmio_probe(struct platform_device *pdev)
606671
goto free_vm_dev;
607672
}
608673

674+
vm_dev->sw_impl = readl(vm_dev->base + VIRTIO_MMIO_SW_IMPL);
675+
if (vm_dev->sw_impl !=0 && vm_dev->sw_impl !=1) {
676+
dev_err(&pdev->dev, "SW_IMPL value must be 0 or 1, not %ld\n",
677+
vm_dev->sw_impl);
678+
rc = -ENODEV;
679+
goto free_vm_dev;
680+
}
681+
609682
vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID);
610683
if (vm_dev->vdev.id.device == 0) {
611684
/*

include/uapi/linux/virtio_mmio.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@
5858
/* Device (host) features set selector - Write Only */
5959
#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014
6060

61+
/* Is device side a software/polling implementation that requires synchronization - Read Only */
62+
#define VIRTIO_MMIO_SW_IMPL 0x018
63+
64+
/* (If SW_IMPL is set) Register used for synchronization between device and host for certain register accesses */
65+
#define VIRTIO_MMIO_SEL_GENERATION 0x01c
66+
6167
/* Bitmask of features activated by the driver (guest)
6268
* (32 bits per set) - Write Only */
6369
#define VIRTIO_MMIO_DRIVER_FEATURES 0x020

0 commit comments

Comments
 (0)