18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel I/OAT DMA Linux driver 48c2ecf20Sopenharmony_ci * Copyright(c) 2007 - 2009 Intel Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci#include <linux/smp.h> 108c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 118c2ecf20Sopenharmony_ci#include <linux/dca.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* either a kernel change is needed, or we need something like this in kernel */ 148c2ecf20Sopenharmony_ci#ifndef CONFIG_SMP 158c2ecf20Sopenharmony_ci#include <asm/smp.h> 168c2ecf20Sopenharmony_ci#undef cpu_physical_id 178c2ecf20Sopenharmony_ci#define cpu_physical_id(cpu) (cpuid_ebx(1) >> 24) 188c2ecf20Sopenharmony_ci#endif 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "dma.h" 218c2ecf20Sopenharmony_ci#include "registers.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * Bit 7 of a tag map entry is the "valid" bit, if it is set then bits 0:6 258c2ecf20Sopenharmony_ci * contain the bit number of the APIC ID to map into the DCA tag. If the valid 268c2ecf20Sopenharmony_ci * bit is not set, then the value must be 0 or 1 and defines the bit in the tag. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci#define DCA_TAG_MAP_VALID 0x80 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define DCA3_TAG_MAP_BIT_TO_INV 0x80 318c2ecf20Sopenharmony_ci#define DCA3_TAG_MAP_BIT_TO_SEL 0x40 328c2ecf20Sopenharmony_ci#define DCA3_TAG_MAP_LITERAL_VAL 0x1 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define DCA_TAG_MAP_MASK 0xDF 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* expected tag map bytes for I/OAT ver.2 */ 378c2ecf20Sopenharmony_ci#define DCA2_TAG_MAP_BYTE0 0x80 388c2ecf20Sopenharmony_ci#define DCA2_TAG_MAP_BYTE1 0x0 398c2ecf20Sopenharmony_ci#define DCA2_TAG_MAP_BYTE2 0x81 408c2ecf20Sopenharmony_ci#define DCA2_TAG_MAP_BYTE3 0x82 418c2ecf20Sopenharmony_ci#define DCA2_TAG_MAP_BYTE4 0x82 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * "Legacy" DCA systems do not implement the DCA register set in the 458c2ecf20Sopenharmony_ci * I/OAT device. Software needs direct support for their tag mappings. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define APICID_BIT(x) (DCA_TAG_MAP_VALID | (x)) 498c2ecf20Sopenharmony_ci#define IOAT_TAG_MAP_LEN 8 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* pack PCI B/D/F into a u16 */ 528c2ecf20Sopenharmony_cistatic inline u16 dcaid_from_pcidev(struct pci_dev *pci) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci return (pci->bus->number << 8) | pci->devfn; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int dca_enabled_in_bios(struct pci_dev *pdev) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci /* CPUID level 9 returns DCA configuration */ 608c2ecf20Sopenharmony_ci /* Bit 0 indicates DCA enabled by the BIOS */ 618c2ecf20Sopenharmony_ci unsigned long cpuid_level_9; 628c2ecf20Sopenharmony_ci int res; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci cpuid_level_9 = cpuid_eax(9); 658c2ecf20Sopenharmony_ci res = test_bit(0, &cpuid_level_9); 668c2ecf20Sopenharmony_ci if (!res) 678c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "DCA is disabled in BIOS\n"); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return res; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ciint system_has_dca_enabled(struct pci_dev *pdev) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_DCA)) 758c2ecf20Sopenharmony_ci return dca_enabled_in_bios(pdev); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "boot cpu doesn't have X86_FEATURE_DCA\n"); 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistruct ioat_dca_slot { 828c2ecf20Sopenharmony_ci struct pci_dev *pdev; /* requester device */ 838c2ecf20Sopenharmony_ci u16 rid; /* requester id, as used by IOAT */ 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define IOAT_DCA_MAX_REQ 6 878c2ecf20Sopenharmony_ci#define IOAT3_DCA_MAX_REQ 2 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistruct ioat_dca_priv { 908c2ecf20Sopenharmony_ci void __iomem *iobase; 918c2ecf20Sopenharmony_ci void __iomem *dca_base; 928c2ecf20Sopenharmony_ci int max_requesters; 938c2ecf20Sopenharmony_ci int requester_count; 948c2ecf20Sopenharmony_ci u8 tag_map[IOAT_TAG_MAP_LEN]; 958c2ecf20Sopenharmony_ci struct ioat_dca_slot req_slots[]; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int ioat_dca_dev_managed(struct dca_provider *dca, 998c2ecf20Sopenharmony_ci struct device *dev) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct ioat_dca_priv *ioatdca = dca_priv(dca); 1028c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1038c2ecf20Sopenharmony_ci int i; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci pdev = to_pci_dev(dev); 1068c2ecf20Sopenharmony_ci for (i = 0; i < ioatdca->max_requesters; i++) { 1078c2ecf20Sopenharmony_ci if (ioatdca->req_slots[i].pdev == pdev) 1088c2ecf20Sopenharmony_ci return 1; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int ioat_dca_add_requester(struct dca_provider *dca, struct device *dev) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct ioat_dca_priv *ioatdca = dca_priv(dca); 1168c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1178c2ecf20Sopenharmony_ci int i; 1188c2ecf20Sopenharmony_ci u16 id; 1198c2ecf20Sopenharmony_ci u16 global_req_table; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* This implementation only supports PCI-Express */ 1228c2ecf20Sopenharmony_ci if (!dev_is_pci(dev)) 1238c2ecf20Sopenharmony_ci return -ENODEV; 1248c2ecf20Sopenharmony_ci pdev = to_pci_dev(dev); 1258c2ecf20Sopenharmony_ci id = dcaid_from_pcidev(pdev); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (ioatdca->requester_count == ioatdca->max_requesters) 1288c2ecf20Sopenharmony_ci return -ENODEV; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci for (i = 0; i < ioatdca->max_requesters; i++) { 1318c2ecf20Sopenharmony_ci if (ioatdca->req_slots[i].pdev == NULL) { 1328c2ecf20Sopenharmony_ci /* found an empty slot */ 1338c2ecf20Sopenharmony_ci ioatdca->requester_count++; 1348c2ecf20Sopenharmony_ci ioatdca->req_slots[i].pdev = pdev; 1358c2ecf20Sopenharmony_ci ioatdca->req_slots[i].rid = id; 1368c2ecf20Sopenharmony_ci global_req_table = 1378c2ecf20Sopenharmony_ci readw(ioatdca->dca_base + IOAT3_DCA_GREQID_OFFSET); 1388c2ecf20Sopenharmony_ci writel(id | IOAT_DCA_GREQID_VALID, 1398c2ecf20Sopenharmony_ci ioatdca->iobase + global_req_table + (i * 4)); 1408c2ecf20Sopenharmony_ci return i; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci /* Error, ioatdma->requester_count is out of whack */ 1448c2ecf20Sopenharmony_ci return -EFAULT; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int ioat_dca_remove_requester(struct dca_provider *dca, 1488c2ecf20Sopenharmony_ci struct device *dev) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct ioat_dca_priv *ioatdca = dca_priv(dca); 1518c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1528c2ecf20Sopenharmony_ci int i; 1538c2ecf20Sopenharmony_ci u16 global_req_table; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* This implementation only supports PCI-Express */ 1568c2ecf20Sopenharmony_ci if (!dev_is_pci(dev)) 1578c2ecf20Sopenharmony_ci return -ENODEV; 1588c2ecf20Sopenharmony_ci pdev = to_pci_dev(dev); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci for (i = 0; i < ioatdca->max_requesters; i++) { 1618c2ecf20Sopenharmony_ci if (ioatdca->req_slots[i].pdev == pdev) { 1628c2ecf20Sopenharmony_ci global_req_table = 1638c2ecf20Sopenharmony_ci readw(ioatdca->dca_base + IOAT3_DCA_GREQID_OFFSET); 1648c2ecf20Sopenharmony_ci writel(0, ioatdca->iobase + global_req_table + (i * 4)); 1658c2ecf20Sopenharmony_ci ioatdca->req_slots[i].pdev = NULL; 1668c2ecf20Sopenharmony_ci ioatdca->req_slots[i].rid = 0; 1678c2ecf20Sopenharmony_ci ioatdca->requester_count--; 1688c2ecf20Sopenharmony_ci return i; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci return -ENODEV; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic u8 ioat_dca_get_tag(struct dca_provider *dca, 1758c2ecf20Sopenharmony_ci struct device *dev, 1768c2ecf20Sopenharmony_ci int cpu) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci u8 tag; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci struct ioat_dca_priv *ioatdca = dca_priv(dca); 1818c2ecf20Sopenharmony_ci int i, apic_id, bit, value; 1828c2ecf20Sopenharmony_ci u8 entry; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci tag = 0; 1858c2ecf20Sopenharmony_ci apic_id = cpu_physical_id(cpu); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci for (i = 0; i < IOAT_TAG_MAP_LEN; i++) { 1888c2ecf20Sopenharmony_ci entry = ioatdca->tag_map[i]; 1898c2ecf20Sopenharmony_ci if (entry & DCA3_TAG_MAP_BIT_TO_SEL) { 1908c2ecf20Sopenharmony_ci bit = entry & 1918c2ecf20Sopenharmony_ci ~(DCA3_TAG_MAP_BIT_TO_SEL | DCA3_TAG_MAP_BIT_TO_INV); 1928c2ecf20Sopenharmony_ci value = (apic_id & (1 << bit)) ? 1 : 0; 1938c2ecf20Sopenharmony_ci } else if (entry & DCA3_TAG_MAP_BIT_TO_INV) { 1948c2ecf20Sopenharmony_ci bit = entry & ~DCA3_TAG_MAP_BIT_TO_INV; 1958c2ecf20Sopenharmony_ci value = (apic_id & (1 << bit)) ? 0 : 1; 1968c2ecf20Sopenharmony_ci } else { 1978c2ecf20Sopenharmony_ci value = (entry & DCA3_TAG_MAP_LITERAL_VAL) ? 1 : 0; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci tag |= (value << i); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return tag; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic const struct dca_ops ioat_dca_ops = { 2068c2ecf20Sopenharmony_ci .add_requester = ioat_dca_add_requester, 2078c2ecf20Sopenharmony_ci .remove_requester = ioat_dca_remove_requester, 2088c2ecf20Sopenharmony_ci .get_tag = ioat_dca_get_tag, 2098c2ecf20Sopenharmony_ci .dev_managed = ioat_dca_dev_managed, 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int ioat_dca_count_dca_slots(void *iobase, u16 dca_offset) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci int slots = 0; 2158c2ecf20Sopenharmony_ci u32 req; 2168c2ecf20Sopenharmony_ci u16 global_req_table; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci global_req_table = readw(iobase + dca_offset + IOAT3_DCA_GREQID_OFFSET); 2198c2ecf20Sopenharmony_ci if (global_req_table == 0) 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci do { 2238c2ecf20Sopenharmony_ci req = readl(iobase + global_req_table + (slots * sizeof(u32))); 2248c2ecf20Sopenharmony_ci slots++; 2258c2ecf20Sopenharmony_ci } while ((req & IOAT_DCA_GREQID_LASTID) == 0); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return slots; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic inline int dca3_tag_map_invalid(u8 *tag_map) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci /* 2338c2ecf20Sopenharmony_ci * If the tag map is not programmed by the BIOS the default is: 2348c2ecf20Sopenharmony_ci * 0x80 0x80 0x80 0x80 0x80 0x00 0x00 0x00 2358c2ecf20Sopenharmony_ci * 2368c2ecf20Sopenharmony_ci * This an invalid map and will result in only 2 possible tags 2378c2ecf20Sopenharmony_ci * 0x1F and 0x00. 0x00 is an invalid DCA tag so we know that 2388c2ecf20Sopenharmony_ci * this entire definition is invalid. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci return ((tag_map[0] == DCA_TAG_MAP_VALID) && 2418c2ecf20Sopenharmony_ci (tag_map[1] == DCA_TAG_MAP_VALID) && 2428c2ecf20Sopenharmony_ci (tag_map[2] == DCA_TAG_MAP_VALID) && 2438c2ecf20Sopenharmony_ci (tag_map[3] == DCA_TAG_MAP_VALID) && 2448c2ecf20Sopenharmony_ci (tag_map[4] == DCA_TAG_MAP_VALID)); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistruct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct dca_provider *dca; 2508c2ecf20Sopenharmony_ci struct ioat_dca_priv *ioatdca; 2518c2ecf20Sopenharmony_ci int slots; 2528c2ecf20Sopenharmony_ci int i; 2538c2ecf20Sopenharmony_ci int err; 2548c2ecf20Sopenharmony_ci u16 dca_offset; 2558c2ecf20Sopenharmony_ci u16 csi_fsb_control; 2568c2ecf20Sopenharmony_ci u16 pcie_control; 2578c2ecf20Sopenharmony_ci u8 bit; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci union { 2608c2ecf20Sopenharmony_ci u64 full; 2618c2ecf20Sopenharmony_ci struct { 2628c2ecf20Sopenharmony_ci u32 low; 2638c2ecf20Sopenharmony_ci u32 high; 2648c2ecf20Sopenharmony_ci }; 2658c2ecf20Sopenharmony_ci } tag_map; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (!system_has_dca_enabled(pdev)) 2688c2ecf20Sopenharmony_ci return NULL; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci dca_offset = readw(iobase + IOAT_DCAOFFSET_OFFSET); 2718c2ecf20Sopenharmony_ci if (dca_offset == 0) 2728c2ecf20Sopenharmony_ci return NULL; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci slots = ioat_dca_count_dca_slots(iobase, dca_offset); 2758c2ecf20Sopenharmony_ci if (slots == 0) 2768c2ecf20Sopenharmony_ci return NULL; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci dca = alloc_dca_provider(&ioat_dca_ops, 2798c2ecf20Sopenharmony_ci struct_size(ioatdca, req_slots, slots)); 2808c2ecf20Sopenharmony_ci if (!dca) 2818c2ecf20Sopenharmony_ci return NULL; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci ioatdca = dca_priv(dca); 2848c2ecf20Sopenharmony_ci ioatdca->iobase = iobase; 2858c2ecf20Sopenharmony_ci ioatdca->dca_base = iobase + dca_offset; 2868c2ecf20Sopenharmony_ci ioatdca->max_requesters = slots; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* some bios might not know to turn these on */ 2898c2ecf20Sopenharmony_ci csi_fsb_control = readw(ioatdca->dca_base + IOAT3_CSI_CONTROL_OFFSET); 2908c2ecf20Sopenharmony_ci if ((csi_fsb_control & IOAT3_CSI_CONTROL_PREFETCH) == 0) { 2918c2ecf20Sopenharmony_ci csi_fsb_control |= IOAT3_CSI_CONTROL_PREFETCH; 2928c2ecf20Sopenharmony_ci writew(csi_fsb_control, 2938c2ecf20Sopenharmony_ci ioatdca->dca_base + IOAT3_CSI_CONTROL_OFFSET); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci pcie_control = readw(ioatdca->dca_base + IOAT3_PCI_CONTROL_OFFSET); 2968c2ecf20Sopenharmony_ci if ((pcie_control & IOAT3_PCI_CONTROL_MEMWR) == 0) { 2978c2ecf20Sopenharmony_ci pcie_control |= IOAT3_PCI_CONTROL_MEMWR; 2988c2ecf20Sopenharmony_ci writew(pcie_control, 2998c2ecf20Sopenharmony_ci ioatdca->dca_base + IOAT3_PCI_CONTROL_OFFSET); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* TODO version, compatibility and configuration checks */ 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* copy out the APIC to DCA tag map */ 3068c2ecf20Sopenharmony_ci tag_map.low = 3078c2ecf20Sopenharmony_ci readl(ioatdca->dca_base + IOAT3_APICID_TAG_MAP_OFFSET_LOW); 3088c2ecf20Sopenharmony_ci tag_map.high = 3098c2ecf20Sopenharmony_ci readl(ioatdca->dca_base + IOAT3_APICID_TAG_MAP_OFFSET_HIGH); 3108c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 3118c2ecf20Sopenharmony_ci bit = tag_map.full >> (8 * i); 3128c2ecf20Sopenharmony_ci ioatdca->tag_map[i] = bit & DCA_TAG_MAP_MASK; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (dca3_tag_map_invalid(ioatdca->tag_map)) { 3168c2ecf20Sopenharmony_ci add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); 3178c2ecf20Sopenharmony_ci pr_warn_once("%s %s: APICID_TAG_MAP set incorrectly by BIOS, disabling DCA\n", 3188c2ecf20Sopenharmony_ci dev_driver_string(&pdev->dev), 3198c2ecf20Sopenharmony_ci dev_name(&pdev->dev)); 3208c2ecf20Sopenharmony_ci free_dca_provider(dca); 3218c2ecf20Sopenharmony_ci return NULL; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci err = register_dca_provider(dca, &pdev->dev); 3258c2ecf20Sopenharmony_ci if (err) { 3268c2ecf20Sopenharmony_ci free_dca_provider(dca); 3278c2ecf20Sopenharmony_ci return NULL; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return dca; 3318c2ecf20Sopenharmony_ci} 332