linux/drivers/acpi/csrt.c
<<
>>
Prefs
   1/*
   2 * Support for Core System Resources Table (CSRT)
   3 *
   4 * Copyright (C) 2013, Intel Corporation
   5 * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
   6 *          Andy Shevchenko <andriy.shevchenko@linux.intel.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#define pr_fmt(fmt) "ACPI: CSRT: " fmt
  14
  15#include <linux/acpi.h>
  16#include <linux/device.h>
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/platform_device.h>
  20#include <linux/sizes.h>
  21
  22ACPI_MODULE_NAME("CSRT");
  23
  24static int __init acpi_csrt_parse_shared_info(struct platform_device *pdev,
  25                                              const struct acpi_csrt_group *grp)
  26{
  27        const struct acpi_csrt_shared_info *si;
  28        struct resource res[3];
  29        size_t nres;
  30        int ret;
  31
  32        memset(res, 0, sizeof(res));
  33        nres = 0;
  34
  35        si = (const struct acpi_csrt_shared_info *)&grp[1];
  36        /*
  37         * The peripherals that are listed on CSRT typically support only
  38         * 32-bit addresses so we only use the low part of MMIO base for
  39         * now.
  40         */
  41        if (!si->mmio_base_high && si->mmio_base_low) {
  42                /*
  43                 * There is no size of the memory resource in shared_info
  44                 * so we assume that it is 4k here.
  45                 */
  46                res[nres].start = si->mmio_base_low;
  47                res[nres].end = res[0].start + SZ_4K - 1;
  48                res[nres++].flags = IORESOURCE_MEM;
  49        }
  50
  51        if (si->gsi_interrupt) {
  52                int irq = acpi_register_gsi(NULL, si->gsi_interrupt,
  53                                            si->interrupt_mode,
  54                                            si->interrupt_polarity);
  55                res[nres].start = irq;
  56                res[nres].end = irq;
  57                res[nres++].flags = IORESOURCE_IRQ;
  58        }
  59
  60        if (si->base_request_line || si->num_handshake_signals) {
  61                /*
  62                 * We pass the driver a DMA resource describing the range
  63                 * of request lines the device supports.
  64                 */
  65                res[nres].start = si->base_request_line;
  66                res[nres].end = res[nres].start + si->num_handshake_signals - 1;
  67                res[nres++].flags = IORESOURCE_DMA;
  68        }
  69
  70        ret = platform_device_add_resources(pdev, res, nres);
  71        if (ret) {
  72                if (si->gsi_interrupt)
  73                        acpi_unregister_gsi(si->gsi_interrupt);
  74                return ret;
  75        }
  76
  77        return 0;
  78}
  79
  80static int __init
  81acpi_csrt_parse_resource_group(const struct acpi_csrt_group *grp)
  82{
  83        struct platform_device *pdev;
  84        char vendor[5], name[16];
  85        int ret, i;
  86
  87        vendor[0] = grp->vendor_id;
  88        vendor[1] = grp->vendor_id >> 8;
  89        vendor[2] = grp->vendor_id >> 16;
  90        vendor[3] = grp->vendor_id >> 24;
  91        vendor[4] = '\0';
  92
  93        if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info))
  94                return -ENODEV;
  95
  96        snprintf(name, sizeof(name), "%s%04X", vendor, grp->device_id);
  97        pdev = platform_device_alloc(name, PLATFORM_DEVID_AUTO);
  98        if (!pdev)
  99                return -ENOMEM;
 100
 101        /* Add resources based on the shared info */
 102        ret = acpi_csrt_parse_shared_info(pdev, grp);
 103        if (ret)
 104                goto fail;
 105
 106        ret = platform_device_add(pdev);
 107        if (ret)
 108                goto fail;
 109
 110        for (i = 0; i < pdev->num_resources; i++)
 111                dev_dbg(&pdev->dev, "%pR\n", &pdev->resource[i]);
 112
 113        return 0;
 114
 115fail:
 116        platform_device_put(pdev);
 117        return ret;
 118}
 119
 120/*
 121 * CSRT or Core System Resources Table is a proprietary ACPI table
 122 * introduced by Microsoft. This table can contain devices that are not in
 123 * the system DSDT table. In particular DMA controllers might be described
 124 * here.
 125 *
 126 * We present these devices as normal platform devices that don't have ACPI
 127 * IDs or handle. The platform device name will be something like
 128 * <VENDOR><DEVID>.<n>.auto for example: INTL9C06.0.auto.
 129 */
 130void __init acpi_csrt_init(void)
 131{
 132        struct acpi_csrt_group *grp, *end;
 133        struct acpi_table_csrt *csrt;
 134        acpi_status status;
 135        int ret;
 136
 137        status = acpi_get_table(ACPI_SIG_CSRT, 0,
 138                                (struct acpi_table_header **)&csrt);
 139        if (ACPI_FAILURE(status)) {
 140                if (status != AE_NOT_FOUND)
 141                        pr_warn("failed to get the CSRT table\n");
 142                return;
 143        }
 144
 145        pr_debug("parsing CSRT table for devices\n");
 146
 147        grp = (struct acpi_csrt_group *)(csrt + 1);
 148        end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length);
 149
 150        while (grp < end) {
 151                ret = acpi_csrt_parse_resource_group(grp);
 152                if (ret) {
 153                        pr_warn("error in parsing resource group: %d\n", ret);
 154                        return;
 155                }
 156
 157                grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
 158        }
 159}
 160
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.