diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-04 18:19:14 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-04 18:19:14 -0700 |
commit | 5f0848190c6dd0f5b8a2aaf0f1d900a96d96bee0 (patch) | |
tree | 37d5630a4e6d849123951f0b3fe3aa685561b9f0 /drivers/platform/x86/intel/vsec.c | |
parent | 5bb3bf24b0aaa76253c77e437b88927a32a10c4e (diff) | |
parent | 3d46d78480757e6d403c3bc2b32d2b05ecbed543 (diff) |
Merge tag 'platform-drivers-x86-v6.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver updates from Hans de Goede:
- Microsoft Surface:
- SSAM hot unplug support
- Surface Pro 8 keyboard cover support
- Tablet mode switch support for Surface Pro 8 and Surface Laptop
Studio
- thinkpad_acpi:
- AMD Automatice Mode Transitions (AMT) support
- Mellanox:
- Vulcan chassis COMe NVSwitch management support
- XH3000 support
- New generic/shared Intel P2SB (Primary to Sideband) support
- Lots of small cleanups
- Various small bugfixes
- Various new hardware ids / quirks additions
* tag 'platform-drivers-x86-v6.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (105 commits)
platform/x86/intel/vsec: Fix wrong type for local status variables
platform/x86: p2sb: Move out of X86_PLATFORM_DEVICES dependency
platform/x86: pmc_atom: Fix comment typo
platform/surface: gpe: Add support for 13" Intel version of Surface Laptop 4
platform/olpc: Fix uninitialized data in debugfs write
platform/mellanox: mlxreg-lc: Fix error flow and extend verbosity
platform/x86: pmc_atom: Match all Lex BayTrail boards with critclk_systems DMI table
platform/x86: sony-laptop: Remove useless comparisons in sony_pic_read_possible_resource()
tools/power/x86/intel-speed-select: Remove unneeded semicolon
tools/power/x86/intel-speed-select: Fix off by one check
platform/surface: tabletsw: Fix __le32 integer access
Documentation/ABI: Add new attributes for mlxreg-io sysfs interfaces
Documentation/ABI: mlxreg-io: Fix contact info
platform/mellanox: mlxreg-io: Add locking for io operations
platform/x86: mlx-platform: Add COME board revision register
platform/x86: mlx-platform: Add support for new system XH3000
platform/x86: mlx-platform: Introduce support for COMe NVSwitch management module for Vulcan chassis
platform/x86: mlx-platform: Add support for systems equipped with two ASICs
platform/x86: mlx-platform: Add cosmetic changes for alignment
platform/x86: mlx-platform: Make activation of some drivers conditional
...
Diffstat (limited to 'drivers/platform/x86/intel/vsec.c')
-rw-r--r-- | drivers/platform/x86/intel/vsec.c | 130 |
1 files changed, 104 insertions, 26 deletions
diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index bed436bf181f..bb81b8b1f7e9 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -15,6 +15,7 @@ #include <linux/auxiliary_bus.h> #include <linux/bits.h> +#include <linux/delay.h> #include <linux/kernel.h> #include <linux/idr.h> #include <linux/module.h> @@ -30,9 +31,13 @@ #define INTEL_DVSEC_TABLE_BAR(x) ((x) & GENMASK(2, 0)) #define INTEL_DVSEC_TABLE_OFFSET(x) ((x) & GENMASK(31, 3)) #define TABLE_OFFSET_SHIFT 3 +#define PMT_XA_START 0 +#define PMT_XA_MAX INT_MAX +#define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX) static DEFINE_IDA(intel_vsec_ida); static DEFINE_IDA(intel_vsec_sdsi_ida); +static DEFINE_XARRAY_ALLOC(auxdev_array); /** * struct intel_vsec_header - Common fields of Intel VSEC and DVSEC registers. @@ -54,12 +59,6 @@ struct intel_vsec_header { u32 offset; }; -/* Platform specific data */ -struct intel_vsec_platform_info { - struct intel_vsec_header **capabilities; - unsigned long quirks; -}; - enum intel_vsec_id { VSEC_ID_TELEMETRY = 2, VSEC_ID_WATCHER = 3, @@ -138,7 +137,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in const char *name) { struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev; - int ret; + int ret, id; ret = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL); if (ret < 0) { @@ -165,14 +164,26 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in return ret; } - return devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux, auxdev); + ret = devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux, + auxdev); + if (ret < 0) + return ret; + + /* Add auxdev to list */ + ret = xa_alloc(&auxdev_array, &id, intel_vsec_dev, PMT_XA_LIMIT, + GFP_KERNEL); + if (ret) + return ret; + + return 0; } static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header, - unsigned long quirks) + struct intel_vsec_platform_info *info) { struct intel_vsec_device *intel_vsec_dev; struct resource *res, *tmp; + unsigned long quirks = info->quirks; int i; if (!intel_vsec_allowed(header->id) || intel_vsec_disabled(header->id, quirks)) @@ -216,7 +227,7 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he intel_vsec_dev->pcidev = pdev; intel_vsec_dev->resource = res; intel_vsec_dev->num_resources = header->num_entries; - intel_vsec_dev->quirks = quirks; + intel_vsec_dev->info = info; if (header->id == VSEC_ID_SDSI) intel_vsec_dev->ida = &intel_vsec_sdsi_ida; @@ -226,14 +237,15 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he return intel_vsec_add_aux(pdev, intel_vsec_dev, intel_vsec_name(header->id)); } -static bool intel_vsec_walk_header(struct pci_dev *pdev, unsigned long quirks, - struct intel_vsec_header **header) +static bool intel_vsec_walk_header(struct pci_dev *pdev, + struct intel_vsec_platform_info *info) { + struct intel_vsec_header **header = info->capabilities; bool have_devices = false; int ret; for ( ; *header; header++) { - ret = intel_vsec_add_dev(pdev, *header, quirks); + ret = intel_vsec_add_dev(pdev, *header, info); if (ret) dev_info(&pdev->dev, "Could not add device for DVSEC id %d\n", (*header)->id); @@ -244,7 +256,8 @@ static bool intel_vsec_walk_header(struct pci_dev *pdev, unsigned long quirks, return have_devices; } -static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, unsigned long quirks) +static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, + struct intel_vsec_platform_info *info) { bool have_devices = false; int pos = 0; @@ -283,7 +296,7 @@ static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, unsigned long quirks) pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER2, &hdr); header.id = PCI_DVSEC_HEADER2_ID(hdr); - ret = intel_vsec_add_dev(pdev, &header, quirks); + ret = intel_vsec_add_dev(pdev, &header, info); if (ret) continue; @@ -293,7 +306,8 @@ static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, unsigned long quirks) return have_devices; } -static bool intel_vsec_walk_vsec(struct pci_dev *pdev, unsigned long quirks) +static bool intel_vsec_walk_vsec(struct pci_dev *pdev, + struct intel_vsec_platform_info *info) { bool have_devices = false; int pos = 0; @@ -327,7 +341,7 @@ static bool intel_vsec_walk_vsec(struct pci_dev *pdev, unsigned long quirks) header.tbir = INTEL_DVSEC_TABLE_BAR(table); header.offset = INTEL_DVSEC_TABLE_OFFSET(table); - ret = intel_vsec_add_dev(pdev, &header, quirks); + ret = intel_vsec_add_dev(pdev, &header, info); if (ret) continue; @@ -341,25 +355,25 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id { struct intel_vsec_platform_info *info; bool have_devices = false; - unsigned long quirks = 0; int ret; ret = pcim_enable_device(pdev); if (ret) return ret; + pci_save_state(pdev); info = (struct intel_vsec_platform_info *)id->driver_data; - if (info) - quirks = info->quirks; + if (!info) + return -EINVAL; - if (intel_vsec_walk_dvsec(pdev, quirks)) + if (intel_vsec_walk_dvsec(pdev, info)) have_devices = true; - if (intel_vsec_walk_vsec(pdev, quirks)) + if (intel_vsec_walk_vsec(pdev, info)) have_devices = true; if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) && - intel_vsec_walk_header(pdev, quirks, info->capabilities)) + intel_vsec_walk_header(pdev, info)) have_devices = true; if (!have_devices) @@ -370,7 +384,8 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id /* TGL info */ static const struct intel_vsec_platform_info tgl_info = { - .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG | VSEC_QUIRK_TABLE_SHIFT, + .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG | + VSEC_QUIRK_TABLE_SHIFT | VSEC_QUIRK_EARLY_HW, }; /* DG1 info */ @@ -390,26 +405,89 @@ static struct intel_vsec_header *dg1_capabilities[] = { static const struct intel_vsec_platform_info dg1_info = { .capabilities = dg1_capabilities, - .quirks = VSEC_QUIRK_NO_DVSEC, + .quirks = VSEC_QUIRK_NO_DVSEC | VSEC_QUIRK_EARLY_HW, }; #define PCI_DEVICE_ID_INTEL_VSEC_ADL 0x467d #define PCI_DEVICE_ID_INTEL_VSEC_DG1 0x490e #define PCI_DEVICE_ID_INTEL_VSEC_OOBMSM 0x09a7 +#define PCI_DEVICE_ID_INTEL_VSEC_RPL 0xa77d #define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d static const struct pci_device_id intel_vsec_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) }, - { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, NULL) }, + { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, &(struct intel_vsec_platform_info) {}) }, + { PCI_DEVICE_DATA(INTEL, VSEC_RPL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) }, { } }; MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids); +static pci_ers_result_t intel_vsec_pci_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + pci_ers_result_t status = PCI_ERS_RESULT_NEED_RESET; + + dev_info(&pdev->dev, "PCI error detected, state %d", state); + + if (state == pci_channel_io_perm_failure) + status = PCI_ERS_RESULT_DISCONNECT; + else + pci_disable_device(pdev); + + return status; +} + +static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev) +{ + struct intel_vsec_device *intel_vsec_dev; + pci_ers_result_t status = PCI_ERS_RESULT_DISCONNECT; + const struct pci_device_id *pci_dev_id; + unsigned long index; + + dev_info(&pdev->dev, "Resetting PCI slot\n"); + + msleep(2000); + if (pci_enable_device(pdev)) { + dev_info(&pdev->dev, + "Failed to re-enable PCI device after reset.\n"); + goto out; + } + + status = PCI_ERS_RESULT_RECOVERED; + + xa_for_each(&auxdev_array, index, intel_vsec_dev) { + /* check if pdev doesn't match */ + if (pdev != intel_vsec_dev->pcidev) + continue; + devm_release_action(&pdev->dev, intel_vsec_remove_aux, + &intel_vsec_dev->auxdev); + } + pci_disable_device(pdev); + pci_restore_state(pdev); + pci_dev_id = pci_match_id(intel_vsec_pci_ids, pdev); + intel_vsec_pci_probe(pdev, pci_dev_id); + +out: + return status; +} + +static void intel_vsec_pci_resume(struct pci_dev *pdev) +{ + dev_info(&pdev->dev, "Done resuming PCI device\n"); +} + +static const struct pci_error_handlers intel_vsec_pci_err_handlers = { + .error_detected = intel_vsec_pci_error_detected, + .slot_reset = intel_vsec_pci_slot_reset, + .resume = intel_vsec_pci_resume, +}; + static struct pci_driver intel_vsec_pci_driver = { .name = "intel_vsec", .id_table = intel_vsec_pci_ids, .probe = intel_vsec_pci_probe, + .err_handler = &intel_vsec_pci_err_handlers, }; module_pci_driver(intel_vsec_pci_driver); |