The software uses a memory-mapped I/O command interface (MC portals) to
communicate with the MC hardware. This command interface is used to
discover, enumerate, configure and remove DPAA2 objects. The DPAA2
objects use MSIs, so the command interface needs to be emulated
such that the correct MSI is configured in the hardware (the guest
has the virtual MSIs).
This patch is adding read/write support for fsl-mc devices. The mc
commands are emulated by the userspace. The host is just passing
the correct command to the hardware.
Also the current patch limits userspace to write complete
64byte command once and read 64byte response by one ioctl.
Signed-off-by: Bharat Bhushan <[email protected]>
Signed-off-by: Diana Craciun <[email protected]>
---
drivers/vfio/fsl-mc/vfio_fsl_mc.c | 122 +++++++++++++++++++++-
drivers/vfio/fsl-mc/vfio_fsl_mc_private.h | 1 +
2 files changed, 121 insertions(+), 2 deletions(-)
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
index ec8ab85d54d6..bf11bcbfd09c 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/vfio.h>
#include <linux/fsl/mc.h>
+#include <linux/delay.h>
#include "vfio_fsl_mc_private.h"
@@ -116,6 +117,11 @@ static int vfio_fsl_mc_regions_init(struct vfio_fsl_mc_device *vdev)
static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev)
{
+ int i;
+
+ for (i = 0; i < vdev->num_regions; i++)
+ iounmap(vdev->regions[i].ioaddr);
+
vdev->num_regions = 0;
kfree(vdev->regions);
}
@@ -309,13 +315,125 @@ static long vfio_fsl_mc_ioctl(void *device_data, unsigned int cmd,
static ssize_t vfio_fsl_mc_read(void *device_data, char __user *buf,
size_t count, loff_t *ppos)
{
- return -EINVAL;
+ struct vfio_fsl_mc_device *vdev = device_data;
+ unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos);
+ loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK;
+ struct vfio_fsl_mc_region *region;
+ u64 data[8];
+ int i;
+
+ /* Read ioctl supported only for DPRC and DPMCP device */
+ if (strcmp(vdev->mc_dev->obj_desc.type, "dprc") &&
+ strcmp(vdev->mc_dev->obj_desc.type, "dpmcp"))
+ return -EINVAL;
+
+ if (index >= vdev->num_regions)
+ return -EINVAL;
+
+ region = &vdev->regions[index];
+
+ if (!(region->flags & VFIO_REGION_INFO_FLAG_READ))
+ return -EINVAL;
+
+ if (!region->ioaddr) {
+ region->ioaddr = ioremap(region->addr, region->size);
+ if (!region->ioaddr)
+ return -ENOMEM;
+ }
+
+ if (count != 64 || off != 0)
+ return -EINVAL;
+
+ for (i = 7; i >= 0; i--)
+ data[i] = readq(region->ioaddr + i * sizeof(uint64_t));
+
+ if (copy_to_user(buf, data, 64))
+ return -EFAULT;
+
+ return count;
+}
+
+#define MC_CMD_COMPLETION_TIMEOUT_MS 5000
+#define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS 500
+
+static int vfio_fsl_mc_send_command(void __iomem *ioaddr, uint64_t *cmd_data)
+{
+ int i;
+ enum mc_cmd_status status;
+ unsigned long timeout_usecs = MC_CMD_COMPLETION_TIMEOUT_MS * 1000;
+
+ /* Write at command parameter into portal */
+ for (i = 7; i >= 1; i--)
+ writeq_relaxed(cmd_data[i], ioaddr + i * sizeof(uint64_t));
+
+ /* Write command header in the end */
+ writeq(cmd_data[0], ioaddr);
+
+ /* Wait for response before returning to user-space
+ * This can be optimized in future to even prepare response
+ * before returning to user-space and avoid read ioctl.
+ */
+ for (;;) {
+ u64 header;
+ struct mc_cmd_header *resp_hdr;
+
+ header = cpu_to_le64(readq_relaxed(ioaddr));
+
+ resp_hdr = (struct mc_cmd_header *)&header;
+ status = (enum mc_cmd_status)resp_hdr->status;
+ if (status != MC_CMD_STATUS_READY)
+ break;
+
+ udelay(MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS);
+ timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS;
+ if (timeout_usecs == 0)
+ return -ETIMEDOUT;
+ }
+
+ return 0;
}
static ssize_t vfio_fsl_mc_write(void *device_data, const char __user *buf,
size_t count, loff_t *ppos)
{
- return -EINVAL;
+ struct vfio_fsl_mc_device *vdev = device_data;
+ unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos);
+ loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK;
+ struct vfio_fsl_mc_region *region;
+ u64 data[8];
+ int ret;
+
+ /* Write ioctl supported only for DPRC and DPMCP device */
+ if (strcmp(vdev->mc_dev->obj_desc.type, "dprc") &&
+ strcmp(vdev->mc_dev->obj_desc.type, "dpmcp"))
+ return -EINVAL;
+
+ if (index >= vdev->num_regions)
+ return -EINVAL;
+
+ region = &vdev->regions[index];
+
+ if (!(region->flags & VFIO_REGION_INFO_FLAG_WRITE))
+ return -EINVAL;
+
+ if (!region->ioaddr) {
+ region->ioaddr = ioremap(region->addr, region->size);
+ if (!region->ioaddr)
+ return -ENOMEM;
+ }
+
+ if (count != 64 || off != 0)
+ return -EINVAL;
+
+ if (copy_from_user(&data, buf, 64))
+ return -EFAULT;
+
+ ret = vfio_fsl_mc_send_command(region->ioaddr, data);
+ if (ret)
+ return ret;
+
+ return count;
+
}
static int vfio_fsl_mc_mmap_mmio(struct vfio_fsl_mc_region region,
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
index be0cdc35b40c..dfd2a2bc0b22 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
@@ -34,6 +34,7 @@ struct vfio_fsl_mc_region {
u32 type;
u64 addr;
resource_size_t size;
+ void __iomem *ioaddr;
};
struct vfio_fsl_mc_device {
--
2.17.1
Hi Diana,
I love your patch! Yet something to improve:
[auto build test ERROR on vfio/next]
[also build test ERROR on linus/master v5.7-rc4 next-20200508]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Diana-Craciun/vfio-fsl-mc-VFIO-support-for-FSL-MC-devices/20200509-034845
base: https://github.com/awilliam/linux-vfio.git next
config: i386-allyesconfig (attached as .config)
compiler: gcc-7 (Ubuntu 7.5.0-6ubuntu2) 7.5.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <[email protected]>
All error/warnings (new ones prefixed by >>):
drivers/vfio/fsl-mc/vfio_fsl_mc.c: In function 'vfio_fsl_mc_release':
drivers/vfio/fsl-mc/vfio_fsl_mc.c:170:9: error: implicit declaration of function 'dprc_reset_container'; did you mean 'resource_contains'? [-Werror=implicit-function-declaration]
ret = dprc_reset_container(mc_cont->mc_io, 0,
^~~~~~~~~~~~~~~~~~~~
resource_contains
drivers/vfio/fsl-mc/vfio_fsl_mc.c:173:6: error: 'DPRC_RESET_OPTION_NON_RECURSIVE' undeclared (first use in this function)
DPRC_RESET_OPTION_NON_RECURSIVE);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/vfio/fsl-mc/vfio_fsl_mc.c:173:6: note: each undeclared identifier is reported only once for each function it appears in
drivers/vfio/fsl-mc/vfio_fsl_mc.c:177:3: error: implicit declaration of function 'fsl_mc_cleanup_irq_pool'; did you mean 'fsl_mc_free_irqs'? [-Werror=implicit-function-declaration]
fsl_mc_cleanup_irq_pool(mc_cont);
^~~~~~~~~~~~~~~~~~~~~~~
fsl_mc_free_irqs
drivers/vfio/fsl-mc/vfio_fsl_mc.c: In function 'vfio_fsl_mc_read':
>> drivers/vfio/fsl-mc/vfio_fsl_mc.c:348:13: error: implicit declaration of function 'readq'; did you mean 'readl'? [-Werror=implicit-function-declaration]
data[i] = readq(region->ioaddr + i * sizeof(uint64_t));
^~~~~
readl
drivers/vfio/fsl-mc/vfio_fsl_mc.c: In function 'vfio_fsl_mc_send_command':
>> drivers/vfio/fsl-mc/vfio_fsl_mc.c:367:3: error: implicit declaration of function 'writeq_relaxed'; did you mean 'writeb_relaxed'? [-Werror=implicit-function-declaration]
writeq_relaxed(cmd_data[i], ioaddr + i * sizeof(uint64_t));
^~~~~~~~~~~~~~
writeb_relaxed
>> drivers/vfio/fsl-mc/vfio_fsl_mc.c:370:2: error: implicit declaration of function 'writeq'; did you mean 'writel'? [-Werror=implicit-function-declaration]
writeq(cmd_data[0], ioaddr);
^~~~~~
writel
In file included from include/linux/byteorder/little_endian.h:5:0,
from arch/x86/include/uapi/asm/byteorder.h:5,
from include/asm-generic/bitops/le.h:6,
from arch/x86/include/asm/bitops.h:395,
from include/linux/bitops.h:29,
from include/linux/kernel.h:12,
from arch/x86/include/asm/percpu.h:45,
from arch/x86/include/asm/current.h:6,
from include/linux/sched.h:12,
from include/linux/ratelimit.h:6,
from include/linux/dev_printk.h:16,
from include/linux/device.h:15,
from drivers/vfio/fsl-mc/vfio_fsl_mc.c:7:
>> drivers/vfio/fsl-mc/vfio_fsl_mc.c:380:24: error: implicit declaration of function 'readq_relaxed'; did you mean 'readw_relaxed'? [-Werror=implicit-function-declaration]
header = cpu_to_le64(readq_relaxed(ioaddr));
^
include/uapi/linux/byteorder/little_endian.h:31:51: note: in definition of macro '__cpu_to_le64'
#define __cpu_to_le64(x) ((__force __le64)(__u64)(x))
^
>> drivers/vfio/fsl-mc/vfio_fsl_mc.c:380:12: note: in expansion of macro 'cpu_to_le64'
header = cpu_to_le64(readq_relaxed(ioaddr));
^~~~~~~~~~~
drivers/vfio/fsl-mc/vfio_fsl_mc.c: In function 'vfio_fsl_mc_bus_notifier':
drivers/vfio/fsl-mc/vfio_fsl_mc.c:517:9: error: 'struct fsl_mc_device' has no member named 'driver_override'
mc_dev->driver_override = kasprintf(GFP_KERNEL, "%s",
^~
drivers/vfio/fsl-mc/vfio_fsl_mc.c: In function 'vfio_fsl_mc_init_device':
drivers/vfio/fsl-mc/vfio_fsl_mc.c:555:8: error: implicit declaration of function 'dprc_setup'; did you mean 'x2apic_setup'? [-Werror=implicit-function-declaration]
ret = dprc_setup(mc_dev);
^~~~~~~~~~
x2apic_setup
drivers/vfio/fsl-mc/vfio_fsl_mc.c:562:8: error: implicit declaration of function 'dprc_scan_container'; did you mean 'init_section_contains'? [-Werror=implicit-function-declaration]
ret = dprc_scan_container(mc_dev, false);
^~~~~~~~~~~~~~~~~~~
init_section_contains
drivers/vfio/fsl-mc/vfio_fsl_mc.c:566:3: error: implicit declaration of function 'dprc_cleanup'; did you mean 'pud_clear'? [-Werror=implicit-function-declaration]
dprc_cleanup(mc_dev);
^~~~~~~~~~~~
pud_clear
drivers/vfio/fsl-mc/vfio_fsl_mc.c: In function 'vfio_fsl_mc_device_remove':
drivers/vfio/fsl-mc/vfio_fsl_mc.c:625:14: error: 'struct fsl_mc_device' has no member named 'driver_override'
kfree(mc_dev->driver_override);
^~
drivers/vfio/fsl-mc/vfio_fsl_mc.c:626:8: error: 'struct fsl_mc_device' has no member named 'driver_override'
mc_dev->driver_override = NULL;
^~
cc1: some warnings being treated as errors
vim +348 drivers/vfio/fsl-mc/vfio_fsl_mc.c
314
315 static ssize_t vfio_fsl_mc_read(void *device_data, char __user *buf,
316 size_t count, loff_t *ppos)
317 {
318 struct vfio_fsl_mc_device *vdev = device_data;
319 unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos);
320 loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK;
321 struct vfio_fsl_mc_region *region;
322 u64 data[8];
323 int i;
324
325 /* Read ioctl supported only for DPRC and DPMCP device */
326 if (strcmp(vdev->mc_dev->obj_desc.type, "dprc") &&
327 strcmp(vdev->mc_dev->obj_desc.type, "dpmcp"))
328 return -EINVAL;
329
330 if (index >= vdev->num_regions)
331 return -EINVAL;
332
333 region = &vdev->regions[index];
334
335 if (!(region->flags & VFIO_REGION_INFO_FLAG_READ))
336 return -EINVAL;
337
338 if (!region->ioaddr) {
339 region->ioaddr = ioremap(region->addr, region->size);
340 if (!region->ioaddr)
341 return -ENOMEM;
342 }
343
344 if (count != 64 || off != 0)
345 return -EINVAL;
346
347 for (i = 7; i >= 0; i--)
> 348 data[i] = readq(region->ioaddr + i * sizeof(uint64_t));
349
350 if (copy_to_user(buf, data, 64))
351 return -EFAULT;
352
353 return count;
354 }
355
356 #define MC_CMD_COMPLETION_TIMEOUT_MS 5000
357 #define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS 500
358
359 static int vfio_fsl_mc_send_command(void __iomem *ioaddr, uint64_t *cmd_data)
360 {
361 int i;
362 enum mc_cmd_status status;
363 unsigned long timeout_usecs = MC_CMD_COMPLETION_TIMEOUT_MS * 1000;
364
365 /* Write at command parameter into portal */
366 for (i = 7; i >= 1; i--)
> 367 writeq_relaxed(cmd_data[i], ioaddr + i * sizeof(uint64_t));
368
369 /* Write command header in the end */
> 370 writeq(cmd_data[0], ioaddr);
371
372 /* Wait for response before returning to user-space
373 * This can be optimized in future to even prepare response
374 * before returning to user-space and avoid read ioctl.
375 */
376 for (;;) {
377 u64 header;
378 struct mc_cmd_header *resp_hdr;
379
> 380 header = cpu_to_le64(readq_relaxed(ioaddr));
381
382 resp_hdr = (struct mc_cmd_header *)&header;
383 status = (enum mc_cmd_status)resp_hdr->status;
384 if (status != MC_CMD_STATUS_READY)
385 break;
386
387 udelay(MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS);
388 timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS;
389 if (timeout_usecs == 0)
390 return -ETIMEDOUT;
391 }
392
393 return 0;
394 }
395
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]