xref: /kernel/linux/linux-5.10/drivers/dma/ioat/dca.c (revision 8c2ecf20)
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