Re: [RFC 1/3] ACPI: Add support for Platform Communication Channel

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



+ Rafael [corrected email addr]

On 14 August 2014 15:57, Ashwin Chaugule <ashwin.chaugule@xxxxxxxxxx> wrote:
> The ACPI 5.0+ spec defines a generic mode of communication
> between the OS and a platform such as the BMC or external power
> controller. This medium (PCC) is typically used by CPPC
> (ACPI CPU Performance management), RAS (ACPI reliability protocol)
> and MPST (ACPI Memory power states).
>
> This patch adds initial support for PCC to be usable by the
> aforementioned PCC clients.
>
> Signed-off-by: Ashwin Chaugule <ashwin.chaugule@xxxxxxxxxx>
> ---
>  drivers/acpi/Kconfig  |  10 +++
>  drivers/acpi/Makefile |   1 +
>  drivers/acpi/pcc.c    | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 203 insertions(+)
>  create mode 100644 drivers/acpi/pcc.c
>
> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index a34a228..16d7c9a 100644
> --- a/drivers/acpi/Kconfig
> +++ b/drivers/acpi/Kconfig
> @@ -364,6 +364,16 @@ config ACPI_REDUCED_HARDWARE_ONLY
>
>         If you are unsure what to do, do not enable this option.
>
> +config ACPI_PCC
> +       bool "ACPI Platform Communication Channel"
> +       def_bool n
> +       depends on ACPI
> +       help
> +       Enable this option if your platform supports PCC as defined in the
> +       ACPI spec 5.0a+. PCC is a generic mechanism for the OS to communicate
> +       with a platform such as a BMC. PCC is typically used by CPPC, RAS
> +       and MPST.
> +
>  source "drivers/acpi/apei/Kconfig"
>
>  config ACPI_EXTLOG
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index ea55e01..35015fa 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -74,6 +74,7 @@ obj-$(CONFIG_ACPI_HED)                += hed.o
>  obj-$(CONFIG_ACPI_EC_DEBUGFS)  += ec_sys.o
>  obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
>  obj-$(CONFIG_ACPI_BGRT)                += bgrt.o
> +obj-$(CONFIG_ACPI_PCC)         += pcc.o
>
>  # processor has its own "processor." module_param namespace
>  processor-y                    := processor_driver.o processor_throttling.o
> diff --git a/drivers/acpi/pcc.c b/drivers/acpi/pcc.c
> new file mode 100644
> index 0000000..105e11a
> --- /dev/null
> +++ b/drivers/acpi/pcc.c
> @@ -0,0 +1,192 @@
> +/*
> + *     Copyright (C) 2014 Linaro Ltd.
> + *     Author: Ashwin Chaugule <ashwin.chaugule@xxxxxxxxxx>
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/io.h>
> +#include <linux/uaccess.h>
> +#include <linux/init.h>
> +#include <linux/cpufreq.h>
> +#include <linux/delay.h>
> +#include <linux/ioctl.h>
> +#include <linux/vmalloc.h>
> +#include <linux/module.h>
> +
> +#include <acpi/actbl.h>
> +
> +#define MAX_PCC_SUBSPACES      256
> +#define PCCS_SS_SIG_MAGIC      0x50434300
> +#define PCC_CMD_COMPLETE       0x1
> +#define PCC_VERSION                    "0.1"
> +
> +struct pcc_ss_desc {
> +       struct acpi_pcct_subspace *pcc_ss_ptr;
> +       raw_spinlock_t lock;
> +};
> +
> +/* Array of pointers to Type 0 Generic Communication Subspace Structures */
> +struct pcc_ss_desc pcc_ss_arr[MAX_PCC_SUBSPACES];
> +
> +/* Total number of subspaces detected in PCCT. */
> +static int total_ss;
> +
> +/*
> + * PCC clients call this function to get a base address of their
> + * Communication channel
> + */
> +int get_pcc_comm_channel(u32 ss_idx, u64 __iomem *addr, int *len)
> +{
> +       struct acpi_pcct_subspace *pcct_subspace = pcc_ss_arr[ss_idx].pcc_ss_ptr;
> +
> +       if (pcct_subspace) {
> +               *addr = pcct_subspace->base_address;
> +               *len = pcct_subspace->length;
> +       } else
> +               return -EINVAL;
> +
> +       pr_debug("base addr: %llx\n", pcct_subspace->base_address);
> +
> +       return 0;
> +}
> +
> +/* Send PCC cmd on behalf of this (subspace id) PCC client */
> +u16 send_pcc_cmd(u8 cmd, u8 sci, u32 ss_idx, u64 __iomem *base_addr)
> +{
> +       struct acpi_pcct_subspace *pcct_subspace = pcc_ss_arr[ss_idx].pcc_ss_ptr;
> +       struct acpi_pcct_shared_memory *generic_comm_base =
> +               (struct acpi_pcct_shared_memory *)base_addr;
> +       struct acpi_generic_address doorbell;
> +       u64 doorbell_preserve;
> +       u64 doorbell_val;
> +       u64 doorbell_write;
> +
> +       /*
> +        * Min time in usec that OSPM is expected to wait
> +        * before sending the next PCC cmd.
> +        */
> +       u16 cmd_delay = pcct_subspace->min_turnaround_time;
> +
> +       pr_debug("cmd: %d, ss_idx: %d, addr: %llx\n", cmd, ss_idx, (u64) base_addr);
> +       if (!generic_comm_base) {
> +               pr_err("No Generic Communication Channel provided.\n");
> +               return -EINVAL;
> +       }
> +
> +       raw_spin_lock(&pcc_ss_arr[ss_idx].lock);
> +
> +       /* Get doorbell details for this subspace. */
> +       doorbell = pcct_subspace->doorbell_register;
> +       doorbell_preserve = pcct_subspace->preserve_mask;
> +       doorbell_write = pcct_subspace->write_mask;
> +
> +       /* Write to the shared comm region. */
> +       iowrite16(cmd, &generic_comm_base->command);
> +
> +       /* Write Subspace MAGIC value so platform can identify destination. */
> +       iowrite32((PCCS_SS_SIG_MAGIC | ss_idx), &generic_comm_base->signature);
> +
> +       /* Flip CMD COMPLETE bit */
> +       iowrite16(0, &generic_comm_base->status);
> +
> +       /* Sync notification from OSPM to Platform. */
> +       acpi_read(&doorbell_val, &doorbell);
> +       acpi_write((doorbell_val & doorbell_preserve) | doorbell_write,
> +                       &doorbell);
> +
> +       /* Wait for Platform to consume. */
> +       while (!(ioread16(&generic_comm_base->status) & PCC_CMD_COMPLETE))
> +               udelay(cmd_delay);
> +
> +       raw_spin_unlock(&pcc_ss_arr[ss_idx].lock);
> +
> +       return generic_comm_base->status;
> +}
> +
> +static int parse_pcc_subspace(struct acpi_subtable_header *header,
> +               const unsigned long end)
> +{
> +       struct acpi_pcct_subspace *pcct_ss;
> +
> +       if (total_ss <= MAX_PCC_SUBSPACES) {
> +               pcct_ss = (struct acpi_pcct_subspace*) header;
> +
> +               if (pcct_ss->header.type != ACPI_PCCT_TYPE_GENERIC_SUBSPACE) {
> +                       pr_err("Incorrect PCC Subspace type detected\n");
> +                       return -EINVAL;
> +               }
> +
> +               pcc_ss_arr[total_ss].pcc_ss_ptr = pcct_ss;
> +               pr_debug("(%s)PCCT base addr: %llx", __func__, pcct_ss->base_address);
> +               raw_spin_lock_init(&pcc_ss_arr[total_ss].lock);
> +
> +               total_ss++;
> +       } else {
> +               pr_err("No more space for PCC subspaces.\n");
> +               return -ENOSPC;
> +       }
> +
> +       return 0;
> +}
> +
> +static int __init pcc_probe(void)
> +{
> +       acpi_status status = AE_OK;
> +       acpi_size pcct_tbl_header_size;
> +       struct acpi_table_pcct *pcct_tbl;
> +
> +       /* Search for PCCT */
> +       status = acpi_get_table_with_size(ACPI_SIG_PCCT, 0,
> +                       (struct acpi_table_header **)&pcct_tbl,
> +                       &pcct_tbl_header_size);
> +
> +       if (ACPI_SUCCESS(status) && !pcct_tbl) {
> +               pr_warn("PCCT header not found.\n");
> +               status = AE_NOT_FOUND;
> +               goto out_err;
> +       }
> +
> +       status = acpi_table_parse_entries(ACPI_SIG_PCCT,
> +                       sizeof(struct acpi_table_pcct), ACPI_PCCT_TYPE_GENERIC_SUBSPACE,
> +                       parse_pcc_subspace, MAX_PCC_SUBSPACES);
> +
> +       if (ACPI_SUCCESS(status))
> +               pr_err("Error parsing PCC subspaces from PCCT\n");
> +
> +       pr_info("Detected %d PCC Subspaces\n", total_ss);
> +
> +out_err:
> +       return (ACPI_SUCCESS(status) ? 1 : 0);
> +}
> +
> +static int __init pcc_init(void)
> +{
> +       int ret;
> +
> +       if (acpi_disabled)
> +               return -ENODEV;
> +
> +       /* Check if PCC support is available. */
> +       ret = pcc_probe();
> +
> +       if (ret) {
> +               pr_debug("PCC probe failed.\n");
> +               return -EINVAL;
> +       }
> +
> +       return ret;
> +}
> +device_initcall(pcc_init);
> +
> +
> --
> 1.9.1
>
--
To unsubscribe from this list: send the line "unsubscribe cpufreq" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel Devel]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Forum]     [Linux SCSI]

  Powered by Linux