The patch adds one more EEH sub-command (VFIO_EEH_PE_INJECT_ERR) to inject the specified EEH error, which is represented by (struct vfio_eeh_pe_err), to the indicated PE for testing purpose. Signed-off-by: Gavin Shan <gwshan@xxxxxxxxxxxxxxxxxx> --- Documentation/vfio.txt | 47 ++++++++++++++++++++++++++++++------------- drivers/vfio/vfio_spapr_eeh.c | 14 +++++++++++++ include/uapi/linux/vfio.h | 34 ++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/Documentation/vfio.txt b/Documentation/vfio.txt index 96978ec..2e7f736 100644 --- a/Documentation/vfio.txt +++ b/Documentation/vfio.txt @@ -328,7 +328,13 @@ So 4 additional ioctls have been added: The code flow from the example above should be slightly changed: - struct vfio_eeh_pe_op pe_op = { .argsz = sizeof(pe_op), .flags = 0 }; + struct vfio_eeh_pe_op *pe_op; + struct vfio_eeh_pe_err *pe_err; + + pe_op = malloc(sizeof(*pe_op) + sizeof(*pe_err)); + pe_err = (void *)pe_op + sizeof(*pe_op); + pe_op->argsz = sizeof(*pe_op) + sizeof(*pe_err); + pe_op->flags = 0; ..... /* Add the group to the container */ @@ -367,8 +373,8 @@ The code flow from the example above should be slightly changed: ioctl(container, VFIO_CHECK_EXTENSION, VFIO_EEH); /* Enable the EEH functionality on the device */ - pe_op.op = VFIO_EEH_PE_ENABLE; - ioctl(container, VFIO_EEH_PE_OP, &pe_op); + pe_op->op = VFIO_EEH_PE_ENABLE; + ioctl(container, VFIO_EEH_PE_OP, pe_op); /* You're suggested to create additional data struct to represent * PE, and put child devices belonging to same IOMMU group to the @@ -376,8 +382,8 @@ The code flow from the example above should be slightly changed: */ /* Check the PE's state and make sure it's in functional state */ - pe_op.op = VFIO_EEH_PE_GET_STATE; - ioctl(container, VFIO_EEH_PE_OP, &pe_op); + pe_op->op = VFIO_EEH_PE_GET_STATE; + ioctl(container, VFIO_EEH_PE_OP, pe_op); /* Save device state using pci_save_state(). * EEH should be enabled on the specified device. @@ -385,11 +391,24 @@ The code flow from the example above should be slightly changed: .... + /* Inject EEH error, which is expected to be caused by 32-bits + * config load. + */ + pe_err->type = VFIO_EEH_ERR_TYPE_32; + pe_err->func = VFIO_EEH_ERR_FUNC_LD_CFG_ADDR; + pe_err->addr = 0ul; + pe_err->mask = 0ul; + pe_op->op = VFIO_EEH_PE_INJECT_ERR; + ioctl(container, VFIO_EEH_PE_OP, pe_op); + + .... + /* When 0xFF's returned from reading PCI config space or IO BARs * of the PCI device. Check the PE's state to see if that has been * frozen. */ - ioctl(container, VFIO_EEH_PE_OP, &pe_op); + pe_op->op = VFIO_EEH_PE_GET_STATE; + ioctl(container, VFIO_EEH_PE_OP, pe_op); /* Waiting for pending PCI transactions to be completed and don't * produce any more PCI traffic from/to the affected PE until @@ -400,22 +419,22 @@ The code flow from the example above should be slightly changed: * standard part of PCI config space, AER registers are dumped * as logs for further analysis. */ - pe_op.op = VFIO_EEH_PE_UNFREEZE_IO; - ioctl(container, VFIO_EEH_PE_OP, &pe_op); + pe_op->op = VFIO_EEH_PE_UNFREEZE_IO; + ioctl(container, VFIO_EEH_PE_OP, pe_op); /* * Issue PE reset: hot or fundamental reset. Usually, hot reset * is enough. However, the firmware of some PCI adapters would * require fundamental reset. */ - pe_op.op = VFIO_EEH_PE_RESET_HOT; - ioctl(container, VFIO_EEH_PE_OP, &pe_op); - pe_op.op = VFIO_EEH_PE_RESET_DEACTIVATE; - ioctl(container, VFIO_EEH_PE_OP, &pe_op); + pe_op->op = VFIO_EEH_PE_RESET_HOT; + ioctl(container, VFIO_EEH_PE_OP, pe_op); + pe_op->op = VFIO_EEH_PE_RESET_DEACTIVATE; + ioctl(container, VFIO_EEH_PE_OP, pe_op); /* Configure the PCI bridges for the affected PE */ - pe_op.op = VFIO_EEH_PE_CONFIGURE; - ioctl(container, VFIO_EEH_PE_OP, &pe_op); + pe_op->op = VFIO_EEH_PE_CONFIGURE; + ioctl(container, VFIO_EEH_PE_OP, pe_op); /* Restored state we saved at initialization time. pci_restore_state() * is good enough as an example. diff --git a/drivers/vfio/vfio_spapr_eeh.c b/drivers/vfio/vfio_spapr_eeh.c index 5fa42db..4f1ebc1 100644 --- a/drivers/vfio/vfio_spapr_eeh.c +++ b/drivers/vfio/vfio_spapr_eeh.c @@ -85,6 +85,20 @@ long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group, case VFIO_EEH_PE_CONFIGURE: ret = eeh_pe_configure(pe); break; + case VFIO_EEH_PE_INJECT_ERR: { + struct vfio_eeh_pe_err err; + + if (op.argsz < minsz + sizeof(err)) + return -EINVAL; + if (copy_from_user(&err, + (void __user *)(arg + minsz), + sizeof(err))) + return -EFAULT; + + ret = eeh_pe_inject_err(pe, err.type, err.func, + err.addr, err.mask); + break; + } default: ret = -EINVAL; } diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h index 82889c3..0b32422 100644 --- a/include/uapi/linux/vfio.h +++ b/include/uapi/linux/vfio.h @@ -468,12 +468,21 @@ struct vfio_iommu_spapr_tce_info { * - unfreeze IO/DMA for frozen PE; * - read PE state; * - reset PE; - * - configure PE. + * - configure PE; + * - inject EEH error. */ +struct vfio_eeh_pe_err { + __u32 type; + __u32 func; + __u64 addr; + __u64 mask; +}; + struct vfio_eeh_pe_op { __u32 argsz; __u32 flags; __u32 op; + __u8 data[]; }; #define VFIO_EEH_PE_DISABLE 0 /* Disable EEH functionality */ @@ -490,6 +499,29 @@ struct vfio_eeh_pe_op { #define VFIO_EEH_PE_RESET_HOT 6 /* Assert hot reset */ #define VFIO_EEH_PE_RESET_FUNDAMENTAL 7 /* Assert fundamental reset */ #define VFIO_EEH_PE_CONFIGURE 8 /* PE configuration */ +#define VFIO_EEH_PE_INJECT_ERR 9 /* Inject EEH error */ +#define VFIO_EEH_ERR_TYPE_32 0 /* 32-bits EEH error type */ +#define VFIO_EEH_ERR_TYPE_64 1 /* 64-bits EEH error type */ +#define VFIO_EEH_ERR_FUNC_LD_MEM_ADDR 0 /* Memory load */ +#define VFIO_EEH_ERR_FUNC_LD_MEM_DATA 1 +#define VFIO_EEH_ERR_FUNC_LD_IO_ADDR 2 /* IO load */ +#define VFIO_EEH_ERR_FUNC_LD_IO_DATA 3 +#define VFIO_EEH_ERR_FUNC_LD_CFG_ADDR 4 /* Config load */ +#define VFIO_EEH_ERR_FUNC_LD_CFG_DATA 5 +#define VFIO_EEH_ERR_FUNC_ST_MEM_ADDR 6 /* Memory store */ +#define VFIO_EEH_ERR_FUNC_ST_MEM_DATA 7 +#define VFIO_EEH_ERR_FUNC_ST_IO_ADDR 8 /* IO store */ +#define VFIO_EEH_ERR_FUNC_ST_IO_DATA 9 +#define VFIO_EEH_ERR_FUNC_ST_CFG_ADDR 10 /* Config store */ +#define VFIO_EEH_ERR_FUNC_ST_CFG_DATA 11 +#define VFIO_EEH_ERR_FUNC_DMA_RD_ADDR 12 /* DMA read */ +#define VFIO_EEH_ERR_FUNC_DMA_RD_DATA 13 +#define VFIO_EEH_ERR_FUNC_DMA_RD_MASTER 14 +#define VFIO_EEH_ERR_FUNC_DMA_RD_TARGET 15 +#define VFIO_EEH_ERR_FUNC_DMA_WR_ADDR 16 /* DMA write */ +#define VFIO_EEH_ERR_FUNC_DMA_WR_DATA 17 +#define VFIO_EEH_ERR_FUNC_DMA_WR_MASTER 18 +#define VFIO_EEH_ERR_FUNC_DMA_WR_TARGET 19 #define VFIO_EEH_PE_OP _IO(VFIO_TYPE, VFIO_BASE + 21) -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html