Page MenuHomeFreeBSD

D25219.diff
No OneTemporary

D25219.diff

diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -191,6 +191,7 @@
static void acpi_hint_device_unit(device_t acdev, device_t child,
const char *name, int *unitp);
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[] = {
/* Device interface */
@@ -226,6 +227,7 @@
DEVMETHOD(bus_get_cpus, acpi_get_cpus),
DEVMETHOD(bus_get_domain, acpi_get_domain),
DEVMETHOD(bus_get_property, acpi_bus_get_prop),
+ DEVMETHOD(bus_get_dma_tag, acpi_get_dma_tag),
/* ACPI bus */
DEVMETHOD(acpi_id_probe, acpi_device_id_probe),
@@ -449,6 +451,102 @@
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, len;
+
+ /*
+ * The minimum and maximum are device-side. To get the CPU-side minimum,
+ * we add the translation offset. This can overflow to signify lower addresses
+ * on the CPU than the device, e.g. "Bus 0xC0000000 -> CPU 0x00000000"
+ * on the RPi4 is represented as 0xC0000000 min + 0xFFFFFFFF40000000 offset.
+ */
+
+ switch (res->Type) {
+ case ACPI_RESOURCE_TYPE_ADDRESS16:
+ min = (uint16_t)(res->Data.Address16.Address.Minimum +
+ res->Data.Address16.Address.TranslationOffset);
+ len = res->Data.Address16.Address.AddressLength;
+ break;
+ case ACPI_RESOURCE_TYPE_ADDRESS32:
+ min = (uint32_t)(res->Data.Address32.Address.Minimum +
+ res->Data.Address32.Address.TranslationOffset);
+ len = res->Data.Address32.Address.AddressLength;
+ break;
+ case ACPI_RESOURCE_TYPE_ADDRESS64:
+ min = (uint64_t)(res->Data.Address64.Address.Minimum +
+ res->Data.Address64.Address.TranslationOffset);
+ len = res->Data.Address64.Address.AddressLength;
+ 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, min + len);
+
+ 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,
+ };
+
+ 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.
*/

File Metadata

Mime Type
text/plain
Expires
Mon, Sep 30, 4:22 PM (22 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
13191942
Default Alt Text
D25219.diff (3 KB)

Event Timeline