1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#pragma pack(push,1) 14 15/* Generic entry header */ 16typedef struct acpi_dmar_remap_hdr { 17 uint16_t type; 18 uint16_t length; 19} acpi_dmar_remap_hdr_t; 20 21/* DMA remapping table "DMAR" */ 22typedef struct acpi_dmar_hdr { 23 acpi_header_t header; 24 uint8_t host_address_width; 25 uint8_t flags; 26 uint8_t res[10]; 27 /* first remapping structure in "linked list" */ 28// acpi_dmar_remap_hdr_t sheader; 29} acpi_dmar_hdr_t; 30 31/******************* 32 *** Entry types *** 33 *******************/ 34 35#define ACPI_DMAR_DRHD_TYPE 0 36#define ACPI_DMAR_RMRR_TYPE 1 37#define ACPI_DMAR_ATSR_TYPE 2 38#define ACPI_DMAR_RHSA_TYPE 3 39#define ACPI_DMAR_TYPE_IS_VALID(x) ((x) < 4) 40 41// device path structure 42typedef struct acpi_device_path { 43 uint8_t device; 44 uint8_t function; 45} acpi_device_path_t; 46 47// device scope structure 48typedef struct acpi_dmar_dscope { 49 uint8_t type; 50 uint8_t length; 51 uint8_t res[2]; 52 uint8_t enum_id; 53 uint8_t start_bus_number; 54 /* 55 * We could access this field as an array, but for 56 * consistancy, we will treat it as a linked list 57 */ 58// acpi_device_path_t path[]; 59} acpi_dmar_dscope_t; 60 61/******************** 62 *** DScope types *** 63 ********************/ 64#define ACPI_DSCOPE_PCI_ENDPOINT 0x01 65#define ACPI_DSCOPE_PCI_BRIDGE 0x02 66#define ACPI_DSCOPE_IOAPIC 0x03 67#define ACPI_DSCOPE_HPET 0x04 68#define ACPI_DSCOPE_VALID(x) \ 69 ((uint8_t)( (x) - ACPI_DSCOPE_PCI_ENDPOINT ) < 4) 70 71/****************************** 72 **** Sub tables of DMAR ****** 73 ******************************/ 74 75// Reserved Memory Region Report 76typedef struct acpi_dmar_rmrr { 77 acpi_dmar_remap_hdr_t header; 78 uint8_t res[2]; 79 uint16_t segment_number; 80 uint64_t base_address; 81 uint64_t limit_address; 82 /* first device scope in "linked list" */ 83// acpi_dmar_dscope_t device_scope; 84} acpi_dmar_rmrr_t; 85 86// DMA Remapping Hardware unit Definition 87typedef struct acpi_dmar_drhd { 88 acpi_dmar_remap_hdr_t header; 89 uint8_t flags; 90 uint8_t res[1]; 91 uint16_t segment_number; 92 uint64_t register_address; 93 /* first device scope in "linked list" */ 94// acpi_dmar_dscope_t device_scope; 95} acpi_dmar_drhd_t; 96 97// Root Port ATS Capability Reporting 98typedef struct acpi_dmar_atsr { 99 acpi_dmar_remap_hdr_t header; 100 uint8_t flags; 101 uint8_t res[1]; 102 uint16_t segment_number; 103 /* first device scope in "linked list" */ 104// acpi_dmar_dscope_t device_scope; 105} acpi_dmar_atsr_t; 106 107// Remaping Hardware Static Affinity structure 108typedef struct acpi_dmar_rhsa { 109 acpi_dmar_remap_hdr_t header; 110 uint8_t res[4]; 111 uint64_t base_address; 112 uint32_t proximity_domain; 113} acpi_dmar_rhsa_t; 114 115#pragma pack(pop) 116 117/******************************** 118 **** DMAR sub table helpers **** 119 ********************************/ 120 121/* Retrieve the header of the first entry */ 122static inline acpi_dmar_remap_hdr_t* 123acpi_dmar_first_remap(acpi_dmar_hdr_t* tbl) 124{ 125 return (acpi_dmar_remap_hdr_t*)(tbl + 1); 126} 127 128/* Retrieve the next DMAR sub header */ 129static inline acpi_dmar_remap_hdr_t* 130acpi_dmar_next_remap(acpi_dmar_hdr_t* tbl, 131 acpi_dmar_remap_hdr_t* hdr) 132{ 133 void* next = (uint8_t*)hdr + hdr->length; 134 void* end = (uint8_t*)tbl + tbl->header.length; 135 if (next < end) { 136 return (acpi_dmar_remap_hdr_t*)next; 137 } else { 138 return NULL; 139 } 140} 141 142/* Retrieve the DMAR sub header located at the specified index */ 143static inline acpi_dmar_remap_hdr_t* 144acpi_dmar_remap_at(acpi_dmar_hdr_t* tbl, int index) 145{ 146 acpi_dmar_remap_hdr_t* next = acpi_dmar_first_remap(tbl); 147 while (next != NULL && index-- > 0) { 148 next = acpi_dmar_next_remap(tbl, next); 149 } 150 return next; 151} 152 153/* Retrieve the next DMAR sub header of the specified type */ 154static inline acpi_dmar_remap_hdr_t* 155acpi_dmar_next_remap_type(acpi_dmar_hdr_t* tbl, 156 acpi_dmar_remap_hdr_t* hdr, int type) 157{ 158 do { 159 hdr = acpi_dmar_next_remap(tbl, hdr); 160 if (hdr == NULL) { 161 return NULL; 162 } 163 if (hdr->type == type) { 164 return hdr; 165 } 166 } while (1); 167} 168 169/* Retrieve the first DMAR sub header of the specified type */ 170static inline acpi_dmar_remap_hdr_t* 171acpi_dmar_first_remap_type(acpi_dmar_hdr_t* tbl, int type) 172{ 173 acpi_dmar_remap_hdr_t* hdr = acpi_dmar_first_remap(tbl); 174 if (hdr == NULL) { 175 return NULL; 176 } 177 178 if (hdr->type != type) { 179 return acpi_dmar_next_remap_type(tbl, hdr, type); 180 } else { 181 return hdr; 182 } 183} 184 185/*********************************** 186 **** DMAR device scope helpers **** 187 ***********************************/ 188 189/* Retrieve the first device scope for a DRHD table */ 190static inline acpi_dmar_dscope_t* 191acpi_dmar_drhd_first_dscope(acpi_dmar_drhd_t* h) 192{ 193 return (acpi_dmar_dscope_t*)(h + 1); 194} 195 196/* Retrieve the first device scope for an RMRR table */ 197static inline acpi_dmar_dscope_t* 198acpi_dmar_rmrr_first_dscope(acpi_dmar_rmrr_t* h) 199{ 200 return (acpi_dmar_dscope_t*)(h + 1); 201} 202 203/* Retrieve the first device scope for an ATSR table */ 204static inline acpi_dmar_dscope_t* 205acpi_dmar_atsr_first_dscope(acpi_dmar_atsr_t* h) 206{ 207 return (acpi_dmar_dscope_t*)(h + 1); 208} 209 210/* Retrieve the first device scope (table independant) */ 211static inline acpi_dmar_dscope_t* 212acpi_dmar_first_dscope(acpi_dmar_remap_hdr_t* h) 213{ 214 switch (h->type) { 215 case ACPI_DMAR_DRHD_TYPE: 216 return acpi_dmar_drhd_first_dscope((acpi_dmar_drhd_t*)h); 217 case ACPI_DMAR_RMRR_TYPE: 218 return acpi_dmar_rmrr_first_dscope((acpi_dmar_rmrr_t*)h); 219 case ACPI_DMAR_ATSR_TYPE: 220 return acpi_dmar_atsr_first_dscope((acpi_dmar_atsr_t*)h); 221 case ACPI_DMAR_RHSA_TYPE: 222 return NULL; /* RHSA has no device scope */ 223 default: 224 return NULL; 225 } 226} 227 228/* Retrieve the next device scope */ 229static inline acpi_dmar_dscope_t* 230acpi_dmar_next_dscope(acpi_dmar_remap_hdr_t* sh, acpi_dmar_dscope_t* scope) 231{ 232 void* next = (uint8_t*)scope + scope->length; 233 void* end = (uint8_t*)sh + sh->length; 234 if (next < end) { 235 return (acpi_dmar_dscope_t*)next; 236 } else { 237 return NULL; 238 } 239} 240 241/* Retrieve the device scope at the given index */ 242static inline acpi_dmar_dscope_t* 243acpi_dmar_dscope_at(acpi_dmar_remap_hdr_t* sh, int index) 244{ 245 acpi_dmar_dscope_t* next = acpi_dmar_first_dscope(sh); 246 while (next != NULL && index-- > 0) { 247 next = acpi_dmar_next_dscope(sh, next); 248 } 249 return next; 250} 251 252static inline acpi_device_path_t* 253acpi_dmar_path_first(acpi_dmar_dscope_t* dscope) 254{ 255 return (acpi_device_path_t*)(dscope + 1); 256} 257 258static inline int 259acpi_dmar_dscope_path_length(acpi_dmar_dscope_t* dscope) 260{ 261 int path_bytes = dscope->length - sizeof(*dscope); 262 return path_bytes / sizeof(acpi_device_path_t); 263} 264