History

dmaengine: idxd: setup event log configuration

Add setup of event log feature for supported device. Event log addresses error reporting that was lacking in gen 1 DSA devices where a second error event does not get reported when a first event is pending software handling. The event log allows a circular buffer that the device can push error events to. It is up to the user to create a large enough event log ring in order to capture the expected events. The evl size can be set in the device sysfs attribute. By default 64 entries are supported as minimal when event log is enabled.

Dave Jiang committed 3 years ago

Commit 244da661 parent 16490916 files · +181 −4Browse files

Unified · Split

6 files
  1. drivers/dma/idxd/device.c +88 −1
  2. drivers/dma/idxd/idxd.h +19 −0
  3. drivers/dma/idxd/init.c +1 −0
  4. drivers/dma/idxd/registers.h +70 −2
  5. drivers/dma/idxd/sysfs.c +2 −1
  6. include/uapi/linux/idxd.h +1 −0
drivers/dma/idxd/device.c+88−1
@@ -752,6 +752,83 @@ void idxd_device_clear_state(struct idxd_device *idxd) · 751 unmodified lines
752752 spin_unlock(&idxd->dev_lock);
753753 }
754754
755+static int idxd_device_evl_setup(struct idxd_device *idxd)
756+{
757+ union gencfg_reg gencfg;
758+ union evlcfg_reg evlcfg;
759+ union genctrl_reg genctrl;
760+ struct device *dev = &idxd->pdev->dev;
761+ void *addr;
762+ dma_addr_t dma_addr;
763+ int size;
764+ struct idxd_evl *evl = idxd->evl;
765+
766+ if (!evl)
767+ return 0;
768+
769+ size = evl_size(idxd);
770+ /*
771+ * Address needs to be page aligned. However, dma_alloc_coherent() provides
772+ * at minimal page size aligned address. No manual alignment required.
773+ */
774+ addr = dma_alloc_coherent(dev, size, &dma_addr, GFP_KERNEL);
775+ if (!addr)
776+ return -ENOMEM;
777+
778+ memset(addr, 0, size);
779+
780+ spin_lock(&evl->lock);
781+ evl->log = addr;
782+ evl->dma = dma_addr;
783+ evl->log_size = size;
784+
785+ memset(&evlcfg, 0, sizeof(evlcfg));
786+ evlcfg.bits[0] = dma_addr & GENMASK(63, 12);
787+ evlcfg.size = evl->size;
788+
789+ iowrite64(evlcfg.bits[0], idxd->reg_base + IDXD_EVLCFG_OFFSET);
790+ iowrite64(evlcfg.bits[1], idxd->reg_base + IDXD_EVLCFG_OFFSET + 8);
791+
792+ genctrl.bits = ioread32(idxd->reg_base + IDXD_GENCTRL_OFFSET);
793+ genctrl.evl_int_en = 1;
794+ iowrite32(genctrl.bits, idxd->reg_base + IDXD_GENCTRL_OFFSET);
795+
796+ gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
797+ gencfg.evl_en = 1;
798+ iowrite32(gencfg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET);
799+
800+ spin_unlock(&evl->lock);
801+ return 0;
802+}
803+
804+static void idxd_device_evl_free(struct idxd_device *idxd)
805+{
806+ union gencfg_reg gencfg;
807+ union genctrl_reg genctrl;
808+ struct device *dev = &idxd->pdev->dev;
809+ struct idxd_evl *evl = idxd->evl;
810+
811+ gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
812+ if (!gencfg.evl_en)
813+ return;
814+
815+ spin_lock(&evl->lock);
816+ gencfg.evl_en = 0;
817+ iowrite32(gencfg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET);
818+
819+ genctrl.bits = ioread32(idxd->reg_base + IDXD_GENCTRL_OFFSET);
820+ genctrl.evl_int_en = 0;
821+ iowrite32(genctrl.bits, idxd->reg_base + IDXD_GENCTRL_OFFSET);
822+
823+ iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET);
824+ iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET + 8);
825+
826+ dma_free_coherent(dev, evl->log_size, evl->log, evl->dma);
827+ evl->log = NULL;
828+ evl->size = IDXD_EVL_SIZE_MIN;
829+ spin_unlock(&evl->lock);
830+}
831+
755832 static void idxd_group_config_write(struct idxd_group *group)
756833 {
757834 struct idxd_device *idxd = group->idxd;
@@ -1451,15 +1528,24 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev) · 693 unmodified lines
14511528 if (rc < 0)
14521529 return -ENXIO;
14531530
1531+ rc = idxd_device_evl_setup(idxd);
1532+ if (rc < 0) {
1533+ idxd->cmd_status = IDXD_SCMD_DEV_EVL_ERR;
1534+ return rc;
1535+ }
1536+
14541537 /* Start device */
14551538 rc = idxd_device_enable(idxd);
1456− if (rc < 0)
1539+ if (rc < 0) {
1540+ idxd_device_evl_free(idxd);
14571541 return rc;
1542+ }
14581543
14591544 /* Setup DMA device without channels */
14601545 rc = idxd_register_dma_device(idxd);
14611546 if (rc < 0) {
14621547 idxd_device_disable(idxd);
1548+ idxd_device_evl_free(idxd);
14631549 idxd->cmd_status = IDXD_SCMD_DEV_DMA_ERR;
14641550 return rc;
14651551 }
@@ -1488,6 +1574,7 @@ void idxd_device_drv_remove(struct idxd_dev *idxd_dev) · 22 unmodified lines
14881574 idxd_device_disable(idxd);
14891575 if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
14901576 idxd_device_reset(idxd);
1577+ idxd_device_evl_free(idxd);
14911578 }
14921579
14931580 static enum idxd_dev_type dev_types[] = {
drivers/dma/idxd/idxd.h+19−0
@@ -262,7 +262,15 @@ struct idxd_driver_data { · 261 unmodified lines
262262 };
263263
264264 struct idxd_evl {
265+ /* Lock to protect event log access. */
266+ spinlock_t lock;
267+ void *log;
268+ dma_addr_t dma;
269+ /* Total size of event log = number of entries * entry size. */
270+ unsigned int log_size;
271+ /* The number of entries in the event log. */
265272 u16 size;
273+ u16 head;
266274 };
267275
268276 struct idxd_device {
@@ -324,6 +332,17 @@ struct idxd_device { · 55 unmodified lines
324332 struct idxd_evl *evl;
325333 };
326334
335+static inline unsigned int evl_ent_size(struct idxd_device *idxd)
336+{
337+ return idxd->hw.gen_cap.evl_support ?
338+ (32 * (1 << idxd->hw.gen_cap.evl_support)) : 0;
339+}
340+
341+static inline unsigned int evl_size(struct idxd_device *idxd)
342+{
343+ return idxd->evl->size * evl_ent_size(idxd);
344+}
345+
327346 /* IDXD software descriptor */
328347 struct idxd_desc {
329348 union {
drivers/dma/idxd/init.c+1−0
@@ -343,6 +343,7 @@ static int idxd_init_evl(struct idxd_device *idxd) · 342 unmodified lines
343343 if (!evl)
344344 return -ENOMEM;
345345
346+ spin_lock_init(&evl->lock);
346347 evl->size = IDXD_EVL_SIZE_MIN;
347348 idxd->evl = evl;
348349 return 0;
drivers/dma/idxd/registers.h+70−2
@@ -3,6 +3,8 @@ · 2 unmodified lines
33 #ifndef _IDXD_REGISTERS_H_
44 #define _IDXD_REGISTERS_H_
55
6+#include <uapi/linux/idxd.h>
7+
68 /* PCI Config */
79 #define PCI_DEVICE_ID_INTEL_DSA_SPR0 0x0b25
810 #define PCI_DEVICE_ID_INTEL_IAX_SPR0 0x0cfe
@@ -119,7 +121,8 @@ union gencfg_reg { · 110 unmodified lines
119121 u32 rdbuf_limit:8;
120122 u32 rsvd:4;
121123 u32 user_int_en:1;
122− u32 rsvd2:19;
124+ u32 evl_en:1;
125+ u32 rsvd2:18;
123126 };
124127 u32 bits;
125128 } __packed;
@@ -129,7 +132,8 @@ union genctrl_reg { · 3 unmodified lines
129132 struct {
130133 u32 softerr_int_en:1;
131134 u32 halt_int_en:1;
132− u32 rsvd:30;
135+ u32 evl_int_en:1;
136+ u32 rsvd:29;
133137 };
134138 u32 bits;
135139 } __packed;
@@ -299,6 +303,21 @@ union iaa_cap_reg { · 163 unmodified lines
299303
300304 #define IDXD_IAACAP_OFFSET 0x180
301305
306+#define IDXD_EVLCFG_OFFSET 0xe0
307+union evlcfg_reg {
308+ struct {
309+ u64 pasid_en:1;
310+ u64 priv:1;
311+ u64 rsvd:10;
312+ u64 base_addr:52;
313+
314+ u64 size:16;
315+ u64 pasid:20;
316+ u64 rsvd2:28;
317+ };
318+ u64 bits[2];
319+} __packed;
320+
302321 #define IDXD_EVL_SIZE_MIN 0x0040
303322 #define IDXD_EVL_SIZE_MAX 0xffff
304323
@@ -539,4 +558,53 @@ union filter_cfg { · 234 unmodified lines
539558 u64 val;
540559 } __packed;
541560
561+struct __evl_entry {
562+ u64 rsvd:2;
563+ u64 desc_valid:1;
564+ u64 wq_idx_valid:1;
565+ u64 batch:1;
566+ u64 fault_rw:1;
567+ u64 priv:1;
568+ u64 err_info_valid:1;
569+ u64 error:8;
570+ u64 wq_idx:8;
571+ u64 batch_id:8;
572+ u64 operation:8;
573+ u64 pasid:20;
574+ u64 rsvd2:4;
575+
576+ u16 batch_idx;
577+ u16 rsvd3;
578+ union {
579+ /* Invalid Flags 0x11 */
580+ u32 invalid_flags;
581+ /* Invalid Int Handle 0x19 */
582+ /* Page fault 0x1a */
583+ /* Page fault 0x06, 0x1f, only operand_id */
584+ /* Page fault before drain or in batch, 0x26, 0x27 */
585+ struct {
586+ u16 int_handle;
587+ u16 rci:1;
588+ u16 ims:1;
589+ u16 rcr:1;
590+ u16 first_err_in_batch:1;
591+ u16 rsvd4_2:9;
592+ u16 operand_id:3;
593+ };
594+ };
595+ u64 fault_addr;
596+ u64 rsvd5;
597+} __packed;
598+
599+struct dsa_evl_entry {
600+ struct __evl_entry e;
601+ struct dsa_completion_record cr;
602+} __packed;
603+
604+struct iax_evl_entry {
605+ struct __evl_entry e;
606+ u64 rsvd[4];
607+ struct iax_completion_record cr;
608+} __packed;
609+
542610 #endif
drivers/dma/idxd/sysfs.c+2−1
@@ -1605,7 +1605,8 @@ static ssize_t event_log_size_store(struct device *dev, · 1604 unmodified lines
16051605 if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
16061606 return -EPERM;
16071607
1608− if (val < IDXD_EVL_SIZE_MIN || val > IDXD_EVL_SIZE_MAX)
1608+ if (val < IDXD_EVL_SIZE_MIN || val > IDXD_EVL_SIZE_MAX ||
1609+ (val * evl_ent_size(idxd) > ULONG_MAX - idxd->evl->dma))
16091610 return -EINVAL;
16101611
16111612 idxd->evl->size = val;
include/uapi/linux/idxd.h+1−0
@@ -30,6 +30,7 @@ enum idxd_scmd_stat { · 29 unmodified lines
3030 IDXD_SCMD_WQ_NO_PRIV = 0x800f0000,
3131 IDXD_SCMD_WQ_IRQ_ERR = 0x80100000,
3232 IDXD_SCMD_WQ_USER_NO_IOMMU = 0x80110000,
33+ IDXD_SCMD_DEV_EVL_ERR = 0x80120000,
3334 };
3435
3536 #define IDXD_SCMD_SOFTERR_MASK 0x80000000

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t