Skip to content

Commit 244da66

Browse files
davejiangvinodkoul
authored andcommitted
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. 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> Link: https://lore.kernel.org/r/20230407203143.2189681-4-fenghua.yu@intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent 1649091 commit 244da66

6 files changed

Lines changed: 181 additions & 4 deletions

File tree

drivers/dma/idxd/device.c

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,83 @@ void idxd_device_clear_state(struct idxd_device *idxd)
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)
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)
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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,15 @@ struct idxd_driver_data {
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 {
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ static int idxd_init_evl(struct idxd_device *idxd)
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

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
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 {
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 {
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 {
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 {
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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1605,7 +1605,8 @@ static ssize_t event_log_size_store(struct device *dev,
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ enum idxd_scmd_stat {
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

0 commit comments

Comments
 (0)