162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright(c) 2015 - 2019 Intel Corporation.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/bitfield.h>
762306a36Sopenharmony_ci#include <linux/pci.h>
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/vmalloc.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "hfi.h"
1462306a36Sopenharmony_ci#include "chip_registers.h"
1562306a36Sopenharmony_ci#include "aspm.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * This file contains PCIe utility routines.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci * Do all the common PCIe setup and initialization.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ciint hfi1_pcie_init(struct hfi1_devdata *dd)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	int ret;
2762306a36Sopenharmony_ci	struct pci_dev *pdev = dd->pcidev;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	ret = pci_enable_device(pdev);
3062306a36Sopenharmony_ci	if (ret) {
3162306a36Sopenharmony_ci		/*
3262306a36Sopenharmony_ci		 * This can happen (in theory) iff:
3362306a36Sopenharmony_ci		 * We did a chip reset, and then failed to reprogram the
3462306a36Sopenharmony_ci		 * BAR, or the chip reset due to an internal error.  We then
3562306a36Sopenharmony_ci		 * unloaded the driver and reloaded it.
3662306a36Sopenharmony_ci		 *
3762306a36Sopenharmony_ci		 * Both reset cases set the BAR back to initial state.  For
3862306a36Sopenharmony_ci		 * the latter case, the AER sticky error bit at offset 0x718
3962306a36Sopenharmony_ci		 * should be set, but the Linux kernel doesn't yet know
4062306a36Sopenharmony_ci		 * about that, it appears.  If the original BAR was retained
4162306a36Sopenharmony_ci		 * in the kernel data structures, this may be OK.
4262306a36Sopenharmony_ci		 */
4362306a36Sopenharmony_ci		dd_dev_err(dd, "pci enable failed: error %d\n", -ret);
4462306a36Sopenharmony_ci		return ret;
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	ret = pci_request_regions(pdev, DRIVER_NAME);
4862306a36Sopenharmony_ci	if (ret) {
4962306a36Sopenharmony_ci		dd_dev_err(dd, "pci_request_regions fails: err %d\n", -ret);
5062306a36Sopenharmony_ci		goto bail;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
5462306a36Sopenharmony_ci	if (ret) {
5562306a36Sopenharmony_ci		/*
5662306a36Sopenharmony_ci		 * If the 64 bit setup fails, try 32 bit.  Some systems
5762306a36Sopenharmony_ci		 * do not setup 64 bit maps on systems with 2GB or less
5862306a36Sopenharmony_ci		 * memory installed.
5962306a36Sopenharmony_ci		 */
6062306a36Sopenharmony_ci		ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
6162306a36Sopenharmony_ci		if (ret) {
6262306a36Sopenharmony_ci			dd_dev_err(dd, "Unable to set DMA mask: %d\n", ret);
6362306a36Sopenharmony_ci			goto bail;
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	pci_set_master(pdev);
6862306a36Sopenharmony_ci	return 0;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cibail:
7162306a36Sopenharmony_ci	hfi1_pcie_cleanup(pdev);
7262306a36Sopenharmony_ci	return ret;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/*
7662306a36Sopenharmony_ci * Clean what was done in hfi1_pcie_init()
7762306a36Sopenharmony_ci */
7862306a36Sopenharmony_civoid hfi1_pcie_cleanup(struct pci_dev *pdev)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	pci_disable_device(pdev);
8162306a36Sopenharmony_ci	/*
8262306a36Sopenharmony_ci	 * Release regions should be called after the disable. OK to
8362306a36Sopenharmony_ci	 * call if request regions has not been called or failed.
8462306a36Sopenharmony_ci	 */
8562306a36Sopenharmony_ci	pci_release_regions(pdev);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/*
8962306a36Sopenharmony_ci * Do remaining PCIe setup, once dd is allocated, and save away
9062306a36Sopenharmony_ci * fields required to re-initialize after a chip reset, or for
9162306a36Sopenharmony_ci * various other purposes
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_ciint hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	unsigned long len;
9662306a36Sopenharmony_ci	resource_size_t addr;
9762306a36Sopenharmony_ci	int ret = 0;
9862306a36Sopenharmony_ci	u32 rcv_array_count;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	addr = pci_resource_start(pdev, 0);
10162306a36Sopenharmony_ci	len = pci_resource_len(pdev, 0);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/*
10462306a36Sopenharmony_ci	 * The TXE PIO buffers are at the tail end of the chip space.
10562306a36Sopenharmony_ci	 * Cut them off and map them separately.
10662306a36Sopenharmony_ci	 */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* sanity check vs expectations */
10962306a36Sopenharmony_ci	if (len != TXE_PIO_SEND + TXE_PIO_SIZE) {
11062306a36Sopenharmony_ci		dd_dev_err(dd, "chip PIO range does not match\n");
11162306a36Sopenharmony_ci		return -EINVAL;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	dd->kregbase1 = ioremap(addr, RCV_ARRAY);
11562306a36Sopenharmony_ci	if (!dd->kregbase1) {
11662306a36Sopenharmony_ci		dd_dev_err(dd, "UC mapping of kregbase1 failed\n");
11762306a36Sopenharmony_ci		return -ENOMEM;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci	dd_dev_info(dd, "UC base1: %p for %x\n", dd->kregbase1, RCV_ARRAY);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/* verify that reads actually work, save revision for reset check */
12262306a36Sopenharmony_ci	dd->revision = readq(dd->kregbase1 + CCE_REVISION);
12362306a36Sopenharmony_ci	if (dd->revision == ~(u64)0) {
12462306a36Sopenharmony_ci		dd_dev_err(dd, "Cannot read chip CSRs\n");
12562306a36Sopenharmony_ci		goto nomem;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	rcv_array_count = readq(dd->kregbase1 + RCV_ARRAY_CNT);
12962306a36Sopenharmony_ci	dd_dev_info(dd, "RcvArray count: %u\n", rcv_array_count);
13062306a36Sopenharmony_ci	dd->base2_start  = RCV_ARRAY + rcv_array_count * 8;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	dd->kregbase2 = ioremap(
13362306a36Sopenharmony_ci		addr + dd->base2_start,
13462306a36Sopenharmony_ci		TXE_PIO_SEND - dd->base2_start);
13562306a36Sopenharmony_ci	if (!dd->kregbase2) {
13662306a36Sopenharmony_ci		dd_dev_err(dd, "UC mapping of kregbase2 failed\n");
13762306a36Sopenharmony_ci		goto nomem;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci	dd_dev_info(dd, "UC base2: %p for %x\n", dd->kregbase2,
14062306a36Sopenharmony_ci		    TXE_PIO_SEND - dd->base2_start);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	dd->piobase = ioremap_wc(addr + TXE_PIO_SEND, TXE_PIO_SIZE);
14362306a36Sopenharmony_ci	if (!dd->piobase) {
14462306a36Sopenharmony_ci		dd_dev_err(dd, "WC mapping of send buffers failed\n");
14562306a36Sopenharmony_ci		goto nomem;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci	dd_dev_info(dd, "WC piobase: %p for %x\n", dd->piobase, TXE_PIO_SIZE);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	dd->physaddr = addr;        /* used for io_remap, etc. */
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/*
15262306a36Sopenharmony_ci	 * Map the chip's RcvArray as write-combining to allow us
15362306a36Sopenharmony_ci	 * to write an entire cacheline worth of entries in one shot.
15462306a36Sopenharmony_ci	 */
15562306a36Sopenharmony_ci	dd->rcvarray_wc = ioremap_wc(addr + RCV_ARRAY,
15662306a36Sopenharmony_ci				     rcv_array_count * 8);
15762306a36Sopenharmony_ci	if (!dd->rcvarray_wc) {
15862306a36Sopenharmony_ci		dd_dev_err(dd, "WC mapping of receive array failed\n");
15962306a36Sopenharmony_ci		goto nomem;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci	dd_dev_info(dd, "WC RcvArray: %p for %x\n",
16262306a36Sopenharmony_ci		    dd->rcvarray_wc, rcv_array_count * 8);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	dd->flags |= HFI1_PRESENT;	/* chip.c CSR routines now work */
16562306a36Sopenharmony_ci	return 0;
16662306a36Sopenharmony_cinomem:
16762306a36Sopenharmony_ci	ret = -ENOMEM;
16862306a36Sopenharmony_ci	hfi1_pcie_ddcleanup(dd);
16962306a36Sopenharmony_ci	return ret;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/*
17362306a36Sopenharmony_ci * Do PCIe cleanup related to dd, after chip-specific cleanup, etc.  Just prior
17462306a36Sopenharmony_ci * to releasing the dd memory.
17562306a36Sopenharmony_ci * Void because all of the core pcie cleanup functions are void.
17662306a36Sopenharmony_ci */
17762306a36Sopenharmony_civoid hfi1_pcie_ddcleanup(struct hfi1_devdata *dd)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	dd->flags &= ~HFI1_PRESENT;
18062306a36Sopenharmony_ci	if (dd->kregbase1)
18162306a36Sopenharmony_ci		iounmap(dd->kregbase1);
18262306a36Sopenharmony_ci	dd->kregbase1 = NULL;
18362306a36Sopenharmony_ci	if (dd->kregbase2)
18462306a36Sopenharmony_ci		iounmap(dd->kregbase2);
18562306a36Sopenharmony_ci	dd->kregbase2 = NULL;
18662306a36Sopenharmony_ci	if (dd->rcvarray_wc)
18762306a36Sopenharmony_ci		iounmap(dd->rcvarray_wc);
18862306a36Sopenharmony_ci	dd->rcvarray_wc = NULL;
18962306a36Sopenharmony_ci	if (dd->piobase)
19062306a36Sopenharmony_ci		iounmap(dd->piobase);
19162306a36Sopenharmony_ci	dd->piobase = NULL;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/* return the PCIe link speed from the given link status */
19562306a36Sopenharmony_cistatic u32 extract_speed(u16 linkstat)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	u32 speed;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	switch (linkstat & PCI_EXP_LNKSTA_CLS) {
20062306a36Sopenharmony_ci	default: /* not defined, assume Gen1 */
20162306a36Sopenharmony_ci	case PCI_EXP_LNKSTA_CLS_2_5GB:
20262306a36Sopenharmony_ci		speed = 2500; /* Gen 1, 2.5GHz */
20362306a36Sopenharmony_ci		break;
20462306a36Sopenharmony_ci	case PCI_EXP_LNKSTA_CLS_5_0GB:
20562306a36Sopenharmony_ci		speed = 5000; /* Gen 2, 5GHz */
20662306a36Sopenharmony_ci		break;
20762306a36Sopenharmony_ci	case PCI_EXP_LNKSTA_CLS_8_0GB:
20862306a36Sopenharmony_ci		speed = 8000; /* Gen 3, 8GHz */
20962306a36Sopenharmony_ci		break;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci	return speed;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/* read the link status and set dd->{lbus_width,lbus_speed,lbus_info} */
21562306a36Sopenharmony_cistatic void update_lbus_info(struct hfi1_devdata *dd)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	u16 linkstat;
21862306a36Sopenharmony_ci	int ret;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	ret = pcie_capability_read_word(dd->pcidev, PCI_EXP_LNKSTA, &linkstat);
22162306a36Sopenharmony_ci	if (ret) {
22262306a36Sopenharmony_ci		dd_dev_err(dd, "Unable to read from PCI config\n");
22362306a36Sopenharmony_ci		return;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	dd->lbus_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, linkstat);
22762306a36Sopenharmony_ci	dd->lbus_speed = extract_speed(linkstat);
22862306a36Sopenharmony_ci	snprintf(dd->lbus_info, sizeof(dd->lbus_info),
22962306a36Sopenharmony_ci		 "PCIe,%uMHz,x%u", dd->lbus_speed, dd->lbus_width);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci/*
23362306a36Sopenharmony_ci * Read in the current PCIe link width and speed.  Find if the link is
23462306a36Sopenharmony_ci * Gen3 capable.
23562306a36Sopenharmony_ci */
23662306a36Sopenharmony_ciint pcie_speeds(struct hfi1_devdata *dd)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	u32 linkcap;
23962306a36Sopenharmony_ci	struct pci_dev *parent = dd->pcidev->bus->self;
24062306a36Sopenharmony_ci	int ret;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (!pci_is_pcie(dd->pcidev)) {
24362306a36Sopenharmony_ci		dd_dev_err(dd, "Can't find PCI Express capability!\n");
24462306a36Sopenharmony_ci		return -EINVAL;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/* find if our max speed is Gen3 and parent supports Gen3 speeds */
24862306a36Sopenharmony_ci	dd->link_gen3_capable = 1;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	ret = pcie_capability_read_dword(dd->pcidev, PCI_EXP_LNKCAP, &linkcap);
25162306a36Sopenharmony_ci	if (ret) {
25262306a36Sopenharmony_ci		dd_dev_err(dd, "Unable to read from PCI config\n");
25362306a36Sopenharmony_ci		return pcibios_err_to_errno(ret);
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if ((linkcap & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_8_0GB) {
25762306a36Sopenharmony_ci		dd_dev_info(dd,
25862306a36Sopenharmony_ci			    "This HFI is not Gen3 capable, max speed 0x%x, need 0x3\n",
25962306a36Sopenharmony_ci			    linkcap & PCI_EXP_LNKCAP_SLS);
26062306a36Sopenharmony_ci		dd->link_gen3_capable = 0;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/*
26462306a36Sopenharmony_ci	 * bus->max_bus_speed is set from the bridge's linkcap Max Link Speed
26562306a36Sopenharmony_ci	 */
26662306a36Sopenharmony_ci	if (parent &&
26762306a36Sopenharmony_ci	    (dd->pcidev->bus->max_bus_speed == PCIE_SPEED_2_5GT ||
26862306a36Sopenharmony_ci	     dd->pcidev->bus->max_bus_speed == PCIE_SPEED_5_0GT)) {
26962306a36Sopenharmony_ci		dd_dev_info(dd, "Parent PCIe bridge does not support Gen3\n");
27062306a36Sopenharmony_ci		dd->link_gen3_capable = 0;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* obtain the link width and current speed */
27462306a36Sopenharmony_ci	update_lbus_info(dd);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	dd_dev_info(dd, "%s\n", dd->lbus_info);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/*
28262306a36Sopenharmony_ci * Restore command and BARs after a reset has wiped them out
28362306a36Sopenharmony_ci *
28462306a36Sopenharmony_ci * Returns 0 on success, otherwise a negative error value
28562306a36Sopenharmony_ci */
28662306a36Sopenharmony_ciint restore_pci_variables(struct hfi1_devdata *dd)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	int ret;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	ret = pci_write_config_word(dd->pcidev, PCI_COMMAND, dd->pci_command);
29162306a36Sopenharmony_ci	if (ret)
29262306a36Sopenharmony_ci		goto error;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	ret = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
29562306a36Sopenharmony_ci				     dd->pcibar0);
29662306a36Sopenharmony_ci	if (ret)
29762306a36Sopenharmony_ci		goto error;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	ret = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1,
30062306a36Sopenharmony_ci				     dd->pcibar1);
30162306a36Sopenharmony_ci	if (ret)
30262306a36Sopenharmony_ci		goto error;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	ret = pci_write_config_dword(dd->pcidev, PCI_ROM_ADDRESS, dd->pci_rom);
30562306a36Sopenharmony_ci	if (ret)
30662306a36Sopenharmony_ci		goto error;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	ret = pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL,
30962306a36Sopenharmony_ci					 dd->pcie_devctl);
31062306a36Sopenharmony_ci	if (ret)
31162306a36Sopenharmony_ci		goto error;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	ret = pcie_capability_write_word(dd->pcidev, PCI_EXP_LNKCTL,
31462306a36Sopenharmony_ci					 dd->pcie_lnkctl);
31562306a36Sopenharmony_ci	if (ret)
31662306a36Sopenharmony_ci		goto error;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	ret = pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL2,
31962306a36Sopenharmony_ci					 dd->pcie_devctl2);
32062306a36Sopenharmony_ci	if (ret)
32162306a36Sopenharmony_ci		goto error;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	ret = pci_write_config_dword(dd->pcidev, PCI_CFG_MSIX0, dd->pci_msix0);
32462306a36Sopenharmony_ci	if (ret)
32562306a36Sopenharmony_ci		goto error;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (pci_find_ext_capability(dd->pcidev, PCI_EXT_CAP_ID_TPH)) {
32862306a36Sopenharmony_ci		ret = pci_write_config_dword(dd->pcidev, PCIE_CFG_TPH2,
32962306a36Sopenharmony_ci					     dd->pci_tph2);
33062306a36Sopenharmony_ci		if (ret)
33162306a36Sopenharmony_ci			goto error;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci	return 0;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cierror:
33662306a36Sopenharmony_ci	dd_dev_err(dd, "Unable to write to PCI config\n");
33762306a36Sopenharmony_ci	return pcibios_err_to_errno(ret);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci/*
34162306a36Sopenharmony_ci * Save BARs and command to rewrite after device reset
34262306a36Sopenharmony_ci *
34362306a36Sopenharmony_ci * Returns 0 on success, otherwise a negative error value
34462306a36Sopenharmony_ci */
34562306a36Sopenharmony_ciint save_pci_variables(struct hfi1_devdata *dd)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	int ret;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	ret = pci_read_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
35062306a36Sopenharmony_ci				    &dd->pcibar0);
35162306a36Sopenharmony_ci	if (ret)
35262306a36Sopenharmony_ci		goto error;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	ret = pci_read_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1,
35562306a36Sopenharmony_ci				    &dd->pcibar1);
35662306a36Sopenharmony_ci	if (ret)
35762306a36Sopenharmony_ci		goto error;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	ret = pci_read_config_dword(dd->pcidev, PCI_ROM_ADDRESS, &dd->pci_rom);
36062306a36Sopenharmony_ci	if (ret)
36162306a36Sopenharmony_ci		goto error;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	ret = pci_read_config_word(dd->pcidev, PCI_COMMAND, &dd->pci_command);
36462306a36Sopenharmony_ci	if (ret)
36562306a36Sopenharmony_ci		goto error;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	ret = pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL,
36862306a36Sopenharmony_ci					&dd->pcie_devctl);
36962306a36Sopenharmony_ci	if (ret)
37062306a36Sopenharmony_ci		goto error;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	ret = pcie_capability_read_word(dd->pcidev, PCI_EXP_LNKCTL,
37362306a36Sopenharmony_ci					&dd->pcie_lnkctl);
37462306a36Sopenharmony_ci	if (ret)
37562306a36Sopenharmony_ci		goto error;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	ret = pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL2,
37862306a36Sopenharmony_ci					&dd->pcie_devctl2);
37962306a36Sopenharmony_ci	if (ret)
38062306a36Sopenharmony_ci		goto error;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	ret = pci_read_config_dword(dd->pcidev, PCI_CFG_MSIX0, &dd->pci_msix0);
38362306a36Sopenharmony_ci	if (ret)
38462306a36Sopenharmony_ci		goto error;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (pci_find_ext_capability(dd->pcidev, PCI_EXT_CAP_ID_TPH)) {
38762306a36Sopenharmony_ci		ret = pci_read_config_dword(dd->pcidev, PCIE_CFG_TPH2,
38862306a36Sopenharmony_ci					    &dd->pci_tph2);
38962306a36Sopenharmony_ci		if (ret)
39062306a36Sopenharmony_ci			goto error;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci	return 0;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cierror:
39562306a36Sopenharmony_ci	dd_dev_err(dd, "Unable to read from PCI config\n");
39662306a36Sopenharmony_ci	return pcibios_err_to_errno(ret);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/*
40062306a36Sopenharmony_ci * BIOS may not set PCIe bus-utilization parameters for best performance.
40162306a36Sopenharmony_ci * Check and optionally adjust them to maximize our throughput.
40262306a36Sopenharmony_ci */
40362306a36Sopenharmony_cistatic int hfi1_pcie_caps;
40462306a36Sopenharmony_cimodule_param_named(pcie_caps, hfi1_pcie_caps, int, 0444);
40562306a36Sopenharmony_ciMODULE_PARM_DESC(pcie_caps, "Max PCIe tuning: Payload (0..3), ReadReq (4..7)");
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci/**
40862306a36Sopenharmony_ci * tune_pcie_caps() - Code to adjust PCIe capabilities.
40962306a36Sopenharmony_ci * @dd: Valid device data structure
41062306a36Sopenharmony_ci *
41162306a36Sopenharmony_ci */
41262306a36Sopenharmony_civoid tune_pcie_caps(struct hfi1_devdata *dd)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	struct pci_dev *parent;
41562306a36Sopenharmony_ci	u16 rc_mpss, rc_mps, ep_mpss, ep_mps;
41662306a36Sopenharmony_ci	u16 rc_mrrs, ep_mrrs, max_mrrs, ectl;
41762306a36Sopenharmony_ci	int ret;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/*
42062306a36Sopenharmony_ci	 * Turn on extended tags in DevCtl in case the BIOS has turned it off
42162306a36Sopenharmony_ci	 * to improve WFR SDMA bandwidth
42262306a36Sopenharmony_ci	 */
42362306a36Sopenharmony_ci	ret = pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL, &ectl);
42462306a36Sopenharmony_ci	if ((!ret) && !(ectl & PCI_EXP_DEVCTL_EXT_TAG)) {
42562306a36Sopenharmony_ci		dd_dev_info(dd, "Enabling PCIe extended tags\n");
42662306a36Sopenharmony_ci		ectl |= PCI_EXP_DEVCTL_EXT_TAG;
42762306a36Sopenharmony_ci		ret = pcie_capability_write_word(dd->pcidev,
42862306a36Sopenharmony_ci						 PCI_EXP_DEVCTL, ectl);
42962306a36Sopenharmony_ci		if (ret)
43062306a36Sopenharmony_ci			dd_dev_info(dd, "Unable to write to PCI config\n");
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci	/* Find out supported and configured values for parent (root) */
43362306a36Sopenharmony_ci	parent = dd->pcidev->bus->self;
43462306a36Sopenharmony_ci	/*
43562306a36Sopenharmony_ci	 * The driver cannot perform the tuning if it does not have
43662306a36Sopenharmony_ci	 * access to the upstream component.
43762306a36Sopenharmony_ci	 */
43862306a36Sopenharmony_ci	if (!parent) {
43962306a36Sopenharmony_ci		dd_dev_info(dd, "Parent not found\n");
44062306a36Sopenharmony_ci		return;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	if (!pci_is_root_bus(parent->bus)) {
44362306a36Sopenharmony_ci		dd_dev_info(dd, "Parent not root\n");
44462306a36Sopenharmony_ci		return;
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci	if (!pci_is_pcie(parent)) {
44762306a36Sopenharmony_ci		dd_dev_info(dd, "Parent is not PCI Express capable\n");
44862306a36Sopenharmony_ci		return;
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci	if (!pci_is_pcie(dd->pcidev)) {
45162306a36Sopenharmony_ci		dd_dev_info(dd, "PCI device is not PCI Express capable\n");
45262306a36Sopenharmony_ci		return;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci	rc_mpss = parent->pcie_mpss;
45562306a36Sopenharmony_ci	rc_mps = ffs(pcie_get_mps(parent)) - 8;
45662306a36Sopenharmony_ci	/* Find out supported and configured values for endpoint (us) */
45762306a36Sopenharmony_ci	ep_mpss = dd->pcidev->pcie_mpss;
45862306a36Sopenharmony_ci	ep_mps = ffs(pcie_get_mps(dd->pcidev)) - 8;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/* Find max payload supported by root, endpoint */
46162306a36Sopenharmony_ci	if (rc_mpss > ep_mpss)
46262306a36Sopenharmony_ci		rc_mpss = ep_mpss;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/* If Supported greater than limit in module param, limit it */
46562306a36Sopenharmony_ci	if (rc_mpss > (hfi1_pcie_caps & 7))
46662306a36Sopenharmony_ci		rc_mpss = hfi1_pcie_caps & 7;
46762306a36Sopenharmony_ci	/* If less than (allowed, supported), bump root payload */
46862306a36Sopenharmony_ci	if (rc_mpss > rc_mps) {
46962306a36Sopenharmony_ci		rc_mps = rc_mpss;
47062306a36Sopenharmony_ci		pcie_set_mps(parent, 128 << rc_mps);
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci	/* If less than (allowed, supported), bump endpoint payload */
47362306a36Sopenharmony_ci	if (rc_mpss > ep_mps) {
47462306a36Sopenharmony_ci		ep_mps = rc_mpss;
47562306a36Sopenharmony_ci		pcie_set_mps(dd->pcidev, 128 << ep_mps);
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	/*
47962306a36Sopenharmony_ci	 * Now the Read Request size.
48062306a36Sopenharmony_ci	 * No field for max supported, but PCIe spec limits it to 4096,
48162306a36Sopenharmony_ci	 * which is code '5' (log2(4096) - 7)
48262306a36Sopenharmony_ci	 */
48362306a36Sopenharmony_ci	max_mrrs = 5;
48462306a36Sopenharmony_ci	if (max_mrrs > ((hfi1_pcie_caps >> 4) & 7))
48562306a36Sopenharmony_ci		max_mrrs = (hfi1_pcie_caps >> 4) & 7;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	max_mrrs = 128 << max_mrrs;
48862306a36Sopenharmony_ci	rc_mrrs = pcie_get_readrq(parent);
48962306a36Sopenharmony_ci	ep_mrrs = pcie_get_readrq(dd->pcidev);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (max_mrrs > rc_mrrs) {
49262306a36Sopenharmony_ci		rc_mrrs = max_mrrs;
49362306a36Sopenharmony_ci		pcie_set_readrq(parent, rc_mrrs);
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci	if (max_mrrs > ep_mrrs) {
49662306a36Sopenharmony_ci		ep_mrrs = max_mrrs;
49762306a36Sopenharmony_ci		pcie_set_readrq(dd->pcidev, ep_mrrs);
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/* End of PCIe capability tuning */
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci/*
50462306a36Sopenharmony_ci * From here through hfi1_pci_err_handler definition is invoked via
50562306a36Sopenharmony_ci * PCI error infrastructure, registered via pci
50662306a36Sopenharmony_ci */
50762306a36Sopenharmony_cistatic pci_ers_result_t
50862306a36Sopenharmony_cipci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct hfi1_devdata *dd = pci_get_drvdata(pdev);
51162306a36Sopenharmony_ci	pci_ers_result_t ret = PCI_ERS_RESULT_RECOVERED;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	switch (state) {
51462306a36Sopenharmony_ci	case pci_channel_io_normal:
51562306a36Sopenharmony_ci		dd_dev_info(dd, "State Normal, ignoring\n");
51662306a36Sopenharmony_ci		break;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	case pci_channel_io_frozen:
51962306a36Sopenharmony_ci		dd_dev_info(dd, "State Frozen, requesting reset\n");
52062306a36Sopenharmony_ci		pci_disable_device(pdev);
52162306a36Sopenharmony_ci		ret = PCI_ERS_RESULT_NEED_RESET;
52262306a36Sopenharmony_ci		break;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	case pci_channel_io_perm_failure:
52562306a36Sopenharmony_ci		if (dd) {
52662306a36Sopenharmony_ci			dd_dev_info(dd, "State Permanent Failure, disabling\n");
52762306a36Sopenharmony_ci			/* no more register accesses! */
52862306a36Sopenharmony_ci			dd->flags &= ~HFI1_PRESENT;
52962306a36Sopenharmony_ci			hfi1_disable_after_error(dd);
53062306a36Sopenharmony_ci		}
53162306a36Sopenharmony_ci		 /* else early, or other problem */
53262306a36Sopenharmony_ci		ret =  PCI_ERS_RESULT_DISCONNECT;
53362306a36Sopenharmony_ci		break;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	default: /* shouldn't happen */
53662306a36Sopenharmony_ci		dd_dev_info(dd, "HFI1 PCI errors detected (state %d)\n",
53762306a36Sopenharmony_ci			    state);
53862306a36Sopenharmony_ci		break;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci	return ret;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic pci_ers_result_t
54462306a36Sopenharmony_cipci_mmio_enabled(struct pci_dev *pdev)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	u64 words = 0U;
54762306a36Sopenharmony_ci	struct hfi1_devdata *dd = pci_get_drvdata(pdev);
54862306a36Sopenharmony_ci	pci_ers_result_t ret = PCI_ERS_RESULT_RECOVERED;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (dd && dd->pport) {
55162306a36Sopenharmony_ci		words = read_port_cntr(dd->pport, C_RX_WORDS, CNTR_INVALID_VL);
55262306a36Sopenharmony_ci		if (words == ~0ULL)
55362306a36Sopenharmony_ci			ret = PCI_ERS_RESULT_NEED_RESET;
55462306a36Sopenharmony_ci		dd_dev_info(dd,
55562306a36Sopenharmony_ci			    "HFI1 mmio_enabled function called, read wordscntr %llx, returning %d\n",
55662306a36Sopenharmony_ci			    words, ret);
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci	return  ret;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic pci_ers_result_t
56262306a36Sopenharmony_cipci_slot_reset(struct pci_dev *pdev)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	struct hfi1_devdata *dd = pci_get_drvdata(pdev);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	dd_dev_info(dd, "HFI1 slot_reset function called, ignored\n");
56762306a36Sopenharmony_ci	return PCI_ERS_RESULT_CAN_RECOVER;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic void
57162306a36Sopenharmony_cipci_resume(struct pci_dev *pdev)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	struct hfi1_devdata *dd = pci_get_drvdata(pdev);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	dd_dev_info(dd, "HFI1 resume function called\n");
57662306a36Sopenharmony_ci	/*
57762306a36Sopenharmony_ci	 * Running jobs will fail, since it's asynchronous
57862306a36Sopenharmony_ci	 * unlike sysfs-requested reset.   Better than
57962306a36Sopenharmony_ci	 * doing nothing.
58062306a36Sopenharmony_ci	 */
58162306a36Sopenharmony_ci	hfi1_init(dd, 1); /* same as re-init after reset */
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ciconst struct pci_error_handlers hfi1_pci_err_handler = {
58562306a36Sopenharmony_ci	.error_detected = pci_error_detected,
58662306a36Sopenharmony_ci	.mmio_enabled = pci_mmio_enabled,
58762306a36Sopenharmony_ci	.slot_reset = pci_slot_reset,
58862306a36Sopenharmony_ci	.resume = pci_resume,
58962306a36Sopenharmony_ci};
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci/*============================================================================*/
59262306a36Sopenharmony_ci/* PCIe Gen3 support */
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci/*
59562306a36Sopenharmony_ci * This code is separated out because it is expected to be removed in the
59662306a36Sopenharmony_ci * final shipping product.  If not, then it will be revisited and items
59762306a36Sopenharmony_ci * will be moved to more standard locations.
59862306a36Sopenharmony_ci */
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci/* ASIC_PCI_SD_HOST_STATUS.FW_DNLD_STS field values */
60162306a36Sopenharmony_ci#define DL_STATUS_HFI0 0x1	/* hfi0 firmware download complete */
60262306a36Sopenharmony_ci#define DL_STATUS_HFI1 0x2	/* hfi1 firmware download complete */
60362306a36Sopenharmony_ci#define DL_STATUS_BOTH 0x3	/* hfi0 and hfi1 firmware download complete */
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/* ASIC_PCI_SD_HOST_STATUS.FW_DNLD_ERR field values */
60662306a36Sopenharmony_ci#define DL_ERR_NONE		0x0	/* no error */
60762306a36Sopenharmony_ci#define DL_ERR_SWAP_PARITY	0x1	/* parity error in SerDes interrupt */
60862306a36Sopenharmony_ci					/*   or response data */
60962306a36Sopenharmony_ci#define DL_ERR_DISABLED	0x2	/* hfi disabled */
61062306a36Sopenharmony_ci#define DL_ERR_SECURITY	0x3	/* security check failed */
61162306a36Sopenharmony_ci#define DL_ERR_SBUS		0x4	/* SBus status error */
61262306a36Sopenharmony_ci#define DL_ERR_XFR_PARITY	0x5	/* parity error during ROM transfer*/
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci/* gasket block secondary bus reset delay */
61562306a36Sopenharmony_ci#define SBR_DELAY_US 200000	/* 200ms */
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic uint pcie_target = 3;
61862306a36Sopenharmony_cimodule_param(pcie_target, uint, S_IRUGO);
61962306a36Sopenharmony_ciMODULE_PARM_DESC(pcie_target, "PCIe target speed (0 skip, 1-3 Gen1-3)");
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic uint pcie_force;
62262306a36Sopenharmony_cimodule_param(pcie_force, uint, S_IRUGO);
62362306a36Sopenharmony_ciMODULE_PARM_DESC(pcie_force, "Force driver to do a PCIe firmware download even if already at target speed");
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic uint pcie_retry = 5;
62662306a36Sopenharmony_cimodule_param(pcie_retry, uint, S_IRUGO);
62762306a36Sopenharmony_ciMODULE_PARM_DESC(pcie_retry, "Driver will try this many times to reach requested speed");
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci#define UNSET_PSET 255
63062306a36Sopenharmony_ci#define DEFAULT_DISCRETE_PSET 2	/* discrete HFI */
63162306a36Sopenharmony_ci#define DEFAULT_MCP_PSET 6	/* MCP HFI */
63262306a36Sopenharmony_cistatic uint pcie_pset = UNSET_PSET;
63362306a36Sopenharmony_cimodule_param(pcie_pset, uint, S_IRUGO);
63462306a36Sopenharmony_ciMODULE_PARM_DESC(pcie_pset, "PCIe Eq Pset value to use, range is 0-10");
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic uint pcie_ctle = 3; /* discrete on, integrated on */
63762306a36Sopenharmony_cimodule_param(pcie_ctle, uint, S_IRUGO);
63862306a36Sopenharmony_ciMODULE_PARM_DESC(pcie_ctle, "PCIe static CTLE mode, bit 0 - discrete on/off, bit 1 - integrated on/off");
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci/* equalization columns */
64162306a36Sopenharmony_ci#define PREC 0
64262306a36Sopenharmony_ci#define ATTN 1
64362306a36Sopenharmony_ci#define POST 2
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci/* discrete silicon preliminary equalization values */
64662306a36Sopenharmony_cistatic const u8 discrete_preliminary_eq[11][3] = {
64762306a36Sopenharmony_ci	/* prec   attn   post */
64862306a36Sopenharmony_ci	{  0x00,  0x00,  0x12 },	/* p0 */
64962306a36Sopenharmony_ci	{  0x00,  0x00,  0x0c },	/* p1 */
65062306a36Sopenharmony_ci	{  0x00,  0x00,  0x0f },	/* p2 */
65162306a36Sopenharmony_ci	{  0x00,  0x00,  0x09 },	/* p3 */
65262306a36Sopenharmony_ci	{  0x00,  0x00,  0x00 },	/* p4 */
65362306a36Sopenharmony_ci	{  0x06,  0x00,  0x00 },	/* p5 */
65462306a36Sopenharmony_ci	{  0x09,  0x00,  0x00 },	/* p6 */
65562306a36Sopenharmony_ci	{  0x06,  0x00,  0x0f },	/* p7 */
65662306a36Sopenharmony_ci	{  0x09,  0x00,  0x09 },	/* p8 */
65762306a36Sopenharmony_ci	{  0x0c,  0x00,  0x00 },	/* p9 */
65862306a36Sopenharmony_ci	{  0x00,  0x00,  0x18 },	/* p10 */
65962306a36Sopenharmony_ci};
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci/* integrated silicon preliminary equalization values */
66262306a36Sopenharmony_cistatic const u8 integrated_preliminary_eq[11][3] = {
66362306a36Sopenharmony_ci	/* prec   attn   post */
66462306a36Sopenharmony_ci	{  0x00,  0x1e,  0x07 },	/* p0 */
66562306a36Sopenharmony_ci	{  0x00,  0x1e,  0x05 },	/* p1 */
66662306a36Sopenharmony_ci	{  0x00,  0x1e,  0x06 },	/* p2 */
66762306a36Sopenharmony_ci	{  0x00,  0x1e,  0x04 },	/* p3 */
66862306a36Sopenharmony_ci	{  0x00,  0x1e,  0x00 },	/* p4 */
66962306a36Sopenharmony_ci	{  0x03,  0x1e,  0x00 },	/* p5 */
67062306a36Sopenharmony_ci	{  0x04,  0x1e,  0x00 },	/* p6 */
67162306a36Sopenharmony_ci	{  0x03,  0x1e,  0x06 },	/* p7 */
67262306a36Sopenharmony_ci	{  0x03,  0x1e,  0x04 },	/* p8 */
67362306a36Sopenharmony_ci	{  0x05,  0x1e,  0x00 },	/* p9 */
67462306a36Sopenharmony_ci	{  0x00,  0x1e,  0x0a },	/* p10 */
67562306a36Sopenharmony_ci};
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic const u8 discrete_ctle_tunings[11][4] = {
67862306a36Sopenharmony_ci	/* DC     LF     HF     BW */
67962306a36Sopenharmony_ci	{  0x48,  0x0b,  0x04,  0x04 },	/* p0 */
68062306a36Sopenharmony_ci	{  0x60,  0x05,  0x0f,  0x0a },	/* p1 */
68162306a36Sopenharmony_ci	{  0x50,  0x09,  0x06,  0x06 },	/* p2 */
68262306a36Sopenharmony_ci	{  0x68,  0x05,  0x0f,  0x0a },	/* p3 */
68362306a36Sopenharmony_ci	{  0x80,  0x05,  0x0f,  0x0a },	/* p4 */
68462306a36Sopenharmony_ci	{  0x70,  0x05,  0x0f,  0x0a },	/* p5 */
68562306a36Sopenharmony_ci	{  0x68,  0x05,  0x0f,  0x0a },	/* p6 */
68662306a36Sopenharmony_ci	{  0x38,  0x0f,  0x00,  0x00 },	/* p7 */
68762306a36Sopenharmony_ci	{  0x48,  0x09,  0x06,  0x06 },	/* p8 */
68862306a36Sopenharmony_ci	{  0x60,  0x05,  0x0f,  0x0a },	/* p9 */
68962306a36Sopenharmony_ci	{  0x38,  0x0f,  0x00,  0x00 },	/* p10 */
69062306a36Sopenharmony_ci};
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic const u8 integrated_ctle_tunings[11][4] = {
69362306a36Sopenharmony_ci	/* DC     LF     HF     BW */
69462306a36Sopenharmony_ci	{  0x38,  0x0f,  0x00,  0x00 },	/* p0 */
69562306a36Sopenharmony_ci	{  0x38,  0x0f,  0x00,  0x00 },	/* p1 */
69662306a36Sopenharmony_ci	{  0x38,  0x0f,  0x00,  0x00 },	/* p2 */
69762306a36Sopenharmony_ci	{  0x38,  0x0f,  0x00,  0x00 },	/* p3 */
69862306a36Sopenharmony_ci	{  0x58,  0x0a,  0x05,  0x05 },	/* p4 */
69962306a36Sopenharmony_ci	{  0x48,  0x0a,  0x05,  0x05 },	/* p5 */
70062306a36Sopenharmony_ci	{  0x40,  0x0a,  0x05,  0x05 },	/* p6 */
70162306a36Sopenharmony_ci	{  0x38,  0x0f,  0x00,  0x00 },	/* p7 */
70262306a36Sopenharmony_ci	{  0x38,  0x0f,  0x00,  0x00 },	/* p8 */
70362306a36Sopenharmony_ci	{  0x38,  0x09,  0x06,  0x06 },	/* p9 */
70462306a36Sopenharmony_ci	{  0x38,  0x0e,  0x01,  0x01 },	/* p10 */
70562306a36Sopenharmony_ci};
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci/* helper to format the value to write to hardware */
70862306a36Sopenharmony_ci#define eq_value(pre, curr, post) \
70962306a36Sopenharmony_ci	((((u32)(pre)) << \
71062306a36Sopenharmony_ci			PCIE_CFG_REG_PL102_GEN3_EQ_PRE_CURSOR_PSET_SHIFT) \
71162306a36Sopenharmony_ci	| (((u32)(curr)) << PCIE_CFG_REG_PL102_GEN3_EQ_CURSOR_PSET_SHIFT) \
71262306a36Sopenharmony_ci	| (((u32)(post)) << \
71362306a36Sopenharmony_ci		PCIE_CFG_REG_PL102_GEN3_EQ_POST_CURSOR_PSET_SHIFT))
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci/*
71662306a36Sopenharmony_ci * Load the given EQ preset table into the PCIe hardware.
71762306a36Sopenharmony_ci */
71862306a36Sopenharmony_cistatic int load_eq_table(struct hfi1_devdata *dd, const u8 eq[11][3], u8 fs,
71962306a36Sopenharmony_ci			 u8 div)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	struct pci_dev *pdev = dd->pcidev;
72262306a36Sopenharmony_ci	u32 hit_error = 0;
72362306a36Sopenharmony_ci	u32 violation;
72462306a36Sopenharmony_ci	u32 i;
72562306a36Sopenharmony_ci	u8 c_minus1, c0, c_plus1;
72662306a36Sopenharmony_ci	int ret;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	for (i = 0; i < 11; i++) {
72962306a36Sopenharmony_ci		/* set index */
73062306a36Sopenharmony_ci		pci_write_config_dword(pdev, PCIE_CFG_REG_PL103, i);
73162306a36Sopenharmony_ci		/* write the value */
73262306a36Sopenharmony_ci		c_minus1 = eq[i][PREC] / div;
73362306a36Sopenharmony_ci		c0 = fs - (eq[i][PREC] / div) - (eq[i][POST] / div);
73462306a36Sopenharmony_ci		c_plus1 = eq[i][POST] / div;
73562306a36Sopenharmony_ci		pci_write_config_dword(pdev, PCIE_CFG_REG_PL102,
73662306a36Sopenharmony_ci				       eq_value(c_minus1, c0, c_plus1));
73762306a36Sopenharmony_ci		/* check if these coefficients violate EQ rules */
73862306a36Sopenharmony_ci		ret = pci_read_config_dword(dd->pcidev,
73962306a36Sopenharmony_ci					    PCIE_CFG_REG_PL105, &violation);
74062306a36Sopenharmony_ci		if (ret) {
74162306a36Sopenharmony_ci			dd_dev_err(dd, "Unable to read from PCI config\n");
74262306a36Sopenharmony_ci			hit_error = 1;
74362306a36Sopenharmony_ci			break;
74462306a36Sopenharmony_ci		}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci		if (violation
74762306a36Sopenharmony_ci		    & PCIE_CFG_REG_PL105_GEN3_EQ_VIOLATE_COEF_RULES_SMASK){
74862306a36Sopenharmony_ci			if (hit_error == 0) {
74962306a36Sopenharmony_ci				dd_dev_err(dd,
75062306a36Sopenharmony_ci					   "Gen3 EQ Table Coefficient rule violations\n");
75162306a36Sopenharmony_ci				dd_dev_err(dd, "         prec   attn   post\n");
75262306a36Sopenharmony_ci			}
75362306a36Sopenharmony_ci			dd_dev_err(dd, "   p%02d:   %02x     %02x     %02x\n",
75462306a36Sopenharmony_ci				   i, (u32)eq[i][0], (u32)eq[i][1],
75562306a36Sopenharmony_ci				   (u32)eq[i][2]);
75662306a36Sopenharmony_ci			dd_dev_err(dd, "            %02x     %02x     %02x\n",
75762306a36Sopenharmony_ci				   (u32)c_minus1, (u32)c0, (u32)c_plus1);
75862306a36Sopenharmony_ci			hit_error = 1;
75962306a36Sopenharmony_ci		}
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci	if (hit_error)
76262306a36Sopenharmony_ci		return -EINVAL;
76362306a36Sopenharmony_ci	return 0;
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci/*
76762306a36Sopenharmony_ci * Steps to be done after the PCIe firmware is downloaded and
76862306a36Sopenharmony_ci * before the SBR for the Pcie Gen3.
76962306a36Sopenharmony_ci * The SBus resource is already being held.
77062306a36Sopenharmony_ci */
77162306a36Sopenharmony_cistatic void pcie_post_steps(struct hfi1_devdata *dd)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	int i;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	set_sbus_fast_mode(dd);
77662306a36Sopenharmony_ci	/*
77762306a36Sopenharmony_ci	 * Write to the PCIe PCSes to set the G3_LOCKED_NEXT bits to 1.
77862306a36Sopenharmony_ci	 * This avoids a spurious framing error that can otherwise be
77962306a36Sopenharmony_ci	 * generated by the MAC layer.
78062306a36Sopenharmony_ci	 *
78162306a36Sopenharmony_ci	 * Use individual addresses since no broadcast is set up.
78262306a36Sopenharmony_ci	 */
78362306a36Sopenharmony_ci	for (i = 0; i < NUM_PCIE_SERDES; i++) {
78462306a36Sopenharmony_ci		sbus_request(dd, pcie_pcs_addrs[dd->hfi1_id][i],
78562306a36Sopenharmony_ci			     0x03, WRITE_SBUS_RECEIVER, 0x00022132);
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	clear_sbus_fast_mode(dd);
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci/*
79262306a36Sopenharmony_ci * Trigger a secondary bus reset (SBR) on ourselves using our parent.
79362306a36Sopenharmony_ci *
79462306a36Sopenharmony_ci * Based on pci_parent_bus_reset() which is not exported by the
79562306a36Sopenharmony_ci * kernel core.
79662306a36Sopenharmony_ci */
79762306a36Sopenharmony_cistatic int trigger_sbr(struct hfi1_devdata *dd)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	struct pci_dev *dev = dd->pcidev;
80062306a36Sopenharmony_ci	struct pci_dev *pdev;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	/* need a parent */
80362306a36Sopenharmony_ci	if (!dev->bus->self) {
80462306a36Sopenharmony_ci		dd_dev_err(dd, "%s: no parent device\n", __func__);
80562306a36Sopenharmony_ci		return -ENOTTY;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	/* should not be anyone else on the bus */
80962306a36Sopenharmony_ci	list_for_each_entry(pdev, &dev->bus->devices, bus_list)
81062306a36Sopenharmony_ci		if (pdev != dev) {
81162306a36Sopenharmony_ci			dd_dev_err(dd,
81262306a36Sopenharmony_ci				   "%s: another device is on the same bus\n",
81362306a36Sopenharmony_ci				   __func__);
81462306a36Sopenharmony_ci			return -ENOTTY;
81562306a36Sopenharmony_ci		}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/*
81862306a36Sopenharmony_ci	 * This is an end around to do an SBR during probe time. A new API needs
81962306a36Sopenharmony_ci	 * to be implemented to have cleaner interface but this fixes the
82062306a36Sopenharmony_ci	 * current brokenness
82162306a36Sopenharmony_ci	 */
82262306a36Sopenharmony_ci	return pci_bridge_secondary_bus_reset(dev->bus->self);
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci/*
82662306a36Sopenharmony_ci * Write the given gasket interrupt register.
82762306a36Sopenharmony_ci */
82862306a36Sopenharmony_cistatic void write_gasket_interrupt(struct hfi1_devdata *dd, int index,
82962306a36Sopenharmony_ci				   u16 code, u16 data)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	write_csr(dd, ASIC_PCIE_SD_INTRPT_LIST + (index * 8),
83262306a36Sopenharmony_ci		  (((u64)code << ASIC_PCIE_SD_INTRPT_LIST_INTRPT_CODE_SHIFT) |
83362306a36Sopenharmony_ci		   ((u64)data << ASIC_PCIE_SD_INTRPT_LIST_INTRPT_DATA_SHIFT)));
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci/*
83762306a36Sopenharmony_ci * Tell the gasket logic how to react to the reset.
83862306a36Sopenharmony_ci */
83962306a36Sopenharmony_cistatic void arm_gasket_logic(struct hfi1_devdata *dd)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	u64 reg;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	reg = (((u64)1 << dd->hfi1_id) <<
84462306a36Sopenharmony_ci	       ASIC_PCIE_SD_HOST_CMD_INTRPT_CMD_SHIFT) |
84562306a36Sopenharmony_ci	      ((u64)pcie_serdes_broadcast[dd->hfi1_id] <<
84662306a36Sopenharmony_ci	       ASIC_PCIE_SD_HOST_CMD_SBUS_RCVR_ADDR_SHIFT |
84762306a36Sopenharmony_ci	       ASIC_PCIE_SD_HOST_CMD_SBR_MODE_SMASK |
84862306a36Sopenharmony_ci	       ((u64)SBR_DELAY_US & ASIC_PCIE_SD_HOST_CMD_TIMER_MASK) <<
84962306a36Sopenharmony_ci	       ASIC_PCIE_SD_HOST_CMD_TIMER_SHIFT);
85062306a36Sopenharmony_ci	write_csr(dd, ASIC_PCIE_SD_HOST_CMD, reg);
85162306a36Sopenharmony_ci	/* read back to push the write */
85262306a36Sopenharmony_ci	read_csr(dd, ASIC_PCIE_SD_HOST_CMD);
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci/*
85662306a36Sopenharmony_ci * CCE_PCIE_CTRL long name helpers
85762306a36Sopenharmony_ci * We redefine these shorter macros to use in the code while leaving
85862306a36Sopenharmony_ci * chip_registers.h to be autogenerated from the hardware spec.
85962306a36Sopenharmony_ci */
86062306a36Sopenharmony_ci#define LANE_BUNDLE_MASK              CCE_PCIE_CTRL_PCIE_LANE_BUNDLE_MASK
86162306a36Sopenharmony_ci#define LANE_BUNDLE_SHIFT             CCE_PCIE_CTRL_PCIE_LANE_BUNDLE_SHIFT
86262306a36Sopenharmony_ci#define LANE_DELAY_MASK               CCE_PCIE_CTRL_PCIE_LANE_DELAY_MASK
86362306a36Sopenharmony_ci#define LANE_DELAY_SHIFT              CCE_PCIE_CTRL_PCIE_LANE_DELAY_SHIFT
86462306a36Sopenharmony_ci#define MARGIN_OVERWRITE_ENABLE_SHIFT CCE_PCIE_CTRL_XMT_MARGIN_OVERWRITE_ENABLE_SHIFT
86562306a36Sopenharmony_ci#define MARGIN_SHIFT                  CCE_PCIE_CTRL_XMT_MARGIN_SHIFT
86662306a36Sopenharmony_ci#define MARGIN_G1_G2_OVERWRITE_MASK   CCE_PCIE_CTRL_XMT_MARGIN_GEN1_GEN2_OVERWRITE_ENABLE_MASK
86762306a36Sopenharmony_ci#define MARGIN_G1_G2_OVERWRITE_SHIFT  CCE_PCIE_CTRL_XMT_MARGIN_GEN1_GEN2_OVERWRITE_ENABLE_SHIFT
86862306a36Sopenharmony_ci#define MARGIN_GEN1_GEN2_MASK         CCE_PCIE_CTRL_XMT_MARGIN_GEN1_GEN2_MASK
86962306a36Sopenharmony_ci#define MARGIN_GEN1_GEN2_SHIFT        CCE_PCIE_CTRL_XMT_MARGIN_GEN1_GEN2_SHIFT
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci /*
87262306a36Sopenharmony_ci  * Write xmt_margin for full-swing (WFR-B) or half-swing (WFR-C).
87362306a36Sopenharmony_ci  */
87462306a36Sopenharmony_cistatic void write_xmt_margin(struct hfi1_devdata *dd, const char *fname)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	u64 pcie_ctrl;
87762306a36Sopenharmony_ci	u64 xmt_margin;
87862306a36Sopenharmony_ci	u64 xmt_margin_oe;
87962306a36Sopenharmony_ci	u64 lane_delay;
88062306a36Sopenharmony_ci	u64 lane_bundle;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	pcie_ctrl = read_csr(dd, CCE_PCIE_CTRL);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	/*
88562306a36Sopenharmony_ci	 * For Discrete, use full-swing.
88662306a36Sopenharmony_ci	 *  - PCIe TX defaults to full-swing.
88762306a36Sopenharmony_ci	 *    Leave this register as default.
88862306a36Sopenharmony_ci	 * For Integrated, use half-swing
88962306a36Sopenharmony_ci	 *  - Copy xmt_margin and xmt_margin_oe
89062306a36Sopenharmony_ci	 *    from Gen1/Gen2 to Gen3.
89162306a36Sopenharmony_ci	 */
89262306a36Sopenharmony_ci	if (dd->pcidev->device == PCI_DEVICE_ID_INTEL1) { /* integrated */
89362306a36Sopenharmony_ci		/* extract initial fields */
89462306a36Sopenharmony_ci		xmt_margin = (pcie_ctrl >> MARGIN_GEN1_GEN2_SHIFT)
89562306a36Sopenharmony_ci			      & MARGIN_GEN1_GEN2_MASK;
89662306a36Sopenharmony_ci		xmt_margin_oe = (pcie_ctrl >> MARGIN_G1_G2_OVERWRITE_SHIFT)
89762306a36Sopenharmony_ci				 & MARGIN_G1_G2_OVERWRITE_MASK;
89862306a36Sopenharmony_ci		lane_delay = (pcie_ctrl >> LANE_DELAY_SHIFT) & LANE_DELAY_MASK;
89962306a36Sopenharmony_ci		lane_bundle = (pcie_ctrl >> LANE_BUNDLE_SHIFT)
90062306a36Sopenharmony_ci			       & LANE_BUNDLE_MASK;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci		/*
90362306a36Sopenharmony_ci		 * For A0, EFUSE values are not set.  Override with the
90462306a36Sopenharmony_ci		 * correct values.
90562306a36Sopenharmony_ci		 */
90662306a36Sopenharmony_ci		if (is_ax(dd)) {
90762306a36Sopenharmony_ci			/*
90862306a36Sopenharmony_ci			 * xmt_margin and OverwiteEnabel should be the
90962306a36Sopenharmony_ci			 * same for Gen1/Gen2 and Gen3
91062306a36Sopenharmony_ci			 */
91162306a36Sopenharmony_ci			xmt_margin = 0x5;
91262306a36Sopenharmony_ci			xmt_margin_oe = 0x1;
91362306a36Sopenharmony_ci			lane_delay = 0xF; /* Delay 240ns. */
91462306a36Sopenharmony_ci			lane_bundle = 0x0; /* Set to 1 lane. */
91562306a36Sopenharmony_ci		}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci		/* overwrite existing values */
91862306a36Sopenharmony_ci		pcie_ctrl = (xmt_margin << MARGIN_GEN1_GEN2_SHIFT)
91962306a36Sopenharmony_ci			| (xmt_margin_oe << MARGIN_G1_G2_OVERWRITE_SHIFT)
92062306a36Sopenharmony_ci			| (xmt_margin << MARGIN_SHIFT)
92162306a36Sopenharmony_ci			| (xmt_margin_oe << MARGIN_OVERWRITE_ENABLE_SHIFT)
92262306a36Sopenharmony_ci			| (lane_delay << LANE_DELAY_SHIFT)
92362306a36Sopenharmony_ci			| (lane_bundle << LANE_BUNDLE_SHIFT);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci		write_csr(dd, CCE_PCIE_CTRL, pcie_ctrl);
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	dd_dev_dbg(dd, "%s: program XMT margin, CcePcieCtrl 0x%llx\n",
92962306a36Sopenharmony_ci		   fname, pcie_ctrl);
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci/*
93362306a36Sopenharmony_ci * Do all the steps needed to transition the PCIe link to Gen3 speed.
93462306a36Sopenharmony_ci */
93562306a36Sopenharmony_ciint do_pcie_gen3_transition(struct hfi1_devdata *dd)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	struct pci_dev *parent = dd->pcidev->bus->self;
93862306a36Sopenharmony_ci	u64 fw_ctrl;
93962306a36Sopenharmony_ci	u64 reg, therm;
94062306a36Sopenharmony_ci	u32 reg32, fs, lf;
94162306a36Sopenharmony_ci	u32 status, err;
94262306a36Sopenharmony_ci	int ret;
94362306a36Sopenharmony_ci	int do_retry, retry_count = 0;
94462306a36Sopenharmony_ci	int intnum = 0;
94562306a36Sopenharmony_ci	uint default_pset;
94662306a36Sopenharmony_ci	uint pset = pcie_pset;
94762306a36Sopenharmony_ci	u16 target_vector, target_speed;
94862306a36Sopenharmony_ci	u16 lnkctl2, vendor;
94962306a36Sopenharmony_ci	u8 div;
95062306a36Sopenharmony_ci	const u8 (*eq)[3];
95162306a36Sopenharmony_ci	const u8 (*ctle_tunings)[4];
95262306a36Sopenharmony_ci	uint static_ctle_mode;
95362306a36Sopenharmony_ci	int return_error = 0;
95462306a36Sopenharmony_ci	u32 target_width;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	/* PCIe Gen3 is for the ASIC only */
95762306a36Sopenharmony_ci	if (dd->icode != ICODE_RTL_SILICON)
95862306a36Sopenharmony_ci		return 0;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	if (pcie_target == 1) {			/* target Gen1 */
96162306a36Sopenharmony_ci		target_vector = PCI_EXP_LNKCTL2_TLS_2_5GT;
96262306a36Sopenharmony_ci		target_speed = 2500;
96362306a36Sopenharmony_ci	} else if (pcie_target == 2) {		/* target Gen2 */
96462306a36Sopenharmony_ci		target_vector = PCI_EXP_LNKCTL2_TLS_5_0GT;
96562306a36Sopenharmony_ci		target_speed = 5000;
96662306a36Sopenharmony_ci	} else if (pcie_target == 3) {		/* target Gen3 */
96762306a36Sopenharmony_ci		target_vector = PCI_EXP_LNKCTL2_TLS_8_0GT;
96862306a36Sopenharmony_ci		target_speed = 8000;
96962306a36Sopenharmony_ci	} else {
97062306a36Sopenharmony_ci		/* off or invalid target - skip */
97162306a36Sopenharmony_ci		dd_dev_info(dd, "%s: Skipping PCIe transition\n", __func__);
97262306a36Sopenharmony_ci		return 0;
97362306a36Sopenharmony_ci	}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	/* if already at target speed, done (unless forced) */
97662306a36Sopenharmony_ci	if (dd->lbus_speed == target_speed) {
97762306a36Sopenharmony_ci		dd_dev_info(dd, "%s: PCIe already at gen%d, %s\n", __func__,
97862306a36Sopenharmony_ci			    pcie_target,
97962306a36Sopenharmony_ci			    pcie_force ? "re-doing anyway" : "skipping");
98062306a36Sopenharmony_ci		if (!pcie_force)
98162306a36Sopenharmony_ci			return 0;
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	/*
98562306a36Sopenharmony_ci	 * The driver cannot do the transition if it has no access to the
98662306a36Sopenharmony_ci	 * upstream component
98762306a36Sopenharmony_ci	 */
98862306a36Sopenharmony_ci	if (!parent) {
98962306a36Sopenharmony_ci		dd_dev_info(dd, "%s: No upstream, Can't do gen3 transition\n",
99062306a36Sopenharmony_ci			    __func__);
99162306a36Sopenharmony_ci		return 0;
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	/* Previous Gen1/Gen2 bus width */
99562306a36Sopenharmony_ci	target_width = dd->lbus_width;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/*
99862306a36Sopenharmony_ci	 * Do the Gen3 transition.  Steps are those of the PCIe Gen3
99962306a36Sopenharmony_ci	 * recipe.
100062306a36Sopenharmony_ci	 */
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	/* step 1: pcie link working in gen1/gen2 */
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	/* step 2: if either side is not capable of Gen3, done */
100562306a36Sopenharmony_ci	if (pcie_target == 3 && !dd->link_gen3_capable) {
100662306a36Sopenharmony_ci		dd_dev_err(dd, "The PCIe link is not Gen3 capable\n");
100762306a36Sopenharmony_ci		ret = -ENOSYS;
100862306a36Sopenharmony_ci		goto done_no_mutex;
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	/* hold the SBus resource across the firmware download and SBR */
101262306a36Sopenharmony_ci	ret = acquire_chip_resource(dd, CR_SBUS, SBUS_TIMEOUT);
101362306a36Sopenharmony_ci	if (ret) {
101462306a36Sopenharmony_ci		dd_dev_err(dd, "%s: unable to acquire SBus resource\n",
101562306a36Sopenharmony_ci			   __func__);
101662306a36Sopenharmony_ci		return ret;
101762306a36Sopenharmony_ci	}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	/* make sure thermal polling is not causing interrupts */
102062306a36Sopenharmony_ci	therm = read_csr(dd, ASIC_CFG_THERM_POLL_EN);
102162306a36Sopenharmony_ci	if (therm) {
102262306a36Sopenharmony_ci		write_csr(dd, ASIC_CFG_THERM_POLL_EN, 0x0);
102362306a36Sopenharmony_ci		msleep(100);
102462306a36Sopenharmony_ci		dd_dev_info(dd, "%s: Disabled therm polling\n",
102562306a36Sopenharmony_ci			    __func__);
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ciretry:
102962306a36Sopenharmony_ci	/* the SBus download will reset the spico for thermal */
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	/* step 3: download SBus Master firmware */
103262306a36Sopenharmony_ci	/* step 4: download PCIe Gen3 SerDes firmware */
103362306a36Sopenharmony_ci	dd_dev_info(dd, "%s: downloading firmware\n", __func__);
103462306a36Sopenharmony_ci	ret = load_pcie_firmware(dd);
103562306a36Sopenharmony_ci	if (ret) {
103662306a36Sopenharmony_ci		/* do not proceed if the firmware cannot be downloaded */
103762306a36Sopenharmony_ci		return_error = 1;
103862306a36Sopenharmony_ci		goto done;
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	/* step 5: set up device parameter settings */
104262306a36Sopenharmony_ci	dd_dev_info(dd, "%s: setting PCIe registers\n", __func__);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	/*
104562306a36Sopenharmony_ci	 * PcieCfgSpcie1 - Link Control 3
104662306a36Sopenharmony_ci	 * Leave at reset value.  No need to set PerfEq - link equalization
104762306a36Sopenharmony_ci	 * will be performed automatically after the SBR when the target
104862306a36Sopenharmony_ci	 * speed is 8GT/s.
104962306a36Sopenharmony_ci	 */
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/* clear all 16 per-lane error bits (PCIe: Lane Error Status) */
105262306a36Sopenharmony_ci	pci_write_config_dword(dd->pcidev, PCIE_CFG_SPCIE2, 0xffff);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	/* step 5a: Set Synopsys Port Logic registers */
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	/*
105762306a36Sopenharmony_ci	 * PcieCfgRegPl2 - Port Force Link
105862306a36Sopenharmony_ci	 *
105962306a36Sopenharmony_ci	 * Set the low power field to 0x10 to avoid unnecessary power
106062306a36Sopenharmony_ci	 * management messages.  All other fields are zero.
106162306a36Sopenharmony_ci	 */
106262306a36Sopenharmony_ci	reg32 = 0x10ul << PCIE_CFG_REG_PL2_LOW_PWR_ENT_CNT_SHIFT;
106362306a36Sopenharmony_ci	pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL2, reg32);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	/*
106662306a36Sopenharmony_ci	 * PcieCfgRegPl100 - Gen3 Control
106762306a36Sopenharmony_ci	 *
106862306a36Sopenharmony_ci	 * turn off PcieCfgRegPl100.Gen3ZRxDcNonCompl
106962306a36Sopenharmony_ci	 * turn on PcieCfgRegPl100.EqEieosCnt
107062306a36Sopenharmony_ci	 * Everything else zero.
107162306a36Sopenharmony_ci	 */
107262306a36Sopenharmony_ci	reg32 = PCIE_CFG_REG_PL100_EQ_EIEOS_CNT_SMASK;
107362306a36Sopenharmony_ci	pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL100, reg32);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/*
107662306a36Sopenharmony_ci	 * PcieCfgRegPl101 - Gen3 EQ FS and LF
107762306a36Sopenharmony_ci	 * PcieCfgRegPl102 - Gen3 EQ Presets to Coefficients Mapping
107862306a36Sopenharmony_ci	 * PcieCfgRegPl103 - Gen3 EQ Preset Index
107962306a36Sopenharmony_ci	 * PcieCfgRegPl105 - Gen3 EQ Status
108062306a36Sopenharmony_ci	 *
108162306a36Sopenharmony_ci	 * Give initial EQ settings.
108262306a36Sopenharmony_ci	 */
108362306a36Sopenharmony_ci	if (dd->pcidev->device == PCI_DEVICE_ID_INTEL0) { /* discrete */
108462306a36Sopenharmony_ci		/* 1000mV, FS=24, LF = 8 */
108562306a36Sopenharmony_ci		fs = 24;
108662306a36Sopenharmony_ci		lf = 8;
108762306a36Sopenharmony_ci		div = 3;
108862306a36Sopenharmony_ci		eq = discrete_preliminary_eq;
108962306a36Sopenharmony_ci		default_pset = DEFAULT_DISCRETE_PSET;
109062306a36Sopenharmony_ci		ctle_tunings = discrete_ctle_tunings;
109162306a36Sopenharmony_ci		/* bit 0 - discrete on/off */
109262306a36Sopenharmony_ci		static_ctle_mode = pcie_ctle & 0x1;
109362306a36Sopenharmony_ci	} else {
109462306a36Sopenharmony_ci		/* 400mV, FS=29, LF = 9 */
109562306a36Sopenharmony_ci		fs = 29;
109662306a36Sopenharmony_ci		lf = 9;
109762306a36Sopenharmony_ci		div = 1;
109862306a36Sopenharmony_ci		eq = integrated_preliminary_eq;
109962306a36Sopenharmony_ci		default_pset = DEFAULT_MCP_PSET;
110062306a36Sopenharmony_ci		ctle_tunings = integrated_ctle_tunings;
110162306a36Sopenharmony_ci		/* bit 1 - integrated on/off */
110262306a36Sopenharmony_ci		static_ctle_mode = (pcie_ctle >> 1) & 0x1;
110362306a36Sopenharmony_ci	}
110462306a36Sopenharmony_ci	pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL101,
110562306a36Sopenharmony_ci			       (fs <<
110662306a36Sopenharmony_ci				PCIE_CFG_REG_PL101_GEN3_EQ_LOCAL_FS_SHIFT) |
110762306a36Sopenharmony_ci			       (lf <<
110862306a36Sopenharmony_ci				PCIE_CFG_REG_PL101_GEN3_EQ_LOCAL_LF_SHIFT));
110962306a36Sopenharmony_ci	ret = load_eq_table(dd, eq, fs, div);
111062306a36Sopenharmony_ci	if (ret)
111162306a36Sopenharmony_ci		goto done;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	/*
111462306a36Sopenharmony_ci	 * PcieCfgRegPl106 - Gen3 EQ Control
111562306a36Sopenharmony_ci	 *
111662306a36Sopenharmony_ci	 * Set Gen3EqPsetReqVec, leave other fields 0.
111762306a36Sopenharmony_ci	 */
111862306a36Sopenharmony_ci	if (pset == UNSET_PSET)
111962306a36Sopenharmony_ci		pset = default_pset;
112062306a36Sopenharmony_ci	if (pset > 10) {	/* valid range is 0-10, inclusive */
112162306a36Sopenharmony_ci		dd_dev_err(dd, "%s: Invalid Eq Pset %u, setting to %d\n",
112262306a36Sopenharmony_ci			   __func__, pset, default_pset);
112362306a36Sopenharmony_ci		pset = default_pset;
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci	dd_dev_info(dd, "%s: using EQ Pset %u\n", __func__, pset);
112662306a36Sopenharmony_ci	pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL106,
112762306a36Sopenharmony_ci			       ((1 << pset) <<
112862306a36Sopenharmony_ci			PCIE_CFG_REG_PL106_GEN3_EQ_PSET_REQ_VEC_SHIFT) |
112962306a36Sopenharmony_ci			PCIE_CFG_REG_PL106_GEN3_EQ_EVAL2MS_DISABLE_SMASK |
113062306a36Sopenharmony_ci			PCIE_CFG_REG_PL106_GEN3_EQ_PHASE23_EXIT_MODE_SMASK);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	/*
113362306a36Sopenharmony_ci	 * step 5b: Do post firmware download steps via SBus
113462306a36Sopenharmony_ci	 */
113562306a36Sopenharmony_ci	dd_dev_info(dd, "%s: doing pcie post steps\n", __func__);
113662306a36Sopenharmony_ci	pcie_post_steps(dd);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	/*
113962306a36Sopenharmony_ci	 * step 5c: Program gasket interrupts
114062306a36Sopenharmony_ci	 */
114162306a36Sopenharmony_ci	/* set the Rx Bit Rate to REFCLK ratio */
114262306a36Sopenharmony_ci	write_gasket_interrupt(dd, intnum++, 0x0006, 0x0050);
114362306a36Sopenharmony_ci	/* disable pCal for PCIe Gen3 RX equalization */
114462306a36Sopenharmony_ci	/* select adaptive or static CTLE */
114562306a36Sopenharmony_ci	write_gasket_interrupt(dd, intnum++, 0x0026,
114662306a36Sopenharmony_ci			       0x5b01 | (static_ctle_mode << 3));
114762306a36Sopenharmony_ci	/*
114862306a36Sopenharmony_ci	 * Enable iCal for PCIe Gen3 RX equalization, and set which
114962306a36Sopenharmony_ci	 * evaluation of RX_EQ_EVAL will launch the iCal procedure.
115062306a36Sopenharmony_ci	 */
115162306a36Sopenharmony_ci	write_gasket_interrupt(dd, intnum++, 0x0026, 0x5202);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (static_ctle_mode) {
115462306a36Sopenharmony_ci		/* apply static CTLE tunings */
115562306a36Sopenharmony_ci		u8 pcie_dc, pcie_lf, pcie_hf, pcie_bw;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci		pcie_dc = ctle_tunings[pset][0];
115862306a36Sopenharmony_ci		pcie_lf = ctle_tunings[pset][1];
115962306a36Sopenharmony_ci		pcie_hf = ctle_tunings[pset][2];
116062306a36Sopenharmony_ci		pcie_bw = ctle_tunings[pset][3];
116162306a36Sopenharmony_ci		write_gasket_interrupt(dd, intnum++, 0x0026, 0x0200 | pcie_dc);
116262306a36Sopenharmony_ci		write_gasket_interrupt(dd, intnum++, 0x0026, 0x0100 | pcie_lf);
116362306a36Sopenharmony_ci		write_gasket_interrupt(dd, intnum++, 0x0026, 0x0000 | pcie_hf);
116462306a36Sopenharmony_ci		write_gasket_interrupt(dd, intnum++, 0x0026, 0x5500 | pcie_bw);
116562306a36Sopenharmony_ci	}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	/* terminate list */
116862306a36Sopenharmony_ci	write_gasket_interrupt(dd, intnum++, 0x0000, 0x0000);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	/*
117162306a36Sopenharmony_ci	 * step 5d: program XMT margin
117262306a36Sopenharmony_ci	 */
117362306a36Sopenharmony_ci	write_xmt_margin(dd, __func__);
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	/*
117662306a36Sopenharmony_ci	 * step 5e: disable active state power management (ASPM). It
117762306a36Sopenharmony_ci	 * will be enabled if required later
117862306a36Sopenharmony_ci	 */
117962306a36Sopenharmony_ci	dd_dev_info(dd, "%s: clearing ASPM\n", __func__);
118062306a36Sopenharmony_ci	aspm_hw_disable_l1(dd);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	/*
118362306a36Sopenharmony_ci	 * step 5f: clear DirectSpeedChange
118462306a36Sopenharmony_ci	 * PcieCfgRegPl67.DirectSpeedChange must be zero to prevent the
118562306a36Sopenharmony_ci	 * change in the speed target from starting before we are ready.
118662306a36Sopenharmony_ci	 * This field defaults to 0 and we are not changing it, so nothing
118762306a36Sopenharmony_ci	 * needs to be done.
118862306a36Sopenharmony_ci	 */
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	/* step 5g: Set target link speed */
119162306a36Sopenharmony_ci	/*
119262306a36Sopenharmony_ci	 * Set target link speed to be target on both device and parent.
119362306a36Sopenharmony_ci	 * On setting the parent: Some system BIOSs "helpfully" set the
119462306a36Sopenharmony_ci	 * parent target speed to Gen2 to match the ASIC's initial speed.
119562306a36Sopenharmony_ci	 * We can set the target Gen3 because we have already checked
119662306a36Sopenharmony_ci	 * that it is Gen3 capable earlier.
119762306a36Sopenharmony_ci	 */
119862306a36Sopenharmony_ci	dd_dev_info(dd, "%s: setting parent target link speed\n", __func__);
119962306a36Sopenharmony_ci	ret = pcie_capability_read_word(parent, PCI_EXP_LNKCTL2, &lnkctl2);
120062306a36Sopenharmony_ci	if (ret) {
120162306a36Sopenharmony_ci		dd_dev_err(dd, "Unable to read from PCI config\n");
120262306a36Sopenharmony_ci		return_error = 1;
120362306a36Sopenharmony_ci		goto done;
120462306a36Sopenharmony_ci	}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	dd_dev_info(dd, "%s: ..old link control2: 0x%x\n", __func__,
120762306a36Sopenharmony_ci		    (u32)lnkctl2);
120862306a36Sopenharmony_ci	/* only write to parent if target is not as high as ours */
120962306a36Sopenharmony_ci	if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) < target_vector) {
121062306a36Sopenharmony_ci		lnkctl2 &= ~PCI_EXP_LNKCTL2_TLS;
121162306a36Sopenharmony_ci		lnkctl2 |= target_vector;
121262306a36Sopenharmony_ci		dd_dev_info(dd, "%s: ..new link control2: 0x%x\n", __func__,
121362306a36Sopenharmony_ci			    (u32)lnkctl2);
121462306a36Sopenharmony_ci		ret = pcie_capability_write_word(parent,
121562306a36Sopenharmony_ci						 PCI_EXP_LNKCTL2, lnkctl2);
121662306a36Sopenharmony_ci		if (ret) {
121762306a36Sopenharmony_ci			dd_dev_err(dd, "Unable to write to PCI config\n");
121862306a36Sopenharmony_ci			return_error = 1;
121962306a36Sopenharmony_ci			goto done;
122062306a36Sopenharmony_ci		}
122162306a36Sopenharmony_ci	} else {
122262306a36Sopenharmony_ci		dd_dev_info(dd, "%s: ..target speed is OK\n", __func__);
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	dd_dev_info(dd, "%s: setting target link speed\n", __func__);
122662306a36Sopenharmony_ci	ret = pcie_capability_read_word(dd->pcidev, PCI_EXP_LNKCTL2, &lnkctl2);
122762306a36Sopenharmony_ci	if (ret) {
122862306a36Sopenharmony_ci		dd_dev_err(dd, "Unable to read from PCI config\n");
122962306a36Sopenharmony_ci		return_error = 1;
123062306a36Sopenharmony_ci		goto done;
123162306a36Sopenharmony_ci	}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	dd_dev_info(dd, "%s: ..old link control2: 0x%x\n", __func__,
123462306a36Sopenharmony_ci		    (u32)lnkctl2);
123562306a36Sopenharmony_ci	lnkctl2 &= ~PCI_EXP_LNKCTL2_TLS;
123662306a36Sopenharmony_ci	lnkctl2 |= target_vector;
123762306a36Sopenharmony_ci	dd_dev_info(dd, "%s: ..new link control2: 0x%x\n", __func__,
123862306a36Sopenharmony_ci		    (u32)lnkctl2);
123962306a36Sopenharmony_ci	ret = pcie_capability_write_word(dd->pcidev, PCI_EXP_LNKCTL2, lnkctl2);
124062306a36Sopenharmony_ci	if (ret) {
124162306a36Sopenharmony_ci		dd_dev_err(dd, "Unable to write to PCI config\n");
124262306a36Sopenharmony_ci		return_error = 1;
124362306a36Sopenharmony_ci		goto done;
124462306a36Sopenharmony_ci	}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	/* step 5h: arm gasket logic */
124762306a36Sopenharmony_ci	/* hold DC in reset across the SBR */
124862306a36Sopenharmony_ci	write_csr(dd, CCE_DC_CTRL, CCE_DC_CTRL_DC_RESET_SMASK);
124962306a36Sopenharmony_ci	(void)read_csr(dd, CCE_DC_CTRL); /* DC reset hold */
125062306a36Sopenharmony_ci	/* save firmware control across the SBR */
125162306a36Sopenharmony_ci	fw_ctrl = read_csr(dd, MISC_CFG_FW_CTRL);
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	dd_dev_info(dd, "%s: arming gasket logic\n", __func__);
125462306a36Sopenharmony_ci	arm_gasket_logic(dd);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	/*
125762306a36Sopenharmony_ci	 * step 6: quiesce PCIe link
125862306a36Sopenharmony_ci	 * The chip has already been reset, so there will be no traffic
125962306a36Sopenharmony_ci	 * from the chip.  Linux has no easy way to enforce that it will
126062306a36Sopenharmony_ci	 * not try to access the device, so we just need to hope it doesn't
126162306a36Sopenharmony_ci	 * do it while we are doing the reset.
126262306a36Sopenharmony_ci	 */
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	/*
126562306a36Sopenharmony_ci	 * step 7: initiate the secondary bus reset (SBR)
126662306a36Sopenharmony_ci	 * step 8: hardware brings the links back up
126762306a36Sopenharmony_ci	 * step 9: wait for link speed transition to be complete
126862306a36Sopenharmony_ci	 */
126962306a36Sopenharmony_ci	dd_dev_info(dd, "%s: calling trigger_sbr\n", __func__);
127062306a36Sopenharmony_ci	ret = trigger_sbr(dd);
127162306a36Sopenharmony_ci	if (ret)
127262306a36Sopenharmony_ci		goto done;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	/* step 10: decide what to do next */
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	/* check if we can read PCI space */
127762306a36Sopenharmony_ci	ret = pci_read_config_word(dd->pcidev, PCI_VENDOR_ID, &vendor);
127862306a36Sopenharmony_ci	if (ret) {
127962306a36Sopenharmony_ci		dd_dev_info(dd,
128062306a36Sopenharmony_ci			    "%s: read of VendorID failed after SBR, err %d\n",
128162306a36Sopenharmony_ci			    __func__, ret);
128262306a36Sopenharmony_ci		return_error = 1;
128362306a36Sopenharmony_ci		goto done;
128462306a36Sopenharmony_ci	}
128562306a36Sopenharmony_ci	if (vendor == 0xffff) {
128662306a36Sopenharmony_ci		dd_dev_info(dd, "%s: VendorID is all 1s after SBR\n", __func__);
128762306a36Sopenharmony_ci		return_error = 1;
128862306a36Sopenharmony_ci		ret = -EIO;
128962306a36Sopenharmony_ci		goto done;
129062306a36Sopenharmony_ci	}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	/* restore PCI space registers we know were reset */
129362306a36Sopenharmony_ci	dd_dev_info(dd, "%s: calling restore_pci_variables\n", __func__);
129462306a36Sopenharmony_ci	ret = restore_pci_variables(dd);
129562306a36Sopenharmony_ci	if (ret) {
129662306a36Sopenharmony_ci		dd_dev_err(dd, "%s: Could not restore PCI variables\n",
129762306a36Sopenharmony_ci			   __func__);
129862306a36Sopenharmony_ci		return_error = 1;
129962306a36Sopenharmony_ci		goto done;
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	/* restore firmware control */
130362306a36Sopenharmony_ci	write_csr(dd, MISC_CFG_FW_CTRL, fw_ctrl);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	/*
130662306a36Sopenharmony_ci	 * Check the gasket block status.
130762306a36Sopenharmony_ci	 *
130862306a36Sopenharmony_ci	 * This is the first CSR read after the SBR.  If the read returns
130962306a36Sopenharmony_ci	 * all 1s (fails), the link did not make it back.
131062306a36Sopenharmony_ci	 *
131162306a36Sopenharmony_ci	 * Once we're sure we can read and write, clear the DC reset after
131262306a36Sopenharmony_ci	 * the SBR.  Then check for any per-lane errors. Then look over
131362306a36Sopenharmony_ci	 * the status.
131462306a36Sopenharmony_ci	 */
131562306a36Sopenharmony_ci	reg = read_csr(dd, ASIC_PCIE_SD_HOST_STATUS);
131662306a36Sopenharmony_ci	dd_dev_info(dd, "%s: gasket block status: 0x%llx\n", __func__, reg);
131762306a36Sopenharmony_ci	if (reg == ~0ull) {	/* PCIe read failed/timeout */
131862306a36Sopenharmony_ci		dd_dev_err(dd, "SBR failed - unable to read from device\n");
131962306a36Sopenharmony_ci		return_error = 1;
132062306a36Sopenharmony_ci		ret = -ENOSYS;
132162306a36Sopenharmony_ci		goto done;
132262306a36Sopenharmony_ci	}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	/* clear the DC reset */
132562306a36Sopenharmony_ci	write_csr(dd, CCE_DC_CTRL, 0);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	/* Set the LED off */
132862306a36Sopenharmony_ci	setextled(dd, 0);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	/* check for any per-lane errors */
133162306a36Sopenharmony_ci	ret = pci_read_config_dword(dd->pcidev, PCIE_CFG_SPCIE2, &reg32);
133262306a36Sopenharmony_ci	if (ret) {
133362306a36Sopenharmony_ci		dd_dev_err(dd, "Unable to read from PCI config\n");
133462306a36Sopenharmony_ci		return_error = 1;
133562306a36Sopenharmony_ci		goto done;
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	dd_dev_info(dd, "%s: per-lane errors: 0x%x\n", __func__, reg32);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	/* extract status, look for our HFI */
134162306a36Sopenharmony_ci	status = (reg >> ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_STS_SHIFT)
134262306a36Sopenharmony_ci			& ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_STS_MASK;
134362306a36Sopenharmony_ci	if ((status & (1 << dd->hfi1_id)) == 0) {
134462306a36Sopenharmony_ci		dd_dev_err(dd,
134562306a36Sopenharmony_ci			   "%s: gasket status 0x%x, expecting 0x%x\n",
134662306a36Sopenharmony_ci			   __func__, status, 1 << dd->hfi1_id);
134762306a36Sopenharmony_ci		ret = -EIO;
134862306a36Sopenharmony_ci		goto done;
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	/* extract error */
135262306a36Sopenharmony_ci	err = (reg >> ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_ERR_SHIFT)
135362306a36Sopenharmony_ci		& ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_ERR_MASK;
135462306a36Sopenharmony_ci	if (err) {
135562306a36Sopenharmony_ci		dd_dev_err(dd, "%s: gasket error %d\n", __func__, err);
135662306a36Sopenharmony_ci		ret = -EIO;
135762306a36Sopenharmony_ci		goto done;
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	/* update our link information cache */
136162306a36Sopenharmony_ci	update_lbus_info(dd);
136262306a36Sopenharmony_ci	dd_dev_info(dd, "%s: new speed and width: %s\n", __func__,
136362306a36Sopenharmony_ci		    dd->lbus_info);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	if (dd->lbus_speed != target_speed ||
136662306a36Sopenharmony_ci	    dd->lbus_width < target_width) { /* not target */
136762306a36Sopenharmony_ci		/* maybe retry */
136862306a36Sopenharmony_ci		do_retry = retry_count < pcie_retry;
136962306a36Sopenharmony_ci		dd_dev_err(dd, "PCIe link speed or width did not match target%s\n",
137062306a36Sopenharmony_ci			   do_retry ? ", retrying" : "");
137162306a36Sopenharmony_ci		retry_count++;
137262306a36Sopenharmony_ci		if (do_retry) {
137362306a36Sopenharmony_ci			msleep(100); /* allow time to settle */
137462306a36Sopenharmony_ci			goto retry;
137562306a36Sopenharmony_ci		}
137662306a36Sopenharmony_ci		ret = -EIO;
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_cidone:
138062306a36Sopenharmony_ci	if (therm) {
138162306a36Sopenharmony_ci		write_csr(dd, ASIC_CFG_THERM_POLL_EN, 0x1);
138262306a36Sopenharmony_ci		msleep(100);
138362306a36Sopenharmony_ci		dd_dev_info(dd, "%s: Re-enable therm polling\n",
138462306a36Sopenharmony_ci			    __func__);
138562306a36Sopenharmony_ci	}
138662306a36Sopenharmony_ci	release_chip_resource(dd, CR_SBUS);
138762306a36Sopenharmony_cidone_no_mutex:
138862306a36Sopenharmony_ci	/* return no error if it is OK to be at current speed */
138962306a36Sopenharmony_ci	if (ret && !return_error) {
139062306a36Sopenharmony_ci		dd_dev_err(dd, "Proceeding at current speed PCIe speed\n");
139162306a36Sopenharmony_ci		ret = 0;
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	dd_dev_info(dd, "%s: done\n", __func__);
139562306a36Sopenharmony_ci	return ret;
139662306a36Sopenharmony_ci}
1397