Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F97475509
D34791.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D34791.diff
View Options
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
@@ -193,6 +193,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 */
@@ -229,6 +230,7 @@
DEVMETHOD(bus_get_domain, acpi_get_domain),
DEVMETHOD(bus_get_property, acpi_bus_get_prop),
DEVMETHOD(bus_get_device_path, acpi_get_device_path),
+ DEVMETHOD(bus_get_dma_tag, acpi_get_dma_tag),
/* ACPI bus */
DEVMETHOD(acpi_id_probe, acpi_device_id_probe),
@@ -451,6 +453,139 @@
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.
*/
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Sep 30, 2:24 PM (22 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
13117041
Default Alt Text
D34791.diff (4 KB)
Attached To
Mode
D34791: Alternative to D25219: ACPI: add support for (inherited) _DMA limits
Attached
Detach File
Event Timeline
Log In to Comment