|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC 03/11] acpi: arm: Code to generate Hardware Domains IORT
From: Manish Jaggi <manish.jaggi@xxxxxxxxxx>
Singed-off-by: Manish Jaggi <manish.jaggi@xxxxxxxxxx>
---
xen/arch/arm/domain_build.c | 28 +++++
xen/drivers/acpi/arm/gen-iort.c | 253 +++++++++++++++++++++++++++++++++++++++-
xen/include/acpi/gen-iort.h | 1 +
xen/include/asm-arm/acpi.h | 1 +
4 files changed, 282 insertions(+), 1 deletion(-)
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index f5d5e3d271..9831943147 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1654,6 +1654,8 @@ static int acpi_create_xsdt(struct domain *d, struct
membank tbl_add[])
ACPI_SIG_FADT, tbl_add[TBL_FADT].start);
acpi_xsdt_modify_entry(xsdt->table_offset_entry, entry_count,
ACPI_SIG_MADT, tbl_add[TBL_MADT].start);
+ acpi_xsdt_modify_entry(xsdt->table_offset_entry, entry_count,
+ ACPI_SIG_IORT, tbl_add[TBL_IORT].start);
xsdt->table_offset_entry[entry_count] = tbl_add[TBL_STAO].start;
xsdt->header.length = table_size;
@@ -1704,6 +1706,28 @@ static int acpi_create_stao(struct domain *d, struct
membank tbl_add[])
return 0;
}
+static int acpi_create_iort(struct domain *d, struct membank tbl_add[])
+{
+ struct acpi_table_iort *hwdom_table;
+ unsigned int size = 0;
+
+ tbl_add[TBL_IORT].start = d->arch.efi_acpi_gpa
+ + acpi_get_table_offset(tbl_add, TBL_IORT);
+ hwdom_table = d->arch.efi_acpi_table
+ + acpi_get_table_offset(tbl_add, TBL_IORT);
+
+ if ( prepare_iort(hwdom_table, &size) )
+ {
+ printk("Failed to write IORT table\n");
+ return -EINVAL;
+ }
+ printk("%s %d %d \r\n", __func__, __LINE__, size);
+
+ tbl_add[TBL_IORT].size = size;
+ printk("%s %d %d \r\n", __func__, __LINE__, size);
+ return 0;
+}
+
static int acpi_create_madt(struct domain *d, struct membank tbl_add[])
{
struct acpi_table_header *table = NULL;
@@ -1899,6 +1923,10 @@ static int prepare_acpi(struct domain *d, struct
kernel_info *kinfo)
if ( rc != 0 )
return rc;
+ rc = acpi_create_iort(d, tbl_add);
+ if ( rc != 0 )
+ return rc;
+
rc = acpi_create_xsdt(d, tbl_add);
if ( rc != 0 )
return rc;
diff --git a/xen/drivers/acpi/arm/gen-iort.c b/xen/drivers/acpi/arm/gen-iort.c
index 3fc32959c6..f368000753 100644
--- a/xen/drivers/acpi/arm/gen-iort.c
+++ b/xen/drivers/acpi/arm/gen-iort.c
@@ -21,6 +21,257 @@
#include <acpi/ridmap.h>
#include <xen/acpi.h>
+/*
+ * Structure of Hardware domain's IORT
+ * -----------------------------------
+ *
+ * Below is the structure of the IORT which this code generates.
+ *
+ * [IORT Header]
+ * [ITS Group 1 ]
+ * [ITS Group N ]
+ * [PCIRC Node 1]
+ * [PCIRC IDMAP entry 1]
+ * [PCIRC IDMAP entry N]
+ * [PCIRC Node N]
+ *
+ * requesterId- deviceId mapping list poplated by parsing IORT is used
+ * to create nodes and idmaps.
+ * We have one small problem, how to resolve the its grooup node offset from
+ * the firmware iort to the ones in hardware domains IORT.
+ *
+ * Since the ITS group node pointer stored with the rid-devid map is used
+ * to populate the ITS Group nodes in the hardware domains' IORT.
+ * We create another map to save the offset of the ITS group node written
+ * in the hardware domain IORT with the ITS node pointer in the firmware IORT.
+ *
+ * This offset is later used when writing pcirc idmaps output_reference.
+ */
+struct its_node_offset_map
+{
+ struct acpi_iort_node *its_node;
+ unsigned int offset;
+ struct list_head entry;
+};
+struct list_head its_map_list;
+
+int set_its_node_offset(struct acpi_iort_node *its_node, unsigned int offset)
+{
+ struct its_node_offset_map *its_map;
+ list_for_each_entry(its_map, &its_map_list, entry)
+ {
+ if ( its_map->its_node == its_node )
+ return 0;
+ }
+
+ its_map = xzalloc(struct its_node_offset_map);
+ if ( !its_map )
+ return -ENOMEM;
+
+ its_map->its_node = its_node;
+ its_map->offset = offset;
+ list_add_tail(&its_map->entry, &its_map_list);
+
+ return 0;
+}
+/*
+ * This method would be used in write_pcirc_nodes when writing idmaps
+ */
+unsigned int get_its_node_offset(struct acpi_iort_node *its_node)
+{
+ struct its_node_offset_map *its_map;
+ list_for_each_entry(its_map, &its_map_list, entry)
+ {
+ if ( its_map->its_node == its_node )
+ return its_map->offset;
+ }
+
+ return 0;
+}
+
+void free_its_node_offset_list(void)
+{
+
+ struct its_node_offset_map *its_map;
+ list_for_each_entry(its_map, &its_map_list, entry)
+ xfree(its_map);
+
+ list_del(&its_map_list);
+}
+
+void write_its_group(u8 *iort, unsigned int *offset, unsigned int *num_nodes)
+{
+ struct rid_deviceid_map *rmap;
+ unsigned int of = *offset;
+ int n=0;
+ INIT_LIST_HEAD(&its_map_list);
+ /*
+ * rid_deviceid_map_list is iterated to get unique its group nodes
+ * Each unique ITS group node is written in hardware domains IORT
+ * by using some values from the firmware ITS group node.
+ */
+ list_for_each_entry(rmap, &rid_deviceid_map_list, entry)
+ {
+ struct acpi_iort_node *node;
+ struct acpi_iort_its_group *grp;
+ struct acpi_iort_its_group *fw_grp;
+
+ /* save its_node_offset_map in a list uniquely */
+ if ( !set_its_node_offset(rmap->its_node, of) )
+ {
+ node = (struct acpi_iort_node *) &iort[of];
+ grp = (struct acpi_iort_its_group *)(&node->node_data);
+
+ node->type = ACPI_IORT_NODE_ITS_GROUP;
+ node->length = sizeof(struct acpi_iort_node) +
+ sizeof(struct acpi_iort_its_group) -
+ sizeof(node->node_data);
+
+ node->revision = rmap->its_node->revision;
+ node->reserved = 0;
+ node->mapping_count = 0;
+ node->mapping_offset= 0;
+
+ fw_grp = (struct acpi_iort_its_group
*)(&rmap->its_node->node_data);
+
+ grp->its_count = fw_grp->its_count;
+ grp->identifiers[0] = fw_grp->identifiers[0];
+
+ of += node->length;
+ n++;
+ }
+ }
+ *offset = of;
+ *num_nodes = n;
+}
+
+/* It is assumed that rid_map_devid is sorted by pcirc_nodes */
+void write_pcirc_nodes(u8 *iort, unsigned int *pos, unsigned int *num_nodes)
+{
+ struct acpi_iort_node *opcirc_node, *pcirc_node;
+ struct acpi_iort_node *hwdom_pcirc_node = NULL;
+ struct rid_deviceid_map *rmap;
+ struct acpi_iort_id_mapping *idmap;
+ int num_idmap = 0, n = 0;
+ unsigned int old_pos = *pos;
+
+ opcirc_node = NULL;
+ /* Iterate rid_map_devid list */
+ list_for_each_entry(rmap, &rid_deviceid_map_list, entry)
+ {
+ struct acpi_iort_root_complex *rc;
+ struct acpi_iort_root_complex *rc_fw;
+ int add_node = 0;
+ pcirc_node = rmap->pcirc_node;
+
+ if ( opcirc_node == NULL ) /* First entry */
+ {
+ add_node = 1;
+ }
+ else if ( opcirc_node != pcirc_node ) /* another pci_rc_node found*/
+ {
+ /* All the idmaps of a pcirc are written, now update node info*/
+ hwdom_pcirc_node->length = num_idmap *
+ sizeof(struct acpi_iort_id_mapping) +
+ sizeof(struct acpi_iort_node) +
+ sizeof(struct acpi_iort_root_complex) -
+ sizeof(pcirc_node->node_data);
+
+ hwdom_pcirc_node->mapping_count = num_idmap;
+ hwdom_pcirc_node->mapping_offset = sizeof(struct acpi_iort_node) +
+ sizeof(struct
acpi_iort_root_complex) -
+ sizeof(pcirc_node->node_data);
+ old_pos += hwdom_pcirc_node->length;
+ add_node = 1;
+ }
+
+ if ( add_node ) /* create the pcirc node */
+ {
+ opcirc_node = pcirc_node;
+ hwdom_pcirc_node = (struct acpi_iort_node *)&iort[old_pos];
+ hwdom_pcirc_node->type = ACPI_IORT_NODE_PCI_ROOT_COMPLEX;
+ hwdom_pcirc_node->mapping_offset = sizeof(struct acpi_iort_node) +
+ sizeof(struct
acpi_iort_root_complex) -
+
sizeof(hwdom_pcirc_node->node_data);
+
+ rc = (struct acpi_iort_root_complex *)
+ &hwdom_pcirc_node->node_data;
+
+ rc_fw = (struct acpi_iort_root_complex *)
+ &pcirc_node->node_data;
+
+ rc->pci_segment_number = rc_fw->pci_segment_number;
+ rc->ats_attribute = rc_fw->ats_attribute;
+ rc->memory_properties = rc_fw->memory_properties;
+
+ idmap = ACPI_ADD_PTR(struct acpi_iort_id_mapping,
+ hwdom_pcirc_node,
+ hwdom_pcirc_node->mapping_offset);
+ n++;
+ num_idmap = 0;
+ }
+
+ idmap->input_base = rmap->idmap.input_base;
+ idmap->id_count = rmap->idmap.id_count;
+ idmap->output_base = rmap->idmap.output_base;
+ idmap->output_reference = get_its_node_offset(rmap->its_node);
+ idmap->flags = 0;
+
+ idmap++;
+ num_idmap++;
+ }
+
+ if ( hwdom_pcirc_node ) /* if no further PCIRC nodes found */
+ {
+ /* All the idmaps of a pcirc are written, now update node info*/
+ hwdom_pcirc_node->length = num_idmap *
+ sizeof(struct acpi_iort_id_mapping) +
+ sizeof(struct acpi_iort_node) +
+ sizeof(struct acpi_iort_root_complex) -1;
+
+ hwdom_pcirc_node->mapping_count = num_idmap;
+ old_pos += hwdom_pcirc_node->length;
+ }
+
+ *pos = old_pos;
+ *num_nodes = n;
+}
+
+int prepare_iort(struct acpi_table_iort *hwdom_iort, unsigned int *iort_size)
+{
+ struct acpi_table_iort *fw_iort;
+ unsigned int num_nodes = 0;
+ unsigned int pos;
+
+ pos = sizeof(struct acpi_table_iort);
+
+ if ( acpi_get_table(ACPI_SIG_IORT, 0,
+ (struct acpi_table_header **)&fw_iort) )
+ {
+ printk("Failed to get IORT table\n");
+ return -ENODEV;
+ }
+
+ /* Write IORT header */
+ ACPI_MEMCPY(hwdom_iort, fw_iort, sizeof(struct acpi_table_iort));
+ hwdom_iort->node_offset = pos;
+ hwdom_iort->node_count = 0;
+
+ /* Write its group nodes */
+ write_its_group((u8*)hwdom_iort, &pos, &num_nodes);
+ hwdom_iort->node_count = num_nodes;
+ /* Write pcirc_nodes*/
+ write_pcirc_nodes((u8*)hwdom_iort, &pos, &num_nodes);
+ /* Update IORT Size in IORT header */
+ hwdom_iort->node_count += num_nodes;
+ hwdom_iort->header.length = pos;
+ hwdom_iort->header.checksum = 0; /* TODO */
+
+ *iort_size = hwdom_iort->header.length;
+
+ return 0;
+}
+
/*
* Size of hardware domains iort is calulcated based on the number of
* mappings in the requesterId - deviceId mapping list.
@@ -49,7 +300,7 @@ int estimate_iort_size(size_t *iort_size)
{
int i = 0;
- for (i=0; i <= pcirc_count; i++)
+ for ( i=0; i <= pcirc_count; i++ )
{
if ( pcirc_array[i] == (uint64_t)rmap->pcirc_node )
break;
diff --git a/xen/include/acpi/gen-iort.h b/xen/include/acpi/gen-iort.h
index 68e666fdce..4de31b7b9f 100644
--- a/xen/include/acpi/gen-iort.h
+++ b/xen/include/acpi/gen-iort.h
@@ -2,5 +2,6 @@
#define _GEN_IORT_H
int estimate_iort_size(size_t *iort_size);
+int prepare_iort(struct acpi_table_iort *hwdom_iort, unsigned int *iort_size);
#endif
diff --git a/xen/include/asm-arm/acpi.h b/xen/include/asm-arm/acpi.h
index c183b6bb6e..f8b5254621 100644
--- a/xen/include/asm-arm/acpi.h
+++ b/xen/include/asm-arm/acpi.h
@@ -36,6 +36,7 @@ typedef enum {
TBL_FADT,
TBL_MADT,
TBL_STAO,
+ TBL_IORT,
TBL_XSDT,
TBL_RSDP,
TBL_EFIT,
--
2.14.1
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |