📄 iommu_acpi.c
字号:
ivhd_block->cap_offset); if ( !iommu ) { amd_iov_error("IVHD Error: No IOMMU for Dev_Id 0x%x Cap 0x%x\n", ivhd_block->header.dev_id, ivhd_block->cap_offset); return -ENODEV; } /* parse Device Entries */ block_length = sizeof(struct acpi_ivhd_block_header); while ( ivhd_block->header.length >= (block_length + sizeof(struct acpi_ivhd_device_header)) ) { ivhd_device = (union acpi_ivhd_device *) ((u8 *)ivhd_block + block_length); amd_iov_info( "IVHD Device Entry:\n"); amd_iov_info( " Type 0x%x\n", ivhd_device->header.type); amd_iov_info( " Dev_Id 0x%x\n", ivhd_device->header.dev_id); amd_iov_info( " Flags 0x%x\n", ivhd_device->header.flags); switch ( ivhd_device->header.type ) { case AMD_IOMMU_ACPI_IVHD_DEV_U32_PAD: dev_length = parse_ivhd_device_padding( sizeof(u32), ivhd_block->header.length, block_length); break; case AMD_IOMMU_ACPI_IVHD_DEV_U64_PAD: dev_length = parse_ivhd_device_padding( sizeof(u64), ivhd_block->header.length, block_length); break; case AMD_IOMMU_ACPI_IVHD_DEV_SELECT: dev_length = parse_ivhd_device_select(ivhd_device, iommu); break; case AMD_IOMMU_ACPI_IVHD_DEV_RANGE_START: dev_length = parse_ivhd_device_range( ivhd_device, ivhd_block->header.length, block_length, iommu); break; case AMD_IOMMU_ACPI_IVHD_DEV_ALIAS_SELECT: dev_length = parse_ivhd_device_alias( ivhd_device, ivhd_block->header.length, block_length, iommu); break; case AMD_IOMMU_ACPI_IVHD_DEV_ALIAS_RANGE: dev_length = parse_ivhd_device_alias_range( ivhd_device, ivhd_block->header.length, block_length, iommu); break; case AMD_IOMMU_ACPI_IVHD_DEV_EXT_SELECT: dev_length = parse_ivhd_device_extended( ivhd_device, ivhd_block->header.length, block_length, iommu); break; case AMD_IOMMU_ACPI_IVHD_DEV_EXT_RANGE: dev_length = parse_ivhd_device_extended_range( ivhd_device, ivhd_block->header.length, block_length, iommu); break; default: amd_iov_error("IVHD Error: Invalid Device Type!\n"); dev_length = 0; break; } block_length += dev_length; if ( !dev_length ) return -ENODEV; } return 0;}static int __init parse_ivrs_block(struct acpi_ivrs_block_header *ivrs_block){ struct acpi_ivhd_block_header *ivhd_block; struct acpi_ivmd_block_header *ivmd_block; switch ( ivrs_block->type ) { case AMD_IOMMU_ACPI_IVHD_TYPE: ivhd_block = (struct acpi_ivhd_block_header *)ivrs_block; return parse_ivhd_block(ivhd_block); case AMD_IOMMU_ACPI_IVMD_ALL_TYPE: case AMD_IOMMU_ACPI_IVMD_ONE_TYPE: case AMD_IOMMU_ACPI_IVMD_RANGE_TYPE: case AMD_IOMMU_ACPI_IVMD_IOMMU_TYPE: ivmd_block = (struct acpi_ivmd_block_header *)ivrs_block; return parse_ivmd_block(ivmd_block); default: amd_iov_error("IVRS Error: Invalid Block Type!\n"); return -ENODEV; } return 0;}static void __init dump_acpi_table_header(struct acpi_table_header *table){#ifdef AMD_IOV_DEBUG int i; amd_iov_info("ACPI Table:\n"); amd_iov_info(" Signature "); for ( i = 0; i < ACPI_NAME_SIZE; i++ ) printk("%c", table->signature[i]); printk("\n"); amd_iov_info(" Length 0x%x\n", table->length); amd_iov_info(" Revision 0x%x\n", table->revision); amd_iov_info(" CheckSum 0x%x\n", table->checksum); amd_iov_info(" OEM_Id "); for ( i = 0; i < ACPI_OEM_ID_SIZE; i++ ) printk("%c", table->oem_id[i]); printk("\n"); amd_iov_info(" OEM_Table_Id "); for ( i = 0; i < ACPI_OEM_TABLE_ID_SIZE; i++ ) printk("%c", table->oem_table_id[i]); printk("\n"); amd_iov_info(" OEM_Revision 0x%x\n", table->oem_revision); amd_iov_info(" Creator_Id "); for ( i = 0; i < ACPI_NAME_SIZE; i++ ) printk("%c", table->asl_compiler_id[i]); printk("\n"); amd_iov_info(" Creator_Revision 0x%x\n", table->asl_compiler_revision);#endif}static int __init parse_ivrs_table(struct acpi_table_header *_table){ struct acpi_ivrs_block_header *ivrs_block; unsigned long length; int error = 0; struct acpi_table_header *table = (struct acpi_table_header *)_table; BUG_ON(!table); dump_acpi_table_header(table); /* parse IVRS blocks */ length = sizeof(struct acpi_ivrs_table_header); while ( (error == 0) && (table->length > (length + sizeof(*ivrs_block))) ) { ivrs_block = (struct acpi_ivrs_block_header *) ((u8 *)table + length); amd_iov_info("IVRS Block:\n"); amd_iov_info(" Type 0x%x\n", ivrs_block->type); amd_iov_info(" Flags 0x%x\n", ivrs_block->flags); amd_iov_info(" Length 0x%x\n", ivrs_block->length); amd_iov_info(" Dev_Id 0x%x\n", ivrs_block->dev_id); if ( table->length < (length + ivrs_block->length) ) { amd_iov_error("IVRS Error: " "Table Length Exceeded: 0x%x -> 0x%lx\n", table->length, (length + ivrs_block->length)); return -ENODEV; } error = parse_ivrs_block(ivrs_block); length += ivrs_block->length; } return error;}static int __init detect_iommu_acpi(struct acpi_table_header *_table){ struct acpi_ivrs_block_header *ivrs_block; struct acpi_table_header *table = (struct acpi_table_header *)_table; unsigned long i; unsigned long length = sizeof(struct acpi_ivrs_table_header); u8 checksum, *raw_table; /* validate checksum: sum of entire table == 0 */ checksum = 0; raw_table = (u8 *)table; for ( i = 0; i < table->length; i++ ) checksum += raw_table[i]; if ( checksum ) { amd_iov_error("IVRS Error: " "Invalid Checksum 0x%x\n", checksum); return -ENODEV; } while ( table->length > (length + sizeof(*ivrs_block)) ) { ivrs_block = (struct acpi_ivrs_block_header *) ((u8 *)table + length); if ( table->length < (length + ivrs_block->length) ) return -ENODEV; if ( ivrs_block->type == AMD_IOMMU_ACPI_IVHD_TYPE ) if ( amd_iommu_detect_one_acpi((void*)ivrs_block) != 0 ) return -ENODEV; length += ivrs_block->length; } return 0;}#define UPDATE_LAST_BDF(x) do {\ if ((x) > last_bdf) \ last_bdf = (x); \ } while(0);static int __init get_last_bdf_ivhd(void *ivhd){ union acpi_ivhd_device *ivhd_device; u16 block_length, dev_length; struct acpi_ivhd_block_header *ivhd_block; ivhd_block = (struct acpi_ivhd_block_header *)ivhd; if ( ivhd_block->header.length < sizeof(struct acpi_ivhd_block_header) ) { amd_iov_error("IVHD Error: Invalid Block Length!\n"); return -ENODEV; } block_length = sizeof(struct acpi_ivhd_block_header); while ( ivhd_block->header.length >= (block_length + sizeof(struct acpi_ivhd_device_header)) ) { ivhd_device = (union acpi_ivhd_device *) ((u8 *)ivhd_block + block_length); switch ( ivhd_device->header.type ) { case AMD_IOMMU_ACPI_IVHD_DEV_U32_PAD: dev_length = sizeof(u32); break; case AMD_IOMMU_ACPI_IVHD_DEV_U64_PAD: dev_length = sizeof(u64); break; case AMD_IOMMU_ACPI_IVHD_DEV_SELECT: UPDATE_LAST_BDF(ivhd_device->header.dev_id); dev_length = sizeof(struct acpi_ivhd_device_header); break; case AMD_IOMMU_ACPI_IVHD_DEV_ALIAS_SELECT: UPDATE_LAST_BDF(ivhd_device->header.dev_id); dev_length = sizeof(struct acpi_ivhd_device_alias); break; case AMD_IOMMU_ACPI_IVHD_DEV_EXT_SELECT: UPDATE_LAST_BDF(ivhd_device->header.dev_id); dev_length = sizeof(struct acpi_ivhd_device_extended); break; case AMD_IOMMU_ACPI_IVHD_DEV_RANGE_START: UPDATE_LAST_BDF(ivhd_device->range.trailer.dev_id); dev_length = sizeof(struct acpi_ivhd_device_range); break; case AMD_IOMMU_ACPI_IVHD_DEV_ALIAS_RANGE: UPDATE_LAST_BDF(ivhd_device->alias_range.trailer.dev_id) dev_length = sizeof(struct acpi_ivhd_device_alias_range); break; case AMD_IOMMU_ACPI_IVHD_DEV_EXT_RANGE: UPDATE_LAST_BDF(ivhd_device->extended_range.trailer.dev_id) dev_length = sizeof(struct acpi_ivhd_device_extended_range); break; default: amd_iov_error("IVHD Error: Invalid Device Type!\n"); dev_length = 0; break; } block_length += dev_length; if ( !dev_length ) return -ENODEV; } return 0;}static int __init get_last_bdf_acpi(struct acpi_table_header *_table){ struct acpi_ivrs_block_header *ivrs_block; struct acpi_table_header *table = (struct acpi_table_header *)_table; unsigned long length = sizeof(struct acpi_ivrs_table_header); while ( table->length > (length + sizeof(*ivrs_block)) ) { ivrs_block = (struct acpi_ivrs_block_header *) ((u8 *)table + length); if ( table->length < (length + ivrs_block->length) ) return -ENODEV; if ( ivrs_block->type == AMD_IOMMU_ACPI_IVHD_TYPE ) if ( get_last_bdf_ivhd((void*)ivrs_block) != 0 ) return -ENODEV; length += ivrs_block->length; } return 0;}int __init amd_iommu_detect_acpi(void){ return acpi_table_parse(AMD_IOMMU_ACPI_IVRS_SIG, detect_iommu_acpi);}int __init amd_iommu_get_ivrs_dev_entries(void){ acpi_table_parse(AMD_IOMMU_ACPI_IVRS_SIG, get_last_bdf_acpi); return last_bdf + 1;}int __init amd_iommu_update_ivrs_mapping_acpi(void){ return acpi_table_parse(AMD_IOMMU_ACPI_IVRS_SIG, parse_ivrs_table);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -