Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: virtio: Add support for zero-length requests

The virtio specification received a new mandatory feature
(VIRTIO_I2C_F_ZERO_LENGTH_REQUEST) for zero length requests. Fail if the
feature isn't offered by the device.

For each read-request, set the VIRTIO_I2C_FLAGS_M_RD flag, as required
by the VIRTIO_I2C_F_ZERO_LENGTH_REQUEST feature.

This allows us to support zero length requests, like SMBUS Quick, where
the buffer need not be sent anymore.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lore.kernel.org/r/7c58868cd26d2fc4bd82d0d8b0dfb55636380110.1634808714.git.viresh.kumar@linaro.org
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Jie Deng <jie.deng@intel.com> # once the spec is merged

authored by

Viresh Kumar and committed by
Michael S. Tsirkin
dcce1625 f1aa12f5

+36 -26
+30 -26
drivers/i2c/busses/i2c-virtio.c
··· 63 63 int outcnt = 0, incnt = 0; 64 64 65 65 /* 66 - * We don't support 0 length messages and so filter out 67 - * 0 length transfers by using i2c_adapter_quirks. 68 - */ 69 - if (!msgs[i].len) 70 - break; 71 - 72 - /* 73 66 * Only 7-bit mode supported for this moment. For the address 74 67 * format, Please check the Virtio I2C Specification. 75 68 */ 76 69 reqs[i].out_hdr.addr = cpu_to_le16(msgs[i].addr << 1); 77 70 71 + if (msgs[i].flags & I2C_M_RD) 72 + reqs[i].out_hdr.flags |= cpu_to_le32(VIRTIO_I2C_FLAGS_M_RD); 73 + 78 74 if (i != num - 1) 79 - reqs[i].out_hdr.flags = cpu_to_le32(VIRTIO_I2C_FLAGS_FAIL_NEXT); 75 + reqs[i].out_hdr.flags |= cpu_to_le32(VIRTIO_I2C_FLAGS_FAIL_NEXT); 80 76 81 77 sg_init_one(&out_hdr, &reqs[i].out_hdr, sizeof(reqs[i].out_hdr)); 82 78 sgs[outcnt++] = &out_hdr; 83 79 84 - reqs[i].buf = i2c_get_dma_safe_msg_buf(&msgs[i], 1); 85 - if (!reqs[i].buf) 86 - break; 80 + if (msgs[i].len) { 81 + reqs[i].buf = i2c_get_dma_safe_msg_buf(&msgs[i], 1); 82 + if (!reqs[i].buf) 83 + break; 87 84 88 - sg_init_one(&msg_buf, reqs[i].buf, msgs[i].len); 85 + sg_init_one(&msg_buf, reqs[i].buf, msgs[i].len); 89 86 90 - if (msgs[i].flags & I2C_M_RD) 91 - sgs[outcnt + incnt++] = &msg_buf; 92 - else 93 - sgs[outcnt++] = &msg_buf; 87 + if (msgs[i].flags & I2C_M_RD) 88 + sgs[outcnt + incnt++] = &msg_buf; 89 + else 90 + sgs[outcnt++] = &msg_buf; 91 + } 94 92 95 93 sg_init_one(&in_hdr, &reqs[i].in_hdr, sizeof(reqs[i].in_hdr)); 96 94 sgs[outcnt + incnt++] = &in_hdr; ··· 189 191 190 192 static u32 virtio_i2c_func(struct i2c_adapter *adap) 191 193 { 192 - return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); 194 + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 193 195 } 194 196 195 197 static struct i2c_algorithm virtio_algorithm = { ··· 197 199 .functionality = virtio_i2c_func, 198 200 }; 199 201 200 - static const struct i2c_adapter_quirks virtio_i2c_quirks = { 201 - .flags = I2C_AQ_NO_ZERO_LEN, 202 - }; 203 - 204 202 static int virtio_i2c_probe(struct virtio_device *vdev) 205 203 { 206 204 struct virtio_i2c *vi; 207 205 int ret; 206 + 207 + if (!virtio_has_feature(vdev, VIRTIO_I2C_F_ZERO_LENGTH_REQUEST)) { 208 + dev_err(&vdev->dev, "Zero-length request feature is mandatory\n"); 209 + return -EINVAL; 210 + } 208 211 209 212 vi = devm_kzalloc(&vdev->dev, sizeof(*vi), GFP_KERNEL); 210 213 if (!vi) ··· 224 225 snprintf(vi->adap.name, sizeof(vi->adap.name), 225 226 "i2c_virtio at virtio bus %d", vdev->index); 226 227 vi->adap.algo = &virtio_algorithm; 227 - vi->adap.quirks = &virtio_i2c_quirks; 228 228 vi->adap.dev.parent = &vdev->dev; 229 229 vi->adap.dev.of_node = vdev->dev.of_node; 230 230 i2c_set_adapdata(&vi->adap, vi); ··· 268 270 } 269 271 #endif 270 272 273 + static const unsigned int features[] = { 274 + VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, 275 + }; 276 + 271 277 static struct virtio_driver virtio_i2c_driver = { 272 - .id_table = id_table, 273 - .probe = virtio_i2c_probe, 274 - .remove = virtio_i2c_remove, 275 - .driver = { 278 + .feature_table = features, 279 + .feature_table_size = ARRAY_SIZE(features), 280 + .id_table = id_table, 281 + .probe = virtio_i2c_probe, 282 + .remove = virtio_i2c_remove, 283 + .driver = { 276 284 .name = "i2c_virtio", 277 285 }, 278 286 #ifdef CONFIG_PM_SLEEP
+6
include/uapi/linux/virtio_i2c.h
··· 11 11 #include <linux/const.h> 12 12 #include <linux/types.h> 13 13 14 + /* Virtio I2C Feature bits */ 15 + #define VIRTIO_I2C_F_ZERO_LENGTH_REQUEST 0 16 + 14 17 /* The bit 0 of the @virtio_i2c_out_hdr.@flags, used to group the requests */ 15 18 #define VIRTIO_I2C_FLAGS_FAIL_NEXT _BITUL(0) 19 + 20 + /* The bit 1 of the @virtio_i2c_out_hdr.@flags, used to mark a buffer as read */ 21 + #define VIRTIO_I2C_FLAGS_M_RD _BITUL(1) 16 22 17 23 /** 18 24 * struct virtio_i2c_out_hdr - the virtio I2C message OUT header