cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pcie_quirks.c (4678B)


      1/*
      2 * NXP Wireless LAN device driver: PCIE and platform specific quirks
      3 *
      4 * This software file (the "File") is distributed by NXP
      5 * under the terms of the GNU General Public License Version 2, June 1991
      6 * (the "License").  You may use, redistribute and/or modify this File in
      7 * accordance with the terms and conditions of the License, a copy of which
      8 * is available by writing to the Free Software Foundation, Inc.,
      9 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
     10 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
     11 *
     12 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
     13 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
     14 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
     15 * this warranty disclaimer.
     16 */
     17
     18#include <linux/dmi.h>
     19
     20#include "pcie_quirks.h"
     21
     22/* quirk table based on DMI matching */
     23static const struct dmi_system_id mwifiex_quirk_table[] = {
     24	{
     25		.ident = "Surface Pro 4",
     26		.matches = {
     27			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
     28			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"),
     29		},
     30		.driver_data = (void *)QUIRK_FW_RST_D3COLD,
     31	},
     32	{
     33		.ident = "Surface Pro 5",
     34		.matches = {
     35			/* match for SKU here due to generic product name "Surface Pro" */
     36			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
     37			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"),
     38		},
     39		.driver_data = (void *)QUIRK_FW_RST_D3COLD,
     40	},
     41	{
     42		.ident = "Surface Pro 5 (LTE)",
     43		.matches = {
     44			/* match for SKU here due to generic product name "Surface Pro" */
     45			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
     46			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"),
     47		},
     48		.driver_data = (void *)QUIRK_FW_RST_D3COLD,
     49	},
     50	{
     51		.ident = "Surface Pro 6",
     52		.matches = {
     53			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
     54			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"),
     55		},
     56		.driver_data = (void *)QUIRK_FW_RST_D3COLD,
     57	},
     58	{
     59		.ident = "Surface Book 1",
     60		.matches = {
     61			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
     62			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"),
     63		},
     64		.driver_data = (void *)QUIRK_FW_RST_D3COLD,
     65	},
     66	{
     67		.ident = "Surface Book 2",
     68		.matches = {
     69			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
     70			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"),
     71		},
     72		.driver_data = (void *)QUIRK_FW_RST_D3COLD,
     73	},
     74	{
     75		.ident = "Surface Laptop 1",
     76		.matches = {
     77			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
     78			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"),
     79		},
     80		.driver_data = (void *)QUIRK_FW_RST_D3COLD,
     81	},
     82	{
     83		.ident = "Surface Laptop 2",
     84		.matches = {
     85			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
     86			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"),
     87		},
     88		.driver_data = (void *)QUIRK_FW_RST_D3COLD,
     89	},
     90	{}
     91};
     92
     93void mwifiex_initialize_quirks(struct pcie_service_card *card)
     94{
     95	struct pci_dev *pdev = card->dev;
     96	const struct dmi_system_id *dmi_id;
     97
     98	dmi_id = dmi_first_match(mwifiex_quirk_table);
     99	if (dmi_id)
    100		card->quirks = (uintptr_t)dmi_id->driver_data;
    101
    102	if (!card->quirks)
    103		dev_info(&pdev->dev, "no quirks enabled\n");
    104	if (card->quirks & QUIRK_FW_RST_D3COLD)
    105		dev_info(&pdev->dev, "quirk reset_d3cold enabled\n");
    106}
    107
    108static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev)
    109{
    110	dev_info(&pdev->dev, "putting into D3cold...\n");
    111
    112	pci_save_state(pdev);
    113	if (pci_is_enabled(pdev))
    114		pci_disable_device(pdev);
    115	pci_set_power_state(pdev, PCI_D3cold);
    116}
    117
    118static int mwifiex_pcie_set_power_d0(struct pci_dev *pdev)
    119{
    120	int ret;
    121
    122	dev_info(&pdev->dev, "putting into D0...\n");
    123
    124	pci_set_power_state(pdev, PCI_D0);
    125	ret = pci_enable_device(pdev);
    126	if (ret) {
    127		dev_err(&pdev->dev, "pci_enable_device failed\n");
    128		return ret;
    129	}
    130	pci_restore_state(pdev);
    131
    132	return 0;
    133}
    134
    135int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev)
    136{
    137	struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);
    138	int ret;
    139
    140	/* Power-cycle (put into D3cold then D0) */
    141	dev_info(&pdev->dev, "Using reset_d3cold quirk to perform FW reset\n");
    142
    143	/* We need to perform power-cycle also for bridge of wifi because
    144	 * on some devices (e.g. Surface Book 1), the OS for some reasons
    145	 * can't know the real power state of the bridge.
    146	 * When tried to power-cycle only wifi, the reset failed with the
    147	 * following dmesg log:
    148	 * "Cannot transition to power state D0 for parent in D3hot".
    149	 */
    150	mwifiex_pcie_set_power_d3cold(pdev);
    151	mwifiex_pcie_set_power_d3cold(parent_pdev);
    152
    153	ret = mwifiex_pcie_set_power_d0(parent_pdev);
    154	if (ret)
    155		return ret;
    156	ret = mwifiex_pcie_set_power_d0(pdev);
    157	if (ret)
    158		return ret;
    159
    160	return 0;
    161}