Merge "msm: kgsl: Use bulk clock functions for GMU"

This commit is contained in:
qctecmdr 2019-12-10 20:15:31 -08:00 • committed by Gerrit - the friendly Code Review server
commit 5202070c22
14 changed files with 170 additions and 251 deletions

View file

@ -885,6 +885,40 @@ static void adreno_of_get_ca_aware_properties(struct adreno_device *adreno_dev,
}
}
/* Dynamically build the OPP table for the GPU device */
static void adreno_build_opp_table(struct device *dev, struct kgsl_pwrctrl *pwr)
{
unsigned long freq = 0;
int i;
/*
* First an annoying step: Some targets have clock drivers that
* "helpfully" builds a OPP table for us but usually it is wrong.
* Go through and filter out unsupported frequencies
*/
for (;;) {
struct dev_pm_opp *opp = dev_pm_opp_find_freq_ceil(dev, &freq);
if (IS_ERR(opp))
break;
for (i = 0; i < pwr->num_pwrlevels; i++) {
if (freq == pwr->pwrlevels[i].gpu_freq)
break;
}
if (i == pwr->num_pwrlevels)
dev_pm_opp_remove(dev, freq);
freq++;
}
/* Now add all of our supported frequencies into the tree */
for (i = 0; i < pwr->num_pwrlevels; i++)
dev_pm_opp_add(dev, pwr->pwrlevels[i].gpu_freq, 0);
}
static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
struct device_node *node)
{
@ -893,45 +927,49 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
struct device_node *child;
int ret;
/* ADD the GPU OPP table if we define it */
if (of_find_property(device->pdev->dev.of_node,
"operating-points-v2", NULL)) {
ret = dev_pm_opp_of_add_table(&device->pdev->dev);
if (ret) {
dev_err(device->dev,
"Unable to set the GPU OPP table: %d\n", ret);
return ret;
}
}
pwr->num_pwrlevels = 0;
for_each_child_of_node(node, child) {
unsigned int index, freq = 0;
u32 index, freq = 0, voltage, bus;
struct kgsl_pwrlevel *level;
if (of_property_read_u32(child, "reg", &index)) {
dev_err(device->dev,
"%pOF: powerlevel index not found\n", child);
of_node_put(child);
return -EINVAL;
ret = of_property_read_u32(child, "reg", &index);
if (ret) {
dev_err(device->dev, "%pOF: powerlevel index not found\n",
child);
goto out;
}
if (of_property_read_u32(child, "qcom,gpu-freq", &freq)) {
dev_err(device->dev,
"%pOF: Unable to read qcom,gpu-freq\n", child);
of_node_put(child);
return -EINVAL;
ret = of_property_read_u32(child, "qcom,gpu-freq", &freq);
if (ret) {
dev_err(device->dev, "%pOF: Unable to read qcom,gpu-freq\n",
child);
goto out;
}
/* Ignore "zero" powerlevels */
if (!freq)
continue;
ret = of_property_read_u32(child, "qcom,level", &voltage);
if (ret) {
dev_err(device->dev, "%pOF: Unable to read qcom,level\n",
child);
goto out;
}
ret = kgsl_of_property_read_ddrtype(child, "qcom,bus-freq",
&bus);
if (ret) {
dev_err(device->dev, "%pOF:Unable to read qcom,bus-freq\n",
child);
goto out;
}
if (index >= KGSL_MAX_PWRLEVELS) {
dev_err(device->dev,
"%pOF: Pwrlevel index %d is out of range\n",
child, index);
dev_err(device->dev, "%pOF: Pwrlevel index %d is out of range\n",
child, index);
continue;
}
@ -941,20 +979,12 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
level = &pwr->pwrlevels[index];
level->gpu_freq = freq;
level->bus_freq = bus;
level->voltage_level = voltage;
of_property_read_u32(child, "qcom,acd-level",
&level->acd_level);
ret = kgsl_of_property_read_ddrtype(child,
"qcom,bus-freq", &level->bus_freq);
if (ret) {
dev_err(device->dev,
"%pOF: Couldn't read the bus frequency for power level %d\n",
child, index);
of_node_put(child);
return ret;
}
level->bus_min = level->bus_freq;
kgsl_of_property_read_ddrtype(child,
"qcom,bus-min", &level->bus_min);
@ -964,7 +994,11 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev,
"qcom,bus-max", &level->bus_max);
}
adreno_build_opp_table(&device->pdev->dev, pwr);
return 0;
out:
of_node_put(child);
return ret;
}
static void adreno_of_get_initial_pwrlevel(struct adreno_device *adreno_dev,

View file

@ -2858,8 +2858,8 @@ int adreno_dispatcher_idle(struct adreno_device *adreno_dev)
* Ensure that this function is not called when dispatcher
* mutex is held and device is started
*/
if (mutex_is_locked(&dispatcher->mutex) &&
(__mutex_owner(&dispatcher->mutex) == current))
if (WARN_ON(mutex_is_locked(&dispatcher->mutex)))
return -EDEADLK;
adreno_get_gpu_halt(adreno_dev);

View file

@ -4346,7 +4346,7 @@ static vm_fault_t
kgsl_gpumem_vm_fault(struct vm_fault *vmf)
{
struct kgsl_mem_entry *entry = vmf->vma->vm_private_data;
int ret;
vm_fault_t ret;
if (!entry)
return VM_FAULT_SIGBUS;
@ -4354,7 +4354,7 @@ kgsl_gpumem_vm_fault(struct vm_fault *vmf)
return VM_FAULT_SIGBUS;
ret = entry->memdesc.ops->vmfault(&entry->memdesc, vmf->vma, vmf);
if ((ret == 0) || (ret == VM_FAULT_NOPAGE))
if (!ret || ret == VM_FAULT_NOPAGE)
entry->priv->gpumem_mapped += PAGE_SIZE;
return ret;
@ -4776,7 +4776,7 @@ static int _register_device(struct kgsl_device *device)
}
device->dev->dma_mask = &dma_mask;
arch_setup_dma_ops(device->dev, 0, 0, NULL, false);
set_dma_ops(device->dev, NULL);
dev_set_drvdata(&device->pdev->dev, device);
return 0;

View file

@ -163,8 +163,8 @@ struct kgsl_memdesc;
struct kgsl_memdesc_ops {
unsigned int vmflags;
int (*vmfault)(struct kgsl_memdesc *memdesc, struct vm_area_struct *vma,
struct vm_fault *vmf);
vm_fault_t (*vmfault)(struct kgsl_memdesc *memdesc,
struct vm_area_struct *vma, struct vm_fault *vmf);
void (*free)(struct kgsl_memdesc *memdesc);
int (*map_kernel)(struct kgsl_memdesc *memdesc);
void (*unmap_kernel)(struct kgsl_memdesc *memdesc);

View file

@ -4,6 +4,7 @@
*/
#include <dt-bindings/regulator/qcom,rpmh-regulator-levels.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/io.h>
@ -559,7 +560,7 @@ static int gmu_dcvs_set(struct kgsl_device *device,
struct rpmh_arc_vals {
unsigned int num;
uint16_t val[MAX_GX_LEVELS];
const u16 *val;
};
static const char gfx_res_id[] = "gfx.lvl";
@ -584,22 +585,9 @@ enum rpmh_vote_type {
static int rpmh_arc_cmds(struct gmu_device *gmu,
struct rpmh_arc_vals *arc, const char *res_id)
{
unsigned int len;
size_t len = 0;
memset(arc, 0, sizeof(*arc));
len = cmd_db_read_aux_data_len(res_id);
if (len == 0)
return -EINVAL;
if (len > (MAX_GX_LEVELS << 1)) {
dev_err(&gmu->pdev->dev,
"gfx cmddb size %d larger than alloc buf %d of %s\n",
len, (MAX_GX_LEVELS << 1), res_id);
return -EINVAL;
}
cmd_db_read_aux_data(res_id, (uint8_t *)arc->val, len);
arc->val = cmd_db_read_aux_data(res_id, &len);
/*
* cmd_db_read_aux_data() gives us a zero-padded table of
@ -703,45 +691,22 @@ static int rpmh_arc_votes_init(struct kgsl_device *device,
{
unsigned int num_freqs;
u16 vlvl_tbl[MAX_GX_LEVELS];
unsigned int *freq_tbl;
int i;
struct dev_pm_opp *opp;
if (type == GMU_ARC_VOTE)
return rpmh_gmu_arc_votes_init(gmu, pri_rail, sec_rail);
num_freqs = gmu->num_gpupwrlevels;
freq_tbl = gmu->gpu_freqs;
if (num_freqs > pri_rail->num || num_freqs > MAX_GX_LEVELS) {
if (num_freqs > pri_rail->num) {
dev_err(&gmu->pdev->dev,
"Defined more GPU DCVS levels than RPMh can support\n");
return -EINVAL;
}
memset(vlvl_tbl, 0, sizeof(vlvl_tbl));
/* Get the values from OPP API */
for (i = 0; i < num_freqs; i++) {
/* Hardcode VLVL 0 because it is not present in OPP */
if (freq_tbl[i] == 0) {
vlvl_tbl[i] = 0;
continue;
}
opp = dev_pm_opp_find_freq_exact(&device->pdev->dev,
freq_tbl[i], true);
if (IS_ERR(opp)) {
dev_err(&gmu->pdev->dev,
"Failed to find opp freq %d for GPU\n",
freq_tbl[i]);
return PTR_ERR(opp);
}
vlvl_tbl[i] = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
}
for (i = 0; i < num_freqs; i++)
vlvl_tbl[i] = gmu->pwrlevels[i].level;
return setup_volt_dependency_tbl(gmu->rpmh_votes.gx_votes, pri_rail,
sec_rail, vlvl_tbl, num_freqs);
@ -978,34 +943,6 @@ static int gmu_reg_probe(struct kgsl_device *device)
return 0;
}
static int gmu_clocks_probe(struct gmu_device *gmu, struct device_node *node)
{
const char *cname;
struct property *prop;
struct clk *c;
int i = 0;
of_property_for_each_string(node, "clock-names", prop, cname) {
c = devm_clk_get(&gmu->pdev->dev, cname);
if (IS_ERR(c)) {
dev_err(&gmu->pdev->dev,
"dt: Couldn't get GMU clock: %s\n", cname);
return PTR_ERR(c);
}
if (i >= MAX_GMU_CLKS) {
dev_err(&gmu->pdev->dev,
"dt: too many GMU clocks defined\n");
return -EINVAL;
}
gmu->clks[i++] = c;
}
return 0;
}
static int gmu_regulators_probe(struct gmu_device *gmu,
struct device_node *node)
{
@ -1218,7 +1155,7 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
struct kgsl_hfi *hfi;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i = 0, ret = -ENXIO, index = 0;
int i = 0, ret = -ENXIO, index;
gmu = kzalloc(sizeof(struct gmu_device), GFP_KERNEL);
@ -1242,11 +1179,20 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
if (ret)
goto error;
/* Set up GMU clocks */
ret = gmu_clocks_probe(gmu, node);
if (ret)
ret = devm_clk_bulk_get_all(&gmu->pdev->dev, &gmu->clks);
if (ret < 0)
goto error;
gmu->num_clks = ret;
/* Get a pointer to the GMU clock */
gmu->gmu_clk = kgsl_of_clk_by_name(gmu->clks, gmu->num_clks, "gmu_clk");
if (!gmu->gmu_clk) {
dev_err(&gmu->pdev->dev, "Couldn't get gmu_clk\n");
ret = -ENODEV;
goto error;
}
/* Set up GMU IOMMU and shared memory with GMU */
ret = gmu_iommu_init(gmu, node);
if (ret)
@ -1288,12 +1234,21 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node)
tasklet_init(&hfi->tasklet, hfi_receiver, (unsigned long) gmu);
hfi->kgsldev = device;
/* Add a dummy level for "off" that the GMU expects */
gmu->gpu_freqs[index++] = 0;
if (WARN(pwr->num_pwrlevels + 1 > ARRAY_SIZE(gmu->pwrlevels),
"Too many GPU powerlevels for the GMU HFI\n")) {
ret = -EINVAL;
goto error;
}
/* Add a dummy level for "off" because the GMU expects it */
gmu->pwrlevels[0].freq = 0;
gmu->pwrlevels[0].level = 0;
/* GMU power levels are in ascending order */
for (i = pwr->num_pwrlevels - 1; i >= 0; i--)
gmu->gpu_freqs[index++] = pwr->pwrlevels[i].gpu_freq;
for (index = 1, i = pwr->num_pwrlevels - 1; i >= 0; i--, index++) {
gmu->pwrlevels[index].freq = pwr->pwrlevels[i].gpu_freq;
gmu->pwrlevels[index].level = pwr->pwrlevels[i].voltage_level;
}
gmu->num_gpupwrlevels = pwr->num_pwrlevels + 1;
@ -1331,48 +1286,30 @@ error:
static int gmu_enable_clks(struct kgsl_device *device)
{
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
int ret, j = 0;
int ret;
if (IS_ERR_OR_NULL(gmu->clks[0]))
return -EINVAL;
ret = clk_set_rate(gmu->clks[0], GMU_FREQUENCY);
ret = clk_set_rate(gmu->gmu_clk, GMU_FREQUENCY);
if (ret) {
dev_err(&gmu->pdev->dev, "fail to set default GMU clk freq %d\n",
GMU_FREQUENCY);
dev_err(&gmu->pdev->dev, "Unable to set GMU clock\n");
return ret;
}
while ((j < MAX_GMU_CLKS) && gmu->clks[j]) {
ret = clk_prepare_enable(gmu->clks[j]);
if (ret) {
dev_err(&gmu->pdev->dev,
"fail to enable gpucc clk idx %d\n",
j);
return ret;
}
j++;
ret = clk_bulk_prepare_enable(gmu->num_clks, gmu->clks);
if (ret) {
dev_err(&gmu->pdev->dev, "Cannot enable GMU clocks\n");
return ret;
}
set_bit(GMU_CLK_ON, &device->gmu_core.flags);
return 0;
}
static int gmu_disable_clks(struct kgsl_device *device)
static void gmu_disable_clks(struct kgsl_device *device)
{
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
int j = 0;
if (IS_ERR_OR_NULL(gmu->clks[0]))
return 0;
while ((j < MAX_GMU_CLKS) && gmu->clks[j]) {
clk_disable_unprepare(gmu->clks[j]);
j++;
}
clk_bulk_disable_unprepare(gmu->num_clks, gmu->clks);
clear_bit(GMU_CLK_ON, &device->gmu_core.flags);
return 0;
}
@ -1619,7 +1556,6 @@ static void gmu_remove(struct kgsl_device *device)
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct gmu_device *gmu = KGSL_GMU_DEVICE(device);
struct kgsl_hfi *hfi;
int i = 0;
if (gmu == NULL || gmu->pdev == NULL)
return;
@ -1635,11 +1571,6 @@ static void gmu_remove(struct kgsl_device *device)
clear_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag);
while ((i < MAX_GMU_CLKS) && gmu->clks[i]) {
gmu->clks[i] = NULL;
i++;
}
icc_put(gmu->icc_path);
if (gmu->fw_image) {
@ -1649,13 +1580,6 @@ static void gmu_remove(struct kgsl_device *device)
gmu_memory_close(gmu);
for (i = 0; i < MAX_GMU_CLKS; i++) {
if (gmu->clks[i]) {
devm_clk_put(&gmu->pdev->dev, gmu->clks[i]);
gmu->clks[i] = NULL;
}
}
if (gmu->gx_gdsc) {
devm_regulator_put(gmu->gx_gdsc);
gmu->gx_gdsc = NULL;

View file

@ -158,7 +158,6 @@ struct icc_path;
* @dump_mem: pointer to GMU debug dump memory
* @gmu_log: gmu event log memory
* @hfi: HFI controller
* @gpu_freqs: GPU frequency table with lowest freq at index 0
* @num_gpupwrlevels: number GPU frequencies in GPU freq table
* @num_bwlevel: number of GPU BW levels
* @num_cnocbwlevel: number CNOC BW levels
@ -194,14 +193,24 @@ struct gmu_device {
struct gmu_memdesc *dump_mem;
struct gmu_memdesc *gmu_log;
struct kgsl_hfi hfi;
unsigned int gpu_freqs[MAX_GX_LEVELS];
/** @pwrlevels: Array of GMU power levels */
struct {
/** @freq: GPU frequency */
unsigned long freq;
/** @level: Voltage level */
u32 level;
} pwrlevels[MAX_GX_LEVELS];
unsigned int num_gpupwrlevels;
unsigned int num_bwlevels;
unsigned int num_cnocbwlevels;
struct rpmh_votes_t rpmh_votes;
struct regulator *cx_gdsc;
struct regulator *gx_gdsc;
struct clk *clks[MAX_GMU_CLKS];
struct clk_bulk_data *clks;
/** @num_clks: Number of entries in the @clks array */
int num_clks;
/** @gmu_clk: Pointer to the core GMU clock */
struct clk *gmu_clk;
enum gmu_load_mode load_mode;
unsigned int wakeup_pwrlevel;
unsigned int pcl;

View file

@ -21,8 +21,6 @@
#error "CNOC levels cannot exceed GX levels"
#endif
#define MAX_GMU_CLKS 6
/*
* These are the different ways the GMU can boot. GMU_WARM_BOOT is waking up
* from slumber. GMU_COLD_BOOT is booting for the first time. GMU_RESET

View file

@ -437,7 +437,7 @@ static int hfi_send_dcvstbl_v1(struct gmu_device *gmu)
for (i = 0; i < gmu->num_gpupwrlevels; i++) {
cmd.gx_votes[i].vote = gmu->rpmh_votes.gx_votes[i];
/* Divide by 1000 to convert to kHz */
cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000;
cmd.gx_votes[i].freq = gmu->pwrlevels[i].freq / 1000;
}
cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0];
@ -483,7 +483,7 @@ static int hfi_send_dcvstbl(struct gmu_device *gmu)
/* Hardcode this to the max threshold since it is not used */
cmd.gx_votes[i].acd = 0xFFFFFFFF;
/* Divide by 1000 to convert to kHz */
cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000;
cmd.gx_votes[i].freq = gmu->pwrlevels[i].freq / 1000;
}
cmd.cx_votes[0].vote = gmu->rpmh_votes.cx_votes[0];

View file

@ -100,7 +100,7 @@ _kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p)
list_add_tail(&p->lru, &pool->page_list);
pool->page_count++;
spin_unlock(&pool->list_lock);
mod_node_page_state(page_pgdat(p), NR_INDIRECTLY_RECLAIMABLE_BYTES,
mod_node_page_state(page_pgdat(p), NR_KERNEL_MISC_RECLAIMABLE,
(PAGE_SIZE << pool->pool_order));
}
@ -117,7 +117,7 @@ _kgsl_pool_get_page(struct kgsl_page_pool *pool)
list_del(&p->lru);
}
spin_unlock(&pool->list_lock);
mod_node_page_state(page_pgdat(p), NR_INDIRECTLY_RECLAIMABLE_BYTES,
mod_node_page_state(page_pgdat(p), NR_KERNEL_MISC_RECLAIMABLE,
-(PAGE_SIZE << pool->pool_order));
return p;
}
@ -256,20 +256,12 @@ void kgsl_pool_free_pages(struct page **pages, unsigned int pcount)
if (!pages)
return;
if (WARN(!kern_addr_valid((unsigned long)pages),
"Address of pages=%pK is not valid\n", pages))
return;
for (i = 0; i < pcount;) {
/*
* Free each page or compound page group individually.
*/
struct page *p = pages[i];
if (WARN(!kern_addr_valid((unsigned long)p),
"Address of page=%pK is not valid\n", p))
return;
i += 1 << compound_order(p);
kgsl_pool_free_page(p);
}

View file

@ -1584,43 +1584,6 @@ static int kgsl_pwrctrl_clk_set_rate(struct clk *grp_clk, unsigned int freq,
return ret;
}
static bool _gpu_freq_supported(struct kgsl_pwrctrl *pwr, unsigned int freq)
{
int i;
for (i = pwr->num_pwrlevels - 1; i >= 0; i--) {
if (pwr->pwrlevels[i].gpu_freq == freq)
return true;
}
return false;
}
void kgsl_pwrctrl_disable_unused_opp(struct kgsl_device *device,
struct device *dev)
{
struct dev_pm_opp *opp;
unsigned long freq = 0;
int ret;
ret = dev_pm_opp_get_opp_count(dev);
/* Return early, If no OPP table or OPP count is zero */
if (ret <= 0)
return;
while (1) {
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
if (IS_ERR(opp))
break;
if (!_gpu_freq_supported(&device->pwrctrl, freq))
dev_pm_opp_disable(dev, freq);
dev_pm_opp_put(opp);
freq++;
}
}
static u32 *kgsl_bus_get_table(struct platform_device *pdev, int *count)
{
u32 *levels;
@ -1702,8 +1665,6 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
pwr->pwrlevels[i].gpu_freq = freq;
}
kgsl_pwrctrl_disable_unused_opp(device, &pdev->dev);
kgsl_clk_set_rate(device, pwr->num_pwrlevels - 1);
freq = clk_round_rate(pwr->grp_clks[6], KGSL_RBBMTIMER_CLK_FREQ);

View file

@ -69,6 +69,8 @@ struct kgsl_pwrlevel {
unsigned int bus_min;
unsigned int bus_max;
unsigned int acd_level;
/** @voltage_level: Voltage level used by the GMU to vote RPMh */
u32 voltage_level;
};
/**
@ -196,7 +198,5 @@ void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy);
void kgsl_pwrctrl_set_constraint(struct kgsl_device *device,
struct kgsl_pwr_constraint *pwrc, uint32_t id);
int kgsl_pwrctrl_set_default_gpu_pwrlevel(struct kgsl_device *device);
void kgsl_pwrctrl_disable_unused_opp(struct kgsl_device *device,
struct device *dev);
#endif /* __KGSL_PWRCTRL_H */

View file

@ -357,32 +357,15 @@ kgsl_sharedmem_init_sysfs(void)
return sysfs_create_files(&kgsl_driver.virtdev.kobj, drv_attr_list);
}
static int kgsl_paged_vmfault(struct kgsl_memdesc *memdesc,
static vm_fault_t kgsl_paged_vmfault(struct kgsl_memdesc *memdesc,
struct vm_area_struct *vma,
struct vm_fault *vmf)
{
int pgoff;
unsigned int offset;
offset = vmf->address - vma->vm_start;
pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
if (offset >= memdesc->size)
return VM_FAULT_SIGBUS;
pgoff = offset >> PAGE_SHIFT;
if (pgoff < memdesc->page_count) {
struct page *page = memdesc->pages[pgoff];
get_page(page);
vmf->page = page;
memdesc->mapsize += PAGE_SIZE;
return 0;
}
return VM_FAULT_SIGBUS;
return vmf_insert_page(vma, vmf->address, memdesc->pages[pgoff]);
}
static void kgsl_paged_unmap_kernel(struct kgsl_memdesc *memdesc)
@ -495,27 +478,17 @@ static int kgsl_paged_map_kernel(struct kgsl_memdesc *memdesc)
return ret;
}
static int kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc,
static vm_fault_t kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc,
struct vm_area_struct *vma,
struct vm_fault *vmf)
{
unsigned long offset, pfn;
int ret;
offset = ((unsigned long) vmf->address - vma->vm_start) >>
PAGE_SHIFT;
pfn = (memdesc->physaddr >> PAGE_SHIFT) + offset;
ret = vm_insert_pfn(vma, (unsigned long) vmf->address, pfn);
if (ret == -ENOMEM || ret == -EAGAIN)
return VM_FAULT_OOM;
else if (ret == -EFAULT)
return VM_FAULT_SIGBUS;
memdesc->mapsize += PAGE_SIZE;
return VM_FAULT_NOPAGE;
return vmf_insert_pfn(vma, vmf->address, pfn);
}
#ifdef CONFIG_ARM64
@ -1054,7 +1027,7 @@ static struct kgsl_memdesc_ops kgsl_secure_pool_ops = {
static struct kgsl_memdesc_ops kgsl_pool_ops = {
.free = kgsl_free_pool_pages,
.vmflags = VM_DONTDUMP | VM_DONTEXPAND | VM_DONTCOPY,
.vmflags = VM_DONTDUMP | VM_DONTEXPAND | VM_DONTCOPY | VM_MIXEDMAP,
.vmfault = kgsl_paged_vmfault,
.map_kernel = kgsl_paged_map_kernel,
.unmap_kernel = kgsl_paged_unmap_kernel,

View file

@ -3,9 +3,13 @@
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/regulator/consumer.h>
#include <linux/string.h>
#include "kgsl_util.h"
@ -25,3 +29,15 @@ bool kgsl_regulator_disable_wait(struct regulator *reg, u32 timeout)
usleep_range((100 >> 2) + 1, 100);
}
}
struct clk *kgsl_of_clk_by_name(struct clk_bulk_data *clks, int count,
const char *id)
{
int i;
for (i = 0; clks && i < count; i++)
if (!strcmp(clks[i].id, id))
return clks[i].clk;
return NULL;
}

View file

@ -7,6 +7,7 @@
#define _KGSL_UTIL_H_
struct regulator;
struct clk_bulk_data;
/**
* kgsl_regulator_disable_wait - Disable a regulator and wait for it
@ -20,4 +21,15 @@ struct regulator;
*/
bool kgsl_regulator_disable_wait(struct regulator *reg, u32 timeout);
/**
* kgsl_of_clk_by_name - Return a clock device for a given name
* @clks: Pointer to an array of bulk clk data
* @count: Number of entries in the array
* @id: Name of the clock to search for
*
* Returns: A pointer to the clock device for the given name or NULL if not
* found
*/
struct clk *kgsl_of_clk_by_name(struct clk_bulk_data *clks, int count,
const char *id);
#endif