| /* | |
| * Support for Core System Resources Table (CSRT) | |
| * | |
| * Copyright (C) 2013, Intel Corporation | |
| * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> | |
| * Andy Shevchenko <andriy.shevchenko@linux.intel.com> | |
| * | |
| * This program is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU General Public License version 2 as | |
| * published by the Free Software Foundation. | |
| */ | |
| #define pr_fmt(fmt) "ACPI: CSRT: " fmt | |
| #include <linux/acpi.h> | |
| #include <linux/device.h> | |
| #include <linux/kernel.h> | |
| #include <linux/module.h> | |
| #include <linux/platform_device.h> | |
| #include <linux/sizes.h> | |
| ACPI_MODULE_NAME("CSRT"); | |
| static int __init acpi_csrt_parse_shared_info(struct platform_device *pdev, | |
| const struct acpi_csrt_group *grp) | |
| { | |
| const struct acpi_csrt_shared_info *si; | |
| struct resource res[3]; | |
| size_t nres; | |
| int ret; | |
| memset(res, 0, sizeof(res)); | |
| nres = 0; | |
| si = (const struct acpi_csrt_shared_info *)&grp[1]; | |
| /* | |
| * The peripherals that are listed on CSRT typically support only | |
| * 32-bit addresses so we only use the low part of MMIO base for | |
| * now. | |
| */ | |
| if (!si->mmio_base_high && si->mmio_base_low) { | |
| /* | |
| * There is no size of the memory resource in shared_info | |
| * so we assume that it is 4k here. | |
| */ | |
| res[nres].start = si->mmio_base_low; | |
| res[nres].end = res[0].start + SZ_4K - 1; | |
| res[nres++].flags = IORESOURCE_MEM; | |
| } | |
| if (si->gsi_interrupt) { | |
| int irq = acpi_register_gsi(NULL, si->gsi_interrupt, | |
| si->interrupt_mode, | |
| si->interrupt_polarity); | |
| res[nres].start = irq; | |
| res[nres].end = irq; | |
| res[nres++].flags = IORESOURCE_IRQ; | |
| } | |
| if (si->base_request_line || si->num_handshake_signals) { | |
| /* | |
| * We pass the driver a DMA resource describing the range | |
| * of request lines the device supports. | |
| */ | |
| res[nres].start = si->base_request_line; | |
| res[nres].end = res[nres].start + si->num_handshake_signals - 1; | |
| res[nres++].flags = IORESOURCE_DMA; | |
| } | |
| ret = platform_device_add_resources(pdev, res, nres); | |
| if (ret) { | |
| if (si->gsi_interrupt) | |
| acpi_unregister_gsi(si->gsi_interrupt); | |
| return ret; | |
| } | |
| return 0; | |
| } | |
| static int __init | |
| acpi_csrt_parse_resource_group(const struct acpi_csrt_group *grp) | |
| { | |
| struct platform_device *pdev; | |
| char vendor[5], name[16]; | |
| int ret, i; | |
| vendor[0] = grp->vendor_id; | |
| vendor[1] = grp->vendor_id >> 8; | |
| vendor[2] = grp->vendor_id >> 16; | |
| vendor[3] = grp->vendor_id >> 24; | |
| vendor[4] = '\0'; | |
| if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info)) | |
| return -ENODEV; | |
| snprintf(name, sizeof(name), "%s%04X", vendor, grp->device_id); | |
| pdev = platform_device_alloc(name, PLATFORM_DEVID_AUTO); | |
| if (!pdev) | |
| return -ENOMEM; | |
| /* Add resources based on the shared info */ | |
| ret = acpi_csrt_parse_shared_info(pdev, grp); | |
| if (ret) | |
| goto fail; | |
| ret = platform_device_add(pdev); | |
| if (ret) | |
| goto fail; | |
| for (i = 0; i < pdev->num_resources; i++) | |
| dev_dbg(&pdev->dev, "%pR\n", &pdev->resource[i]); | |
| return 0; | |
| fail: | |
| platform_device_put(pdev); | |
| return ret; | |
| } | |
| /* | |
| * CSRT or Core System Resources Table is a proprietary ACPI table | |
| * introduced by Microsoft. This table can contain devices that are not in | |
| * the system DSDT table. In particular DMA controllers might be described | |
| * here. | |
| * | |
| * We present these devices as normal platform devices that don't have ACPI | |
| * IDs or handle. The platform device name will be something like | |
| * <VENDOR><DEVID>.<n>.auto for example: INTL9C06.0.auto. | |
| */ | |
| void __init acpi_csrt_init(void) | |
| { | |
| struct acpi_csrt_group *grp, *end; | |
| struct acpi_table_csrt *csrt; | |
| acpi_status status; | |
| int ret; | |
| status = acpi_get_table(ACPI_SIG_CSRT, 0, | |
| (struct acpi_table_header **)&csrt); | |
| if (ACPI_FAILURE(status)) { | |
| if (status != AE_NOT_FOUND) | |
| pr_warn("failed to get the CSRT table\n"); | |
| return; | |
| } | |
| pr_debug("parsing CSRT table for devices\n"); | |
| grp = (struct acpi_csrt_group *)(csrt + 1); | |
| end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length); | |
| while (grp < end) { | |
| ret = acpi_csrt_parse_resource_group(grp); | |
| if (ret) { | |
| pr_warn("error in parsing resource group: %d\n", ret); | |
| return; | |
| } | |
| grp = (struct acpi_csrt_group *)((void *)grp + grp->length); | |
| } | |
| } |