18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCI Backend Common Data Structures & Function Declarations
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#ifndef __XEN_PCIBACK_H__
88c2ecf20Sopenharmony_ci#define __XEN_PCIBACK_H__
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/pci.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <xen/xenbus.h>
138c2ecf20Sopenharmony_ci#include <linux/list.h>
148c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
158c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
168c2ecf20Sopenharmony_ci#include <linux/atomic.h>
178c2ecf20Sopenharmony_ci#include <xen/events.h>
188c2ecf20Sopenharmony_ci#include <xen/interface/io/pciif.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define DRV_NAME	"xen-pciback"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistruct pci_dev_entry {
238c2ecf20Sopenharmony_ci	struct list_head list;
248c2ecf20Sopenharmony_ci	struct pci_dev *dev;
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define _PDEVF_op_active	(0)
288c2ecf20Sopenharmony_ci#define PDEVF_op_active		(1<<(_PDEVF_op_active))
298c2ecf20Sopenharmony_ci#define _PCIB_op_pending	(1)
308c2ecf20Sopenharmony_ci#define PCIB_op_pending		(1<<(_PCIB_op_pending))
318c2ecf20Sopenharmony_ci#define _EOI_pending		(2)
328c2ecf20Sopenharmony_ci#define EOI_pending		(1<<(_EOI_pending))
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct xen_pcibk_device {
358c2ecf20Sopenharmony_ci	void *pci_dev_data;
368c2ecf20Sopenharmony_ci	struct mutex dev_lock;
378c2ecf20Sopenharmony_ci	struct xenbus_device *xdev;
388c2ecf20Sopenharmony_ci	struct xenbus_watch be_watch;
398c2ecf20Sopenharmony_ci	u8 be_watching;
408c2ecf20Sopenharmony_ci	int evtchn_irq;
418c2ecf20Sopenharmony_ci	struct xen_pci_sharedinfo *sh_info;
428c2ecf20Sopenharmony_ci	unsigned long flags;
438c2ecf20Sopenharmony_ci	struct work_struct op_work;
448c2ecf20Sopenharmony_ci	struct xen_pci_op op;
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistruct xen_pcibk_dev_data {
488c2ecf20Sopenharmony_ci	struct list_head config_fields;
498c2ecf20Sopenharmony_ci	struct pci_saved_state *pci_saved_state;
508c2ecf20Sopenharmony_ci	unsigned int permissive:1;
518c2ecf20Sopenharmony_ci	unsigned int allow_interrupt_control:1;
528c2ecf20Sopenharmony_ci	unsigned int warned_on_write:1;
538c2ecf20Sopenharmony_ci	unsigned int enable_intx:1;
548c2ecf20Sopenharmony_ci	unsigned int isr_on:1; /* Whether the IRQ handler is installed. */
558c2ecf20Sopenharmony_ci	unsigned int ack_intr:1; /* .. and ACK-ing */
568c2ecf20Sopenharmony_ci	unsigned long handled;
578c2ecf20Sopenharmony_ci	unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
588c2ecf20Sopenharmony_ci	char irq_name[]; /* xen-pcibk[000:04:00.0] */
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* Used by XenBus and xen_pcibk_ops.c */
628c2ecf20Sopenharmony_ciextern wait_queue_head_t xen_pcibk_aer_wait_queue;
638c2ecf20Sopenharmony_ci/* Used by pcistub.c and conf_space_quirks.c */
648c2ecf20Sopenharmony_ciextern struct list_head xen_pcibk_quirks;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
678c2ecf20Sopenharmony_cistruct pci_dev *pcistub_get_pci_dev_by_slot(struct xen_pcibk_device *pdev,
688c2ecf20Sopenharmony_ci					    int domain, int bus,
698c2ecf20Sopenharmony_ci					    int slot, int func);
708c2ecf20Sopenharmony_cistruct pci_dev *pcistub_get_pci_dev(struct xen_pcibk_device *pdev,
718c2ecf20Sopenharmony_ci				    struct pci_dev *dev);
728c2ecf20Sopenharmony_civoid pcistub_put_pci_dev(struct pci_dev *dev);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/* Ensure a device is turned off or reset */
758c2ecf20Sopenharmony_civoid xen_pcibk_reset_device(struct pci_dev *pdev);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/* Access a virtual configuration space for a PCI device */
788c2ecf20Sopenharmony_ciint xen_pcibk_config_init(void);
798c2ecf20Sopenharmony_ciint xen_pcibk_config_init_dev(struct pci_dev *dev);
808c2ecf20Sopenharmony_civoid xen_pcibk_config_free_dyn_fields(struct pci_dev *dev);
818c2ecf20Sopenharmony_civoid xen_pcibk_config_reset_dev(struct pci_dev *dev);
828c2ecf20Sopenharmony_civoid xen_pcibk_config_free_dev(struct pci_dev *dev);
838c2ecf20Sopenharmony_ciint xen_pcibk_config_read(struct pci_dev *dev, int offset, int size,
848c2ecf20Sopenharmony_ci			  u32 *ret_val);
858c2ecf20Sopenharmony_ciint xen_pcibk_config_write(struct pci_dev *dev, int offset, int size,
868c2ecf20Sopenharmony_ci			   u32 value);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/* Handle requests for specific devices from the frontend */
898c2ecf20Sopenharmony_citypedef int (*publish_pci_dev_cb) (struct xen_pcibk_device *pdev,
908c2ecf20Sopenharmony_ci				   unsigned int domain, unsigned int bus,
918c2ecf20Sopenharmony_ci				   unsigned int devfn, unsigned int devid);
928c2ecf20Sopenharmony_citypedef int (*publish_pci_root_cb) (struct xen_pcibk_device *pdev,
938c2ecf20Sopenharmony_ci				    unsigned int domain, unsigned int bus);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/* Backend registration for the two types of BDF representation:
968c2ecf20Sopenharmony_ci *  vpci - BDFs start at 00
978c2ecf20Sopenharmony_ci *  passthrough - BDFs are exactly like in the host.
988c2ecf20Sopenharmony_ci */
998c2ecf20Sopenharmony_cistruct xen_pcibk_backend {
1008c2ecf20Sopenharmony_ci	const char *name;
1018c2ecf20Sopenharmony_ci	int (*init)(struct xen_pcibk_device *pdev);
1028c2ecf20Sopenharmony_ci	void (*free)(struct xen_pcibk_device *pdev);
1038c2ecf20Sopenharmony_ci	int (*find)(struct pci_dev *pcidev, struct xen_pcibk_device *pdev,
1048c2ecf20Sopenharmony_ci		    unsigned int *domain, unsigned int *bus,
1058c2ecf20Sopenharmony_ci		    unsigned int *devfn);
1068c2ecf20Sopenharmony_ci	int (*publish)(struct xen_pcibk_device *pdev, publish_pci_root_cb cb);
1078c2ecf20Sopenharmony_ci	void (*release)(struct xen_pcibk_device *pdev, struct pci_dev *dev,
1088c2ecf20Sopenharmony_ci                        bool lock);
1098c2ecf20Sopenharmony_ci	int (*add)(struct xen_pcibk_device *pdev, struct pci_dev *dev,
1108c2ecf20Sopenharmony_ci		   int devid, publish_pci_dev_cb publish_cb);
1118c2ecf20Sopenharmony_ci	struct pci_dev *(*get)(struct xen_pcibk_device *pdev,
1128c2ecf20Sopenharmony_ci			       unsigned int domain, unsigned int bus,
1138c2ecf20Sopenharmony_ci			       unsigned int devfn);
1148c2ecf20Sopenharmony_ci};
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ciextern const struct xen_pcibk_backend xen_pcibk_vpci_backend;
1178c2ecf20Sopenharmony_ciextern const struct xen_pcibk_backend xen_pcibk_passthrough_backend;
1188c2ecf20Sopenharmony_ciextern const struct xen_pcibk_backend *xen_pcibk_backend;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic inline int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
1218c2ecf20Sopenharmony_ci					struct pci_dev *dev,
1228c2ecf20Sopenharmony_ci					int devid,
1238c2ecf20Sopenharmony_ci					publish_pci_dev_cb publish_cb)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->add)
1268c2ecf20Sopenharmony_ci		return xen_pcibk_backend->add(pdev, dev, devid, publish_cb);
1278c2ecf20Sopenharmony_ci	return -1;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
1318c2ecf20Sopenharmony_ci					     struct pci_dev *dev, bool lock)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->release)
1348c2ecf20Sopenharmony_ci		return xen_pcibk_backend->release(pdev, dev, lock);
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic inline struct pci_dev *
1388c2ecf20Sopenharmony_cixen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, unsigned int domain,
1398c2ecf20Sopenharmony_ci		      unsigned int bus, unsigned int devfn)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->get)
1428c2ecf20Sopenharmony_ci		return xen_pcibk_backend->get(pdev, domain, bus, devfn);
1438c2ecf20Sopenharmony_ci	return NULL;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci/**
1478c2ecf20Sopenharmony_ci* Add for domain0 PCIE-AER handling. Get guest domain/bus/devfn in xen_pcibk
1488c2ecf20Sopenharmony_ci* before sending aer request to pcifront, so that guest could identify
1498c2ecf20Sopenharmony_ci* device, coopearte with xen_pcibk to finish aer recovery job if device driver
1508c2ecf20Sopenharmony_ci* has the capability
1518c2ecf20Sopenharmony_ci*/
1528c2ecf20Sopenharmony_cistatic inline int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
1538c2ecf20Sopenharmony_ci					     struct xen_pcibk_device *pdev,
1548c2ecf20Sopenharmony_ci					     unsigned int *domain,
1558c2ecf20Sopenharmony_ci					     unsigned int *bus,
1568c2ecf20Sopenharmony_ci					     unsigned int *devfn)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->find)
1598c2ecf20Sopenharmony_ci		return xen_pcibk_backend->find(pcidev, pdev, domain, bus,
1608c2ecf20Sopenharmony_ci					       devfn);
1618c2ecf20Sopenharmony_ci	return -1;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic inline int xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->init)
1678c2ecf20Sopenharmony_ci		return xen_pcibk_backend->init(pdev);
1688c2ecf20Sopenharmony_ci	return -1;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic inline int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
1728c2ecf20Sopenharmony_ci					      publish_pci_root_cb cb)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->publish)
1758c2ecf20Sopenharmony_ci		return xen_pcibk_backend->publish(pdev, cb);
1768c2ecf20Sopenharmony_ci	return -1;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic inline void xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->free)
1828c2ecf20Sopenharmony_ci		return xen_pcibk_backend->free(pdev);
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci/* Handles events from front-end */
1868c2ecf20Sopenharmony_ciirqreturn_t xen_pcibk_handle_event(int irq, void *dev_id);
1878c2ecf20Sopenharmony_civoid xen_pcibk_do_op(struct work_struct *data);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic inline void xen_pcibk_lateeoi(struct xen_pcibk_device *pdev,
1908c2ecf20Sopenharmony_ci				     unsigned int eoi_flag)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	if (test_and_clear_bit(_EOI_pending, &pdev->flags))
1938c2ecf20Sopenharmony_ci		xen_irq_lateeoi(pdev->evtchn_irq, eoi_flag);
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ciint xen_pcibk_xenbus_register(void);
1978c2ecf20Sopenharmony_civoid xen_pcibk_xenbus_unregister(void);
1988c2ecf20Sopenharmony_ci#endif
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci/* Handles shared IRQs that can to device domain and control domain. */
2018c2ecf20Sopenharmony_civoid xen_pcibk_irq_handler(struct pci_dev *dev, int reset);
202