|
@@ -1161,36 +1161,66 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
|
|
|
struct arm_smmu_queue *q = &smmu->evtq.q;
|
|
|
u64 evt[EVTQ_ENT_DWORDS];
|
|
|
|
|
|
- while (!queue_remove_raw(q, evt)) {
|
|
|
- u8 id = evt[0] >> EVTQ_0_ID_SHIFT & EVTQ_0_ID_MASK;
|
|
|
+ do {
|
|
|
+ while (!queue_remove_raw(q, evt)) {
|
|
|
+ u8 id = evt[0] >> EVTQ_0_ID_SHIFT & EVTQ_0_ID_MASK;
|
|
|
|
|
|
- dev_info(smmu->dev, "event 0x%02x received:\n", id);
|
|
|
- for (i = 0; i < ARRAY_SIZE(evt); ++i)
|
|
|
- dev_info(smmu->dev, "\t0x%016llx\n",
|
|
|
- (unsigned long long)evt[i]);
|
|
|
- }
|
|
|
+ dev_info(smmu->dev, "event 0x%02x received:\n", id);
|
|
|
+ for (i = 0; i < ARRAY_SIZE(evt); ++i)
|
|
|
+ dev_info(smmu->dev, "\t0x%016llx\n",
|
|
|
+ (unsigned long long)evt[i]);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Not much we can do on overflow, so scream and pretend we're
|
|
|
+ * trying harder.
|
|
|
+ */
|
|
|
+ if (queue_sync_prod(q) == -EOVERFLOW)
|
|
|
+ dev_err(smmu->dev, "EVTQ overflow detected -- events lost\n");
|
|
|
+ } while (!queue_empty(q));
|
|
|
|
|
|
/* Sync our overflow flag, as we believe we're up to speed */
|
|
|
q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
|
-static irqreturn_t arm_smmu_evtq_handler(int irq, void *dev)
|
|
|
-{
|
|
|
- irqreturn_t ret = IRQ_WAKE_THREAD;
|
|
|
- struct arm_smmu_device *smmu = dev;
|
|
|
- struct arm_smmu_queue *q = &smmu->evtq.q;
|
|
|
-
|
|
|
- /*
|
|
|
- * Not much we can do on overflow, so scream and pretend we're
|
|
|
- * trying harder.
|
|
|
- */
|
|
|
- if (queue_sync_prod(q) == -EOVERFLOW)
|
|
|
- dev_err(smmu->dev, "EVTQ overflow detected -- events lost\n");
|
|
|
- else if (queue_empty(q))
|
|
|
- ret = IRQ_NONE;
|
|
|
+static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
|
|
|
+{
|
|
|
+ u32 sid, ssid;
|
|
|
+ u16 grpid;
|
|
|
+ bool ssv, last;
|
|
|
+
|
|
|
+ sid = evt[0] >> PRIQ_0_SID_SHIFT & PRIQ_0_SID_MASK;
|
|
|
+ ssv = evt[0] & PRIQ_0_SSID_V;
|
|
|
+ ssid = ssv ? evt[0] >> PRIQ_0_SSID_SHIFT & PRIQ_0_SSID_MASK : 0;
|
|
|
+ last = evt[0] & PRIQ_0_PRG_LAST;
|
|
|
+ grpid = evt[1] >> PRIQ_1_PRG_IDX_SHIFT & PRIQ_1_PRG_IDX_MASK;
|
|
|
+
|
|
|
+ dev_info(smmu->dev, "unexpected PRI request received:\n");
|
|
|
+ dev_info(smmu->dev,
|
|
|
+ "\tsid 0x%08x.0x%05x: [%u%s] %sprivileged %s%s%s access at iova 0x%016llx\n",
|
|
|
+ sid, ssid, grpid, last ? "L" : "",
|
|
|
+ evt[0] & PRIQ_0_PERM_PRIV ? "" : "un",
|
|
|
+ evt[0] & PRIQ_0_PERM_READ ? "R" : "",
|
|
|
+ evt[0] & PRIQ_0_PERM_WRITE ? "W" : "",
|
|
|
+ evt[0] & PRIQ_0_PERM_EXEC ? "X" : "",
|
|
|
+ evt[1] & PRIQ_1_ADDR_MASK << PRIQ_1_ADDR_SHIFT);
|
|
|
+
|
|
|
+ if (last) {
|
|
|
+ struct arm_smmu_cmdq_ent cmd = {
|
|
|
+ .opcode = CMDQ_OP_PRI_RESP,
|
|
|
+ .substream_valid = ssv,
|
|
|
+ .pri = {
|
|
|
+ .sid = sid,
|
|
|
+ .ssid = ssid,
|
|
|
+ .grpid = grpid,
|
|
|
+ .resp = PRI_RESP_DENY,
|
|
|
+ },
|
|
|
+ };
|
|
|
|
|
|
- return ret;
|
|
|
+ arm_smmu_cmdq_issue_cmd(smmu, &cmd);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
|
|
@@ -1199,63 +1229,19 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
|
|
|
struct arm_smmu_queue *q = &smmu->priq.q;
|
|
|
u64 evt[PRIQ_ENT_DWORDS];
|
|
|
|
|
|
- while (!queue_remove_raw(q, evt)) {
|
|
|
- u32 sid, ssid;
|
|
|
- u16 grpid;
|
|
|
- bool ssv, last;
|
|
|
-
|
|
|
- sid = evt[0] >> PRIQ_0_SID_SHIFT & PRIQ_0_SID_MASK;
|
|
|
- ssv = evt[0] & PRIQ_0_SSID_V;
|
|
|
- ssid = ssv ? evt[0] >> PRIQ_0_SSID_SHIFT & PRIQ_0_SSID_MASK : 0;
|
|
|
- last = evt[0] & PRIQ_0_PRG_LAST;
|
|
|
- grpid = evt[1] >> PRIQ_1_PRG_IDX_SHIFT & PRIQ_1_PRG_IDX_MASK;
|
|
|
-
|
|
|
- dev_info(smmu->dev, "unexpected PRI request received:\n");
|
|
|
- dev_info(smmu->dev,
|
|
|
- "\tsid 0x%08x.0x%05x: [%u%s] %sprivileged %s%s%s access at iova 0x%016llx\n",
|
|
|
- sid, ssid, grpid, last ? "L" : "",
|
|
|
- evt[0] & PRIQ_0_PERM_PRIV ? "" : "un",
|
|
|
- evt[0] & PRIQ_0_PERM_READ ? "R" : "",
|
|
|
- evt[0] & PRIQ_0_PERM_WRITE ? "W" : "",
|
|
|
- evt[0] & PRIQ_0_PERM_EXEC ? "X" : "",
|
|
|
- evt[1] & PRIQ_1_ADDR_MASK << PRIQ_1_ADDR_SHIFT);
|
|
|
-
|
|
|
- if (last) {
|
|
|
- struct arm_smmu_cmdq_ent cmd = {
|
|
|
- .opcode = CMDQ_OP_PRI_RESP,
|
|
|
- .substream_valid = ssv,
|
|
|
- .pri = {
|
|
|
- .sid = sid,
|
|
|
- .ssid = ssid,
|
|
|
- .grpid = grpid,
|
|
|
- .resp = PRI_RESP_DENY,
|
|
|
- },
|
|
|
- };
|
|
|
+ do {
|
|
|
+ while (!queue_remove_raw(q, evt))
|
|
|
+ arm_smmu_handle_ppr(smmu, evt);
|
|
|
|
|
|
- arm_smmu_cmdq_issue_cmd(smmu, &cmd);
|
|
|
- }
|
|
|
- }
|
|
|
+ if (queue_sync_prod(q) == -EOVERFLOW)
|
|
|
+ dev_err(smmu->dev, "PRIQ overflow detected -- requests lost\n");
|
|
|
+ } while (!queue_empty(q));
|
|
|
|
|
|
/* Sync our overflow flag, as we believe we're up to speed */
|
|
|
q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons);
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
|
-static irqreturn_t arm_smmu_priq_handler(int irq, void *dev)
|
|
|
-{
|
|
|
- irqreturn_t ret = IRQ_WAKE_THREAD;
|
|
|
- struct arm_smmu_device *smmu = dev;
|
|
|
- struct arm_smmu_queue *q = &smmu->priq.q;
|
|
|
-
|
|
|
- /* PRIQ overflow indicates a programming error */
|
|
|
- if (queue_sync_prod(q) == -EOVERFLOW)
|
|
|
- dev_err(smmu->dev, "PRIQ overflow detected -- requests lost\n");
|
|
|
- else if (queue_empty(q))
|
|
|
- ret = IRQ_NONE;
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
static irqreturn_t arm_smmu_cmdq_sync_handler(int irq, void *dev)
|
|
|
{
|
|
|
/* We don't actually use CMD_SYNC interrupts for anything */
|
|
@@ -1288,15 +1274,11 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
|
|
|
if (active & GERROR_MSI_GERROR_ABT_ERR)
|
|
|
dev_warn(smmu->dev, "GERROR MSI write aborted\n");
|
|
|
|
|
|
- if (active & GERROR_MSI_PRIQ_ABT_ERR) {
|
|
|
+ if (active & GERROR_MSI_PRIQ_ABT_ERR)
|
|
|
dev_warn(smmu->dev, "PRIQ MSI write aborted\n");
|
|
|
- arm_smmu_priq_handler(irq, smmu->dev);
|
|
|
- }
|
|
|
|
|
|
- if (active & GERROR_MSI_EVTQ_ABT_ERR) {
|
|
|
+ if (active & GERROR_MSI_EVTQ_ABT_ERR)
|
|
|
dev_warn(smmu->dev, "EVTQ MSI write aborted\n");
|
|
|
- arm_smmu_evtq_handler(irq, smmu->dev);
|
|
|
- }
|
|
|
|
|
|
if (active & GERROR_MSI_CMDQ_ABT_ERR) {
|
|
|
dev_warn(smmu->dev, "CMDQ MSI write aborted\n");
|
|
@@ -2235,10 +2217,10 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
|
|
|
/* Request interrupt lines */
|
|
|
irq = smmu->evtq.q.irq;
|
|
|
if (irq) {
|
|
|
- ret = devm_request_threaded_irq(smmu->dev, irq,
|
|
|
- arm_smmu_evtq_handler,
|
|
|
+ ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
|
|
|
arm_smmu_evtq_thread,
|
|
|
- 0, "arm-smmu-v3-evtq", smmu);
|
|
|
+ IRQF_ONESHOT,
|
|
|
+ "arm-smmu-v3-evtq", smmu);
|
|
|
if (ret < 0)
|
|
|
dev_warn(smmu->dev, "failed to enable evtq irq\n");
|
|
|
}
|
|
@@ -2263,10 +2245,10 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
|
|
|
if (smmu->features & ARM_SMMU_FEAT_PRI) {
|
|
|
irq = smmu->priq.q.irq;
|
|
|
if (irq) {
|
|
|
- ret = devm_request_threaded_irq(smmu->dev, irq,
|
|
|
- arm_smmu_priq_handler,
|
|
|
+ ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
|
|
|
arm_smmu_priq_thread,
|
|
|
- 0, "arm-smmu-v3-priq",
|
|
|
+ IRQF_ONESHOT,
|
|
|
+ "arm-smmu-v3-priq",
|
|
|
smmu);
|
|
|
if (ret < 0)
|
|
|
dev_warn(smmu->dev,
|