[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 |