brintos

brintos / linux-shallow public Read only

0
0
Text · 3.9 KiB · dd6d21f Raw
148 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// NXP Wireless LAN device driver: PCIE and platform specific quirks3 4#include <linux/dmi.h>5 6#include "pcie_quirks.h"7 8/* quirk table based on DMI matching */9static const struct dmi_system_id mwifiex_quirk_table[] = {10	{11		.ident = "Surface Pro 4",12		.matches = {13			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),14			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"),15		},16		.driver_data = (void *)QUIRK_FW_RST_D3COLD,17	},18	{19		.ident = "Surface Pro 5",20		.matches = {21			/* match for SKU here due to generic product name "Surface Pro" */22			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),23			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"),24		},25		.driver_data = (void *)QUIRK_FW_RST_D3COLD,26	},27	{28		.ident = "Surface Pro 5 (LTE)",29		.matches = {30			/* match for SKU here due to generic product name "Surface Pro" */31			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),32			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"),33		},34		.driver_data = (void *)QUIRK_FW_RST_D3COLD,35	},36	{37		.ident = "Surface Pro 6",38		.matches = {39			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),40			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"),41		},42		.driver_data = (void *)QUIRK_FW_RST_D3COLD,43	},44	{45		.ident = "Surface Book 1",46		.matches = {47			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),48			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"),49		},50		.driver_data = (void *)QUIRK_FW_RST_D3COLD,51	},52	{53		.ident = "Surface Book 2",54		.matches = {55			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),56			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"),57		},58		.driver_data = (void *)QUIRK_FW_RST_D3COLD,59	},60	{61		.ident = "Surface Laptop 1",62		.matches = {63			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),64			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"),65		},66		.driver_data = (void *)QUIRK_FW_RST_D3COLD,67	},68	{69		.ident = "Surface Laptop 2",70		.matches = {71			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),72			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"),73		},74		.driver_data = (void *)QUIRK_FW_RST_D3COLD,75	},76	{}77};78 79void mwifiex_initialize_quirks(struct pcie_service_card *card)80{81	struct pci_dev *pdev = card->dev;82	const struct dmi_system_id *dmi_id;83 84	dmi_id = dmi_first_match(mwifiex_quirk_table);85	if (dmi_id)86		card->quirks = (uintptr_t)dmi_id->driver_data;87 88	if (!card->quirks)89		dev_info(&pdev->dev, "no quirks enabled\n");90	if (card->quirks & QUIRK_FW_RST_D3COLD)91		dev_info(&pdev->dev, "quirk reset_d3cold enabled\n");92}93 94static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev)95{96	dev_info(&pdev->dev, "putting into D3cold...\n");97 98	pci_save_state(pdev);99	if (pci_is_enabled(pdev))100		pci_disable_device(pdev);101	pci_set_power_state(pdev, PCI_D3cold);102}103 104static int mwifiex_pcie_set_power_d0(struct pci_dev *pdev)105{106	int ret;107 108	dev_info(&pdev->dev, "putting into D0...\n");109 110	pci_set_power_state(pdev, PCI_D0);111	ret = pci_enable_device(pdev);112	if (ret) {113		dev_err(&pdev->dev, "pci_enable_device failed\n");114		return ret;115	}116	pci_restore_state(pdev);117 118	return 0;119}120 121int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev)122{123	struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);124	int ret;125 126	/* Power-cycle (put into D3cold then D0) */127	dev_info(&pdev->dev, "Using reset_d3cold quirk to perform FW reset\n");128 129	/* We need to perform power-cycle also for bridge of wifi because130	 * on some devices (e.g. Surface Book 1), the OS for some reasons131	 * can't know the real power state of the bridge.132	 * When tried to power-cycle only wifi, the reset failed with the133	 * following dmesg log:134	 * "Cannot transition to power state D0 for parent in D3hot".135	 */136	mwifiex_pcie_set_power_d3cold(pdev);137	mwifiex_pcie_set_power_d3cold(parent_pdev);138 139	ret = mwifiex_pcie_set_power_d0(parent_pdev);140	if (ret)141		return ret;142	ret = mwifiex_pcie_set_power_d0(pdev);143	if (ret)144		return ret;145 146	return 0;147}148