Merge "msm: kgsl: Cleanup the device tree probing for memory pools"

This commit is contained in:
qctecmdr 2019-12-09 07:59:45 -08:00 • committed by Gerrit - the friendly Code Review server
commit 9275751079
10 changed files with 272 additions and 317 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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();
}
/**

View file

@ -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,

View file

@ -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,

View file

@ -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"

View file

@ -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);
}

View file

@ -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 */

View file

@ -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;

View file

@ -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 */