// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright(c) 2015 - 2019 Intel Corporation.
*/
#include <linux/bitfield.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include "hfi.h"
#include "chip_registers.h"
#include "aspm.h"
/*
* This file contains PCIe utility routines.
*/
/*
* Do all the common PCIe setup and initialization.
*/
int hfi1_pcie_init(struct hfi1_devdata *dd)
{
int ret;
struct pci_dev *pdev = dd->pcidev;
ret = pci_enable_device(pdev);
if (ret) {
/*
* This can happen (in theory) iff:
* We did a chip reset, and then failed to reprogram the
* BAR, or the chip reset due to an internal error. We then
* unloaded the driver and reloaded it.
*
* Both reset cases set the BAR back to initial state. For
* the latter case, the AER sticky error bit at offset 0x718
* should be set, but the Linux kernel doesn't yet know
* about that, it appears. If the original BAR was retained
* in the kernel data structures, this may be OK.
*/
dd_dev_err(dd, "pci enable failed: error %d\n", -ret);
return ret;
}
ret = pci_request_regions(pdev, DRIVER_NAME);
if (ret) {
dd_dev_err(dd, "pci_request_regions fails: err %d\n", -ret);
goto bail;
}
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (ret) {
/*
* If the 64 bit setup fails, try 32 bit. Some systems
* do not setup 64 bit maps on systems with 2GB or less
* memory installed.
*/
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (ret) {
dd_dev_err(dd, "Unable to set DMA mask: %d\n", ret);
goto bail;
}
}
pci_set_master(pdev);
return 0;
bail:
hfi1_pcie_cleanup(pdev);
return ret;
}
/*
* Clean what was done in hfi1_pcie_init()
*/
void hfi1_pcie_cleanup(struct pci_dev *pdev)
{
pci_disable_device(pdev);
/*
* Release regions should be called after the disable. OK to
* call if request regions has not been called or failed.
*/
pci_release_regions(pdev);
}
/*
* Do remaining PCIe setup, once dd is allocated, and save away
* fields required to re-initialize after a chip reset, or for
* various other purposes
*/
int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev)
{
unsigned long len;
resource_size_t addr;
int ret = 0;
u32 rcv_array_count;
addr = pci_resource_start(pdev, 0);
len = pci_resource_len(pdev