linux/drivers/pci/npem.c

// SPDX-License-Identifier: GPL-2.0
/*
 * PCIe Enclosure management driver created for LED interfaces based on
 * indications. It says *what indications* blink but does not specify *how*
 * they blink - it is hardware defined.
 *
 * The driver name refers to Native PCIe Enclosure Management. It is
 * first indication oriented standard with specification.
 *
 * Native PCIe Enclosure Management (NPEM)
 *	PCIe Base Specification r6.1 sec 6.28, 7.9.19
 *
 * _DSM Definitions for PCIe SSD Status LED
 *	 PCI Firmware Specification, r3.3 sec 4.7
 *
 * Two backends are supported to manipulate indications: Direct NPEM register
 * access (npem_ops) and indirect access through the ACPI _DSM (dsm_ops).
 * _DSM is used if supported, else NPEM.
 *
 * Copyright (c) 2021-2022 Dell Inc.
 * Copyright (c) 2023-2024 Intel Corporation
 *	Mariusz Tkaczyk <[email protected]>
 */

#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/iopoll.h>
#include <linux/leds.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/types.h>
#include <linux/uleds.h>

#include "pci.h"

struct indication {};

static const struct indication npem_indications[] =;

/* _DSM PCIe SSD LED States correspond to NPEM register values */
static const struct indication dsm_indications[] =;

#define for_each_indication(ind, inds)

/*
 * The driver has internal list of supported indications. Ideally, the driver
 * should not touch bits that are not defined and for which LED devices are
 * not exposed but in reality, it needs to turn them off.
 *
 * Otherwise, there will be no possibility to turn off indications turned on by
 * other utilities or turned on by default and it leads to bad user experience.
 *
 * Additionally, it excludes NPEM commands like RESET or ENABLE.
 */
static u32 reg_to_indications(u32 caps, const struct indication *inds)
{}

/**
 * struct npem_led - LED details
 * @indication: indication details
 * @npem: NPEM device
 * @name: LED name
 * @led: LED device
 */
struct npem_led {};

/**
 * struct npem_ops - backend specific callbacks
 * @get_active_indications: get active indications
 *	npem: NPEM device
 *	inds: response buffer
 * @set_active_indications: set new indications
 *	npem: npem device
 *	inds: bit mask to set
 * @inds: supported indications array, set of indications is backend specific
 * @name: backend name
 */
struct npem_ops {};

/**
 * struct npem - NPEM device properties
 * @dev: PCI device this driver is attached to
 * @ops: backend specific callbacks
 * @lock: serializes concurrent access to NPEM device by multiple LED devices
 * @pos: cached offset of NPEM Capability Register in Configuration Space;
 *	only used if NPEM registers are accessed directly and not through _DSM
 * @supported_indications: cached bit mask of supported indications;
 *	non-indication and reserved bits in the NPEM Capability Register are
 *	cleared in this bit mask
 * @active_indications: cached bit mask of active indications;
 *	non-indication and reserved bits in the NPEM Control Register are
 *	cleared in this bit mask
 * @active_inds_initialized: whether @active_indications has been initialized;
 *	On Dell platforms, it is required that IPMI drivers are loaded before
 *	the GET_STATE_DSM method is invoked: They use an IPMI OpRegion to
 *	get/set the active LEDs. By initializing @active_indications lazily
 *	(on first access to an LED), IPMI drivers are given a chance to load.
 *	If they are not loaded in time, users will see various errors on LED
 *	access in dmesg. Once they are loaded, the errors go away and LED
 *	access becomes possible.
 * @led_cnt: size of @leds array
 * @leds: array containing LED class devices of all supported LEDs
 */
struct npem {};

static int npem_read_reg(struct npem *npem, u16 reg, u32 *val)
{}

static int npem_write_ctrl(struct npem *npem, u32 reg)
{}

static int npem_get_active_indications(struct npem *npem, u32 *inds)
{}

static int npem_set_active_indications(struct npem *npem, u32 inds)
{}

static const struct npem_ops npem_ops =;

#define DSM_GUID
#define GET_SUPPORTED_STATES_DSM
#define GET_STATE_DSM
#define SET_STATE_DSM

static const guid_t dsm_guid =;

static bool npem_has_dsm(struct pci_dev *pdev)
{}

struct dsm_output {};

/**
 * dsm_evaluate() - send DSM PCIe SSD Status LED command
 * @pdev: PCI device
 * @dsm_func: DSM LED Function
 * @output: buffer to copy DSM Response
 * @value_to_set: value for SET_STATE_DSM function
 *
 * To not bother caller with ACPI context, the returned _DSM Output Buffer is
 * copied.
 */
static int dsm_evaluate(struct pci_dev *pdev, u64 dsm_func,
			struct dsm_output *output, u32 value_to_set)
{}

static int dsm_get(struct pci_dev *pdev, u64 dsm_func, u32 *buf)
{}

static int dsm_get_active_indications(struct npem *npem, u32 *buf)
{}

static int dsm_set_active_indications(struct npem *npem, u32 value)
{}

static const struct npem_ops dsm_ops =;

static int npem_initialize_active_indications(struct npem *npem)
{}

/*
 * The status of each indicator is cached on first brightness_ get/set time
 * and updated at write time.  brightness_get() is only responsible for
 * reflecting the last written/cached value.
 */
static enum led_brightness brightness_get(struct led_classdev *led)
{}

static int brightness_set(struct led_classdev *led,
			  enum led_brightness brightness)
{}

static void npem_free(struct npem *npem)
{}

static int pci_npem_set_led_classdev(struct npem *npem, struct npem_led *nled)
{}

static int pci_npem_init(struct pci_dev *dev, const struct npem_ops *ops,
			 int pos, u32 caps)
{}

void pci_npem_remove(struct pci_dev *dev)
{}

void pci_npem_create(struct pci_dev *dev)
{}