drivers/pci/pcie/edr.c

Source file repositories/reference/linux-study-clean/drivers/pci/pcie/edr.c

File Facts

System
Linux kernel
Corpus path
drivers/pci/pcie/edr.c
Extension
.c
Size
6577 bytes
Lines
256
Domain
Representative Device Path
Bucket
PCIe NVMe Storage Path
Inferred role
Representative Device Path: implementation source
Status
source implementation candidate

Why This File Exists

Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * PCI Error Disconnect Recover support
 * Author: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
 *
 * Copyright (C) 2020 Intel Corp.
 */

#define dev_fmt(fmt) "EDR: " fmt

#include <linux/pci.h>
#include <linux/pci-acpi.h>

#include "portdrv.h"
#include "../pci.h"

#define EDR_PORT_DPC_ENABLE_DSM		0x0C
#define EDR_PORT_LOCATE_DSM		0x0D
#define EDR_OST_SUCCESS			0x80
#define EDR_OST_FAILED			0x81

/*
 * _DSM wrapper function to enable/disable DPC
 * @pdev   : PCI device structure
 *
 * returns 0 on success or errno on failure.
 */
static int acpi_enable_dpc(struct pci_dev *pdev)
{
	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
	union acpi_object *obj, argv4, req;
	int status = 0;

	/*
	 * Per PCI Firmware r3.3, sec 4.6.12, EDR_PORT_DPC_ENABLE_DSM is
	 * optional. Return success if it's not implemented.
	 */
	if (!acpi_check_dsm(adev->handle, &pci_acpi_dsm_guid, 6,
			    1ULL << EDR_PORT_DPC_ENABLE_DSM))
		return 0;

	req.type = ACPI_TYPE_INTEGER;
	req.integer.value = 1;

	argv4.type = ACPI_TYPE_PACKAGE;
	argv4.package.count = 1;
	argv4.package.elements = &req;

	obj = acpi_evaluate_dsm(adev->handle, &pci_acpi_dsm_guid, 6,
				EDR_PORT_DPC_ENABLE_DSM, &argv4);
	if (!obj)
		return 0;

	if (obj->type != ACPI_TYPE_INTEGER) {
		pci_err(pdev, FW_BUG "Enable DPC _DSM returned non integer\n");
		status = -EIO;
	}

	if (obj->integer.value != 1) {
		pci_err(pdev, "Enable DPC _DSM failed to enable DPC\n");
		status = -EIO;
	}

	ACPI_FREE(obj);

	return status;
}

/*
 * _DSM wrapper function to locate DPC port
 * @pdev   : Device which received EDR event
 *
 * Returns pci_dev or NULL.  Caller is responsible for dropping a reference
 * on the returned pci_dev with pci_dev_put().
 */
static struct pci_dev *acpi_dpc_port_get(struct pci_dev *pdev)
{
	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
	union acpi_object *obj;
	u16 port;

	/*
	 * If EDR_PORT_LOCATE_DSM is not implemented under the target of
	 * EDR, the target is the port that experienced the containment
	 * event (PCI Firmware r3.3, sec 4.6.13).
	 */
	if (!acpi_check_dsm(adev->handle, &pci_acpi_dsm_guid, 5,
			    1ULL << EDR_PORT_LOCATE_DSM))
		return pci_dev_get(pdev);

Annotation

Implementation Notes