mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
AMD/IOMMU: size command buffer dynamically
With the present synchronous model, we need two slots for every
operation (the operation itself and a wait command). There can be one
such pair of commands pending per CPU. To ensure that under all normal
circumstances a slot is always available when one is requested, size the
command ring according to the number of present CPUs.
This is part of XSA-373 / CVE-2021-28692.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Paul Durrant <paul@xen.org>
(cherry picked from commit df242851dd)
This commit is contained in:
1 parent
9e3c8b1448
commit
83c0f6bbb2
3 files changed
+29
-10
No files matched your search
@@ -35,8 +35,8 @@ static int queue_iommu_command(struct amd_iommu *iommu, u32 cmd[])
|
||||
if ( head != tail )
|
||||
{
|
||||
memcpy(iommu->cmd_buffer.buffer +
|
||||
(iommu->cmd_buffer.tail * IOMMU_CMD_BUFFER_ENTRY_SIZE),
|
||||
cmd, IOMMU_CMD_BUFFER_ENTRY_SIZE);
|
||||
(iommu->cmd_buffer.tail * sizeof(cmd_entry_t)),
|
||||
cmd, sizeof(cmd_entry_t));
|
||||
|
||||
iommu->cmd_buffer.tail = tail;
|
||||
return 1;
|
||||
|
||||
@@ -125,7 +125,7 @@ static void register_iommu_cmd_buffer_in_mmio_space(struct amd_iommu *iommu)
|
||||
writel(entry, iommu->mmio_base + IOMMU_CMD_BUFFER_BASE_LOW_OFFSET);
|
||||
|
||||
power_of2_entries = get_order_from_bytes(iommu->cmd_buffer.alloc_size) +
|
||||
IOMMU_CMD_BUFFER_POWER_OF2_ENTRIES_PER_PAGE;
|
||||
PAGE_SHIFT - IOMMU_CMD_BUFFER_ENTRY_ORDER;
|
||||
|
||||
entry = 0;
|
||||
iommu_set_addr_hi_to_reg(&entry, addr_hi);
|
||||
@@ -1050,9 +1050,31 @@ static void *__init allocate_ring_buffer(struct ring_buffer *ring_buf,
|
||||
static void * __init allocate_cmd_buffer(struct amd_iommu *iommu)
|
||||
{
|
||||
/* allocate 'command buffer' in power of 2 increments of 4K */
|
||||
static unsigned int __read_mostly nr_ents;
|
||||
|
||||
if ( !nr_ents )
|
||||
{
|
||||
unsigned int order;
|
||||
|
||||
/*
|
||||
* With the present synchronous model, we need two slots for every
|
||||
* operation (the operation itself and a wait command). There can be
|
||||
* one such pair of requests pending per CPU. One extra entry is
|
||||
* needed as the ring is considered full when there's only one entry
|
||||
* left.
|
||||
*/
|
||||
BUILD_BUG_ON(CONFIG_NR_CPUS * 2 >= IOMMU_CMD_BUFFER_MAX_ENTRIES);
|
||||
order = get_order_from_bytes((num_present_cpus() * 2 + 1) <<
|
||||
IOMMU_CMD_BUFFER_ENTRY_ORDER);
|
||||
nr_ents = 1u << (order + PAGE_SHIFT - IOMMU_CMD_BUFFER_ENTRY_ORDER);
|
||||
|
||||
AMD_IOMMU_DEBUG("using %u-entry cmd ring(s)\n", nr_ents);
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(sizeof(cmd_entry_t) != (1u << IOMMU_CMD_BUFFER_ENTRY_ORDER));
|
||||
|
||||
return allocate_ring_buffer(&iommu->cmd_buffer, sizeof(cmd_entry_t),
|
||||
IOMMU_CMD_BUFFER_DEFAULT_ENTRIES,
|
||||
"Command Buffer", false);
|
||||
nr_ents, "Command Buffer", false);
|
||||
}
|
||||
|
||||
static void * __init allocate_event_log(struct amd_iommu *iommu)
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
#ifndef _ASM_X86_64_AMD_IOMMU_DEFS_H
|
||||
#define _ASM_X86_64_AMD_IOMMU_DEFS_H
|
||||
|
||||
/* IOMMU Command Buffer entries: in power of 2 increments, minimum of 256 */
|
||||
#define IOMMU_CMD_BUFFER_DEFAULT_ENTRIES 512
|
||||
|
||||
/* IOMMU Event Log entries: in power of 2 increments, minimum of 256 */
|
||||
#define IOMMU_EVENT_LOG_DEFAULT_ENTRIES 512
|
||||
|
||||
@@ -168,8 +165,8 @@ struct amd_iommu_dte {
|
||||
#define IOMMU_CMD_BUFFER_LENGTH_MASK 0x0F000000
|
||||
#define IOMMU_CMD_BUFFER_LENGTH_SHIFT 24
|
||||
|
||||
#define IOMMU_CMD_BUFFER_ENTRY_SIZE 16
|
||||
#define IOMMU_CMD_BUFFER_POWER_OF2_ENTRIES_PER_PAGE 8
|
||||
#define IOMMU_CMD_BUFFER_ENTRY_ORDER 4
|
||||
#define IOMMU_CMD_BUFFER_MAX_ENTRIES (1u << 15)
|
||||
|
||||
#define IOMMU_CMD_OPCODE_MASK 0xF0000000
|
||||
#define IOMMU_CMD_OPCODE_SHIFT 28
|
||||
|
||||