Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/vmm/amd/ivrs_drv.c
Show First 20 Lines • Show All 178 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id, | ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id, | ||||
uint32_t end_id, uint8_t cfg, bool ats) | uint32_t end_id, uint8_t cfg, bool ats) | ||||
{ | { | ||||
struct ivhd_dev_cfg *dev_cfg; | struct ivhd_dev_cfg *dev_cfg; | ||||
/* If device doesn't have special data, don't add it. */ | KASSERT(softc->dev_cfg_cap <= softc->dev_cfg_cnt, | ||||
if (!cfg) | ("Impossible case: number of dev_cfg exceeding capacity")); | ||||
return; | if (softc->dev_cfg_cap == softc->dev_cfg_cnt) { | ||||
if (softc->dev_cfg_cap == 0) | |||||
grehan: Test (or assignment) inverted ? | |||||
softc->dev_cfg_cap <<= 2; | |||||
else | |||||
softc->dev_cfg_cap = 1; | |||||
softc->dev_cfg = realloc(softc->dev_cfg, | |||||
sizeof(*softc->dev_cfg) * softc->dev_cfg_cap, M_DEVBUF, | |||||
M_WAITOK); | |||||
} | |||||
dev_cfg = &softc->dev_cfg[softc->dev_cfg_cnt++]; | dev_cfg = &softc->dev_cfg[softc->dev_cfg_cnt++]; | ||||
dev_cfg->start_id = start_id; | dev_cfg->start_id = start_id; | ||||
dev_cfg->end_id = end_id; | dev_cfg->end_id = end_id; | ||||
dev_cfg->data = cfg; | dev_cfg->data = cfg; | ||||
dev_cfg->enable_ats = ats; | dev_cfg->enable_ats = ats; | ||||
} | } | ||||
/* | /* | ||||
* Record device attributes as suggested by BIOS. | * Record device attributes as suggested by BIOS. | ||||
*/ | */ | ||||
static int | static int | ||||
ivhd_dev_parse(ACPI_IVRS_HARDWARE1 *ivhd, struct amdvi_softc *softc) | ivhd_dev_parse(ACPI_IVRS_HARDWARE1 *ivhd, struct amdvi_softc *softc) | ||||
{ | { | ||||
ACPI_IVRS_DE_HEADER *de; | ACPI_IVRS_DE_HEADER *de; | ||||
uint8_t *p, *end; | uint8_t *p, *end; | ||||
int range_start_id = 0, range_end_id = 0; | int range_start_id = -1, range_end_id = -1, i; | ||||
uint32_t *extended; | uint32_t *extended; | ||||
uint8_t all_data = 0, range_data = 0; | uint8_t all_data = 0, range_data = 0; | ||||
bool range_enable_ats = false, enable_ats; | bool range_enable_ats = false, enable_ats; | ||||
softc->start_dev_rid = ~0; | |||||
softc->end_dev_rid = 0; | |||||
switch (ivhd->Header.Type) { | switch (ivhd->Header.Type) { | ||||
case IVRS_TYPE_HARDWARE_LEGACY: | case IVRS_TYPE_HARDWARE_LEGACY: | ||||
p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE1); | p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE1); | ||||
break; | break; | ||||
case IVRS_TYPE_HARDWARE_EFR: | case IVRS_TYPE_HARDWARE_EFR: | ||||
case IVRS_TYPE_HARDWARE_MIXED: | case IVRS_TYPE_HARDWARE_MIXED: | ||||
p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE2); | p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE2); | ||||
break; | break; | ||||
default: | default: | ||||
device_printf(softc->dev, | device_printf(softc->dev, | ||||
"unknown type: 0x%x\n", ivhd->Header.Type); | "unknown type: 0x%x\n", ivhd->Header.Type); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
end = (uint8_t *)ivhd + ivhd->Header.Length; | end = (uint8_t *)ivhd + ivhd->Header.Length; | ||||
while (p < end) { | while (p < end) { | ||||
de = (ACPI_IVRS_DE_HEADER *)p; | de = (ACPI_IVRS_DE_HEADER *)p; | ||||
softc->start_dev_rid = MIN(softc->start_dev_rid, de->Id); | |||||
softc->end_dev_rid = MAX(softc->end_dev_rid, de->Id); | |||||
switch (de->Type) { | switch (de->Type) { | ||||
case ACPI_IVRS_TYPE_ALL: | case ACPI_IVRS_TYPE_ALL: | ||||
all_data = de->DataSetting; | all_data = de->DataSetting; | ||||
for (i = 0; i < softc->dev_cfg_cnt; i++) | |||||
softc->dev_cfg[i].data |= all_data; | |||||
break; | break; | ||||
case ACPI_IVRS_TYPE_SELECT: | case ACPI_IVRS_TYPE_SELECT: | ||||
case ACPI_IVRS_TYPE_ALIAS_SELECT: | case ACPI_IVRS_TYPE_ALIAS_SELECT: | ||||
case ACPI_IVRS_TYPE_EXT_SELECT: | case ACPI_IVRS_TYPE_EXT_SELECT: | ||||
enable_ats = false; | enable_ats = false; | ||||
if (de->Type == ACPI_IVRS_TYPE_EXT_SELECT) { | if (de->Type == ACPI_IVRS_TYPE_EXT_SELECT) { | ||||
extended = (uint32_t *)(de + 1); | extended = (uint32_t *)(de + 1); | ||||
enable_ats = | enable_ats = | ||||
(*extended & IVHD_DEV_EXT_ATS_DISABLE) ? | (*extended & IVHD_DEV_EXT_ATS_DISABLE) ? | ||||
false : true; | false : true; | ||||
} | } | ||||
ivhd_dev_add_entry(softc, de->Id, de->Id, | ivhd_dev_add_entry(softc, de->Id, de->Id, | ||||
de->DataSetting | all_data, enable_ats); | de->DataSetting | all_data, enable_ats); | ||||
break; | break; | ||||
case ACPI_IVRS_TYPE_START: | case ACPI_IVRS_TYPE_START: | ||||
case ACPI_IVRS_TYPE_ALIAS_START: | case ACPI_IVRS_TYPE_ALIAS_START: | ||||
case ACPI_IVRS_TYPE_EXT_START: | case ACPI_IVRS_TYPE_EXT_START: | ||||
if (range_start_id != -1) { | |||||
device_printf(softc->dev, | |||||
"Unexpected start-of-range device entry\n"); | |||||
return (EINVAL); | |||||
} | |||||
range_start_id = de->Id; | range_start_id = de->Id; | ||||
range_data = de->DataSetting; | range_data = de->DataSetting; | ||||
if (de->Type == ACPI_IVRS_TYPE_EXT_START) { | if (de->Type == ACPI_IVRS_TYPE_EXT_START) { | ||||
extended = (uint32_t *)(de + 1); | extended = (uint32_t *)(de + 1); | ||||
range_enable_ats = | range_enable_ats = | ||||
(*extended & IVHD_DEV_EXT_ATS_DISABLE) ? | (*extended & IVHD_DEV_EXT_ATS_DISABLE) ? | ||||
false : true; | false : true; | ||||
} | } | ||||
break; | break; | ||||
case ACPI_IVRS_TYPE_END: | case ACPI_IVRS_TYPE_END: | ||||
if (range_start_id == -1) { | |||||
device_printf(softc->dev, | |||||
"Unexpected end-of-range device entry\n"); | |||||
return (EINVAL); | |||||
} | |||||
range_end_id = de->Id; | range_end_id = de->Id; | ||||
if (range_end_id < range_start_id) { | |||||
device_printf(softc->dev, | |||||
"Device entry range going backward\n"); | |||||
return (EINVAL); | |||||
} | |||||
ivhd_dev_add_entry(softc, range_start_id, range_end_id, | ivhd_dev_add_entry(softc, range_start_id, range_end_id, | ||||
range_data | all_data, range_enable_ats); | range_data | all_data, range_enable_ats); | ||||
range_start_id = range_end_id = 0; | range_start_id = range_end_id = -1; | ||||
range_data = 0; | range_data = 0; | ||||
all_data = 0; | all_data = 0; | ||||
break; | break; | ||||
case ACPI_IVRS_TYPE_PAD4: | case ACPI_IVRS_TYPE_PAD4: | ||||
break; | break; | ||||
case ACPI_IVRS_TYPE_SPECIAL: | case ACPI_IVRS_TYPE_SPECIAL: | ||||
/* HPET or IOAPIC */ | /* HPET or IOAPIC */ | ||||
break; | break; | ||||
default: | default: | ||||
if ((de->Type < 5) || | if ((de->Type < 5) || | ||||
(de->Type >= ACPI_IVRS_TYPE_PAD8)) | (de->Type >= ACPI_IVRS_TYPE_PAD8)) | ||||
device_printf(softc->dev, | device_printf(softc->dev, | ||||
"Unknown dev entry:0x%x\n", de->Type); | "Unknown dev entry:0x%x\n", de->Type); | ||||
} | } | ||||
if (softc->dev_cfg_cnt > | |||||
(sizeof(softc->dev_cfg) / sizeof(softc->dev_cfg[0]))) { | |||||
device_printf(softc->dev, | |||||
"WARN Too many device entries.\n"); | |||||
return (EINVAL); | |||||
} | |||||
if (de->Type < 0x40) | if (de->Type < 0x40) | ||||
p += sizeof(ACPI_IVRS_DEVICE4); | p += sizeof(ACPI_IVRS_DEVICE4); | ||||
else if (de->Type < 0x80) | else if (de->Type < 0x80) | ||||
p += sizeof(ACPI_IVRS_DEVICE8A); | p += sizeof(ACPI_IVRS_DEVICE8A); | ||||
else { | else { | ||||
printf("Variable size IVHD type 0x%x not supported\n", | printf("Variable size IVHD type 0x%x not supported\n", | ||||
de->Type); | de->Type); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
KASSERT((softc->end_dev_rid >= softc->start_dev_rid), | |||||
("Device end[0x%x] < start[0x%x.\n", | |||||
softc->end_dev_rid, softc->start_dev_rid)); | |||||
return (0); | return (0); | ||||
} | } | ||||
static bool | static bool | ||||
ivhd_is_newer(ACPI_IVRS_HEADER *old, ACPI_IVRS_HEADER *new) | ivhd_is_newer(ACPI_IVRS_HEADER *old, ACPI_IVRS_HEADER *new) | ||||
{ | { | ||||
if (old->DeviceId == new->DeviceId) { | if (old->DeviceId == new->DeviceId) { | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 295 Lines • ▼ Show 20 Lines | if (max_ptp_level < amdvi_ptp_level) { | ||||
device_printf(dev, "insufficient PTP level:%d\n", | device_printf(dev, "insufficient PTP level:%d\n", | ||||
max_ptp_level); | max_ptp_level); | ||||
return (EINVAL); | return (EINVAL); | ||||
} else { | } else { | ||||
device_printf(softc->dev, "supported paging level:%d, will use only: %d\n", | device_printf(softc->dev, "supported paging level:%d, will use only: %d\n", | ||||
max_ptp_level, amdvi_ptp_level); | max_ptp_level, amdvi_ptp_level); | ||||
} | } | ||||
device_printf(softc->dev, "device range: 0x%x - 0x%x\n", | |||||
softc->start_dev_rid, softc->end_dev_rid); | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
ivhd_attach(device_t dev) | ivhd_attach(device_t dev) | ||||
{ | { | ||||
ACPI_IVRS_HARDWARE1 *ivhd; | ACPI_IVRS_HARDWARE1 *ivhd; | ||||
ACPI_IVRS_HARDWARE2 *ivhd_efr; | ACPI_IVRS_HARDWARE2 *ivhd_efr; | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | case IVRS_TYPE_HARDWARE_MIXED: | ||||
break; | break; | ||||
} | } | ||||
softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress); | softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress); | ||||
status = ivhd_dev_parse(ivhd, softc); | status = ivhd_dev_parse(ivhd, softc); | ||||
if (status != 0) { | if (status != 0) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"endpoint device parsing error=%d\n", status); | "endpoint device parsing error=%d\n", status); | ||||
goto fail; | |||||
} | } | ||||
status = ivhd_print_cap(softc, ivhd); | status = ivhd_print_cap(softc, ivhd); | ||||
if (status != 0) { | if (status != 0) | ||||
return (status); | goto fail; | ||||
} | |||||
status = amdvi_setup_hw(softc); | status = amdvi_setup_hw(softc); | ||||
if (status != 0) { | if (status != 0) { | ||||
device_printf(dev, "couldn't be initialised, error=%d\n", | device_printf(dev, "couldn't be initialised, error=%d\n", | ||||
status); | status); | ||||
return (status); | goto fail; | ||||
} | } | ||||
return (0); | return (0); | ||||
fail: | |||||
free(softc->dev_cfg, M_DEVBUF); | |||||
return (status); | |||||
} | } | ||||
static int | static int | ||||
ivhd_detach(device_t dev) | ivhd_detach(device_t dev) | ||||
{ | { | ||||
struct amdvi_softc *softc; | struct amdvi_softc *softc; | ||||
softc = device_get_softc(dev); | softc = device_get_softc(dev); | ||||
amdvi_teardown_hw(softc); | amdvi_teardown_hw(softc); | ||||
free(softc->dev_cfg, M_DEVBUF); | |||||
/* | /* | ||||
* XXX: delete the device. | * XXX: delete the device. | ||||
* don't allow detach, return EBUSY. | * don't allow detach, return EBUSY. | ||||
*/ | */ | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 39 Lines |
Test (or assignment) inverted ?