From: Fenghua Yu <fenghua.yu@intel.com>
To: "Vinod Koul" <vkoul@kernel.org>, "Dave Jiang" <dave.jiang@intel.com>
Cc: dmaengine@vger.kernel.org,
"linux-kernel" <linux-kernel@vger.kernel.org>,
Tony Zhu <tony.zhu@intel.com>, Fenghua Yu <fenghua.yu@intel.com>
Subject: [PATCH v4 11/16] dmaengine: idxd: process batch descriptor completion record faults
Date: Fri, 7 Apr 2023 13:31:38 -0700 [thread overview]
Message-ID: <20230407203143.2189681-12-fenghua.yu@intel.com> (raw)
In-Reply-To: <20230407203143.2189681-1-fenghua.yu@intel.com>
From: Dave Jiang <dave.jiang@intel.com>
Add event log processing for faulting of user batch descriptor completion
record.
When encountering an event log entry for a page fault on a completion
record, the driver is expected to do the following:
1. If the "first error in batch" bit in event log entry error info is
set, discard any previously recorded errors associated with the
"batch identifier".
2. Fix the page fault according to the fault address in the event log. If
successful, write the completion record to the fault address in user space.
3. If an error is encountered while writing the completion record and it is
associated to a descriptor in the batch, the driver associates the error
with the batch identifier of the event log entry and tracks it until the
event log entry for the corresponding batch desc is encountered.
While processing an event log entry for a batch descriptor with error
indicating that one or more descs in the batch had event log entries,
the driver will do the following before writing the batch completion
record:
1. If the status field of the completion record is 0x1, the driver will
change it to error code 0x5 (one or more operations in batch completed
with status not successful) and changes the result field to 1.
2. If the status is error code 0x6 (page fault on batch descriptor list
address), change the result field to 1.
3. If status is any other value, the completion record is not changed.
4. Clear the recorded error in preparation for next batch with same batch
identifier.
The result field is for user software to determine whether to set the
"Batch Error" flag bit in the descriptor for continuation of partial
batch descriptor completion. See DSA spec 2.0 for additional information.
If no error has been recorded for the batch, the batch completion record is
written to user space as is.
Tested-by: Tony Zhu <tony.zhu@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Co-developed-by: Fenghua Yu <fenghua.yu@intel.com>
Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
---
v4:
- Change dev_err() to dev_dbg_ratelimited() (Tony Luck).
v3:
- Call new function idxd_copy_cr().
v2:
- Call iommu_access_remote_vm() to copy completion record to user.
drivers/dma/idxd/idxd.h | 3 ++
drivers/dma/idxd/init.c | 4 ++
drivers/dma/idxd/irq.c | 91 ++++++++++++++++++++++++++----------
drivers/dma/idxd/registers.h | 4 +-
include/uapi/linux/idxd.h | 1 +
5 files changed, 78 insertions(+), 25 deletions(-)
diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h
index 3963c83165a6..4c4baa80c731 100644
--- a/drivers/dma/idxd/idxd.h
+++ b/drivers/dma/idxd/idxd.h
@@ -265,6 +265,8 @@ struct idxd_driver_data {
int compl_size;
int align;
int evl_cr_off;
+ int cr_status_off;
+ int cr_result_off;
};
struct idxd_evl {
@@ -278,6 +280,7 @@ struct idxd_evl {
u16 size;
u16 head;
unsigned long *bmap;
+ bool batch_fail[IDXD_MAX_BATCH_IDENT];
};
struct idxd_evl_fault {
diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index be4f3676e1a6..9b3e7f0770d1 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -48,6 +48,8 @@ static struct idxd_driver_data idxd_driver_data[] = {
.align = 32,
.dev_type = &dsa_device_type,
.evl_cr_off = offsetof(struct dsa_evl_entry, cr),
+ .cr_status_off = offsetof(struct dsa_completion_record, status),
+ .cr_result_off = offsetof(struct dsa_completion_record, result),
},
[IDXD_TYPE_IAX] = {
.name_prefix = "iax",
@@ -56,6 +58,8 @@ static struct idxd_driver_data idxd_driver_data[] = {
.align = 64,
.dev_type = &iax_device_type,
.evl_cr_off = offsetof(struct iax_evl_entry, cr),
+ .cr_status_off = offsetof(struct iax_completion_record, status),
+ .cr_result_off = offsetof(struct iax_completion_record, error_code),
},
};
diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c
index 96983975f974..c660d63a3eb8 100644
--- a/drivers/dma/idxd/irq.c
+++ b/drivers/dma/idxd/irq.c
@@ -225,37 +225,79 @@ static void idxd_evl_fault_work(struct work_struct *work)
struct idxd_wq *wq = fault->wq;
struct idxd_device *idxd = wq->idxd;
struct device *dev = &idxd->pdev->dev;
+ struct idxd_evl *evl = idxd->evl;
struct __evl_entry *entry_head = fault->entry;
void *cr = (void *)entry_head + idxd->data->evl_cr_off;
- int cr_size = idxd->data->compl_size, copied;
+ int cr_size = idxd->data->compl_size;
+ u8 *status = (u8 *)cr + idxd->data->cr_status_off;
+ u8 *result = (u8 *)cr + idxd->data->cr_result_off;
+ int copied, copy_size;
+ bool *bf;
switch (fault->status) {
case DSA_COMP_CRA_XLAT:
- case DSA_COMP_DRAIN_EVL:
- /*
- * Copy completion record to fault_addr in user address space
- * that is found by wq and PASID.
- */
- copied = idxd_copy_cr(wq, entry_head->pasid,
- entry_head->fault_addr,
- cr, cr_size);
- /*
- * The task that triggered the page fault is unknown currently
- * because multiple threads may share the user address
- * space or the task exits already before this fault.
- * So if the copy fails, SIGSEGV can not be sent to the task.
- * Just print an error for the failure. The user application
- * waiting for the completion record will time out on this
- * failure.
- */
- if (copied != cr_size) {
- dev_dbg_ratelimited(dev, "Failed to write to completion record. (%d:%d)\n",
- cr_size, copied);
+ if (entry_head->batch && entry_head->first_err_in_batch)
+ evl->batch_fail[entry_head->batch_id] = false;
+
+ copy_size = cr_size;
+ break;
+ case DSA_COMP_BATCH_EVL_ERR:
+ bf = &evl->batch_fail[entry_head->batch_id];
+
+ copy_size = entry_head->rcr || *bf ? cr_size : 0;
+ if (*bf) {
+ if (*status == DSA_COMP_SUCCESS)
+ *status = DSA_COMP_BATCH_FAIL;
+ *result = 1;
+ *bf = false;
}
break;
+ case DSA_COMP_DRAIN_EVL:
+ copy_size = cr_size;
+ break;
default:
- dev_dbg_ratelimited(dev, "Unrecognized error code: %#x\n",
- DSA_COMP_STATUS(entry_head->error));
+ copy_size = 0;
+ dev_dbg_ratelimited(dev, "Unrecognized error code: %#x\n", fault->status);
+ break;
+ }
+
+ if (copy_size == 0)
+ return;
+
+ /*
+ * Copy completion record to fault_addr in user address space
+ * that is found by wq and PASID.
+ */
+ copied = idxd_copy_cr(wq, entry_head->pasid, entry_head->fault_addr,
+ cr, copy_size);
+ /*
+ * The task that triggered the page fault is unknown currently
+ * because multiple threads may share the user address
+ * space or the task exits already before this fault.
+ * So if the copy fails, SIGSEGV can not be sent to the task.
+ * Just print an error for the failure. The user application
+ * waiting for the completion record will time out on this
+ * failure.
+ */
+ switch (fault->status) {
+ case DSA_COMP_CRA_XLAT:
+ if (copied != copy_size) {
+ dev_dbg_ratelimited(dev, "Failed to write to completion record: (%d:%d)\n",
+ copy_size, copied);
+ if (entry_head->batch)
+ evl->batch_fail[entry_head->batch_id] = true;
+ }
+ break;
+ case DSA_COMP_BATCH_EVL_ERR:
+ if (copied != copy_size) {
+ dev_dbg_ratelimited(dev, "Failed to write to batch completion record: (%d:%d)\n",
+ copy_size, copied);
+ }
+ break;
+ case DSA_COMP_DRAIN_EVL:
+ if (copied != copy_size)
+ dev_dbg_ratelimited(dev, "Failed to write to drain completion record: (%d:%d)\n",
+ copy_size, copied);
break;
}
@@ -274,7 +316,8 @@ static void process_evl_entry(struct idxd_device *idxd,
} else {
status = DSA_COMP_STATUS(entry_head->error);
- if (status == DSA_COMP_CRA_XLAT || status == DSA_COMP_DRAIN_EVL) {
+ if (status == DSA_COMP_CRA_XLAT || status == DSA_COMP_DRAIN_EVL ||
+ status == DSA_COMP_BATCH_EVL_ERR) {
struct idxd_evl_fault *fault;
int ent_size = evl_ent_size(idxd);
diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h
index 148db94f9373..9f3959d001b6 100644
--- a/drivers/dma/idxd/registers.h
+++ b/drivers/dma/idxd/registers.h
@@ -35,7 +35,7 @@ union gen_cap_reg {
u64 drain_readback:1;
u64 rsvd2:3;
u64 evl_support:2;
- u64 rsvd4:1;
+ u64 batch_continuation:1;
u64 max_xfer_shift:5;
u64 max_batch_shift:4;
u64 max_ims_mult:6;
@@ -577,6 +577,8 @@ union evl_status_reg {
u64 bits;
} __packed;
+#define IDXD_MAX_BATCH_IDENT 256
+
struct __evl_entry {
u64 rsvd:2;
u64 desc_valid:1;
diff --git a/include/uapi/linux/idxd.h b/include/uapi/linux/idxd.h
index 37732016f3b0..2645fa8662cc 100644
--- a/include/uapi/linux/idxd.h
+++ b/include/uapi/linux/idxd.h
@@ -134,6 +134,7 @@ enum dsa_completion_status {
DSA_COMP_HW_ERR_DRB,
DSA_COMP_TRANSLATION_FAIL,
DSA_COMP_DRAIN_EVL = 0x26,
+ DSA_COMP_BATCH_EVL_ERR,
};
enum iax_completion_status {
--
2.37.1
next prev parent reply other threads:[~2023-04-07 20:32 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-07 20:31 [PATCH v4 00/16] Enable DSA 2.0 Event Log and completion record faulting features Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 01/16] dmaengine: idxd: make misc interrupt one shot Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 02/16] dmaengine: idxd: add event log size sysfs attribute Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 03/16] dmaengine: idxd: setup event log configuration Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 04/16] dmaengine: idxd: add interrupt handling for event log Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 05/16] dmanegine: idxd: add debugfs for event log dump Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 06/16] dmaengine: idxd: add per DSA wq workqueue for processing cr faults Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 07/16] dmaengine: idxd: create kmem cache for event log fault items Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 08/16] dmaengine: idxd: add idxd_copy_cr() to copy user completion record during page fault handling Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 09/16] dmaengine: idxd: process user page faults for completion record Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 10/16] dmaengine: idxd: add descs_completed field " Fenghua Yu
2023-04-07 20:31 ` Fenghua Yu [this message]
2023-04-07 20:31 ` [PATCH v4 12/16] dmaengine: idxd: add per file user counters for completion record faults Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 13/16] dmaengine: idxd: add a device to represent the file opened Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 14/16] dmaengine: idxd: expose fault counters to sysfs Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 15/16] dmaengine: idxd: add pid to exported sysfs attribute for opened file Fenghua Yu
2023-04-07 20:31 ` [PATCH v4 16/16] dmaengine: idxd: add per wq PRS disable Fenghua Yu
2023-04-12 17:18 ` [PATCH v4 00/16] Enable DSA 2.0 Event Log and completion record faulting features Vinod Koul
2023-04-12 17:49 ` Fenghua Yu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230407203143.2189681-12-fenghua.yu@intel.com \
--to=fenghua.yu@intel.com \
--cc=dave.jiang@intel.com \
--cc=dmaengine@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=tony.zhu@intel.com \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox