mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-13 08:07:32 -04:00
Merge "msm: kgsl: Cleanup the device tree probing for memory pools"
This commit is contained in:
commit
9275751079
10 changed files with 272 additions and 317 deletions
|
|
@ -223,15 +223,14 @@ unsigned int adreno_get_rptr(struct adreno_ringbuffer *rb)
|
|||
static void __iomem *efuse_base;
|
||||
static size_t efuse_len;
|
||||
|
||||
int adreno_efuse_map(struct adreno_device *adreno_dev)
|
||||
int adreno_efuse_map(struct platform_device *pdev)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
struct resource *res;
|
||||
|
||||
if (efuse_base != NULL)
|
||||
return 0;
|
||||
|
||||
res = platform_get_resource_byname(device->pdev, IORESOURCE_MEM,
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"qfprom_memory");
|
||||
|
||||
if (res == NULL)
|
||||
|
|
@ -245,7 +244,7 @@ int adreno_efuse_map(struct adreno_device *adreno_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void adreno_efuse_unmap(struct adreno_device *adreno_dev)
|
||||
void adreno_efuse_unmap(void)
|
||||
{
|
||||
if (efuse_base != NULL) {
|
||||
iounmap(efuse_base);
|
||||
|
|
@ -254,8 +253,7 @@ void adreno_efuse_unmap(struct adreno_device *adreno_dev)
|
|||
}
|
||||
}
|
||||
|
||||
int adreno_efuse_read_u32(struct adreno_device *adreno_dev, unsigned int offset,
|
||||
unsigned int *val)
|
||||
int adreno_efuse_read_u32(unsigned int offset, unsigned int *val)
|
||||
{
|
||||
if (efuse_base == NULL)
|
||||
return -ENODEV;
|
||||
|
|
@ -263,11 +261,9 @@ int adreno_efuse_read_u32(struct adreno_device *adreno_dev, unsigned int offset,
|
|||
if (offset >= efuse_len)
|
||||
return -ERANGE;
|
||||
|
||||
if (val != NULL) {
|
||||
*val = readl_relaxed(efuse_base + offset);
|
||||
/* Make sure memory is updated before returning */
|
||||
rmb();
|
||||
}
|
||||
*val = readl_relaxed(efuse_base + offset);
|
||||
/* Make sure memory is updated before returning */
|
||||
rmb();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1256,27 +1252,28 @@ static void adreno_isense_probe(struct kgsl_device *device)
|
|||
|
||||
static void adreno_efuse_read_soc_hw_rev(struct adreno_device *adreno_dev)
|
||||
{
|
||||
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
|
||||
unsigned int val;
|
||||
unsigned int soc_hw_rev[3];
|
||||
int ret;
|
||||
|
||||
if (of_property_read_u32_array(
|
||||
KGSL_DEVICE(adreno_dev)->pdev->dev.of_node,
|
||||
device->pdev->dev.of_node,
|
||||
"qcom,soc-hw-rev-efuse", soc_hw_rev, 3))
|
||||
return;
|
||||
|
||||
ret = adreno_efuse_map(adreno_dev);
|
||||
ret = adreno_efuse_map(device->pdev);
|
||||
if (ret) {
|
||||
dev_err(KGSL_DEVICE(adreno_dev)->dev,
|
||||
dev_err(device->dev,
|
||||
"Unable to map hardware revision fuse: ret=%d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = adreno_efuse_read_u32(adreno_dev, soc_hw_rev[0], &val);
|
||||
adreno_efuse_unmap(adreno_dev);
|
||||
ret = adreno_efuse_read_u32(soc_hw_rev[0], &val);
|
||||
adreno_efuse_unmap();
|
||||
|
||||
if (ret) {
|
||||
dev_err(KGSL_DEVICE(adreno_dev)->dev,
|
||||
dev_err(device->dev,
|
||||
"Unable to read hardware revision fuse: ret=%d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1298,11 +1295,11 @@ static bool adreno_is_gpu_disabled(struct adreno_device *adreno_dev)
|
|||
* Read the fuse value to disable GPU driver if fuse
|
||||
* is blown. By default(fuse value is 0) GPU is enabled.
|
||||
*/
|
||||
if (adreno_efuse_map(adreno_dev))
|
||||
if (adreno_efuse_map(device->pdev))
|
||||
return false;
|
||||
|
||||
ret = adreno_efuse_read_u32(adreno_dev, pte_row0_msb[0], &row0);
|
||||
adreno_efuse_unmap(adreno_dev);
|
||||
ret = adreno_efuse_read_u32(pte_row0_msb[0], &row0);
|
||||
adreno_efuse_unmap();
|
||||
|
||||
if (ret)
|
||||
return false;
|
||||
|
|
@ -1822,7 +1819,7 @@ static void _set_secvid(struct kgsl_device *device)
|
|||
}
|
||||
}
|
||||
|
||||
static int adreno_switch_to_unsecure_mode(struct adreno_device *adreno_dev,
|
||||
int adreno_switch_to_unsecure_mode(struct adreno_device *adreno_dev,
|
||||
struct adreno_ringbuffer *rb)
|
||||
{
|
||||
unsigned int *cmds;
|
||||
|
|
@ -1844,31 +1841,6 @@ static int adreno_switch_to_unsecure_mode(struct adreno_device *adreno_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int adreno_set_unsecured_mode(struct adreno_device *adreno_dev,
|
||||
struct adreno_ringbuffer *rb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!adreno_is_a5xx(adreno_dev) && !adreno_is_a6xx(adreno_dev))
|
||||
return -EINVAL;
|
||||
|
||||
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CRITICAL_PACKETS) &&
|
||||
adreno_is_a5xx(adreno_dev)) {
|
||||
ret = a5xx_critical_packet_submit(adreno_dev, rb);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* GPU comes up in secured mode, make it unsecured by default */
|
||||
if (adreno_dev->zap_loaded)
|
||||
ret = adreno_switch_to_unsecure_mode(adreno_dev, rb);
|
||||
else
|
||||
adreno_writereg(adreno_dev,
|
||||
ADRENO_REG_RBBM_SECVID_TRUST_CONTROL, 0x0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev)
|
||||
{
|
||||
int i;
|
||||
|
|
|
|||
|
|
@ -663,8 +663,6 @@ enum adreno_regs {
|
|||
ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI,
|
||||
ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO,
|
||||
ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,
|
||||
ADRENO_REG_RBBM_SECVID_TRUST_CONTROL,
|
||||
ADRENO_REG_RBBM_SECVID_TRUST_CONFIG,
|
||||
ADRENO_REG_RBBM_SECVID_TSB_CONTROL,
|
||||
ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
|
||||
ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI,
|
||||
|
|
@ -913,10 +911,17 @@ long adreno_ioctl_helper(struct kgsl_device_private *dev_priv,
|
|||
unsigned int cmd, unsigned long arg,
|
||||
const struct kgsl_ioctl *cmds, int len);
|
||||
|
||||
int a5xx_critical_packet_submit(struct adreno_device *adreno_dev,
|
||||
struct adreno_ringbuffer *rb);
|
||||
int adreno_set_unsecured_mode(struct adreno_device *adreno_dev,
|
||||
struct adreno_ringbuffer *rb);
|
||||
/*
|
||||
* adreno_switch_to_unsecure_mode - Execute a zap shader
|
||||
* @adreno_dev: An Adreno GPU handle
|
||||
* @rb: The ringbuffer to execute on
|
||||
*
|
||||
* Execute the zap shader from the CP to take the GPU out of secure mode.
|
||||
* Return: 0 on success or negative on failure
|
||||
*/
|
||||
int adreno_switch_to_unsecure_mode(struct adreno_device *adreno_dev,
|
||||
struct adreno_ringbuffer *rb);
|
||||
|
||||
void adreno_spin_idle_debug(struct adreno_device *adreno_dev, const char *str);
|
||||
int adreno_spin_idle(struct adreno_device *device, unsigned int timeout);
|
||||
int adreno_idle(struct kgsl_device *device);
|
||||
|
|
@ -955,10 +960,9 @@ long adreno_ioctl_perfcounter_get(struct kgsl_device_private *dev_priv,
|
|||
long adreno_ioctl_perfcounter_put(struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data);
|
||||
|
||||
int adreno_efuse_map(struct adreno_device *adreno_dev);
|
||||
int adreno_efuse_read_u32(struct adreno_device *adreno_dev, unsigned int offset,
|
||||
unsigned int *val);
|
||||
void adreno_efuse_unmap(struct adreno_device *adreno_dev);
|
||||
int adreno_efuse_map(struct platform_device *pdev);
|
||||
int adreno_efuse_read_u32(unsigned int offset, unsigned int *val);
|
||||
void adreno_efuse_unmap(void);
|
||||
|
||||
bool adreno_is_cx_dbgc_register(struct kgsl_device *device,
|
||||
unsigned int offset);
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ static void a3xx_efuse_speed_bin(struct adreno_device *adreno_dev)
|
|||
"qcom,gpu-speed-bin", speed_bin, 3))
|
||||
return;
|
||||
|
||||
adreno_efuse_read_u32(adreno_dev, speed_bin[0], &val);
|
||||
adreno_efuse_read_u32(speed_bin[0], &val);
|
||||
|
||||
adreno_dev->speed_bin = (val & speed_bin[1]) >> speed_bin[2];
|
||||
}
|
||||
|
|
@ -151,7 +151,7 @@ static void a3xx_check_features(struct adreno_device *adreno_dev)
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
if (adreno_efuse_map(adreno_dev))
|
||||
if (adreno_efuse_map(KGSL_DEVICE(adreno_dev)->pdev))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(a3xx_efuse_funcs); i++) {
|
||||
|
|
@ -159,7 +159,7 @@ static void a3xx_check_features(struct adreno_device *adreno_dev)
|
|||
a3xx_efuse_funcs[i].func(adreno_dev);
|
||||
}
|
||||
|
||||
adreno_efuse_unmap(adreno_dev);
|
||||
adreno_efuse_unmap();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -49,11 +49,9 @@ static void a530_efuse_leakage(struct adreno_device *adreno_dev)
|
|||
unsigned int row0, row2;
|
||||
unsigned int multiplier, gfx_active, leakage_pwr_on, coeff;
|
||||
|
||||
adreno_efuse_read_u32(adreno_dev,
|
||||
A530_QFPROM_RAW_PTE_ROW0_MSB, &row0);
|
||||
adreno_efuse_read_u32(A530_QFPROM_RAW_PTE_ROW0_MSB, &row0);
|
||||
|
||||
adreno_efuse_read_u32(adreno_dev,
|
||||
A530_QFPROM_RAW_PTE_ROW2_MSB, &row2);
|
||||
adreno_efuse_read_u32(A530_QFPROM_RAW_PTE_ROW2_MSB, &row2);
|
||||
|
||||
multiplier = (row0 >> 1) & 0x3;
|
||||
gfx_active = (row2 >> 2) & 0xFF;
|
||||
|
|
@ -78,7 +76,7 @@ static void a530_efuse_speed_bin(struct adreno_device *adreno_dev)
|
|||
"qcom,gpu-speed-bin", speed_bin, 3))
|
||||
return;
|
||||
|
||||
adreno_efuse_read_u32(adreno_dev, speed_bin[0], &val);
|
||||
adreno_efuse_read_u32(speed_bin[0], &val);
|
||||
|
||||
adreno_dev->speed_bin = (val & speed_bin[1]) >> speed_bin[2];
|
||||
}
|
||||
|
|
@ -98,7 +96,7 @@ static void a5xx_check_features(struct adreno_device *adreno_dev)
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
if (adreno_efuse_map(adreno_dev))
|
||||
if (adreno_efuse_map(KGSL_DEVICE(adreno_dev)->pdev))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(a5xx_efuse_funcs); i++) {
|
||||
|
|
@ -106,7 +104,7 @@ static void a5xx_check_features(struct adreno_device *adreno_dev)
|
|||
a5xx_efuse_funcs[i].func(adreno_dev);
|
||||
}
|
||||
|
||||
adreno_efuse_unmap(adreno_dev);
|
||||
adreno_efuse_unmap();
|
||||
}
|
||||
|
||||
static void a5xx_platform_setup(struct adreno_device *adreno_dev)
|
||||
|
|
@ -1811,7 +1809,7 @@ static void _set_ordinals(struct adreno_device *adreno_dev,
|
|||
*cmds++ = 0x0;
|
||||
}
|
||||
|
||||
int a5xx_critical_packet_submit(struct adreno_device *adreno_dev,
|
||||
static int a5xx_critical_packet_submit(struct adreno_device *adreno_dev,
|
||||
struct adreno_ringbuffer *rb)
|
||||
{
|
||||
unsigned int *cmds;
|
||||
|
|
@ -1907,8 +1905,22 @@ static int a5xx_rb_start(struct adreno_device *adreno_dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* GPU comes up in secured mode, make it unsecured by default */
|
||||
ret = adreno_set_unsecured_mode(adreno_dev, rb);
|
||||
/* Run the critical packets if we need to */
|
||||
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_CRITICAL_PACKETS)) {
|
||||
ret = a5xx_critical_packet_submit(adreno_dev, rb);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to execute the zap shader if it exists, otherwise just try
|
||||
* directly writing to the control register
|
||||
*/
|
||||
if (!adreno_dev->zap_loaded)
|
||||
kgsl_regwrite(device, A5XX_RBBM_SECVID_TRUST_CNTL, 0);
|
||||
else
|
||||
ret = adreno_switch_to_unsecure_mode(adreno_dev, rb);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -2433,10 +2445,6 @@ static unsigned int a5xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
|
|||
A5XX_RBBM_PERFCTR_LOAD_VALUE_LO),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,
|
||||
A5XX_RBBM_PERFCTR_LOAD_VALUE_HI),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TRUST_CONTROL,
|
||||
A5XX_RBBM_SECVID_TRUST_CNTL),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TRUST_CONFIG,
|
||||
A5XX_RBBM_SECVID_TRUST_CONFIG),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TSB_CONTROL,
|
||||
A5XX_RBBM_SECVID_TSB_CNTL),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
|
||||
|
|
|
|||
|
|
@ -816,8 +816,15 @@ static int a6xx_rb_start(struct adreno_device *adreno_dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* GPU comes up in secured mode, make it unsecured by default */
|
||||
ret = adreno_set_unsecured_mode(adreno_dev, rb);
|
||||
/*
|
||||
* Take the GPU out of secure mode. Try the zap shader if it is loaded,
|
||||
* otherwise just try to write directly to the secure control register
|
||||
*/
|
||||
if (!adreno_dev->zap_loaded)
|
||||
kgsl_regwrite(device, A6XX_RBBM_SECVID_TRUST_CNTL, 0);
|
||||
else
|
||||
ret = adreno_switch_to_unsecure_mode(adreno_dev, rb);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -2168,7 +2175,7 @@ static void a6xx_efuse_speed_bin(struct adreno_device *adreno_dev)
|
|||
"qcom,gpu-speed-bin", speed_bin, 3))
|
||||
return;
|
||||
|
||||
adreno_efuse_read_u32(adreno_dev, speed_bin[0], &val);
|
||||
adreno_efuse_read_u32(speed_bin[0], &val);
|
||||
|
||||
adreno_dev->speed_bin = (val & speed_bin[1]) >> speed_bin[2];
|
||||
}
|
||||
|
|
@ -2185,14 +2192,14 @@ static void a6xx_check_features(struct adreno_device *adreno_dev)
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
if (adreno_efuse_map(adreno_dev))
|
||||
if (adreno_efuse_map(KGSL_DEVICE(adreno_dev)->pdev))
|
||||
return;
|
||||
for (i = 0; i < ARRAY_SIZE(a6xx_efuse_funcs); i++) {
|
||||
if (a6xx_efuse_funcs[i].check(adreno_dev))
|
||||
a6xx_efuse_funcs[i].func(adreno_dev);
|
||||
}
|
||||
|
||||
adreno_efuse_unmap(adreno_dev);
|
||||
adreno_efuse_unmap();
|
||||
}
|
||||
static void a6xx_platform_setup(struct adreno_device *adreno_dev)
|
||||
{
|
||||
|
|
@ -2370,8 +2377,6 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
|
|||
A6XX_GMU_CM3_CFG),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_GMU_RBBM_INT_UNMASKED_STATUS,
|
||||
A6XX_GMU_RBBM_INT_UNMASKED_STATUS),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TRUST_CONTROL,
|
||||
A6XX_RBBM_SECVID_TRUST_CNTL),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
|
||||
A6XX_RBBM_SECVID_TSB_TRUSTED_BASE_LO),
|
||||
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "kgsl_debugfs.h"
|
||||
#include "kgsl_device.h"
|
||||
#include "kgsl_mmu.h"
|
||||
#include "kgsl_pool.h"
|
||||
#include "kgsl_sync.h"
|
||||
#include "kgsl_trace.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -12,15 +12,10 @@
|
|||
#include "kgsl_pool.h"
|
||||
#include "kgsl_sharedmem.h"
|
||||
|
||||
#define KGSL_MAX_POOLS 4
|
||||
#define KGSL_MAX_POOL_ORDER 8
|
||||
#define KGSL_MAX_RESERVED_PAGES 4096
|
||||
|
||||
/**
|
||||
* struct kgsl_page_pool - Structure to hold information for the pool
|
||||
* @pool_order: Page order describing the size of the page
|
||||
* @page_count: Number of pages currently present in the pool
|
||||
* @reserved_pages: Number of pages reserved at init for the pool
|
||||
* @allocation_allowed: Tells if reserved pool gets exhausted, can we allocate
|
||||
* from system memory
|
||||
* @list_lock: Spinlock for page list in the pool
|
||||
|
|
@ -29,29 +24,37 @@
|
|||
struct kgsl_page_pool {
|
||||
unsigned int pool_order;
|
||||
int page_count;
|
||||
unsigned int reserved_pages;
|
||||
bool allocation_allowed;
|
||||
spinlock_t list_lock;
|
||||
struct list_head page_list;
|
||||
};
|
||||
|
||||
static struct kgsl_page_pool kgsl_pools[KGSL_MAX_POOLS];
|
||||
static struct kgsl_page_pool kgsl_pools[4];
|
||||
static int kgsl_num_pools;
|
||||
static int kgsl_pool_max_pages;
|
||||
|
||||
static void kgsl_pool_free_page(struct page *page);
|
||||
|
||||
/* Returns KGSL pool corresponding to input page order*/
|
||||
static struct kgsl_page_pool *
|
||||
_kgsl_get_pool_from_order(unsigned int order)
|
||||
/* Return the index of the pool for the specified order */
|
||||
static int kgsl_get_pool_index(int order)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < kgsl_num_pools; i++) {
|
||||
if (kgsl_pools[i].pool_order == order)
|
||||
return &kgsl_pools[i];
|
||||
return i;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Returns KGSL pool corresponding to input page order*/
|
||||
static struct kgsl_page_pool *
|
||||
_kgsl_get_pool_from_order(int order)
|
||||
{
|
||||
int index = kgsl_get_pool_index(order);
|
||||
|
||||
return index >= 0 ? &kgsl_pools[index] : NULL;
|
||||
}
|
||||
|
||||
/* Map the page into kernel and zero it out */
|
||||
|
|
@ -74,6 +77,9 @@ _kgsl_pool_zero_page(struct page *p, unsigned int pool_order)
|
|||
static void
|
||||
_kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p)
|
||||
{
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
_kgsl_pool_zero_page(p, pool->pool_order);
|
||||
|
||||
spin_lock(&pool->list_lock);
|
||||
|
|
@ -102,27 +108,20 @@ _kgsl_pool_get_page(struct kgsl_page_pool *pool)
|
|||
return p;
|
||||
}
|
||||
|
||||
/* Returns the number of pages in specified pool */
|
||||
static int
|
||||
kgsl_pool_size(struct kgsl_page_pool *kgsl_pool)
|
||||
{
|
||||
int size;
|
||||
|
||||
spin_lock(&kgsl_pool->list_lock);
|
||||
size = kgsl_pool->page_count * (1 << kgsl_pool->pool_order);
|
||||
spin_unlock(&kgsl_pool->list_lock);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Returns the number of pages in all kgsl page pools */
|
||||
static int kgsl_pool_size_total(void)
|
||||
{
|
||||
int i;
|
||||
int total = 0;
|
||||
|
||||
for (i = 0; i < kgsl_num_pools; i++)
|
||||
total += kgsl_pool_size(&kgsl_pools[i]);
|
||||
for (i = 0; i < kgsl_num_pools; i++) {
|
||||
struct kgsl_page_pool *kgsl_pool = &kgsl_pools[i];
|
||||
|
||||
spin_lock(&kgsl_pool->list_lock);
|
||||
total += kgsl_pool->page_count * (1 << kgsl_pool->pool_order);
|
||||
spin_unlock(&kgsl_pool->list_lock);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
|
@ -142,13 +141,11 @@ _kgsl_pool_shrink(struct kgsl_page_pool *pool, int num_pages)
|
|||
for (j = 0; j < num_pages >> pool->pool_order; j++) {
|
||||
struct page *page = _kgsl_pool_get_page(pool);
|
||||
|
||||
if (page != NULL) {
|
||||
__free_pages(page, pool->pool_order);
|
||||
pcount += (1 << pool->pool_order);
|
||||
} else {
|
||||
/* Break as this pool is empty */
|
||||
if (!page)
|
||||
break;
|
||||
}
|
||||
|
||||
__free_pages(page, pool->pool_order);
|
||||
pcount += (1 << pool->pool_order);
|
||||
}
|
||||
|
||||
return pcount;
|
||||
|
|
@ -238,19 +235,11 @@ void kgsl_pool_free_sgt(struct sg_table *sgt)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* kgsl_pool_free_pages() - Free pages in the pages array
|
||||
* @pages: pointer of the pages array
|
||||
*
|
||||
* Free the pages by collapsing any physical adjacent pages.
|
||||
* Pages are added back to the pool, if pool has sufficient space
|
||||
* otherwise they are given back to system.
|
||||
*/
|
||||
void kgsl_pool_free_pages(struct page **pages, unsigned int pcount)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (pages == NULL || pcount == 0)
|
||||
if (!pages)
|
||||
return;
|
||||
|
||||
if (WARN(!kern_addr_valid((unsigned long)pages),
|
||||
|
|
@ -271,16 +260,6 @@ void kgsl_pool_free_pages(struct page **pages, unsigned int pcount)
|
|||
kgsl_pool_free_page(p);
|
||||
}
|
||||
}
|
||||
static int kgsl_pool_idx_lookup(unsigned int order)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < kgsl_num_pools; i++)
|
||||
if (order == kgsl_pools[i].pool_order)
|
||||
return i;
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int kgsl_pool_get_retry_order(unsigned int order)
|
||||
{
|
||||
|
|
@ -293,9 +272,9 @@ static int kgsl_pool_get_retry_order(unsigned int order)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int kgsl_gfp_mask(unsigned int page_order)
|
||||
static gfp_t kgsl_gfp_mask(int page_order)
|
||||
{
|
||||
unsigned int gfp_mask = __GFP_HIGHMEM;
|
||||
gfp_t gfp_mask = __GFP_HIGHMEM;
|
||||
|
||||
if (page_order > 0) {
|
||||
gfp_mask |= __GFP_COMP | __GFP_NORETRY | __GFP_NOWARN;
|
||||
|
|
@ -309,7 +288,36 @@ static unsigned int kgsl_gfp_mask(unsigned int page_order)
|
|||
return gfp_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Return true if the pool of specified page size is supported
|
||||
* or no pools are supported otherwise return false.
|
||||
*/
|
||||
static bool kgsl_pool_available(unsigned int page_size)
|
||||
{
|
||||
int order = ilog2(page_size >> PAGE_SHIFT);
|
||||
|
||||
if (!kgsl_num_pools)
|
||||
return true;
|
||||
|
||||
return (kgsl_get_pool_index(order) >= 0);
|
||||
}
|
||||
|
||||
static int kgsl_get_page_size(size_t size, unsigned int align)
|
||||
{
|
||||
if (align >= ilog2(SZ_1M) && size >= SZ_1M &&
|
||||
kgsl_pool_available(SZ_1M))
|
||||
return SZ_1M;
|
||||
else if (align >= ilog2(SZ_64K) && size >= SZ_64K &&
|
||||
kgsl_pool_available(SZ_64K))
|
||||
return SZ_64K;
|
||||
else if (align >= ilog2(SZ_8K) && size >= SZ_8K &&
|
||||
kgsl_pool_available(SZ_8K))
|
||||
return SZ_8K;
|
||||
|
||||
return PAGE_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* kgsl_pool_alloc_page() - Allocate a page of requested size
|
||||
* @page_size: Size of the page to be allocated
|
||||
* @pages: pointer to hold list of pages, should be big enough to hold
|
||||
|
|
@ -318,7 +326,7 @@ static unsigned int kgsl_gfp_mask(unsigned int page_order)
|
|||
*
|
||||
* Return total page count on success and negative value on failure
|
||||
*/
|
||||
int kgsl_pool_alloc_page(int *page_size, struct page **pages,
|
||||
static int kgsl_pool_alloc_page(int *page_size, struct page **pages,
|
||||
unsigned int pages_len, unsigned int *align)
|
||||
{
|
||||
int j;
|
||||
|
|
@ -372,7 +380,7 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages,
|
|||
}
|
||||
}
|
||||
|
||||
pool_idx = kgsl_pool_idx_lookup(order);
|
||||
pool_idx = kgsl_get_pool_index(order);
|
||||
page = _kgsl_pool_get_page(pool);
|
||||
|
||||
/* Allocate a new page if not allocated from pool */
|
||||
|
|
@ -413,13 +421,65 @@ done:
|
|||
return pcount;
|
||||
|
||||
eagain:
|
||||
*page_size = kgsl_get_page_size(size,
|
||||
ilog2(size));
|
||||
*page_size = kgsl_get_page_size(size, ilog2(size));
|
||||
*align = ilog2(*page_size);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
void kgsl_pool_free_page(struct page *page)
|
||||
int kgsl_pool_alloc_pages(u64 size, struct page ***pages)
|
||||
{
|
||||
int count = 0;
|
||||
int npages = size >> PAGE_SHIFT;
|
||||
struct page **local = kvcalloc(npages, sizeof(*local), GFP_KERNEL);
|
||||
u32 page_size, align;
|
||||
u64 len = size;
|
||||
|
||||
if (!local)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Start with 1MB alignment to get the biggest page we can */
|
||||
align = ilog2(SZ_1M);
|
||||
|
||||
page_size = kgsl_get_page_size(len, align);
|
||||
|
||||
while (len) {
|
||||
int ret = kgsl_pool_alloc_page(&page_size, &local[count],
|
||||
npages, &align);
|
||||
|
||||
if (ret == -EAGAIN)
|
||||
continue;
|
||||
else if (ret <= 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ) {
|
||||
int n = 1 << compound_order(local[i]);
|
||||
|
||||
kgsl_pool_free_page(local[i]);
|
||||
i += n;
|
||||
}
|
||||
kvfree(local);
|
||||
|
||||
if (!kgsl_sharedmem_get_noretry()) {
|
||||
pr_err_ratelimited("kgsl: out of memory: only allocated %lldKb of %lldKb requested\n",
|
||||
(size - len) >> 10, size >> 10);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
count += ret;
|
||||
npages -= ret;
|
||||
len -= page_size;
|
||||
|
||||
page_size = kgsl_get_page_size(len, align);
|
||||
}
|
||||
|
||||
*pages = local;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void kgsl_pool_free_page(struct page *page)
|
||||
{
|
||||
struct kgsl_page_pool *pool;
|
||||
int page_order;
|
||||
|
|
@ -445,42 +505,6 @@ void kgsl_pool_free_page(struct page *page)
|
|||
__free_pages(page, page_order);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the pool of specified page size is supported
|
||||
* or no pools are supported otherwise return false.
|
||||
*/
|
||||
bool kgsl_pool_avaialable(int page_size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!kgsl_num_pools)
|
||||
return true;
|
||||
|
||||
for (i = 0; i < kgsl_num_pools; i++)
|
||||
if (ilog2(page_size >> PAGE_SHIFT) == kgsl_pools[i].pool_order)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void kgsl_pool_reserve_pages(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < kgsl_num_pools; i++) {
|
||||
struct page *page;
|
||||
|
||||
for (j = 0; j < kgsl_pools[i].reserved_pages; j++) {
|
||||
int order = kgsl_pools[i].pool_order;
|
||||
gfp_t gfp_mask = kgsl_gfp_mask(order);
|
||||
|
||||
page = alloc_pages(gfp_mask, order);
|
||||
if (page != NULL)
|
||||
_kgsl_pool_add_page(&kgsl_pools[i], page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Functions for the shrinker */
|
||||
|
||||
static unsigned long
|
||||
|
|
@ -514,79 +538,86 @@ static struct shrinker kgsl_pool_shrinker = {
|
|||
.batch = 0,
|
||||
};
|
||||
|
||||
static void kgsl_pool_config(unsigned int order, unsigned int reserved_pages,
|
||||
bool allocation_allowed)
|
||||
static void kgsl_pool_reserve_pages(struct kgsl_page_pool *pool,
|
||||
struct device_node *node)
|
||||
{
|
||||
#ifdef CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS
|
||||
if (order > 0) {
|
||||
pr_err("kgsl: pool order:%d not supprted\n", order);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if ((order > KGSL_MAX_POOL_ORDER) ||
|
||||
(reserved_pages > KGSL_MAX_RESERVED_PAGES))
|
||||
return;
|
||||
u32 reserved = 0;
|
||||
int i;
|
||||
|
||||
kgsl_pools[kgsl_num_pools].pool_order = order;
|
||||
kgsl_pools[kgsl_num_pools].reserved_pages = reserved_pages;
|
||||
kgsl_pools[kgsl_num_pools].allocation_allowed = allocation_allowed;
|
||||
spin_lock_init(&kgsl_pools[kgsl_num_pools].list_lock);
|
||||
INIT_LIST_HEAD(&kgsl_pools[kgsl_num_pools].page_list);
|
||||
kgsl_num_pools++;
|
||||
of_property_read_u32(node, "qcom,mempool-reserved", &reserved);
|
||||
|
||||
/* Limit the total number of reserved pages to 4096 */
|
||||
reserved = min_t(u32, reserved, 4096);
|
||||
|
||||
for (i = 0; i < reserved; i++) {
|
||||
gfp_t gfp_mask = kgsl_gfp_mask(pool->pool_order);
|
||||
struct page *page;
|
||||
|
||||
page = alloc_pages(gfp_mask, pool->pool_order);
|
||||
_kgsl_pool_add_page(pool, page);
|
||||
}
|
||||
}
|
||||
|
||||
static void kgsl_of_parse_mempools(struct device_node *node)
|
||||
static int kgsl_of_parse_mempool(struct kgsl_page_pool *pool,
|
||||
struct device_node *node)
|
||||
{
|
||||
struct device_node *child;
|
||||
unsigned int page_size, reserved_pages = 0;
|
||||
bool allocation_allowed;
|
||||
u32 size;
|
||||
int order;
|
||||
|
||||
for_each_child_of_node(node, child) {
|
||||
unsigned int index;
|
||||
if (of_property_read_u32(node, "qcom,mempool-page-size", &size))
|
||||
return -EINVAL;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &index))
|
||||
return;
|
||||
order = ilog2(size >> PAGE_SHIFT);
|
||||
|
||||
if (index >= KGSL_MAX_POOLS)
|
||||
continue;
|
||||
|
||||
if (of_property_read_u32(child, "qcom,mempool-page-size",
|
||||
&page_size))
|
||||
return;
|
||||
|
||||
of_property_read_u32(child, "qcom,mempool-reserved",
|
||||
&reserved_pages);
|
||||
|
||||
allocation_allowed = of_property_read_bool(child,
|
||||
"qcom,mempool-allocate");
|
||||
|
||||
kgsl_pool_config(ilog2(page_size >> PAGE_SHIFT), reserved_pages,
|
||||
allocation_allowed);
|
||||
if (order > 8) {
|
||||
pr_err("kgsl: %pOF: pool order %d is too big\n", node, order);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pool->pool_order = order;
|
||||
pool->allocation_allowed = of_property_read_bool(node,
|
||||
"qcom,mempool-allocate");
|
||||
|
||||
spin_lock_init(&pool->list_lock);
|
||||
INIT_LIST_HEAD(&pool->page_list);
|
||||
|
||||
kgsl_pool_reserve_pages(pool, node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kgsl_of_get_mempools(struct device_node *parent)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct device_node *node, *child;
|
||||
int index = 0;
|
||||
|
||||
node = of_find_compatible_node(parent, NULL, "qcom,gpu-mempools");
|
||||
if (node != NULL) {
|
||||
/* Get Max pages limit for mempool */
|
||||
of_property_read_u32(node, "qcom,mempool-max-pages",
|
||||
&kgsl_pool_max_pages);
|
||||
kgsl_of_parse_mempools(node);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
/* Get Max pages limit for mempool */
|
||||
of_property_read_u32(node, "qcom,mempool-max-pages",
|
||||
&kgsl_pool_max_pages);
|
||||
|
||||
for_each_child_of_node(node, child) {
|
||||
if (!kgsl_of_parse_mempool(&kgsl_pools[index], child))
|
||||
index++;
|
||||
|
||||
if (index == ARRAY_SIZE(kgsl_pools)) {
|
||||
of_node_put(child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kgsl_num_pools = index;
|
||||
of_node_put(node);
|
||||
}
|
||||
|
||||
void kgsl_init_page_pools(struct platform_device *pdev)
|
||||
{
|
||||
|
||||
/* Get GPU mempools data and configure pools */
|
||||
kgsl_of_get_mempools(pdev->dev.of_node);
|
||||
|
||||
/* Reserve the appropriate number of pages for each pool */
|
||||
kgsl_pool_reserve_pages();
|
||||
|
||||
/* Initialize shrinker */
|
||||
register_shrinker(&kgsl_pool_shrinker);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,29 @@
|
|||
#define __KGSL_POOL_H
|
||||
|
||||
void kgsl_pool_free_sgt(struct sg_table *sgt);
|
||||
|
||||
/**
|
||||
* kgsl_pool_alloc_pages - Allocate an array of pages from the pool
|
||||
* @size: Size of the allocation
|
||||
* @pages: Pointer to an array of pages
|
||||
*
|
||||
* Allocate a list of pages and store it in the pointer pointed to by @pages.
|
||||
* Return: The number of entries in the array pointed to by @page or negative
|
||||
* on error.
|
||||
*/
|
||||
int kgsl_pool_alloc_pages(u64 size, struct page ***pages);
|
||||
|
||||
/**
|
||||
* kgsl_pool_free_pages - Free pages in an pages array
|
||||
* @pages: pointer to an array of page structs
|
||||
* @page_count: Number of entries in @pages
|
||||
*
|
||||
* Free the pages by collapsing any physical adjacent pages.
|
||||
* Pages are added back to the pool, if pool has sufficient space
|
||||
* otherwise they are given back to system.
|
||||
*/
|
||||
void kgsl_pool_free_pages(struct page **pages, unsigned int page_count);
|
||||
void kgsl_init_page_pools(struct platform_device *pdev);
|
||||
void kgsl_exit_page_pools(void);
|
||||
int kgsl_pool_alloc_page(int *page_size, struct page **pages,
|
||||
unsigned int pages_len, unsigned int *align);
|
||||
void kgsl_pool_free_page(struct page *p);
|
||||
bool kgsl_pool_avaialable(int size);
|
||||
#endif /* __KGSL_POOL_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/random.h>
|
||||
|
||||
#include "kgsl_device.h"
|
||||
#include "kgsl_pool.h"
|
||||
#include "kgsl_sharedmem.h"
|
||||
|
||||
/*
|
||||
|
|
@ -966,59 +967,6 @@ int kgsl_memdesc_sg_dma(struct kgsl_memdesc *memdesc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct page **kgsl_pool_alloc_pages(u64 size, u32 *pages_count)
|
||||
{
|
||||
int count = 0;
|
||||
int npages = size >> PAGE_SHIFT;
|
||||
struct page **pages = kvcalloc(npages, sizeof(*pages), GFP_KERNEL);
|
||||
u32 page_size;
|
||||
u64 len = size;
|
||||
u32 align = ilog2(SZ_1M);
|
||||
|
||||
if (!pages)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/*
|
||||
* Start with an 1M alignment to get the largest supported pagesize we
|
||||
* can
|
||||
*/
|
||||
page_size = kgsl_get_page_size(len, align);
|
||||
|
||||
while (len) {
|
||||
int ret = kgsl_pool_alloc_page(&page_size, &pages[count],
|
||||
npages, &align);
|
||||
|
||||
if (ret == -EAGAIN)
|
||||
continue;
|
||||
else if (ret <= 0) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ) {
|
||||
int n = 1 << compound_order(pages[i]);
|
||||
|
||||
kgsl_pool_free_page(pages[i]);
|
||||
i += n;
|
||||
}
|
||||
kvfree(pages);
|
||||
|
||||
if (!sharedmem_noretry_flag)
|
||||
pr_err_ratelimited("kgsl: out of memory: only allocated %lldKb of %lldKb requested\n",
|
||||
(size - len) >> 10, size >> 10);
|
||||
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
count += ret;
|
||||
npages -= ret;
|
||||
len -= page_size;
|
||||
|
||||
page_size = kgsl_get_page_size(len, align);
|
||||
}
|
||||
|
||||
*pages_count = count;
|
||||
return pages;
|
||||
}
|
||||
|
||||
static void _kgsl_contiguous_free(struct kgsl_memdesc *memdesc)
|
||||
{
|
||||
dma_free_attrs(memdesc->dev, memdesc->size,
|
||||
|
|
@ -1126,10 +1074,10 @@ static int kgsl_alloc_secure_pages(struct kgsl_device *device,
|
|||
memdesc->priv |= priv;
|
||||
|
||||
memdesc->ops = &kgsl_secure_pool_ops;
|
||||
pages = kgsl_pool_alloc_pages(size, &count);
|
||||
count = kgsl_pool_alloc_pages(size, &pages);
|
||||
|
||||
if (IS_ERR(pages))
|
||||
return PTR_ERR(pages);
|
||||
if (count < 0)
|
||||
return count;
|
||||
|
||||
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
|
||||
if (!sgt) {
|
||||
|
|
@ -1181,10 +1129,10 @@ static int kgsl_alloc_pages(struct kgsl_device *device,
|
|||
memdesc->priv |= priv;
|
||||
|
||||
memdesc->ops = &kgsl_pool_ops;
|
||||
pages = kgsl_pool_alloc_pages(size, &count);
|
||||
count = kgsl_pool_alloc_pages(size, &pages);
|
||||
|
||||
if (IS_ERR(pages))
|
||||
return PTR_ERR(pages);
|
||||
if (count < 0)
|
||||
return count;
|
||||
|
||||
memdesc->pages = pages;
|
||||
memdesc->size = size;
|
||||
|
|
|
|||
|
|
@ -350,35 +350,4 @@ static inline void kgsl_free_sgt(struct sg_table *sgt)
|
|||
}
|
||||
}
|
||||
|
||||
#include "kgsl_pool.h"
|
||||
|
||||
/**
|
||||
* kgsl_get_page_size() - Get supported pagesize
|
||||
* @size: Size of the page
|
||||
* @align: Desired alignment of the size
|
||||
*
|
||||
* Return supported pagesize
|
||||
*/
|
||||
#ifndef CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS
|
||||
static inline int kgsl_get_page_size(size_t size, unsigned int align)
|
||||
{
|
||||
if (align >= ilog2(SZ_1M) && size >= SZ_1M &&
|
||||
kgsl_pool_avaialable(SZ_1M))
|
||||
return SZ_1M;
|
||||
else if (align >= ilog2(SZ_64K) && size >= SZ_64K &&
|
||||
kgsl_pool_avaialable(SZ_64K))
|
||||
return SZ_64K;
|
||||
else if (align >= ilog2(SZ_8K) && size >= SZ_8K &&
|
||||
kgsl_pool_avaialable(SZ_8K))
|
||||
return SZ_8K;
|
||||
else
|
||||
return PAGE_SIZE;
|
||||
}
|
||||
#else
|
||||
static inline int kgsl_get_page_size(size_t size, unsigned int align)
|
||||
{
|
||||
return PAGE_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __KGSL_SHAREDMEM_H */
|
||||
|
|
|
|||
Loading…
Reference in a new issue