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