/* SPDX-License-Identifier: GPL-2.0-only */

#ifndef INTEL_COMMON_ACPI_PIRQ_GEN_H
#define INTEL_COMMON_ACPI_PIRQ_GEN_H

#include <assert.h>
#include <device/device.h>

#define MAX_SLOTS	32

enum pci_pin {
	PCI_INT_NONE = 0,
	PCI_INT_A,
	PCI_INT_B,
	PCI_INT_C,
	PCI_INT_D,
	PCI_INT_MAX = PCI_INT_D,
};

enum pirq {
	PIRQ_INVALID,
	PIRQ_A,
	PIRQ_B,
	PIRQ_C,
	PIRQ_D,
	PIRQ_E,
	PIRQ_F,
	PIRQ_G,
	PIRQ_H,
	PIRQ_COUNT = PIRQ_H,
};

static inline size_t pirq_idx(enum pirq pirq)
{
	assert(pirq > PIRQ_INVALID && pirq <= PIRQ_H);
	return (size_t)(pirq - PIRQ_A);
}

/*
 * This struct represents an assignment of slot/pin -> IRQ. Some chipsets may
 * want to provide both PIC-mode and APIC-mode IRQs (e.g. selected using PICM
 * set by the OS), therefore a field for each of a PIRQ for PIC-mode and a
 * GSI for APIC-mode are provided.
 *
 * For APIC mode, only GSIs are supported (`acpi_gsi`).
 *
 * For PIC mode, if the pirq_map_type is PIRQ_GSI, then `pic_pirq` is used as an
 * index into `struct pic_pirq_map.gsi`, or for SOURCE_PATH, `pic_pirq` indexes
 * into `struct pic_pirq_map.source_path` to pick the path to the LNKx device.
 *
 * The reasoning for this structure is related to older vs. newer Intel
 * platforms; older platforms supported routing of PCI IRQs to a PIRQ
 * only. Newer platforms support routing IRQs to either a PIRQ or (for some PCI
 * devices) a non-PIRQ GSI.
 */
struct slot_pin_irq_map {
	unsigned int slot;
	enum pci_pin pin;
	/* PIRQ # for PIC mode */
	unsigned int pic_pirq;
	/* GSI # for APIC mode */
	unsigned int apic_gsi;
};

enum pirq_map_type {
	PIRQ_GSI,
	PIRQ_SOURCE_PATH,
};

/*
 * A PIRQ can be either be statically assigned a GSI or OSPM can use the Methods
 * on the ACPI device (source_path) to assign IRQs at runtime.
 */
struct pic_pirq_map {
	enum pirq_map_type type;
	union {
		unsigned int gsi[PIRQ_COUNT];
		char source_path[PIRQ_COUNT][DEVICE_PATH_MAX];
	};
};

/*
 * Generate an ACPI _PRT table by providing PIRQ and/or GSI information for each
 * slot/pin combination, and optionally providing paths to LNKx devices that can
 * provide IRQs in PIC mode.
 */
void intel_write_pci0_PRT(const struct slot_pin_irq_map *pin_irq_map,
			  unsigned int map_count,
			  const struct pic_pirq_map *pirq_map);

bool is_slot_pin_assigned(const struct slot_pin_irq_map *pin_irq_map,
			  unsigned int map_count, unsigned int slot,
			  enum pci_pin pin);

#endif