Skip to content

Commit 6c5e610

Browse files
Koichiro Denbjorn-helgaas
authored andcommitted
PCI: endpoint: pci-epf-test: Add BAR subrange mapping test support
Extend pci-epf-test so that pci_endpoint_test can exercise BAR subrange mapping end-to-end. Add BAR_SUBRANGE_SETUP/CLEAR commands that program (and tear down) a simple 2-subrange layout for a selected BAR. The endpoint deliberately permutes the physical backing regions (swap the halves) and writes a deterministic signature byte per subrange. This allows the RC to verify that the submap order is actually applied, not just that reads/writes work with an identity mapping. Advertise CAP_SUBRANGE_MAPPING only when the underlying EPC supports dynamic_inbound_mapping and subrange_mapping. Also bump the default BAR sizes (BAR0-4) to 128 KiB so that split subranges are large enough to satisfy common inbound-translation alignment constraints. E.g. for DWC EP, the default and maximum CX_ATU_MIN_REGION_SIZE is 64 kB, so 128 KiB is sufficient for DWC-based EP platforms for 2-subrange testing. Signed-off-by: Koichiro Den <den@valinux.co.jp> Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Link: https://patch.msgid.link/20260124145012.2794108-7-den@valinux.co.jp
1 parent dd3ce16 commit 6c5e610

1 file changed

Lines changed: 171 additions & 1 deletion

File tree

drivers/pci/endpoint/functions/pci-epf-test.c

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#define COMMAND_COPY BIT(5)
3434
#define COMMAND_ENABLE_DOORBELL BIT(6)
3535
#define COMMAND_DISABLE_DOORBELL BIT(7)
36+
#define COMMAND_BAR_SUBRANGE_SETUP BIT(8)
37+
#define COMMAND_BAR_SUBRANGE_CLEAR BIT(9)
3638

3739
#define STATUS_READ_SUCCESS BIT(0)
3840
#define STATUS_READ_FAIL BIT(1)
@@ -48,6 +50,10 @@
4850
#define STATUS_DOORBELL_ENABLE_FAIL BIT(11)
4951
#define STATUS_DOORBELL_DISABLE_SUCCESS BIT(12)
5052
#define STATUS_DOORBELL_DISABLE_FAIL BIT(13)
53+
#define STATUS_BAR_SUBRANGE_SETUP_SUCCESS BIT(14)
54+
#define STATUS_BAR_SUBRANGE_SETUP_FAIL BIT(15)
55+
#define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS BIT(16)
56+
#define STATUS_BAR_SUBRANGE_CLEAR_FAIL BIT(17)
5157

5258
#define FLAG_USE_DMA BIT(0)
5359

@@ -57,6 +63,9 @@
5763
#define CAP_MSI BIT(1)
5864
#define CAP_MSIX BIT(2)
5965
#define CAP_INTX BIT(3)
66+
#define CAP_SUBRANGE_MAPPING BIT(4)
67+
68+
#define PCI_EPF_TEST_BAR_SUBRANGE_NSUB 2
6069

6170
static struct workqueue_struct *kpcitest_workqueue;
6271

@@ -102,7 +111,7 @@ static struct pci_epf_header test_header = {
102111
.interrupt_pin = PCI_INTERRUPT_INTA,
103112
};
104113

105-
static size_t bar_size[] = { 512, 512, 1024, 16384, 131072, 1048576 };
114+
static size_t bar_size[] = { 131072, 131072, 131072, 131072, 131072, 1048576 };
106115

107116
static void pci_epf_test_dma_callback(void *param)
108117
{
@@ -806,6 +815,155 @@ static void pci_epf_test_disable_doorbell(struct pci_epf_test *epf_test,
806815
reg->status = cpu_to_le32(status);
807816
}
808817

818+
static u8 pci_epf_test_subrange_sig_byte(enum pci_barno barno,
819+
unsigned int subno)
820+
{
821+
return 0x50 + (barno * 8) + subno;
822+
}
823+
824+
static void pci_epf_test_bar_subrange_setup(struct pci_epf_test *epf_test,
825+
struct pci_epf_test_reg *reg)
826+
{
827+
struct pci_epf_bar_submap *submap, *old_submap;
828+
struct pci_epf *epf = epf_test->epf;
829+
struct pci_epc *epc = epf->epc;
830+
struct pci_epf_bar *bar;
831+
unsigned int nsub = PCI_EPF_TEST_BAR_SUBRANGE_NSUB, old_nsub;
832+
/* reg->size carries BAR number for BAR_SUBRANGE_* commands. */
833+
enum pci_barno barno = le32_to_cpu(reg->size);
834+
u32 status = le32_to_cpu(reg->status);
835+
unsigned int i, phys_idx;
836+
size_t sub_size;
837+
u8 *addr;
838+
int ret;
839+
840+
if (barno >= PCI_STD_NUM_BARS) {
841+
dev_err(&epf->dev, "Invalid barno: %d\n", barno);
842+
goto err;
843+
}
844+
845+
/* Host side should've avoided test_reg_bar, this is a safeguard. */
846+
if (barno == epf_test->test_reg_bar) {
847+
dev_err(&epf->dev, "test_reg_bar cannot be used for subrange test\n");
848+
goto err;
849+
}
850+
851+
if (!epf_test->epc_features->dynamic_inbound_mapping ||
852+
!epf_test->epc_features->subrange_mapping) {
853+
dev_err(&epf->dev, "epc driver does not support subrange mapping\n");
854+
goto err;
855+
}
856+
857+
bar = &epf->bar[barno];
858+
if (!bar->size || !bar->addr) {
859+
dev_err(&epf->dev, "bar size/addr (%zu/%p) is invalid\n",
860+
bar->size, bar->addr);
861+
goto err;
862+
}
863+
864+
if (bar->size % nsub) {
865+
dev_err(&epf->dev, "BAR size %zu is not divisible by %u\n",
866+
bar->size, nsub);
867+
goto err;
868+
}
869+
870+
sub_size = bar->size / nsub;
871+
872+
submap = kcalloc(nsub, sizeof(*submap), GFP_KERNEL);
873+
if (!submap)
874+
goto err;
875+
876+
for (i = 0; i < nsub; i++) {
877+
/* Swap the two halves so RC can verify ordering. */
878+
phys_idx = i ^ 1;
879+
submap[i].phys_addr = bar->phys_addr + (phys_idx * sub_size);
880+
submap[i].size = sub_size;
881+
}
882+
883+
old_submap = bar->submap;
884+
old_nsub = bar->num_submap;
885+
886+
bar->submap = submap;
887+
bar->num_submap = nsub;
888+
889+
ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, bar);
890+
if (ret) {
891+
dev_err(&epf->dev, "pci_epc_set_bar() failed: %d\n", ret);
892+
bar->submap = old_submap;
893+
bar->num_submap = old_nsub;
894+
kfree(submap);
895+
goto err;
896+
}
897+
kfree(old_submap);
898+
899+
/*
900+
* Fill deterministic signatures into the physical regions that
901+
* each BAR subrange maps to. RC verifies these to ensure the
902+
* submap order is really applied.
903+
*/
904+
addr = (u8 *)bar->addr;
905+
for (i = 0; i < nsub; i++) {
906+
phys_idx = i ^ 1;
907+
memset(addr + (phys_idx * sub_size),
908+
pci_epf_test_subrange_sig_byte(barno, i),
909+
sub_size);
910+
}
911+
912+
status |= STATUS_BAR_SUBRANGE_SETUP_SUCCESS;
913+
reg->status = cpu_to_le32(status);
914+
return;
915+
916+
err:
917+
status |= STATUS_BAR_SUBRANGE_SETUP_FAIL;
918+
reg->status = cpu_to_le32(status);
919+
}
920+
921+
static void pci_epf_test_bar_subrange_clear(struct pci_epf_test *epf_test,
922+
struct pci_epf_test_reg *reg)
923+
{
924+
struct pci_epf *epf = epf_test->epf;
925+
struct pci_epf_bar_submap *submap;
926+
struct pci_epc *epc = epf->epc;
927+
/* reg->size carries BAR number for BAR_SUBRANGE_* commands. */
928+
enum pci_barno barno = le32_to_cpu(reg->size);
929+
u32 status = le32_to_cpu(reg->status);
930+
struct pci_epf_bar *bar;
931+
unsigned int nsub;
932+
int ret;
933+
934+
if (barno >= PCI_STD_NUM_BARS) {
935+
dev_err(&epf->dev, "Invalid barno: %d\n", barno);
936+
goto err;
937+
}
938+
939+
bar = &epf->bar[barno];
940+
submap = bar->submap;
941+
nsub = bar->num_submap;
942+
943+
if (!submap || !nsub)
944+
goto err;
945+
946+
bar->submap = NULL;
947+
bar->num_submap = 0;
948+
949+
ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no, bar);
950+
if (ret) {
951+
bar->submap = submap;
952+
bar->num_submap = nsub;
953+
dev_err(&epf->dev, "pci_epc_set_bar() failed: %d\n", ret);
954+
goto err;
955+
}
956+
kfree(submap);
957+
958+
status |= STATUS_BAR_SUBRANGE_CLEAR_SUCCESS;
959+
reg->status = cpu_to_le32(status);
960+
return;
961+
962+
err:
963+
status |= STATUS_BAR_SUBRANGE_CLEAR_FAIL;
964+
reg->status = cpu_to_le32(status);
965+
}
966+
809967
static void pci_epf_test_cmd_handler(struct work_struct *work)
810968
{
811969
u32 command;
@@ -861,6 +1019,14 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
8611019
pci_epf_test_disable_doorbell(epf_test, reg);
8621020
pci_epf_test_raise_irq(epf_test, reg);
8631021
break;
1022+
case COMMAND_BAR_SUBRANGE_SETUP:
1023+
pci_epf_test_bar_subrange_setup(epf_test, reg);
1024+
pci_epf_test_raise_irq(epf_test, reg);
1025+
break;
1026+
case COMMAND_BAR_SUBRANGE_CLEAR:
1027+
pci_epf_test_bar_subrange_clear(epf_test, reg);
1028+
pci_epf_test_raise_irq(epf_test, reg);
1029+
break;
8641030
default:
8651031
dev_err(dev, "Invalid command 0x%x\n", command);
8661032
break;
@@ -933,6 +1099,10 @@ static void pci_epf_test_set_capabilities(struct pci_epf *epf)
9331099
if (epf_test->epc_features->intx_capable)
9341100
caps |= CAP_INTX;
9351101

1102+
if (epf_test->epc_features->dynamic_inbound_mapping &&
1103+
epf_test->epc_features->subrange_mapping)
1104+
caps |= CAP_SUBRANGE_MAPPING;
1105+
9361106
reg->caps = cpu_to_le32(caps);
9371107
}
9381108

0 commit comments

Comments
 (0)