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