static int register_pcc_channel(int pcc_subspace_idx) { struct acpi_pcct_hw_reduced *cppc_ss; unsigned int len; u64 usecs_lat; if (pcc_subspace_idx >= 0) { pcc_channel = pcc_mbox_request_channel(&cppc_mbox_cl, pcc_subspace_idx); if (IS_ERR(pcc_channel)) { pr_err("Failed to find PCC communication channel\n"); return -ENODEV; } /* * The PCC mailbox controller driver should * have parsed the PCCT (global table of all * PCC channels) and stored pointers to the * subspace communication region in con_priv. */ cppc_ss = pcc_channel->con_priv; if (!cppc_ss) { pr_err("No PCC subspace found for CPPC\n"); return -ENODEV; } /* * This is the shared communication region * for the OS and Platform to communicate over. */ comm_base_addr = cppc_ss->base_address; len = cppc_ss->length; /* * cppc_ss->latency is just a Nominal value. In reality * the remote processor could be much slower to reply. * So add an arbitrary amount of wait on top of Nominal. */ usecs_lat = NUM_RETRIES * cppc_ss->latency; deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC); pcc_mrtt = cppc_ss->min_turnaround_time; pcc_mpar = cppc_ss->max_access_rate; pcc_comm_addr = acpi_os_ioremap(comm_base_addr, len); if (!pcc_comm_addr) { pr_err("Failed to ioremap PCC comm region mem\n"); return -ENOMEM; } /* Set flag so that we dont come here for each CPU. */ pcc_channel_acquired = true; } return 0; }
static int register_pcc_channel(int pcc_ss_idx) { struct acpi_pcct_hw_reduced *cppc_ss; u64 usecs_lat; if (pcc_ss_idx >= 0) { pcc_data[pcc_ss_idx]->pcc_channel = pcc_mbox_request_channel(&cppc_mbox_cl, pcc_ss_idx); if (IS_ERR(pcc_data[pcc_ss_idx]->pcc_channel)) { pr_err("Failed to find PCC channel for subspace %d\n", pcc_ss_idx); return -ENODEV; } /* * The PCC mailbox controller driver should * have parsed the PCCT (global table of all * PCC channels) and stored pointers to the * subspace communication region in con_priv. */ cppc_ss = (pcc_data[pcc_ss_idx]->pcc_channel)->con_priv; if (!cppc_ss) { pr_err("No PCC subspace found for %d CPPC\n", pcc_ss_idx); return -ENODEV; } /* * cppc_ss->latency is just a Nominal value. In reality * the remote processor could be much slower to reply. * So add an arbitrary amount of wait on top of Nominal. */ usecs_lat = NUM_RETRIES * cppc_ss->latency; pcc_data[pcc_ss_idx]->deadline_us = usecs_lat; pcc_data[pcc_ss_idx]->pcc_mrtt = cppc_ss->min_turnaround_time; pcc_data[pcc_ss_idx]->pcc_mpar = cppc_ss->max_access_rate; pcc_data[pcc_ss_idx]->pcc_nominal = cppc_ss->latency; pcc_data[pcc_ss_idx]->pcc_comm_addr = acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length); if (!pcc_data[pcc_ss_idx]->pcc_comm_addr) { pr_err("Failed to ioremap PCC comm region mem for %d\n", pcc_ss_idx); return -ENOMEM; } /* Set flag so that we dont come here for each CPU. */ pcc_data[pcc_ss_idx]->pcc_channel_acquired = true; } return 0; }
static void __iomem *acpi_map(acpi_physical_address pg_off, unsigned long pg_sz) { unsigned long pfn; pfn = pg_off >> PAGE_SHIFT; if (should_use_kmap(pfn)) { if (pg_sz > PAGE_SIZE) return NULL; return (void __iomem __force *)kmap(pfn_to_page(pfn)); } else return acpi_os_ioremap(pg_off, pg_sz); }
int psb_intel_opregion_setup(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; struct psb_intel_opregion *opregion = &dev_priv->opregion; u32 opregion_phy, mboxes; void __iomem *base; int err = 0; pci_read_config_dword(dev->pdev, PCI_ASLS, &opregion_phy); if (opregion_phy == 0) { DRM_DEBUG_DRIVER("ACPI Opregion not supported\n"); return -ENOTSUPP; } INIT_WORK(&opregion->asle_work, psb_intel_opregion_asle_work); DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy); base = acpi_os_ioremap(opregion_phy, 8*1024); if (!base) return -ENOMEM; if (memcmp(base, OPREGION_SIGNATURE, 16)) { DRM_DEBUG_DRIVER("opregion signature mismatch\n"); err = -EINVAL; goto err_out; } opregion->header = base; opregion->vbt = base + OPREGION_VBT_OFFSET; opregion->lid_state = base + ACPI_CLID; mboxes = opregion->header->mboxes; if (mboxes & MBOX_ACPI) { DRM_DEBUG_DRIVER("Public ACPI methods supported\n"); opregion->acpi = base + OPREGION_ACPI_OFFSET; } if (mboxes & MBOX_ASLE) { DRM_DEBUG_DRIVER("ASLE supported\n"); opregion->asle = base + OPREGION_ASLE_OFFSET; } return 0; err_out: iounmap(base); return err; }
static int register_pcc_channel(int pcc_subspace_idx) { struct acpi_pcct_hw_reduced *cppc_ss; unsigned int len; if (pcc_subspace_idx >= 0) { pcc_channel = pcc_mbox_request_channel(&cppc_mbox_cl, pcc_subspace_idx); if (IS_ERR(pcc_channel)) { pr_err("Failed to find PCC communication channel\n"); return -ENODEV; } /* * The PCC mailbox controller driver should * have parsed the PCCT (global table of all * PCC channels) and stored pointers to the * subspace communication region in con_priv. */ cppc_ss = pcc_channel->con_priv; if (!cppc_ss) { pr_err("No PCC subspace found for CPPC\n"); return -ENODEV; } /* * This is the shared communication region * for the OS and Platform to communicate over. */ comm_base_addr = cppc_ss->base_address; len = cppc_ss->length; pcc_cmd_delay = cppc_ss->min_turnaround_time; pcc_comm_addr = acpi_os_ioremap(comm_base_addr, len); if (!pcc_comm_addr) { pr_err("Failed to ioremap PCC comm region mem\n"); return -ENOMEM; } /* Set flag so that we dont come here for each CPU. */ pcc_channel_acquired = true; } return 0; }
acpi_status acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width) { void __iomem *virt_addr; unsigned int size = width / 8; bool unmap = false; u64 dummy; rcu_read_lock(); virt_addr = acpi_map_vaddr_lookup(phys_addr, size); if (!virt_addr) { rcu_read_unlock(); virt_addr = acpi_os_ioremap(phys_addr, size); if (!virt_addr) return AE_BAD_ADDRESS; unmap = true; } if (!value) value = &dummy; switch (width) { case 8: *(u8 *) value = readb(virt_addr); break; case 16: *(u16 *) value = readw(virt_addr); break; case 32: *(u32 *) value = readl(virt_addr); break; case 64: *(u64 *) value = read64(virt_addr); break; default: BUG(); } if (unmap) iounmap(virt_addr); else rcu_read_unlock(); return AE_OK; }
acpi_status acpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width) { void __iomem *virt_addr; unsigned int size = width / 8; bool unmap = false; rcu_read_lock(); virt_addr = acpi_map_vaddr_lookup(phys_addr, size); if (!virt_addr) { rcu_read_unlock(); virt_addr = acpi_os_ioremap(phys_addr, size); if (!virt_addr) return AE_BAD_ADDRESS; unmap = true; } switch (width) { case 8: writeb(value, virt_addr); break; case 16: writew(value, virt_addr); break; case 32: writel(value, virt_addr); break; case 64: write64(value, virt_addr); break; default: BUG(); } if (unmap) iounmap(virt_addr); else rcu_read_unlock(); return AE_OK; }
/** * acpi_pcc_probe - Parse the ACPI tree for the PCCT. * * Return: 0 for Success, else errno. */ static int __init acpi_pcc_probe(void) { acpi_size pcct_tbl_header_size; struct acpi_table_header *pcct_tbl; struct acpi_subtable_header *pcct_entry; int count, i; acpi_status status = AE_OK; /* Search for PCCT */ status = acpi_get_table_with_size(ACPI_SIG_PCCT, 0, &pcct_tbl, &pcct_tbl_header_size); if (ACPI_FAILURE(status) || !pcct_tbl) { pr_warn("PCCT header not found.\n"); return -ENODEV; } count = acpi_table_parse_entries(ACPI_SIG_PCCT, sizeof(struct acpi_table_pcct), ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE, parse_pcc_subspace, MAX_PCC_SUBSPACES); if (count <= 0) { pr_err("Error parsing PCC subspaces from PCCT\n"); return -EINVAL; } pcc_mbox_channels = kzalloc(sizeof(struct mbox_chan) * count, GFP_KERNEL); if (!pcc_mbox_channels) { pr_err("Could not allocate space for PCC mbox channels\n"); return -ENOMEM; } pcc_doorbell_vaddr = kcalloc(count, sizeof(void *), GFP_KERNEL); if (!pcc_doorbell_vaddr) { kfree(pcc_mbox_channels); return -ENOMEM; } /* Point to the first PCC subspace entry */ pcct_entry = (struct acpi_subtable_header *) ( (unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct)); for (i = 0; i < count; i++) { struct acpi_generic_address *db_reg; struct acpi_pcct_hw_reduced *pcct_ss; pcc_mbox_channels[i].con_priv = pcct_entry; pcct_entry = (struct acpi_subtable_header *) ((unsigned long) pcct_entry + pcct_entry->length); /* If doorbell is in system memory cache the virt address */ pcct_ss = (struct acpi_pcct_hw_reduced *)pcct_entry; db_reg = &pcct_ss->doorbell_register; if (db_reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) pcc_doorbell_vaddr[i] = acpi_os_ioremap(db_reg->address, db_reg->bit_width/8); } pcc_mbox_ctrl.num_chans = count; pr_info("Detected %d PCC Subspaces\n", pcc_mbox_ctrl.num_chans); return 0; }