162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCI Backend - Common data structures for overriding the configuration space
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifndef __XEN_PCIBACK_CONF_SPACE_H__
962306a36Sopenharmony_ci#define __XEN_PCIBACK_CONF_SPACE_H__
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/list.h>
1262306a36Sopenharmony_ci#include <linux/err.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* conf_field_init can return an errno in a ptr with ERR_PTR() */
1562306a36Sopenharmony_citypedef void *(*conf_field_init) (struct pci_dev *dev, int offset);
1662306a36Sopenharmony_citypedef void (*conf_field_reset) (struct pci_dev *dev, int offset, void *data);
1762306a36Sopenharmony_citypedef void (*conf_field_free) (struct pci_dev *dev, int offset, void *data);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_citypedef int (*conf_dword_write) (struct pci_dev *dev, int offset, u32 value,
2062306a36Sopenharmony_ci				 void *data);
2162306a36Sopenharmony_citypedef int (*conf_word_write) (struct pci_dev *dev, int offset, u16 value,
2262306a36Sopenharmony_ci				void *data);
2362306a36Sopenharmony_citypedef int (*conf_byte_write) (struct pci_dev *dev, int offset, u8 value,
2462306a36Sopenharmony_ci				void *data);
2562306a36Sopenharmony_citypedef int (*conf_dword_read) (struct pci_dev *dev, int offset, u32 *value,
2662306a36Sopenharmony_ci				void *data);
2762306a36Sopenharmony_citypedef int (*conf_word_read) (struct pci_dev *dev, int offset, u16 *value,
2862306a36Sopenharmony_ci			       void *data);
2962306a36Sopenharmony_citypedef int (*conf_byte_read) (struct pci_dev *dev, int offset, u8 *value,
3062306a36Sopenharmony_ci			       void *data);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* These are the fields within the configuration space which we
3362306a36Sopenharmony_ci * are interested in intercepting reads/writes to and changing their
3462306a36Sopenharmony_ci * values.
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_cistruct config_field {
3762306a36Sopenharmony_ci	unsigned int offset;
3862306a36Sopenharmony_ci	unsigned int size;
3962306a36Sopenharmony_ci	unsigned int mask;
4062306a36Sopenharmony_ci	conf_field_init init;
4162306a36Sopenharmony_ci	conf_field_reset reset;
4262306a36Sopenharmony_ci	conf_field_free release;
4362306a36Sopenharmony_ci	void (*clean) (struct config_field *field);
4462306a36Sopenharmony_ci	union {
4562306a36Sopenharmony_ci		struct {
4662306a36Sopenharmony_ci			conf_dword_write write;
4762306a36Sopenharmony_ci			conf_dword_read read;
4862306a36Sopenharmony_ci		} dw;
4962306a36Sopenharmony_ci		struct {
5062306a36Sopenharmony_ci			conf_word_write write;
5162306a36Sopenharmony_ci			conf_word_read read;
5262306a36Sopenharmony_ci		} w;
5362306a36Sopenharmony_ci		struct {
5462306a36Sopenharmony_ci			conf_byte_write write;
5562306a36Sopenharmony_ci			conf_byte_read read;
5662306a36Sopenharmony_ci		} b;
5762306a36Sopenharmony_ci	} u;
5862306a36Sopenharmony_ci	struct list_head list;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct config_field_entry {
6262306a36Sopenharmony_ci	struct list_head list;
6362306a36Sopenharmony_ci	const struct config_field *field;
6462306a36Sopenharmony_ci	unsigned int base_offset;
6562306a36Sopenharmony_ci	void *data;
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define INTERRUPT_TYPE_NONE (0)
6962306a36Sopenharmony_ci#define INTERRUPT_TYPE_INTX (1<<0)
7062306a36Sopenharmony_ci#define INTERRUPT_TYPE_MSI  (1<<1)
7162306a36Sopenharmony_ci#define INTERRUPT_TYPE_MSIX (1<<2)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciextern bool xen_pcibk_permissive;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* Add fields to a device - the add_fields macro expects to get a pointer to
7862306a36Sopenharmony_ci * the first entry in an array (of which the ending is marked by size==0)
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_ciint xen_pcibk_config_add_field_offset(struct pci_dev *dev,
8162306a36Sopenharmony_ci				    const struct config_field *field,
8262306a36Sopenharmony_ci				    unsigned int offset);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic inline int xen_pcibk_config_add_field(struct pci_dev *dev,
8562306a36Sopenharmony_ci					   const struct config_field *field)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	return xen_pcibk_config_add_field_offset(dev, field, 0);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic inline int xen_pcibk_config_add_fields(struct pci_dev *dev,
9162306a36Sopenharmony_ci					    const struct config_field *field)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	int i, err = 0;
9462306a36Sopenharmony_ci	for (i = 0; field[i].size != 0; i++) {
9562306a36Sopenharmony_ci		err = xen_pcibk_config_add_field(dev, &field[i]);
9662306a36Sopenharmony_ci		if (err)
9762306a36Sopenharmony_ci			break;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci	return err;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic inline int xen_pcibk_config_add_fields_offset(struct pci_dev *dev,
10362306a36Sopenharmony_ci					const struct config_field *field,
10462306a36Sopenharmony_ci					unsigned int offset)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	int i, err = 0;
10762306a36Sopenharmony_ci	for (i = 0; field[i].size != 0; i++) {
10862306a36Sopenharmony_ci		err = xen_pcibk_config_add_field_offset(dev, &field[i], offset);
10962306a36Sopenharmony_ci		if (err)
11062306a36Sopenharmony_ci			break;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	return err;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* Read/Write the real configuration space */
11662306a36Sopenharmony_ciint xen_pcibk_read_config_byte(struct pci_dev *dev, int offset, u8 *value,
11762306a36Sopenharmony_ci			       void *data);
11862306a36Sopenharmony_ciint xen_pcibk_read_config_word(struct pci_dev *dev, int offset, u16 *value,
11962306a36Sopenharmony_ci			       void *data);
12062306a36Sopenharmony_ciint xen_pcibk_read_config_dword(struct pci_dev *dev, int offset, u32 *value,
12162306a36Sopenharmony_ci				void *data);
12262306a36Sopenharmony_ciint xen_pcibk_write_config_byte(struct pci_dev *dev, int offset, u8 value,
12362306a36Sopenharmony_ci				 void *data);
12462306a36Sopenharmony_ciint xen_pcibk_write_config_word(struct pci_dev *dev, int offset, u16 value,
12562306a36Sopenharmony_ci				void *data);
12662306a36Sopenharmony_ciint xen_pcibk_write_config_dword(struct pci_dev *dev, int offset, u32 value,
12762306a36Sopenharmony_ci				 void *data);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ciint xen_pcibk_config_capability_init(void);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciint xen_pcibk_config_header_add_fields(struct pci_dev *dev);
13262306a36Sopenharmony_ciint xen_pcibk_config_capability_add_fields(struct pci_dev *dev);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ciint xen_pcibk_get_interrupt_type(struct pci_dev *dev);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#endif				/* __XEN_PCIBACK_CONF_SPACE_H__ */
137