18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * Copyright 2016-2019 HabanaLabs, Ltd. 58c2ecf20Sopenharmony_ci * All Rights Reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "habanalabs.h" 98c2ecf20Sopenharmony_ci#include "../include/hw_ip/pci/pci_general.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define HL_PLDM_PCI_ELBI_TIMEOUT_MSEC (HL_PCI_ELBI_TIMEOUT_MSEC * 10) 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define IATU_REGION_CTRL_REGION_EN_MASK BIT(31) 168c2ecf20Sopenharmony_ci#define IATU_REGION_CTRL_MATCH_MODE_MASK BIT(30) 178c2ecf20Sopenharmony_ci#define IATU_REGION_CTRL_NUM_MATCH_EN_MASK BIT(19) 188c2ecf20Sopenharmony_ci#define IATU_REGION_CTRL_BAR_NUM_MASK GENMASK(10, 8) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/** 218c2ecf20Sopenharmony_ci * hl_pci_bars_map() - Map PCI BARs. 228c2ecf20Sopenharmony_ci * @hdev: Pointer to hl_device structure. 238c2ecf20Sopenharmony_ci * @name: Array of BAR names. 248c2ecf20Sopenharmony_ci * @is_wc: Array with flag per BAR whether a write-combined mapping is needed. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * Request PCI regions and map them to kernel virtual addresses. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * Return: 0 on success, non-zero for failure. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ciint hl_pci_bars_map(struct hl_device *hdev, const char * const name[3], 318c2ecf20Sopenharmony_ci bool is_wc[3]) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct pci_dev *pdev = hdev->pdev; 348c2ecf20Sopenharmony_ci int rc, i, bar; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, HL_NAME); 378c2ecf20Sopenharmony_ci if (rc) { 388c2ecf20Sopenharmony_ci dev_err(hdev->dev, "Cannot obtain PCI resources\n"); 398c2ecf20Sopenharmony_ci return rc; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci for (i = 0 ; i < 3 ; i++) { 438c2ecf20Sopenharmony_ci bar = i * 2; /* 64-bit BARs */ 448c2ecf20Sopenharmony_ci hdev->pcie_bar[bar] = is_wc[i] ? 458c2ecf20Sopenharmony_ci pci_ioremap_wc_bar(pdev, bar) : 468c2ecf20Sopenharmony_ci pci_ioremap_bar(pdev, bar); 478c2ecf20Sopenharmony_ci if (!hdev->pcie_bar[bar]) { 488c2ecf20Sopenharmony_ci dev_err(hdev->dev, "pci_ioremap%s_bar failed for %s\n", 498c2ecf20Sopenharmony_ci is_wc[i] ? "_wc" : "", name[i]); 508c2ecf20Sopenharmony_ci rc = -ENODEV; 518c2ecf20Sopenharmony_ci goto err; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return 0; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cierr: 588c2ecf20Sopenharmony_ci for (i = 2 ; i >= 0 ; i--) { 598c2ecf20Sopenharmony_ci bar = i * 2; /* 64-bit BARs */ 608c2ecf20Sopenharmony_ci if (hdev->pcie_bar[bar]) 618c2ecf20Sopenharmony_ci iounmap(hdev->pcie_bar[bar]); 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci pci_release_regions(pdev); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return rc; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/** 708c2ecf20Sopenharmony_ci * hl_pci_bars_unmap() - Unmap PCI BARS. 718c2ecf20Sopenharmony_ci * @hdev: Pointer to hl_device structure. 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * Release all PCI BARs and unmap their virtual addresses. 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_cistatic void hl_pci_bars_unmap(struct hl_device *hdev) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct pci_dev *pdev = hdev->pdev; 788c2ecf20Sopenharmony_ci int i, bar; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci for (i = 2 ; i >= 0 ; i--) { 818c2ecf20Sopenharmony_ci bar = i * 2; /* 64-bit BARs */ 828c2ecf20Sopenharmony_ci iounmap(hdev->pcie_bar[bar]); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci pci_release_regions(pdev); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/** 898c2ecf20Sopenharmony_ci * hl_pci_elbi_write() - Write through the ELBI interface. 908c2ecf20Sopenharmony_ci * @hdev: Pointer to hl_device structure. 918c2ecf20Sopenharmony_ci * @addr: Address to write to 928c2ecf20Sopenharmony_ci * @data: Data to write 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * Return: 0 on success, negative value for failure. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_cistatic int hl_pci_elbi_write(struct hl_device *hdev, u64 addr, u32 data) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct pci_dev *pdev = hdev->pdev; 998c2ecf20Sopenharmony_ci ktime_t timeout; 1008c2ecf20Sopenharmony_ci u64 msec; 1018c2ecf20Sopenharmony_ci u32 val; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (hdev->pldm) 1048c2ecf20Sopenharmony_ci msec = HL_PLDM_PCI_ELBI_TIMEOUT_MSEC; 1058c2ecf20Sopenharmony_ci else 1068c2ecf20Sopenharmony_ci msec = HL_PCI_ELBI_TIMEOUT_MSEC; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* Clear previous status */ 1098c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, 0); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_ADDR, (u32) addr); 1128c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_DATA, data); 1138c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_CTRL, 1148c2ecf20Sopenharmony_ci PCI_CONFIG_ELBI_CTRL_WRITE); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci timeout = ktime_add_ms(ktime_get(), msec); 1178c2ecf20Sopenharmony_ci for (;;) { 1188c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, &val); 1198c2ecf20Sopenharmony_ci if (val & PCI_CONFIG_ELBI_STS_MASK) 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci if (ktime_compare(ktime_get(), timeout) > 0) { 1228c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, 1238c2ecf20Sopenharmony_ci &val); 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci usleep_range(300, 500); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if ((val & PCI_CONFIG_ELBI_STS_MASK) == PCI_CONFIG_ELBI_STS_DONE) 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (val & PCI_CONFIG_ELBI_STS_ERR) 1348c2ecf20Sopenharmony_ci return -EIO; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (!(val & PCI_CONFIG_ELBI_STS_MASK)) { 1378c2ecf20Sopenharmony_ci dev_err(hdev->dev, "ELBI write didn't finish in time\n"); 1388c2ecf20Sopenharmony_ci return -EIO; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci dev_err(hdev->dev, "ELBI write has undefined bits in status\n"); 1428c2ecf20Sopenharmony_ci return -EIO; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/** 1468c2ecf20Sopenharmony_ci * hl_pci_iatu_write() - iatu write routine. 1478c2ecf20Sopenharmony_ci * @hdev: Pointer to hl_device structure. 1488c2ecf20Sopenharmony_ci * @addr: Address to write to 1498c2ecf20Sopenharmony_ci * @data: Data to write 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * Return: 0 on success, negative value for failure. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ciint hl_pci_iatu_write(struct hl_device *hdev, u32 addr, u32 data) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct asic_fixed_properties *prop = &hdev->asic_prop; 1568c2ecf20Sopenharmony_ci u32 dbi_offset; 1578c2ecf20Sopenharmony_ci int rc; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci dbi_offset = addr & 0xFFF; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Ignore result of writing to pcie_aux_dbi_reg_addr as it could fail 1628c2ecf20Sopenharmony_ci * in case the firmware security is enabled 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci hl_pci_elbi_write(hdev, prop->pcie_aux_dbi_reg_addr, 0x00300000); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci rc = hl_pci_elbi_write(hdev, prop->pcie_dbi_base_address + dbi_offset, 1678c2ecf20Sopenharmony_ci data); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (rc) 1708c2ecf20Sopenharmony_ci return -EIO; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/** 1768c2ecf20Sopenharmony_ci * hl_pci_reset_link_through_bridge() - Reset PCI link. 1778c2ecf20Sopenharmony_ci * @hdev: Pointer to hl_device structure. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistatic void hl_pci_reset_link_through_bridge(struct hl_device *hdev) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct pci_dev *pdev = hdev->pdev; 1828c2ecf20Sopenharmony_ci struct pci_dev *parent_port; 1838c2ecf20Sopenharmony_ci u16 val; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci parent_port = pdev->bus->self; 1868c2ecf20Sopenharmony_ci pci_read_config_word(parent_port, PCI_BRIDGE_CONTROL, &val); 1878c2ecf20Sopenharmony_ci val |= PCI_BRIDGE_CTL_BUS_RESET; 1888c2ecf20Sopenharmony_ci pci_write_config_word(parent_port, PCI_BRIDGE_CONTROL, val); 1898c2ecf20Sopenharmony_ci ssleep(1); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci val &= ~(PCI_BRIDGE_CTL_BUS_RESET); 1928c2ecf20Sopenharmony_ci pci_write_config_word(parent_port, PCI_BRIDGE_CONTROL, val); 1938c2ecf20Sopenharmony_ci ssleep(3); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/** 1978c2ecf20Sopenharmony_ci * hl_pci_set_inbound_region() - Configure inbound region 1988c2ecf20Sopenharmony_ci * @hdev: Pointer to hl_device structure. 1998c2ecf20Sopenharmony_ci * @region: Inbound region number. 2008c2ecf20Sopenharmony_ci * @pci_region: Inbound region parameters. 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * Configure the iATU inbound region. 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * Return: 0 on success, negative value for failure. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ciint hl_pci_set_inbound_region(struct hl_device *hdev, u8 region, 2078c2ecf20Sopenharmony_ci struct hl_inbound_pci_region *pci_region) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct asic_fixed_properties *prop = &hdev->asic_prop; 2108c2ecf20Sopenharmony_ci u64 bar_phys_base, region_base, region_end_address; 2118c2ecf20Sopenharmony_ci u32 offset, ctrl_reg_val; 2128c2ecf20Sopenharmony_ci int rc = 0; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* region offset */ 2158c2ecf20Sopenharmony_ci offset = (0x200 * region) + 0x100; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (pci_region->mode == PCI_ADDRESS_MATCH_MODE) { 2188c2ecf20Sopenharmony_ci bar_phys_base = hdev->pcie_bar_phys[pci_region->bar]; 2198c2ecf20Sopenharmony_ci region_base = bar_phys_base + pci_region->offset_in_bar; 2208c2ecf20Sopenharmony_ci region_end_address = region_base + pci_region->size - 1; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, offset + 0x8, 2238c2ecf20Sopenharmony_ci lower_32_bits(region_base)); 2248c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, offset + 0xC, 2258c2ecf20Sopenharmony_ci upper_32_bits(region_base)); 2268c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, offset + 0x10, 2278c2ecf20Sopenharmony_ci lower_32_bits(region_end_address)); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Point to the specified address */ 2318c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, offset + 0x14, 2328c2ecf20Sopenharmony_ci lower_32_bits(pci_region->addr)); 2338c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, offset + 0x18, 2348c2ecf20Sopenharmony_ci upper_32_bits(pci_region->addr)); 2358c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, offset + 0x0, 0); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* Enable + bar/address match + match enable + bar number */ 2388c2ecf20Sopenharmony_ci ctrl_reg_val = FIELD_PREP(IATU_REGION_CTRL_REGION_EN_MASK, 1); 2398c2ecf20Sopenharmony_ci ctrl_reg_val |= FIELD_PREP(IATU_REGION_CTRL_MATCH_MODE_MASK, 2408c2ecf20Sopenharmony_ci pci_region->mode); 2418c2ecf20Sopenharmony_ci ctrl_reg_val |= FIELD_PREP(IATU_REGION_CTRL_NUM_MATCH_EN_MASK, 1); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (pci_region->mode == PCI_BAR_MATCH_MODE) 2448c2ecf20Sopenharmony_ci ctrl_reg_val |= FIELD_PREP(IATU_REGION_CTRL_BAR_NUM_MASK, 2458c2ecf20Sopenharmony_ci pci_region->bar); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, offset + 0x4, ctrl_reg_val); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* Return the DBI window to the default location 2508c2ecf20Sopenharmony_ci * Ignore result of writing to pcie_aux_dbi_reg_addr as it could fail 2518c2ecf20Sopenharmony_ci * in case the firmware security is enabled 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ci hl_pci_elbi_write(hdev, prop->pcie_aux_dbi_reg_addr, 0); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (rc) 2568c2ecf20Sopenharmony_ci dev_err(hdev->dev, "failed to map bar %u to 0x%08llx\n", 2578c2ecf20Sopenharmony_ci pci_region->bar, pci_region->addr); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return rc; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/** 2638c2ecf20Sopenharmony_ci * hl_pci_set_outbound_region() - Configure outbound region 0 2648c2ecf20Sopenharmony_ci * @hdev: Pointer to hl_device structure. 2658c2ecf20Sopenharmony_ci * @pci_region: Outbound region parameters. 2668c2ecf20Sopenharmony_ci * 2678c2ecf20Sopenharmony_ci * Configure the iATU outbound region 0. 2688c2ecf20Sopenharmony_ci * 2698c2ecf20Sopenharmony_ci * Return: 0 on success, negative value for failure. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ciint hl_pci_set_outbound_region(struct hl_device *hdev, 2728c2ecf20Sopenharmony_ci struct hl_outbound_pci_region *pci_region) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct asic_fixed_properties *prop = &hdev->asic_prop; 2758c2ecf20Sopenharmony_ci u64 outbound_region_end_address; 2768c2ecf20Sopenharmony_ci int rc = 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Outbound Region 0 */ 2798c2ecf20Sopenharmony_ci outbound_region_end_address = 2808c2ecf20Sopenharmony_ci pci_region->addr + pci_region->size - 1; 2818c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, 0x008, 2828c2ecf20Sopenharmony_ci lower_32_bits(pci_region->addr)); 2838c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, 0x00C, 2848c2ecf20Sopenharmony_ci upper_32_bits(pci_region->addr)); 2858c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, 0x010, 2868c2ecf20Sopenharmony_ci lower_32_bits(outbound_region_end_address)); 2878c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, 0x014, 0); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if ((hdev->power9_64bit_dma_enable) && (hdev->dma_mask == 64)) 2908c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, 0x018, 0x08000000); 2918c2ecf20Sopenharmony_ci else 2928c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, 0x018, 0); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, 0x020, 2958c2ecf20Sopenharmony_ci upper_32_bits(outbound_region_end_address)); 2968c2ecf20Sopenharmony_ci /* Increase region size */ 2978c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, 0x000, 0x00002000); 2988c2ecf20Sopenharmony_ci /* Enable */ 2998c2ecf20Sopenharmony_ci rc |= hl_pci_iatu_write(hdev, 0x004, 0x80000000); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Return the DBI window to the default location 3028c2ecf20Sopenharmony_ci * Ignore result of writing to pcie_aux_dbi_reg_addr as it could fail 3038c2ecf20Sopenharmony_ci * in case the firmware security is enabled 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_ci hl_pci_elbi_write(hdev, prop->pcie_aux_dbi_reg_addr, 0); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return rc; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/** 3118c2ecf20Sopenharmony_ci * hl_pci_set_dma_mask() - Set DMA masks for the device. 3128c2ecf20Sopenharmony_ci * @hdev: Pointer to hl_device structure. 3138c2ecf20Sopenharmony_ci * 3148c2ecf20Sopenharmony_ci * This function sets the DMA masks (regular and consistent) for a specified 3158c2ecf20Sopenharmony_ci * value. If it doesn't succeed, it tries to set it to a fall-back value 3168c2ecf20Sopenharmony_ci * 3178c2ecf20Sopenharmony_ci * Return: 0 on success, non-zero for failure. 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_cistatic int hl_pci_set_dma_mask(struct hl_device *hdev) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct pci_dev *pdev = hdev->pdev; 3228c2ecf20Sopenharmony_ci int rc; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* set DMA mask */ 3258c2ecf20Sopenharmony_ci rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(hdev->dma_mask)); 3268c2ecf20Sopenharmony_ci if (rc) { 3278c2ecf20Sopenharmony_ci dev_err(hdev->dev, 3288c2ecf20Sopenharmony_ci "Failed to set pci dma mask to %d bits, error %d\n", 3298c2ecf20Sopenharmony_ci hdev->dma_mask, rc); 3308c2ecf20Sopenharmony_ci return rc; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(hdev->dma_mask)); 3348c2ecf20Sopenharmony_ci if (rc) { 3358c2ecf20Sopenharmony_ci dev_err(hdev->dev, 3368c2ecf20Sopenharmony_ci "Failed to set pci consistent dma mask to %d bits, error %d\n", 3378c2ecf20Sopenharmony_ci hdev->dma_mask, rc); 3388c2ecf20Sopenharmony_ci return rc; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/** 3458c2ecf20Sopenharmony_ci * hl_pci_init() - PCI initialization code. 3468c2ecf20Sopenharmony_ci * @hdev: Pointer to hl_device structure. 3478c2ecf20Sopenharmony_ci * @cpu_boot_status_reg: status register of the device's CPU 3488c2ecf20Sopenharmony_ci * @boot_err0_reg: boot error register of the device's CPU 3498c2ecf20Sopenharmony_ci * @preboot_ver_timeout: how much to wait before bailing out on reading 3508c2ecf20Sopenharmony_ci * the preboot version 3518c2ecf20Sopenharmony_ci * 3528c2ecf20Sopenharmony_ci * Set DMA masks, initialize the PCI controller and map the PCI BARs. 3538c2ecf20Sopenharmony_ci * 3548c2ecf20Sopenharmony_ci * Return: 0 on success, non-zero for failure. 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_ciint hl_pci_init(struct hl_device *hdev, u32 cpu_boot_status_reg, 3578c2ecf20Sopenharmony_ci u32 boot_err0_reg, u32 preboot_ver_timeout) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct pci_dev *pdev = hdev->pdev; 3608c2ecf20Sopenharmony_ci int rc; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (hdev->reset_pcilink) 3638c2ecf20Sopenharmony_ci hl_pci_reset_link_through_bridge(hdev); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci rc = pci_enable_device_mem(pdev); 3668c2ecf20Sopenharmony_ci if (rc) { 3678c2ecf20Sopenharmony_ci dev_err(hdev->dev, "can't enable PCI device\n"); 3688c2ecf20Sopenharmony_ci return rc; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci pci_set_master(pdev); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci rc = hdev->asic_funcs->pci_bars_map(hdev); 3748c2ecf20Sopenharmony_ci if (rc) { 3758c2ecf20Sopenharmony_ci dev_err(hdev->dev, "Failed to initialize PCI BARs\n"); 3768c2ecf20Sopenharmony_ci goto disable_device; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci rc = hdev->asic_funcs->init_iatu(hdev); 3808c2ecf20Sopenharmony_ci if (rc) { 3818c2ecf20Sopenharmony_ci dev_err(hdev->dev, "Failed to initialize iATU\n"); 3828c2ecf20Sopenharmony_ci goto unmap_pci_bars; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci rc = hl_pci_set_dma_mask(hdev); 3868c2ecf20Sopenharmony_ci if (rc) 3878c2ecf20Sopenharmony_ci goto unmap_pci_bars; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Before continuing in the initialization, we need to read the preboot 3908c2ecf20Sopenharmony_ci * version to determine whether we run with a security-enabled firmware 3918c2ecf20Sopenharmony_ci * The check will be done in each ASIC's specific code 3928c2ecf20Sopenharmony_ci */ 3938c2ecf20Sopenharmony_ci rc = hl_fw_read_preboot_ver(hdev, cpu_boot_status_reg, boot_err0_reg, 3948c2ecf20Sopenharmony_ci preboot_ver_timeout); 3958c2ecf20Sopenharmony_ci if (rc) 3968c2ecf20Sopenharmony_ci goto unmap_pci_bars; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ciunmap_pci_bars: 4018c2ecf20Sopenharmony_ci hl_pci_bars_unmap(hdev); 4028c2ecf20Sopenharmony_cidisable_device: 4038c2ecf20Sopenharmony_ci pci_clear_master(pdev); 4048c2ecf20Sopenharmony_ci pci_disable_device(pdev); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return rc; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/** 4108c2ecf20Sopenharmony_ci * hl_fw_fini() - PCI finalization code. 4118c2ecf20Sopenharmony_ci * @hdev: Pointer to hl_device structure 4128c2ecf20Sopenharmony_ci * 4138c2ecf20Sopenharmony_ci * Unmap PCI bars and disable PCI device. 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_civoid hl_pci_fini(struct hl_device *hdev) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci hl_pci_bars_unmap(hdev); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci pci_clear_master(hdev->pdev); 4208c2ecf20Sopenharmony_ci pci_disable_device(hdev->pdev); 4218c2ecf20Sopenharmony_ci} 422