Skip to content

Commit fc97f5f

Browse files
damien-lemoalbjorn-helgaas
authored andcommitted
PCI: epf-test: Improve handling of command and status registers
The pci-epf-test driver uses the test register BAR memory directly to get and execute a test registers set by the RC side and defined using a struct pci_epf_test_reg. This direct use relies on using the register BAR address as a pointer to a struct pci_epf_test_reg to execute the test case and to send back the test result through the status field of struct pci_epf_test_reg. In practice, the status field is always updated before an interrupt is raised in pci_epf_test_raise_irq(), to ensure that the RC side sees the updated status when receiving an interrupt. However, such assignment direct access does not ensure that changes to the status register make it to memory, and so visible to the host, before an interrupt is raised, thus potentially resulting in the RC host not seeing the correct status result for a test. Avoid this potential problem by using READ_ONCE()/WRITE_ONCE() when accessing the command and status fields of a pci_epf_test_reg structure. This ensure that a test start (pci_epf_test_cmd_handler() function) and completion (with the function pci_epf_test_raise_irq()) achieve a correct synchronization with the MMIO register accesses on the RC host. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Damien Le Moal <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Manivannan Sadhasivam <[email protected]>
1 parent 48d19fc commit fc97f5f

File tree

1 file changed

+9
-4
lines changed

1 file changed

+9
-4
lines changed

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -613,9 +613,14 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
613613
struct pci_epf *epf = epf_test->epf;
614614
struct device *dev = &epf->dev;
615615
struct pci_epc *epc = epf->epc;
616+
u32 status = reg->status | STATUS_IRQ_RAISED;
616617
int count;
617618

618-
reg->status |= STATUS_IRQ_RAISED;
619+
/*
620+
* Set the status before raising the IRQ to ensure that the host sees
621+
* the updated value when it gets the IRQ.
622+
*/
623+
WRITE_ONCE(reg->status, status);
619624

620625
switch (reg->irq_type) {
621626
case IRQ_TYPE_LEGACY:
@@ -659,12 +664,12 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
659664
enum pci_barno test_reg_bar = epf_test->test_reg_bar;
660665
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
661666

662-
command = reg->command;
667+
command = READ_ONCE(reg->command);
663668
if (!command)
664669
goto reset_handler;
665670

666-
reg->command = 0;
667-
reg->status = 0;
671+
WRITE_ONCE(reg->command, 0);
672+
WRITE_ONCE(reg->status, 0);
668673

669674
if (reg->irq_type > IRQ_TYPE_MSIX) {
670675
dev_err(dev, "Failed to detect IRQ type\n");

0 commit comments

Comments
 (0)