Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/acpica/acpi.c
| Context not available. | |||||
| static void acpi_hint_device_unit(device_t acdev, device_t child, | static void acpi_hint_device_unit(device_t acdev, device_t child, | ||||
| const char *name, int *unitp); | const char *name, int *unitp); | ||||
| static void acpi_reset_interfaces(device_t dev); | static void acpi_reset_interfaces(device_t dev); | ||||
| static bus_dma_tag_t acpi_get_dma_tag(device_t dev, device_t child); | |||||
| static device_method_t acpi_methods[] = { | static device_method_t acpi_methods[] = { | ||||
| /* Device interface */ | /* Device interface */ | ||||
| Context not available. | |||||
| DEVMETHOD(bus_get_domain, acpi_get_domain), | DEVMETHOD(bus_get_domain, acpi_get_domain), | ||||
| DEVMETHOD(bus_get_property, acpi_bus_get_prop), | DEVMETHOD(bus_get_property, acpi_bus_get_prop), | ||||
| DEVMETHOD(bus_get_device_path, acpi_get_device_path), | DEVMETHOD(bus_get_device_path, acpi_get_device_path), | ||||
| DEVMETHOD(bus_get_dma_tag, acpi_get_dma_tag), | |||||
| /* ACPI bus */ | /* ACPI bus */ | ||||
| DEVMETHOD(acpi_id_probe, acpi_device_id_probe), | DEVMETHOD(acpi_id_probe, acpi_device_id_probe), | ||||
| Context not available. | |||||
| return (0); | return (0); | ||||
| } | } | ||||
| struct dma_limits { | |||||
| bus_addr_t lowaddr; | |||||
| }; | |||||
| static ACPI_STATUS | |||||
| dma_on_resource(ACPI_RESOURCE *res, void *arg) | |||||
| { | |||||
| struct dma_limits *limits = arg; | |||||
| bus_addr_t min, max; | |||||
| /* | |||||
| * Note: | |||||
| * | |||||
| * BUS_SPACE_MAXADDR used in .lowaddr of dma_limits is the last-address of the | |||||
| * last page of the range, such as 0xffffffff. dma_on_resource has been setup | |||||
| * to match the BUS_SPACE_MAXADDR convention. | |||||
| * | |||||
| * On FreeBSD this leads to the likes of sysctl hw.busdma.zone0.lowaddr showing | |||||
| * showing values like 0xbfffffff, as needed/expected, not 0xc0000000. | |||||
| */ | |||||
| /* | |||||
| * _DMA interpetation notes: | |||||
| * | |||||
| * The minimum and maximum are device-side. To get the matching CPU-side figure, | |||||
| * we add the translation offset. This can overflow to signify lower addresses | |||||
| * on the CPU than the device, e.g. "Bus 0xC0000000 -> CPU 0x00000000" is | |||||
| * represented as 0xC0000000 min + 0xFFFFFFFF40000000 offset. | |||||
| */ | |||||
| /* | |||||
| * Overall summary: | |||||
| * | |||||
| * Set limits->lowaddr to the .Address.Maximum translated | |||||
| * to the CPU-side. | |||||
| * | |||||
| * But also validate the implementation limitation that the | |||||
| * CPU-side minimum ends up at 0x0. | |||||
| */ | |||||
| switch (res->Type) { | |||||
| case ACPI_RESOURCE_TYPE_ADDRESS16: | |||||
| min = (uint16_t)(res->Data.Address16.Address.Minimum + | |||||
| res->Data.Address16.Address.TranslationOffset); | |||||
| max = (uint16_t)(res->Data.Address16.Address.Maximum + | |||||
| res->Data.Address16.Address.TranslationOffset); | |||||
| break; | |||||
| case ACPI_RESOURCE_TYPE_ADDRESS32: | |||||
| min = (uint32_t)(res->Data.Address32.Address.Minimum + | |||||
| res->Data.Address32.Address.TranslationOffset); | |||||
| max = (uint32_t)(res->Data.Address32.Address.Maximum + | |||||
| res->Data.Address32.Address.TranslationOffset); | |||||
| break; | |||||
| case ACPI_RESOURCE_TYPE_ADDRESS64: | |||||
| min = (uint64_t)(res->Data.Address64.Address.Minimum + | |||||
| res->Data.Address64.Address.TranslationOffset); | |||||
| max = (uint64_t)(res->Data.Address64.Address.Maximum + | |||||
| res->Data.Address64.Address.TranslationOffset); | |||||
| break; | |||||
| case ACPI_RESOURCE_TYPE_END_TAG: | |||||
| return (AE_OK); | |||||
| default: | |||||
| printf("ACPI: warning: DMA limit with unsupported resource type %d\n", | |||||
| res->Type); | |||||
| return (AE_OK); | |||||
| } | |||||
| if (min != 0) | |||||
| printf("ACPI: warning: DMA limit with non-zero minimum address" | |||||
| " not supported yet\n"); | |||||
| limits->lowaddr = MIN(limits->lowaddr, max); | |||||
| return (AE_OK); | |||||
| } | |||||
| static int | |||||
| get_dma_tag(ACPI_HANDLE handle, bus_dma_tag_t *result) | |||||
| { | |||||
| ACPI_HANDLE parent; | |||||
| unsigned int coherent; | |||||
| struct dma_limits limits = { | |||||
| .lowaddr = BUS_SPACE_MAXADDR, | |||||
| }; | |||||
| /* | |||||
| * Note: | |||||
| * | |||||
| * BUS_SPACE_MAXADDR used in .lowaddr of dma_limits is the last-address of the | |||||
| * last page of the range, such as 0xffffffff. Follow the BUS_SPACE_MAXADDR | |||||
| * like last-address convention. | |||||
| * | |||||
| * On FreeBSD this leads to the likes of sysctl hw.busdma.zone0.lowaddr showing | |||||
| * showing values like 0xbfffffff, as needed/expected, not 0xc0000000. | |||||
| */ | |||||
| if (ACPI_FAILURE(AcpiWalkResources(handle, "_DMA", | |||||
| dma_on_resource, (void *)&limits))) { | |||||
| /* Inherit resources from parent handle if we don't have our own */ | |||||
| if (ACPI_SUCCESS(AcpiGetParent(handle, &parent))) | |||||
| return (get_dma_tag(parent, result)); | |||||
| /* The root (which has no parent) has no restrictions */ | |||||
| *result = NULL; | |||||
| return (0); | |||||
| } | |||||
| if (ACPI_FAILURE(acpi_GetInteger(handle, "_CCA", &coherent))) | |||||
| coherent = 0; | |||||
| if (bus_dma_tag_create(NULL, 1, 0, | |||||
| limits.lowaddr, BUS_SPACE_MAXADDR, NULL, NULL, | |||||
| BUS_SPACE_MAXSIZE, BUS_SPACE_UNRESTRICTED, BUS_SPACE_MAXSIZE, | |||||
| coherent ? BUS_DMA_COHERENT : 0, NULL, NULL, | |||||
| result) != 0) | |||||
| return (ENOMEM); | |||||
| return (0); | |||||
| } | |||||
| static bus_dma_tag_t | |||||
| acpi_get_dma_tag(device_t dev, device_t child) | |||||
| { | |||||
| bus_dma_tag_t result; | |||||
| if (get_dma_tag(acpi_get_handle(child), &result) != 0) { | |||||
| device_printf(child, "could not get ACPI DMA limits\n"); | |||||
| return (NULL); | |||||
| } | |||||
| return (result); | |||||
| } | |||||
| /* | /* | ||||
| * Fetch some descriptive data from ACPI to put in our attach message. | * Fetch some descriptive data from ACPI to put in our attach message. | ||||
| */ | */ | ||||
| Context not available. | |||||