mirror of https://gitee.com/openkylin/linux.git
virt: acrn: Introduce PCI configuration space PIO accesses combiner
A User VM can access its virtual PCI configuration spaces via port IO approach, which has two following steps: 1) writes address into port 0xCF8 2) put/get data in/from port 0xCFC To distribute a complete PCI configuration space access one time, HSM need to combine such two accesses together. Combine two paired PIO I/O requests into one PCI I/O request and continue the I/O request distribution. Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Shuo Liu <shuo.a.liu@intel.com> Link: https://lore.kernel.org/r/20210207031040.49576-11-shuo.a.liu@intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
72f293de3f
commit
3c4c331667
|
@ -154,6 +154,7 @@ extern rwlock_t acrn_vm_list_lock;
|
||||||
* @default_client: The default I/O request client
|
* @default_client: The default I/O request client
|
||||||
* @ioreq_buf: I/O request shared buffer
|
* @ioreq_buf: I/O request shared buffer
|
||||||
* @ioreq_page: The page of the I/O request shared buffer
|
* @ioreq_page: The page of the I/O request shared buffer
|
||||||
|
* @pci_conf_addr: Address of a PCI configuration access emulation
|
||||||
*/
|
*/
|
||||||
struct acrn_vm {
|
struct acrn_vm {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
@ -168,6 +169,7 @@ struct acrn_vm {
|
||||||
struct acrn_ioreq_client *default_client;
|
struct acrn_ioreq_client *default_client;
|
||||||
struct acrn_io_request_buffer *ioreq_buf;
|
struct acrn_io_request_buffer *ioreq_buf;
|
||||||
struct page *ioreq_page;
|
struct page *ioreq_page;
|
||||||
|
u32 pci_conf_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct acrn_vm *acrn_vm_create(struct acrn_vm *vm,
|
struct acrn_vm *acrn_vm_create(struct acrn_vm *vm,
|
||||||
|
|
|
@ -222,6 +222,80 @@ int acrn_ioreq_client_wait(struct acrn_ioreq_client *client)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_cfg_addr(struct acrn_io_request *req)
|
||||||
|
{
|
||||||
|
return ((req->type == ACRN_IOREQ_TYPE_PORTIO) &&
|
||||||
|
(req->reqs.pio_request.address == 0xcf8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_cfg_data(struct acrn_io_request *req)
|
||||||
|
{
|
||||||
|
return ((req->type == ACRN_IOREQ_TYPE_PORTIO) &&
|
||||||
|
((req->reqs.pio_request.address >= 0xcfc) &&
|
||||||
|
(req->reqs.pio_request.address < (0xcfc + 4))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The low 8-bit of supported pci_reg addr.*/
|
||||||
|
#define PCI_LOWREG_MASK 0xFC
|
||||||
|
/* The high 4-bit of supported pci_reg addr */
|
||||||
|
#define PCI_HIGHREG_MASK 0xF00
|
||||||
|
/* Max number of supported functions */
|
||||||
|
#define PCI_FUNCMAX 7
|
||||||
|
/* Max number of supported slots */
|
||||||
|
#define PCI_SLOTMAX 31
|
||||||
|
/* Max number of supported buses */
|
||||||
|
#define PCI_BUSMAX 255
|
||||||
|
#define CONF1_ENABLE 0x80000000UL
|
||||||
|
/*
|
||||||
|
* A PCI configuration space access via PIO 0xCF8 and 0xCFC normally has two
|
||||||
|
* following steps:
|
||||||
|
* 1) writes address into 0xCF8 port
|
||||||
|
* 2) accesses data in/from 0xCFC
|
||||||
|
* This function combines such paired PCI configuration space I/O requests into
|
||||||
|
* one ACRN_IOREQ_TYPE_PCICFG type I/O request and continues the processing.
|
||||||
|
*/
|
||||||
|
static bool handle_cf8cfc(struct acrn_vm *vm,
|
||||||
|
struct acrn_io_request *req, u16 vcpu)
|
||||||
|
{
|
||||||
|
int offset, pci_cfg_addr, pci_reg;
|
||||||
|
bool is_handled = false;
|
||||||
|
|
||||||
|
if (is_cfg_addr(req)) {
|
||||||
|
WARN_ON(req->reqs.pio_request.size != 4);
|
||||||
|
if (req->reqs.pio_request.direction == ACRN_IOREQ_DIR_WRITE)
|
||||||
|
vm->pci_conf_addr = req->reqs.pio_request.value;
|
||||||
|
else
|
||||||
|
req->reqs.pio_request.value = vm->pci_conf_addr;
|
||||||
|
is_handled = true;
|
||||||
|
} else if (is_cfg_data(req)) {
|
||||||
|
if (!(vm->pci_conf_addr & CONF1_ENABLE)) {
|
||||||
|
if (req->reqs.pio_request.direction ==
|
||||||
|
ACRN_IOREQ_DIR_READ)
|
||||||
|
req->reqs.pio_request.value = 0xffffffff;
|
||||||
|
is_handled = true;
|
||||||
|
} else {
|
||||||
|
offset = req->reqs.pio_request.address - 0xcfc;
|
||||||
|
|
||||||
|
req->type = ACRN_IOREQ_TYPE_PCICFG;
|
||||||
|
pci_cfg_addr = vm->pci_conf_addr;
|
||||||
|
req->reqs.pci_request.bus =
|
||||||
|
(pci_cfg_addr >> 16) & PCI_BUSMAX;
|
||||||
|
req->reqs.pci_request.dev =
|
||||||
|
(pci_cfg_addr >> 11) & PCI_SLOTMAX;
|
||||||
|
req->reqs.pci_request.func =
|
||||||
|
(pci_cfg_addr >> 8) & PCI_FUNCMAX;
|
||||||
|
pci_reg = (pci_cfg_addr & PCI_LOWREG_MASK) +
|
||||||
|
((pci_cfg_addr >> 16) & PCI_HIGHREG_MASK);
|
||||||
|
req->reqs.pci_request.reg = pci_reg + offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_handled)
|
||||||
|
ioreq_complete_request(vm, vcpu, req);
|
||||||
|
|
||||||
|
return is_handled;
|
||||||
|
}
|
||||||
|
|
||||||
static bool in_range(struct acrn_ioreq_range *range,
|
static bool in_range(struct acrn_ioreq_range *range,
|
||||||
struct acrn_io_request *req)
|
struct acrn_io_request *req)
|
||||||
{
|
{
|
||||||
|
@ -382,6 +456,8 @@ static int acrn_ioreq_dispatch(struct acrn_vm *vm)
|
||||||
ioreq_complete_request(vm, i, req);
|
ioreq_complete_request(vm, i, req);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (handle_cf8cfc(vm, req, i))
|
||||||
|
continue;
|
||||||
|
|
||||||
spin_lock_bh(&vm->ioreq_clients_lock);
|
spin_lock_bh(&vm->ioreq_clients_lock);
|
||||||
client = find_ioreq_client(vm, req);
|
client = find_ioreq_client(vm, req);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#define ACRN_IOREQ_TYPE_PORTIO 0
|
#define ACRN_IOREQ_TYPE_PORTIO 0
|
||||||
#define ACRN_IOREQ_TYPE_MMIO 1
|
#define ACRN_IOREQ_TYPE_MMIO 1
|
||||||
|
#define ACRN_IOREQ_TYPE_PCICFG 2
|
||||||
|
|
||||||
#define ACRN_IOREQ_DIR_READ 0
|
#define ACRN_IOREQ_DIR_READ 0
|
||||||
#define ACRN_IOREQ_DIR_WRITE 1
|
#define ACRN_IOREQ_DIR_WRITE 1
|
||||||
|
@ -59,6 +60,30 @@ struct acrn_pio_request {
|
||||||
__u32 value;
|
__u32 value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct acrn_pci_request - Info of a PCI I/O request
|
||||||
|
* @direction: Access direction of this request (ACRN_IOREQ_DIR_*)
|
||||||
|
* @reserved: Reserved for alignment and should be 0
|
||||||
|
* @size: Access size of this PCI I/O request
|
||||||
|
* @value: Read/write value of this PIO I/O request
|
||||||
|
* @bus: PCI bus value of this PCI I/O request
|
||||||
|
* @dev: PCI device value of this PCI I/O request
|
||||||
|
* @func: PCI function value of this PCI I/O request
|
||||||
|
* @reg: PCI config space offset of this PCI I/O request
|
||||||
|
*
|
||||||
|
* Need keep same header layout with &struct acrn_pio_request.
|
||||||
|
*/
|
||||||
|
struct acrn_pci_request {
|
||||||
|
__u32 direction;
|
||||||
|
__u32 reserved[3];
|
||||||
|
__u64 size;
|
||||||
|
__u32 value;
|
||||||
|
__u32 bus;
|
||||||
|
__u32 dev;
|
||||||
|
__u32 func;
|
||||||
|
__u32 reg;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct acrn_io_request - 256-byte ACRN I/O request
|
* struct acrn_io_request - 256-byte ACRN I/O request
|
||||||
* @type: Type of this request (ACRN_IOREQ_TYPE_*).
|
* @type: Type of this request (ACRN_IOREQ_TYPE_*).
|
||||||
|
@ -67,6 +92,7 @@ struct acrn_pio_request {
|
||||||
* @reserved0: Reserved fields.
|
* @reserved0: Reserved fields.
|
||||||
* @reqs: Union of different types of request. Byte offset: 64.
|
* @reqs: Union of different types of request. Byte offset: 64.
|
||||||
* @reqs.pio_request: PIO request data of the I/O request.
|
* @reqs.pio_request: PIO request data of the I/O request.
|
||||||
|
* @reqs.pci_request: PCI configuration space request data of the I/O request.
|
||||||
* @reqs.mmio_request: MMIO request data of the I/O request.
|
* @reqs.mmio_request: MMIO request data of the I/O request.
|
||||||
* @reqs.data: Raw data of the I/O request.
|
* @reqs.data: Raw data of the I/O request.
|
||||||
* @reserved1: Reserved fields.
|
* @reserved1: Reserved fields.
|
||||||
|
@ -126,6 +152,7 @@ struct acrn_io_request {
|
||||||
__u32 reserved0[14];
|
__u32 reserved0[14];
|
||||||
union {
|
union {
|
||||||
struct acrn_pio_request pio_request;
|
struct acrn_pio_request pio_request;
|
||||||
|
struct acrn_pci_request pci_request;
|
||||||
struct acrn_mmio_request mmio_request;
|
struct acrn_mmio_request mmio_request;
|
||||||
__u64 data[8];
|
__u64 data[8];
|
||||||
} reqs;
|
} reqs;
|
||||||
|
|
Loading…
Reference in New Issue