blob: 8e0c32108f96bae4ab4bdadca3cf182e01927b2d [file] [log] [blame]
/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#ifndef __ADRENO_RINGBUFFER_H
#define __ADRENO_RINGBUFFER_H
#include "kgsl_iommu.h"
#include "adreno_iommu.h"
#include "adreno_dispatch.h"
/* Given a ringbuffer, return the adreno device that owns it */
#define _RB_OFFSET(_id) (offsetof(struct adreno_device, ringbuffers) + \
((_id) * sizeof(struct adreno_ringbuffer)))
#define ADRENO_RB_DEVICE(_rb) \
((struct adreno_device *) (((void *) (_rb)) - _RB_OFFSET((_rb)->id)))
/* Adreno ringbuffer size in bytes */
#define KGSL_RB_SIZE (32 * 1024)
/*
* A handy macro to convert the RB size to dwords since most ringbuffer
* operations happen in dword increments
*/
#define KGSL_RB_DWORDS (KGSL_RB_SIZE >> 2)
struct kgsl_device;
struct kgsl_device_private;
/**
* struct adreno_submit_time - utility structure to store the wall clock / GPU
* ticks at command submit time
* @ticks: GPU ticks at submit time (from the 19.2Mhz timer)
* @ktime: local clock time (in nanoseconds)
* @utime: Wall clock time
* @drawobj: the object that we want to profile
*/
struct adreno_submit_time {
uint64_t ticks;
u64 ktime;
struct timespec utime;
struct kgsl_drawobj *drawobj;
};
/**
* struct adreno_ringbuffer_pagetable_info - Contains fields used during a
* pagetable switch.
* @current_global_ptname: The current pagetable id being used by the GPU.
* Only the ringbuffers[0] current_global_ptname is used to keep track of
* the current pagetable id
* @current_rb_ptname: The current pagetable active on the given RB
* @incoming_ptname: Contains the incoming pagetable we are switching to. After
* switching of pagetable this value equals current_rb_ptname.
* @switch_pt_enable: Flag used during pagetable switch to check if pt
* switch can be skipped
* @ttbr0: value to program into TTBR0 during pagetable switch.
* @contextidr: value to program into CONTEXTIDR during pagetable switch.
*/
struct adreno_ringbuffer_pagetable_info {
int current_global_ptname;
int current_rb_ptname;
int incoming_ptname;
int switch_pt_enable;
uint64_t ttbr0;
unsigned int contextidr;
};
#define PT_INFO_OFFSET(_field) \
offsetof(struct adreno_ringbuffer_pagetable_info, _field)
/**
* struct adreno_ringbuffer - Definition for an adreno ringbuffer object
* @flags: Internal control flags for the ringbuffer
* @buffer_desc: Pointer to the ringbuffer memory descripto
* @_wptr: The next value of wptr to be written to the hardware on submit
* @wptr: Local copy of the wptr offset last written to hardware
* @last_wptr: offset of the last wptr that was written to CFF
* @rb_ctx: The context that represents a ringbuffer
* @id: Priority level of the ringbuffer, also used as an ID
* @fault_detect_ts: The last retired global timestamp read during fault detect
* @timestamp: The RB's global timestamp
* @events: A kgsl_event_group for this context - contains the list of GPU
* events
* @drawctxt_active: The last pagetable that this ringbuffer is set to
* @preemption_desc: The memory descriptor containing
* preemption info written/read by CP
* @secure_preemption_desc: The memory descriptor containing
* preemption info written/read by CP for secure contexts
* @perfcounter_save_restore_desc: Used by CP to save/restore the perfcounter
* values across preemption
* @pagetable_desc: Memory to hold information about the pagetables being used
* and the commands to switch pagetable on the RB
* @dispatch_q: The dispatcher side queue for this ringbuffer
* @ts_expire_waitq: Wait queue to wait for rb timestamp to expire
* @ts_expire_waitq: Wait q to wait for rb timestamp to expire
* @wptr_preempt_end: Used during preemption to check that preemption occurred
* at the right rptr
* @gpr11: The gpr11 value of this RB
* @preempted_midway: Indicates that the RB was preempted before rptr = wptr
* @sched_timer: Timer that tracks how long RB has been waiting to be scheduled
* or how long it has been scheduled for after preempting in
* @starve_timer_state: Indicates the state of the wait.
* @preempt_lock: Lock to protect the wptr pointer while it is being updated
*/
struct adreno_ringbuffer {
uint32_t flags;
struct kgsl_memdesc buffer_desc;
unsigned int _wptr;
unsigned int wptr;
unsigned int last_wptr;
int id;
unsigned int fault_detect_ts;
unsigned int timestamp;
struct kgsl_event_group events;
struct adreno_context *drawctxt_active;
struct kgsl_memdesc preemption_desc;
struct kgsl_memdesc secure_preemption_desc;
struct kgsl_memdesc perfcounter_save_restore_desc;
struct kgsl_memdesc pagetable_desc;
struct adreno_dispatcher_drawqueue dispatch_q;
wait_queue_head_t ts_expire_waitq;
unsigned int wptr_preempt_end;
unsigned int gpr11;
int preempted_midway;
unsigned long sched_timer;
enum adreno_dispatcher_starve_timer_states starve_timer_state;
spinlock_t preempt_lock;
/**
* @profile_desc: global memory to construct IB1s to do user side
* profiling
*/
struct kgsl_memdesc profile_desc;
/**
* @profile_index: Pointer to the next "slot" in profile_desc for a user
* profiling IB1. This allows for PAGE_SIZE / 16 = 256 simultaneous
* commands per ringbuffer with user profiling enabled
* enough.
*/
u32 profile_index;
};
/* Returns the current ringbuffer */
#define ADRENO_CURRENT_RINGBUFFER(a) ((a)->cur_rb)
int cp_secure_mode(struct adreno_device *adreno_dev, uint *cmds, int set);
int adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
struct kgsl_context *context,
struct kgsl_drawobj *drawobj,
uint32_t *timestamp);
int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
struct kgsl_drawobj_cmd *cmdobj,
struct adreno_submit_time *time);
int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt);
int adreno_ringbuffer_start(struct adreno_device *adreno_dev,
unsigned int start_type);
void adreno_ringbuffer_stop(struct adreno_device *adreno_dev);
void adreno_ringbuffer_close(struct adreno_device *adreno_dev);
int adreno_ringbuffer_issue_internal_cmds(struct adreno_ringbuffer *rb,
unsigned int flags,
unsigned int *cmdaddr,
int sizedwords);
void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb,
struct adreno_submit_time *time);
int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb,
struct adreno_submit_time *time, unsigned int timeout);
void kgsl_cp_intrcallback(struct kgsl_device *device);
unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
unsigned int numcmds);
void adreno_ringbuffer_read_pfp_ucode(struct kgsl_device *device);
void adreno_ringbuffer_read_pm4_ucode(struct kgsl_device *device);
int adreno_ringbuffer_waittimestamp(struct adreno_ringbuffer *rb,
unsigned int timestamp,
unsigned int msecs);
int adreno_rb_readtimestamp(struct adreno_device *adreno_dev,
void *priv, enum kgsl_timestamp_type type,
unsigned int *timestamp);
static inline int adreno_ringbuffer_count(struct adreno_ringbuffer *rb,
unsigned int rptr)
{
if (rb->wptr >= rptr)
return rb->wptr - rptr;
return rb->wptr + KGSL_RB_DWORDS - rptr;
}
/* Increment a value by 4 bytes with wrap-around based on size */
static inline unsigned int adreno_ringbuffer_inc_wrapped(unsigned int val,
unsigned int size)
{
return (val + sizeof(unsigned int)) % size;
}
/* Decrement a value by 4 bytes with wrap-around based on size */
static inline unsigned int adreno_ringbuffer_dec_wrapped(unsigned int val,
unsigned int size)
{
return (val + size - sizeof(unsigned int)) % size;
}
static inline int adreno_ringbuffer_set_pt_ctx(struct adreno_ringbuffer *rb,
struct kgsl_pagetable *pt, struct adreno_context *context,
unsigned long flags)
{
return adreno_iommu_set_pt_ctx(rb, pt, context, flags);
}
#endif /* __ADRENO_RINGBUFFER_H */