Currently, there is no way for the pci-endpoint-test driver (RC side), to know which features the EPC supports. Expose some of the EPC:s capabilities in the test_reg_bar, such that the pci-endpoint-test driver can know if a feature (e.g. MSI-X or DMA) is supported before attempting to test it. Signed-off-by: Niklas Cassel <cassel@xxxxxxxxxx> --- drivers/misc/pci_endpoint_test.c | 34 +++++++++++++++ drivers/pci/endpoint/functions/pci-epf-test.c | 43 +++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 3aaaf47fa4ee..7eb045dc81b6 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -69,6 +69,20 @@ #define PCI_ENDPOINT_TEST_FLAGS 0x2c #define FLAG_USE_DMA BIT(0) +#define CAPS_MAGIC 0x25ccf687 +#define PCI_ENDPOINT_TEST_CAPS_MAGIC 0x30 +#define PCI_ENDPOINT_TEST_CAPS_VERSION 0x34 +#define PCI_ENDPOINT_TEST_CAPS 0x38 + +#define CAPS_MSI_SUPPORT BIT(0) +#define CAPS_MSIX_SUPPORT BIT(1) +#define CAPS_DMA_SUPPORT BIT(2) +#define CAPS_DMA_IS_PRIVATE BIT(3) /* only valid if DMA_SUPPORT */ +#define CAPS_DOORBELL_SUPPORT BIT(4) +#define CAPS_DOORBELL_BAR_MASK GENMASK(7, 5) /* only valid if DOORBELL_SUPPORT */ +#define CAPS_DOORBELL_BAR_SHIFT 5 +#define CAPS_DOORBELL_BAR(x) (((x) & CAPS_DOORBELL_BAR_MASK) >> CAPS_DOORBELL_BAR_SHIFT) + #define PCI_DEVICE_ID_TI_AM654 0xb00c #define PCI_DEVICE_ID_TI_J7200 0xb00f #define PCI_DEVICE_ID_TI_AM64 0xb010 @@ -805,6 +819,24 @@ static const struct file_operations pci_endpoint_test_fops = { .unlocked_ioctl = pci_endpoint_test_ioctl, }; +static void pci_endpoint_get_caps(struct pci_endpoint_test *test) +{ + u32 caps_magic, caps; + + /* check if endpoint has CAPS support */ + caps_magic = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CAPS_MAGIC); + if (caps_magic != CAPS_MAGIC) + return; + + caps = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_CAPS); + pr_info("CAPS: MSI support: %u\n", (caps & CAPS_MSI_SUPPORT) ? 1 : 0); + pr_info("CAPS: MSI-X support: %u\n", (caps & CAPS_MSIX_SUPPORT) ? 1 : 0); + pr_info("CAPS: DMA support: %u\n", (caps & CAPS_DMA_SUPPORT) ? 1 : 0); + pr_info("CAPS: DMA is private: %u\n", (caps & CAPS_DMA_IS_PRIVATE) ? 1 : 0); + pr_info("CAPS: DOORBELL support: %u\n", (caps & CAPS_DOORBELL_SUPPORT) ? 1 : 0); + pr_info("CAPS: DOORBELL BAR: %lu\n", CAPS_DOORBELL_BAR(caps)); +} + static int pci_endpoint_test_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -906,6 +938,8 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, goto err_kfree_test_name; } + pci_endpoint_get_caps(test); + misc_device = &test->miscdev; misc_device->minor = MISC_DYNAMIC_MINOR; misc_device->name = kstrdup(name, GFP_KERNEL); diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index a73bc0771d35..2dd90e2e8565 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -44,6 +44,18 @@ #define TIMER_RESOLUTION 1 +#define CAPS_MAGIC 0x25ccf687 +#define CAPS_VERSION 0x1 + +#define CAPS_MSI_SUPPORT BIT(0) +#define CAPS_MSIX_SUPPORT BIT(1) +#define CAPS_DMA_SUPPORT BIT(2) +#define CAPS_DMA_IS_PRIVATE BIT(3) /* only valid if DMA_SUPPORT */ +#define CAPS_DOORBELL_SUPPORT BIT(4) +#define CAPS_DOORBELL_BAR_MASK GENMASK(7, 5) /* only valid if DOORBELL_SUPPORT */ +#define CAPS_DOORBELL_BAR_SHIFT 5 +#define CAPS_DOORBELL_BAR(x) (((x) & CAPS_DOORBELL_BAR_MASK) >> CAPS_DOORBELL_BAR_SHIFT) + static struct workqueue_struct *kpcitest_workqueue; struct pci_epf_test { @@ -74,6 +86,9 @@ struct pci_epf_test_reg { u32 irq_type; u32 irq_number; u32 flags; + u32 caps_magic; + u32 caps_version; + u32 caps; } __packed; static struct pci_epf_header test_header = { @@ -741,6 +756,32 @@ static void pci_epf_test_clear_bar(struct pci_epf *epf) } } +static void pci_epf_test_init_caps(struct pci_epf *epf) +{ + struct pci_epf_test *epf_test = epf_get_drvdata(epf); + const struct pci_epc_features *epc_features = epf_test->epc_features; + enum pci_barno test_reg_bar = epf_test->test_reg_bar; + struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar]; + u32 caps = 0; + + reg->caps_magic = cpu_to_le32(CAPS_MAGIC); + reg->caps_version = cpu_to_le32(CAPS_VERSION); + + if (epc_features->msi_capable) + caps |= CAPS_MSI_SUPPORT; + + if (epc_features->msix_capable) + caps |= CAPS_MSIX_SUPPORT; + + if (epf_test->dma_supported) + caps |= CAPS_DMA_SUPPORT; + + if (epf_test->dma_private) + caps |= CAPS_DMA_IS_PRIVATE; + + reg->caps = cpu_to_le64(caps); +} + static int pci_epf_test_epc_init(struct pci_epf *epf) { struct pci_epf_test *epf_test = epf_get_drvdata(epf); @@ -765,6 +806,8 @@ static int pci_epf_test_epc_init(struct pci_epf *epf) } } + pci_epf_test_init_caps(epf); + ret = pci_epf_test_set_bar(epf); if (ret) return ret; -- 2.47.0