162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci * Quirks for AMD IOMMU
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2019 Kai-Heng Feng <kai.heng.feng@canonical.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#ifdef CONFIG_DMI
1062306a36Sopenharmony_ci#include <linux/dmi.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "amd_iommu.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define IVHD_SPECIAL_IOAPIC		1
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct ivrs_quirk_entry {
1762306a36Sopenharmony_ci	u8 id;
1862306a36Sopenharmony_ci	u32 devid;
1962306a36Sopenharmony_ci};
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cienum {
2262306a36Sopenharmony_ci	DELL_INSPIRON_7375 = 0,
2362306a36Sopenharmony_ci	DELL_LATITUDE_5495,
2462306a36Sopenharmony_ci	LENOVO_IDEAPAD_330S_15ARR,
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic const struct ivrs_quirk_entry ivrs_ioapic_quirks[][3] __initconst = {
2862306a36Sopenharmony_ci	/* ivrs_ioapic[4]=00:14.0 ivrs_ioapic[5]=00:00.2 */
2962306a36Sopenharmony_ci	[DELL_INSPIRON_7375] = {
3062306a36Sopenharmony_ci		{ .id = 4, .devid = 0xa0 },
3162306a36Sopenharmony_ci		{ .id = 5, .devid = 0x2 },
3262306a36Sopenharmony_ci		{}
3362306a36Sopenharmony_ci	},
3462306a36Sopenharmony_ci	/* ivrs_ioapic[4]=00:14.0 */
3562306a36Sopenharmony_ci	[DELL_LATITUDE_5495] = {
3662306a36Sopenharmony_ci		{ .id = 4, .devid = 0xa0 },
3762306a36Sopenharmony_ci		{}
3862306a36Sopenharmony_ci	},
3962306a36Sopenharmony_ci	/* ivrs_ioapic[32]=00:14.0 */
4062306a36Sopenharmony_ci	[LENOVO_IDEAPAD_330S_15ARR] = {
4162306a36Sopenharmony_ci		{ .id = 32, .devid = 0xa0 },
4262306a36Sopenharmony_ci		{}
4362306a36Sopenharmony_ci	},
4462306a36Sopenharmony_ci	{}
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int __init ivrs_ioapic_quirk_cb(const struct dmi_system_id *d)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	const struct ivrs_quirk_entry *i;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	for (i = d->driver_data; i->id != 0 && i->devid != 0; i++)
5262306a36Sopenharmony_ci		add_special_device(IVHD_SPECIAL_IOAPIC, i->id, (u32 *)&i->devid, 0);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	return 0;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic const struct dmi_system_id ivrs_quirks[] __initconst = {
5862306a36Sopenharmony_ci	{
5962306a36Sopenharmony_ci		.callback = ivrs_ioapic_quirk_cb,
6062306a36Sopenharmony_ci		.ident = "Dell Inspiron 7375",
6162306a36Sopenharmony_ci		.matches = {
6262306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
6362306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7375"),
6462306a36Sopenharmony_ci		},
6562306a36Sopenharmony_ci		.driver_data = (void *)&ivrs_ioapic_quirks[DELL_INSPIRON_7375],
6662306a36Sopenharmony_ci	},
6762306a36Sopenharmony_ci	{
6862306a36Sopenharmony_ci		.callback = ivrs_ioapic_quirk_cb,
6962306a36Sopenharmony_ci		.ident = "Dell Latitude 5495",
7062306a36Sopenharmony_ci		.matches = {
7162306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
7262306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 5495"),
7362306a36Sopenharmony_ci		},
7462306a36Sopenharmony_ci		.driver_data = (void *)&ivrs_ioapic_quirks[DELL_LATITUDE_5495],
7562306a36Sopenharmony_ci	},
7662306a36Sopenharmony_ci	{
7762306a36Sopenharmony_ci		/*
7862306a36Sopenharmony_ci		 * Acer Aspire A315-41 requires the very same workaround as
7962306a36Sopenharmony_ci		 * Dell Latitude 5495
8062306a36Sopenharmony_ci		 */
8162306a36Sopenharmony_ci		.callback = ivrs_ioapic_quirk_cb,
8262306a36Sopenharmony_ci		.ident = "Acer Aspire A315-41",
8362306a36Sopenharmony_ci		.matches = {
8462306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
8562306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A315-41"),
8662306a36Sopenharmony_ci		},
8762306a36Sopenharmony_ci		.driver_data = (void *)&ivrs_ioapic_quirks[DELL_LATITUDE_5495],
8862306a36Sopenharmony_ci	},
8962306a36Sopenharmony_ci	{
9062306a36Sopenharmony_ci		.callback = ivrs_ioapic_quirk_cb,
9162306a36Sopenharmony_ci		.ident = "Lenovo ideapad 330S-15ARR",
9262306a36Sopenharmony_ci		.matches = {
9362306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
9462306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "81FB"),
9562306a36Sopenharmony_ci		},
9662306a36Sopenharmony_ci		.driver_data = (void *)&ivrs_ioapic_quirks[LENOVO_IDEAPAD_330S_15ARR],
9762306a36Sopenharmony_ci	},
9862306a36Sopenharmony_ci	{}
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_civoid __init amd_iommu_apply_ivrs_quirks(void)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	dmi_check_system(ivrs_quirks);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci#endif
106