18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCI Backend - Common data structures for overriding the configuration space 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef __XEN_PCIBACK_CONF_SPACE_H__ 98c2ecf20Sopenharmony_ci#define __XEN_PCIBACK_CONF_SPACE_H__ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/list.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* conf_field_init can return an errno in a ptr with ERR_PTR() */ 158c2ecf20Sopenharmony_citypedef void *(*conf_field_init) (struct pci_dev *dev, int offset); 168c2ecf20Sopenharmony_citypedef void (*conf_field_reset) (struct pci_dev *dev, int offset, void *data); 178c2ecf20Sopenharmony_citypedef void (*conf_field_free) (struct pci_dev *dev, int offset, void *data); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_citypedef int (*conf_dword_write) (struct pci_dev *dev, int offset, u32 value, 208c2ecf20Sopenharmony_ci void *data); 218c2ecf20Sopenharmony_citypedef int (*conf_word_write) (struct pci_dev *dev, int offset, u16 value, 228c2ecf20Sopenharmony_ci void *data); 238c2ecf20Sopenharmony_citypedef int (*conf_byte_write) (struct pci_dev *dev, int offset, u8 value, 248c2ecf20Sopenharmony_ci void *data); 258c2ecf20Sopenharmony_citypedef int (*conf_dword_read) (struct pci_dev *dev, int offset, u32 *value, 268c2ecf20Sopenharmony_ci void *data); 278c2ecf20Sopenharmony_citypedef int (*conf_word_read) (struct pci_dev *dev, int offset, u16 *value, 288c2ecf20Sopenharmony_ci void *data); 298c2ecf20Sopenharmony_citypedef int (*conf_byte_read) (struct pci_dev *dev, int offset, u8 *value, 308c2ecf20Sopenharmony_ci void *data); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* These are the fields within the configuration space which we 338c2ecf20Sopenharmony_ci * are interested in intercepting reads/writes to and changing their 348c2ecf20Sopenharmony_ci * values. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistruct config_field { 378c2ecf20Sopenharmony_ci unsigned int offset; 388c2ecf20Sopenharmony_ci unsigned int size; 398c2ecf20Sopenharmony_ci unsigned int mask; 408c2ecf20Sopenharmony_ci conf_field_init init; 418c2ecf20Sopenharmony_ci conf_field_reset reset; 428c2ecf20Sopenharmony_ci conf_field_free release; 438c2ecf20Sopenharmony_ci void (*clean) (struct config_field *field); 448c2ecf20Sopenharmony_ci union { 458c2ecf20Sopenharmony_ci struct { 468c2ecf20Sopenharmony_ci conf_dword_write write; 478c2ecf20Sopenharmony_ci conf_dword_read read; 488c2ecf20Sopenharmony_ci } dw; 498c2ecf20Sopenharmony_ci struct { 508c2ecf20Sopenharmony_ci conf_word_write write; 518c2ecf20Sopenharmony_ci conf_word_read read; 528c2ecf20Sopenharmony_ci } w; 538c2ecf20Sopenharmony_ci struct { 548c2ecf20Sopenharmony_ci conf_byte_write write; 558c2ecf20Sopenharmony_ci conf_byte_read read; 568c2ecf20Sopenharmony_ci } b; 578c2ecf20Sopenharmony_ci } u; 588c2ecf20Sopenharmony_ci struct list_head list; 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct config_field_entry { 628c2ecf20Sopenharmony_ci struct list_head list; 638c2ecf20Sopenharmony_ci const struct config_field *field; 648c2ecf20Sopenharmony_ci unsigned int base_offset; 658c2ecf20Sopenharmony_ci void *data; 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define INTERRUPT_TYPE_NONE (0) 698c2ecf20Sopenharmony_ci#define INTERRUPT_TYPE_INTX (1<<0) 708c2ecf20Sopenharmony_ci#define INTERRUPT_TYPE_MSI (1<<1) 718c2ecf20Sopenharmony_ci#define INTERRUPT_TYPE_MSIX (1<<2) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciextern bool xen_pcibk_permissive; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Add fields to a device - the add_fields macro expects to get a pointer to 788c2ecf20Sopenharmony_ci * the first entry in an array (of which the ending is marked by size==0) 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ciint xen_pcibk_config_add_field_offset(struct pci_dev *dev, 818c2ecf20Sopenharmony_ci const struct config_field *field, 828c2ecf20Sopenharmony_ci unsigned int offset); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic inline int xen_pcibk_config_add_field(struct pci_dev *dev, 858c2ecf20Sopenharmony_ci const struct config_field *field) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci return xen_pcibk_config_add_field_offset(dev, field, 0); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic inline int xen_pcibk_config_add_fields(struct pci_dev *dev, 918c2ecf20Sopenharmony_ci const struct config_field *field) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci int i, err = 0; 948c2ecf20Sopenharmony_ci for (i = 0; field[i].size != 0; i++) { 958c2ecf20Sopenharmony_ci err = xen_pcibk_config_add_field(dev, &field[i]); 968c2ecf20Sopenharmony_ci if (err) 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci return err; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic inline int xen_pcibk_config_add_fields_offset(struct pci_dev *dev, 1038c2ecf20Sopenharmony_ci const struct config_field *field, 1048c2ecf20Sopenharmony_ci unsigned int offset) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci int i, err = 0; 1078c2ecf20Sopenharmony_ci for (i = 0; field[i].size != 0; i++) { 1088c2ecf20Sopenharmony_ci err = xen_pcibk_config_add_field_offset(dev, &field[i], offset); 1098c2ecf20Sopenharmony_ci if (err) 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci return err; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* Read/Write the real configuration space */ 1168c2ecf20Sopenharmony_ciint xen_pcibk_read_config_byte(struct pci_dev *dev, int offset, u8 *value, 1178c2ecf20Sopenharmony_ci void *data); 1188c2ecf20Sopenharmony_ciint xen_pcibk_read_config_word(struct pci_dev *dev, int offset, u16 *value, 1198c2ecf20Sopenharmony_ci void *data); 1208c2ecf20Sopenharmony_ciint xen_pcibk_read_config_dword(struct pci_dev *dev, int offset, u32 *value, 1218c2ecf20Sopenharmony_ci void *data); 1228c2ecf20Sopenharmony_ciint xen_pcibk_write_config_byte(struct pci_dev *dev, int offset, u8 value, 1238c2ecf20Sopenharmony_ci void *data); 1248c2ecf20Sopenharmony_ciint xen_pcibk_write_config_word(struct pci_dev *dev, int offset, u16 value, 1258c2ecf20Sopenharmony_ci void *data); 1268c2ecf20Sopenharmony_ciint xen_pcibk_write_config_dword(struct pci_dev *dev, int offset, u32 value, 1278c2ecf20Sopenharmony_ci void *data); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ciint xen_pcibk_config_capability_init(void); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ciint xen_pcibk_config_header_add_fields(struct pci_dev *dev); 1328c2ecf20Sopenharmony_ciint xen_pcibk_config_capability_add_fields(struct pci_dev *dev); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ciint xen_pcibk_get_interrupt_type(struct pci_dev *dev); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#endif /* __XEN_PCIBACK_CONF_SPACE_H__ */ 137