162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCI Backend Common Data Structures & Function Declarations
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#ifndef __XEN_PCIBACK_H__
862306a36Sopenharmony_ci#define __XEN_PCIBACK_H__
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/pci.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <xen/xenbus.h>
1362306a36Sopenharmony_ci#include <linux/list.h>
1462306a36Sopenharmony_ci#include <linux/spinlock.h>
1562306a36Sopenharmony_ci#include <linux/workqueue.h>
1662306a36Sopenharmony_ci#include <linux/atomic.h>
1762306a36Sopenharmony_ci#include <xen/events.h>
1862306a36Sopenharmony_ci#include <xen/interface/io/pciif.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define DRV_NAME	"xen-pciback"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct pci_dev_entry {
2362306a36Sopenharmony_ci	struct list_head list;
2462306a36Sopenharmony_ci	struct pci_dev *dev;
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define _PDEVF_op_active	(0)
2862306a36Sopenharmony_ci#define PDEVF_op_active		(1<<(_PDEVF_op_active))
2962306a36Sopenharmony_ci#define _PCIB_op_pending	(1)
3062306a36Sopenharmony_ci#define PCIB_op_pending		(1<<(_PCIB_op_pending))
3162306a36Sopenharmony_ci#define _EOI_pending		(2)
3262306a36Sopenharmony_ci#define EOI_pending		(1<<(_EOI_pending))
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistruct xen_pcibk_device {
3562306a36Sopenharmony_ci	void *pci_dev_data;
3662306a36Sopenharmony_ci	struct mutex dev_lock;
3762306a36Sopenharmony_ci	struct xenbus_device *xdev;
3862306a36Sopenharmony_ci	struct xenbus_watch be_watch;
3962306a36Sopenharmony_ci	u8 be_watching;
4062306a36Sopenharmony_ci	int evtchn_irq;
4162306a36Sopenharmony_ci	struct xen_pci_sharedinfo *sh_info;
4262306a36Sopenharmony_ci	unsigned long flags;
4362306a36Sopenharmony_ci	struct work_struct op_work;
4462306a36Sopenharmony_ci	struct xen_pci_op op;
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistruct xen_pcibk_dev_data {
4862306a36Sopenharmony_ci	struct list_head config_fields;
4962306a36Sopenharmony_ci	struct pci_saved_state *pci_saved_state;
5062306a36Sopenharmony_ci	unsigned int permissive:1;
5162306a36Sopenharmony_ci	unsigned int allow_interrupt_control:1;
5262306a36Sopenharmony_ci	unsigned int warned_on_write:1;
5362306a36Sopenharmony_ci	unsigned int enable_intx:1;
5462306a36Sopenharmony_ci	unsigned int isr_on:1; /* Whether the IRQ handler is installed. */
5562306a36Sopenharmony_ci	unsigned int ack_intr:1; /* .. and ACK-ing */
5662306a36Sopenharmony_ci	unsigned long handled;
5762306a36Sopenharmony_ci	unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
5862306a36Sopenharmony_ci	char irq_name[]; /* xen-pcibk[000:04:00.0] */
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* Used by XenBus and xen_pcibk_ops.c */
6262306a36Sopenharmony_ciextern wait_queue_head_t xen_pcibk_aer_wait_queue;
6362306a36Sopenharmony_ci/* Used by pcistub.c and conf_space_quirks.c */
6462306a36Sopenharmony_ciextern struct list_head xen_pcibk_quirks;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
6762306a36Sopenharmony_cistruct pci_dev *pcistub_get_pci_dev_by_slot(struct xen_pcibk_device *pdev,
6862306a36Sopenharmony_ci					    int domain, int bus,
6962306a36Sopenharmony_ci					    int slot, int func);
7062306a36Sopenharmony_cistruct pci_dev *pcistub_get_pci_dev(struct xen_pcibk_device *pdev,
7162306a36Sopenharmony_ci				    struct pci_dev *dev);
7262306a36Sopenharmony_civoid pcistub_put_pci_dev(struct pci_dev *dev);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic inline bool xen_pcibk_pv_support(void)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	return IS_ENABLED(CONFIG_XEN_PCIDEV_BACKEND);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Ensure a device is turned off or reset */
8062306a36Sopenharmony_civoid xen_pcibk_reset_device(struct pci_dev *pdev);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* Access a virtual configuration space for a PCI device */
8362306a36Sopenharmony_ciint xen_pcibk_config_init(void);
8462306a36Sopenharmony_ciint xen_pcibk_config_init_dev(struct pci_dev *dev);
8562306a36Sopenharmony_civoid xen_pcibk_config_free_dyn_fields(struct pci_dev *dev);
8662306a36Sopenharmony_civoid xen_pcibk_config_reset_dev(struct pci_dev *dev);
8762306a36Sopenharmony_civoid xen_pcibk_config_free_dev(struct pci_dev *dev);
8862306a36Sopenharmony_ciint xen_pcibk_config_read(struct pci_dev *dev, int offset, int size,
8962306a36Sopenharmony_ci			  u32 *ret_val);
9062306a36Sopenharmony_ciint xen_pcibk_config_write(struct pci_dev *dev, int offset, int size,
9162306a36Sopenharmony_ci			   u32 value);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/* Handle requests for specific devices from the frontend */
9462306a36Sopenharmony_citypedef int (*publish_pci_dev_cb) (struct xen_pcibk_device *pdev,
9562306a36Sopenharmony_ci				   unsigned int domain, unsigned int bus,
9662306a36Sopenharmony_ci				   unsigned int devfn, unsigned int devid);
9762306a36Sopenharmony_citypedef int (*publish_pci_root_cb) (struct xen_pcibk_device *pdev,
9862306a36Sopenharmony_ci				    unsigned int domain, unsigned int bus);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* Backend registration for the two types of BDF representation:
10162306a36Sopenharmony_ci *  vpci - BDFs start at 00
10262306a36Sopenharmony_ci *  passthrough - BDFs are exactly like in the host.
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_cistruct xen_pcibk_backend {
10562306a36Sopenharmony_ci	const char *name;
10662306a36Sopenharmony_ci	int (*init)(struct xen_pcibk_device *pdev);
10762306a36Sopenharmony_ci	void (*free)(struct xen_pcibk_device *pdev);
10862306a36Sopenharmony_ci	int (*find)(struct pci_dev *pcidev, struct xen_pcibk_device *pdev,
10962306a36Sopenharmony_ci		    unsigned int *domain, unsigned int *bus,
11062306a36Sopenharmony_ci		    unsigned int *devfn);
11162306a36Sopenharmony_ci	int (*publish)(struct xen_pcibk_device *pdev, publish_pci_root_cb cb);
11262306a36Sopenharmony_ci	void (*release)(struct xen_pcibk_device *pdev, struct pci_dev *dev,
11362306a36Sopenharmony_ci                        bool lock);
11462306a36Sopenharmony_ci	int (*add)(struct xen_pcibk_device *pdev, struct pci_dev *dev,
11562306a36Sopenharmony_ci		   int devid, publish_pci_dev_cb publish_cb);
11662306a36Sopenharmony_ci	struct pci_dev *(*get)(struct xen_pcibk_device *pdev,
11762306a36Sopenharmony_ci			       unsigned int domain, unsigned int bus,
11862306a36Sopenharmony_ci			       unsigned int devfn);
11962306a36Sopenharmony_ci};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ciextern const struct xen_pcibk_backend xen_pcibk_vpci_backend;
12262306a36Sopenharmony_ciextern const struct xen_pcibk_backend xen_pcibk_passthrough_backend;
12362306a36Sopenharmony_ciextern const struct xen_pcibk_backend *xen_pcibk_backend;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic inline int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
12662306a36Sopenharmony_ci					struct pci_dev *dev,
12762306a36Sopenharmony_ci					int devid,
12862306a36Sopenharmony_ci					publish_pci_dev_cb publish_cb)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->add)
13162306a36Sopenharmony_ci		return xen_pcibk_backend->add(pdev, dev, devid, publish_cb);
13262306a36Sopenharmony_ci	return -1;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
13662306a36Sopenharmony_ci					     struct pci_dev *dev, bool lock)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->release)
13962306a36Sopenharmony_ci		return xen_pcibk_backend->release(pdev, dev, lock);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic inline struct pci_dev *
14362306a36Sopenharmony_cixen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, unsigned int domain,
14462306a36Sopenharmony_ci		      unsigned int bus, unsigned int devfn)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->get)
14762306a36Sopenharmony_ci		return xen_pcibk_backend->get(pdev, domain, bus, devfn);
14862306a36Sopenharmony_ci	return NULL;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci/**
15262306a36Sopenharmony_ci* Add for domain0 PCIE-AER handling. Get guest domain/bus/devfn in xen_pcibk
15362306a36Sopenharmony_ci* before sending aer request to pcifront, so that guest could identify
15462306a36Sopenharmony_ci* device, coopearte with xen_pcibk to finish aer recovery job if device driver
15562306a36Sopenharmony_ci* has the capability
15662306a36Sopenharmony_ci*/
15762306a36Sopenharmony_cistatic inline int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev,
15862306a36Sopenharmony_ci					     struct xen_pcibk_device *pdev,
15962306a36Sopenharmony_ci					     unsigned int *domain,
16062306a36Sopenharmony_ci					     unsigned int *bus,
16162306a36Sopenharmony_ci					     unsigned int *devfn)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->find)
16462306a36Sopenharmony_ci		return xen_pcibk_backend->find(pcidev, pdev, domain, bus,
16562306a36Sopenharmony_ci					       devfn);
16662306a36Sopenharmony_ci	return -1;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic inline int xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->init)
17262306a36Sopenharmony_ci		return xen_pcibk_backend->init(pdev);
17362306a36Sopenharmony_ci	return -1;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic inline int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev,
17762306a36Sopenharmony_ci					      publish_pci_root_cb cb)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->publish)
18062306a36Sopenharmony_ci		return xen_pcibk_backend->publish(pdev, cb);
18162306a36Sopenharmony_ci	return -1;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic inline void xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	if (xen_pcibk_backend && xen_pcibk_backend->free)
18762306a36Sopenharmony_ci		return xen_pcibk_backend->free(pdev);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/* Handles events from front-end */
19162306a36Sopenharmony_ciirqreturn_t xen_pcibk_handle_event(int irq, void *dev_id);
19262306a36Sopenharmony_civoid xen_pcibk_do_op(struct work_struct *data);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic inline void xen_pcibk_lateeoi(struct xen_pcibk_device *pdev,
19562306a36Sopenharmony_ci				     unsigned int eoi_flag)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	if (test_and_clear_bit(_EOI_pending, &pdev->flags))
19862306a36Sopenharmony_ci		xen_irq_lateeoi(pdev->evtchn_irq, eoi_flag);
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ciint xen_pcibk_xenbus_register(void);
20262306a36Sopenharmony_civoid xen_pcibk_xenbus_unregister(void);
20362306a36Sopenharmony_ci#endif
204