Hi @ventt,
Thank you for your response. I went through the link you provided and followed the way suggested.
In the Linux kernel code, I have found following api which reset the secondary bus according to the PCIe standard and then wait for secondary bus to be ready again:
void pci_reset_secondary_bus(struct pci_dev *dev)
{
u16 ctrl;
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
/*
* PCI spec v3.0 7.6.4.2 requires minimum Trst of 1ms. Double
* this to 2ms to ensure that we meet the minimum requirement.
*/
msleep(2);
ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
}
/**
* pci_bridge_wait_for_secondary_bus - Wait for secondary bus to be accessible
* @dev: PCI bridge
* @reset_type: reset type in human-readable form
*
* Handle necessary delays before access to the devices on the secondary
* side of the bridge are permitted after D3cold to D0 transition
* or Conventional Reset.
*
* For PCIe this means the delays in PCIe 5.0 section 6.6.1. For
* conventional PCI it means Tpvrh + Trhfa specified in PCI 3.0 section
* 4.3.2.
*
* Return 0 on success or -ENOTTY if the first device on the secondary bus
* failed to become accessible.
*/
int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type)
{
struct pci_dev *child;
int delay;
if (pci_dev_is_disconnected(dev))
return 0;
if (!pci_is_bridge(dev))
return 0;
down_read(&pci_bus_sem);
/*
* We only deal with devices that are present currently on the bus.
* For any hot-added devices the access delay is handled in pciehp
* board_added(). In case of ACPI hotplug the firmware is expected
* to configure the devices before OS is notified.
*/
if (!dev->subordinate || list_empty(&dev->subordinate->devices)) {
up_read(&pci_bus_sem);
return 0;
}
/* Take d3cold_delay requirements into account */
delay = pci_bus_max_d3cold_delay(dev->subordinate);
if (!delay) {
up_read(&pci_bus_sem);
return 0;
}
child = list_first_entry(&dev->subordinate->devices, struct pci_dev,
bus_list);
up_read(&pci_bus_sem);
/*
* Conventional PCI and PCI-X we need to wait Tpvrh + Trhfa before
* accessing the device after reset (that is 1000 ms + 100 ms).
*/
if (!pci_is_pcie(dev)) {
pci_dbg(dev, "waiting %d ms for secondary bus\n", 1000 + delay);
msleep(1000 + delay);
return 0;
}
/*
* For PCIe downstream and root ports that do not support speeds
* greater than 5 GT/s need to wait minimum 100 ms. For higher
* speeds (gen3) we need to wait first for the data link layer to
* become active.
*
* However, 100 ms is the minimum and the PCIe spec says the
* software must allow at least 1s before it can determine that the
* device that did not respond is a broken device. Also device can
* take longer than that to respond if it indicates so through Request
* Retry Status completions.
*
* Therefore we wait for 100 ms and check for the device presence
* until the timeout expires.
*/
if (!pcie_downstream_port(dev))
return 0;
if (pcie_get_speed_cap(dev) <= PCIE_SPEED_5_0GT) {
u16 status;
pci_dbg(dev, "waiting %d ms for downstream link\n", delay);
msleep(delay);
if (!pci_dev_wait(child, reset_type, PCI_RESET_WAIT - delay))
return 0;
/*
* If the port supports active link reporting we now check
* whether the link is active and if not bail out early with
* the assumption that the device is not present anymore.
*/
if (!dev->link_active_reporting)
return -ENOTTY;
pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &status);
if (!(status & PCI_EXP_LNKSTA_DLLLA))
return -ENOTTY;
return pci_dev_wait(child, reset_type,
PCIE_RESET_READY_POLL_MS - PCI_RESET_WAIT);
}
pci_dbg(dev, "waiting %d ms for downstream link, after activation\n",
delay);
if (!pcie_wait_for_link_delay(dev, true, delay)) {
/* Did not train, no need to wait any further */
pci_info(dev, "Data Link Layer Link Active not set in 1000 msec\n");
return -ENOTTY;
}
return pci_dev_wait(child, reset_type,
PCIE_RESET_READY_POLL_MS - delay);
}
But whole those mechanisms require about 1.5sec to be completed which is not acceptable for our system.
Isn't there a command/way on the FPGA side just to terminate active Avalon DMA transaction rather then resetting whole PCIe subsystem?
Thank you.