drm: ati-3.19-rc1

git-svn-id: svn://kolibrios.org@5271 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2014-12-27 15:58:21 +00:00
parent 16bc56fa96
commit b4abefe936
121 changed files with 7563 additions and 2674 deletions

View File

@ -0,0 +1,715 @@
/*
* Copyright (C) 2014 Red Hat
* Copyright (C) 2014 Intel Corp.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Rob Clark <robdclark@gmail.com>
* Daniel Vetter <daniel.vetter@ffwll.ch>
*/
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_plane_helper.h>
static void kfree_state(struct drm_atomic_state *state)
{
kfree(state->connectors);
kfree(state->connector_states);
kfree(state->crtcs);
kfree(state->crtc_states);
kfree(state->planes);
kfree(state->plane_states);
kfree(state);
}
/**
* drm_atomic_state_alloc - allocate atomic state
* @dev: DRM device
*
* This allocates an empty atomic state to track updates.
*/
struct drm_atomic_state *
drm_atomic_state_alloc(struct drm_device *dev)
{
struct drm_atomic_state *state;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;
state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector);
state->crtcs = kcalloc(dev->mode_config.num_crtc,
sizeof(*state->crtcs), GFP_KERNEL);
if (!state->crtcs)
goto fail;
state->crtc_states = kcalloc(dev->mode_config.num_crtc,
sizeof(*state->crtc_states), GFP_KERNEL);
if (!state->crtc_states)
goto fail;
state->planes = kcalloc(dev->mode_config.num_total_plane,
sizeof(*state->planes), GFP_KERNEL);
if (!state->planes)
goto fail;
state->plane_states = kcalloc(dev->mode_config.num_total_plane,
sizeof(*state->plane_states), GFP_KERNEL);
if (!state->plane_states)
goto fail;
state->connectors = kcalloc(state->num_connector,
sizeof(*state->connectors),
GFP_KERNEL);
if (!state->connectors)
goto fail;
state->connector_states = kcalloc(state->num_connector,
sizeof(*state->connector_states),
GFP_KERNEL);
if (!state->connector_states)
goto fail;
state->dev = dev;
DRM_DEBUG_KMS("Allocate atomic state %p\n", state);
return state;
fail:
kfree_state(state);
return NULL;
}
EXPORT_SYMBOL(drm_atomic_state_alloc);
/**
* drm_atomic_state_clear - clear state object
* @state: atomic state
*
* When the w/w mutex algorithm detects a deadlock we need to back off and drop
* all locks. So someone else could sneak in and change the current modeset
* configuration. Which means that all the state assembled in @state is no
* longer an atomic update to the current state, but to some arbitrary earlier
* state. Which could break assumptions the driver's ->atomic_check likely
* relies on.
*
* Hence we must clear all cached state and completely start over, using this
* function.
*/
void drm_atomic_state_clear(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
struct drm_mode_config *config = &dev->mode_config;
int i;
DRM_DEBUG_KMS("Clearing atomic state %p\n", state);
for (i = 0; i < state->num_connector; i++) {
struct drm_connector *connector = state->connectors[i];
if (!connector)
continue;
WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
connector->funcs->atomic_destroy_state(connector,
state->connector_states[i]);
}
for (i = 0; i < config->num_crtc; i++) {
struct drm_crtc *crtc = state->crtcs[i];
if (!crtc)
continue;
crtc->funcs->atomic_destroy_state(crtc,
state->crtc_states[i]);
}
for (i = 0; i < config->num_total_plane; i++) {
struct drm_plane *plane = state->planes[i];
if (!plane)
continue;
plane->funcs->atomic_destroy_state(plane,
state->plane_states[i]);
}
}
EXPORT_SYMBOL(drm_atomic_state_clear);
/**
* drm_atomic_state_free - free all memory for an atomic state
* @state: atomic state to deallocate
*
* This frees all memory associated with an atomic state, including all the
* per-object state for planes, crtcs and connectors.
*/
void drm_atomic_state_free(struct drm_atomic_state *state)
{
drm_atomic_state_clear(state);
DRM_DEBUG_KMS("Freeing atomic state %p\n", state);
kfree_state(state);
}
EXPORT_SYMBOL(drm_atomic_state_free);
/**
* drm_atomic_get_crtc_state - get crtc state
* @state: global atomic state object
* @crtc: crtc to get state object for
*
* This function returns the crtc state for the given crtc, allocating it if
* needed. It will also grab the relevant crtc lock to make sure that the state
* is consistent.
*
* Returns:
*
* Either the allocated state or the error code encoded into the pointer. When
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
* entire atomic sequence must be restarted. All other errors are fatal.
*/
struct drm_crtc_state *
drm_atomic_get_crtc_state(struct drm_atomic_state *state,
struct drm_crtc *crtc)
{
int ret, index;
struct drm_crtc_state *crtc_state;
index = drm_crtc_index(crtc);
if (state->crtc_states[index])
return state->crtc_states[index];
ret = drm_modeset_lock(&crtc->mutex, state->acquire_ctx);
if (ret)
return ERR_PTR(ret);
crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
if (!crtc_state)
return ERR_PTR(-ENOMEM);
state->crtc_states[index] = crtc_state;
state->crtcs[index] = crtc;
crtc_state->state = state;
DRM_DEBUG_KMS("Added [CRTC:%d] %p state to %p\n",
crtc->base.id, crtc_state, state);
return crtc_state;
}
EXPORT_SYMBOL(drm_atomic_get_crtc_state);
/**
* drm_atomic_get_plane_state - get plane state
* @state: global atomic state object
* @plane: plane to get state object for
*
* This function returns the plane state for the given plane, allocating it if
* needed. It will also grab the relevant plane lock to make sure that the state
* is consistent.
*
* Returns:
*
* Either the allocated state or the error code encoded into the pointer. When
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
* entire atomic sequence must be restarted. All other errors are fatal.
*/
struct drm_plane_state *
drm_atomic_get_plane_state(struct drm_atomic_state *state,
struct drm_plane *plane)
{
int ret, index;
struct drm_plane_state *plane_state;
index = drm_plane_index(plane);
if (state->plane_states[index])
return state->plane_states[index];
ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
if (ret)
return ERR_PTR(ret);
plane_state = plane->funcs->atomic_duplicate_state(plane);
if (!plane_state)
return ERR_PTR(-ENOMEM);
state->plane_states[index] = plane_state;
state->planes[index] = plane;
plane_state->state = state;
DRM_DEBUG_KMS("Added [PLANE:%d] %p state to %p\n",
plane->base.id, plane_state, state);
if (plane_state->crtc) {
struct drm_crtc_state *crtc_state;
crtc_state = drm_atomic_get_crtc_state(state,
plane_state->crtc);
if (IS_ERR(crtc_state))
return ERR_CAST(crtc_state);
}
return plane_state;
}
EXPORT_SYMBOL(drm_atomic_get_plane_state);
/**
* drm_atomic_get_connector_state - get connector state
* @state: global atomic state object
* @connector: connector to get state object for
*
* This function returns the connector state for the given connector,
* allocating it if needed. It will also grab the relevant connector lock to
* make sure that the state is consistent.
*
* Returns:
*
* Either the allocated state or the error code encoded into the pointer. When
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
* entire atomic sequence must be restarted. All other errors are fatal.
*/
struct drm_connector_state *
drm_atomic_get_connector_state(struct drm_atomic_state *state,
struct drm_connector *connector)
{
int ret, index;
struct drm_mode_config *config = &connector->dev->mode_config;
struct drm_connector_state *connector_state;
ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
if (ret)
return ERR_PTR(ret);
index = drm_connector_index(connector);
/*
* Construction of atomic state updates can race with a connector
* hot-add which might overflow. In this case flip the table and just
* restart the entire ioctl - no one is fast enough to livelock a cpu
* with physical hotplug events anyway.
*
* Note that we only grab the indexes once we have the right lock to
* prevent hotplug/unplugging of connectors. So removal is no problem,
* at most the array is a bit too large.
*/
if (index >= state->num_connector) {
DRM_DEBUG_KMS("Hot-added connector would overflow state array, restarting\n");
return ERR_PTR(-EAGAIN);
}
if (state->connector_states[index])
return state->connector_states[index];
connector_state = connector->funcs->atomic_duplicate_state(connector);
if (!connector_state)
return ERR_PTR(-ENOMEM);
state->connector_states[index] = connector_state;
state->connectors[index] = connector;
connector_state->state = state;
DRM_DEBUG_KMS("Added [CONNECTOR:%d] %p state to %p\n",
connector->base.id, connector_state, state);
if (connector_state->crtc) {
struct drm_crtc_state *crtc_state;
crtc_state = drm_atomic_get_crtc_state(state,
connector_state->crtc);
if (IS_ERR(crtc_state))
return ERR_CAST(crtc_state);
}
return connector_state;
}
EXPORT_SYMBOL(drm_atomic_get_connector_state);
/**
* drm_atomic_set_crtc_for_plane - set crtc for plane
* @state: the incoming atomic state
* @plane: the plane whose incoming state to update
* @crtc: crtc to use for the plane
*
* Changing the assigned crtc for a plane requires us to grab the lock and state
* for the new crtc, as needed. This function takes care of all these details
* besides updating the pointer in the state object itself.
*
* Returns:
* 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
* then the w/w mutex code has detected a deadlock and the entire atomic
* sequence must be restarted. All other errors are fatal.
*/
int
drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
struct drm_plane *plane, struct drm_crtc *crtc)
{
struct drm_plane_state *plane_state =
drm_atomic_get_plane_state(state, plane);
struct drm_crtc_state *crtc_state;
if (WARN_ON(IS_ERR(plane_state)))
return PTR_ERR(plane_state);
if (plane_state->crtc) {
crtc_state = drm_atomic_get_crtc_state(plane_state->state,
plane_state->crtc);
if (WARN_ON(IS_ERR(crtc_state)))
return PTR_ERR(crtc_state);
crtc_state->plane_mask &= ~(1 << drm_plane_index(plane));
}
plane_state->crtc = crtc;
if (crtc) {
crtc_state = drm_atomic_get_crtc_state(plane_state->state,
crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
crtc_state->plane_mask |= (1 << drm_plane_index(plane));
}
if (crtc)
DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
plane_state, crtc->base.id);
else
DRM_DEBUG_KMS("Link plane state %p to [NOCRTC]\n", plane_state);
return 0;
}
EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
/**
* drm_atomic_set_fb_for_plane - set crtc for plane
* @plane_state: atomic state object for the plane
* @fb: fb to use for the plane
*
* Changing the assigned framebuffer for a plane requires us to grab a reference
* to the new fb and drop the reference to the old fb, if there is one. This
* function takes care of all these details besides updating the pointer in the
* state object itself.
*/
void
drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
struct drm_framebuffer *fb)
{
if (plane_state->fb)
drm_framebuffer_unreference(plane_state->fb);
if (fb)
drm_framebuffer_reference(fb);
plane_state->fb = fb;
if (fb)
DRM_DEBUG_KMS("Set [FB:%d] for plane state %p\n",
fb->base.id, plane_state);
else
DRM_DEBUG_KMS("Set [NOFB] for plane state %p\n", plane_state);
}
EXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
/**
* drm_atomic_set_crtc_for_connector - set crtc for connector
* @conn_state: atomic state object for the connector
* @crtc: crtc to use for the connector
*
* Changing the assigned crtc for a connector requires us to grab the lock and
* state for the new crtc, as needed. This function takes care of all these
* details besides updating the pointer in the state object itself.
*
* Returns:
* 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
* then the w/w mutex code has detected a deadlock and the entire atomic
* sequence must be restarted. All other errors are fatal.
*/
int
drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
struct drm_crtc *crtc)
{
struct drm_crtc_state *crtc_state;
if (crtc) {
crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
}
conn_state->crtc = crtc;
if (crtc)
DRM_DEBUG_KMS("Link connector state %p to [CRTC:%d]\n",
conn_state, crtc->base.id);
else
DRM_DEBUG_KMS("Link connector state %p to [NOCRTC]\n",
conn_state);
return 0;
}
EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
/**
* drm_atomic_add_affected_connectors - add connectors for crtc
* @state: atomic state
* @crtc: DRM crtc
*
* This function walks the current configuration and adds all connectors
* currently using @crtc to the atomic configuration @state. Note that this
* function must acquire the connection mutex. This can potentially cause
* unneeded seralization if the update is just for the planes on one crtc. Hence
* drivers and helpers should only call this when really needed (e.g. when a
* full modeset needs to happen due to some change).
*
* Returns:
* 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
* then the w/w mutex code has detected a deadlock and the entire atomic
* sequence must be restarted. All other errors are fatal.
*/
int
drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
struct drm_crtc *crtc)
{
struct drm_mode_config *config = &state->dev->mode_config;
struct drm_connector *connector;
struct drm_connector_state *conn_state;
int ret;
ret = drm_modeset_lock(&config->connection_mutex, state->acquire_ctx);
if (ret)
return ret;
DRM_DEBUG_KMS("Adding all current connectors for [CRTC:%d] to %p\n",
crtc->base.id, state);
/*
* Changed connectors are already in @state, so only need to look at the
* current configuration.
*/
list_for_each_entry(connector, &config->connector_list, head) {
if (connector->state->crtc != crtc)
continue;
conn_state = drm_atomic_get_connector_state(state, connector);
if (IS_ERR(conn_state))
return PTR_ERR(conn_state);
}
return 0;
}
EXPORT_SYMBOL(drm_atomic_add_affected_connectors);
/**
* drm_atomic_connectors_for_crtc - count number of connected outputs
* @state: atomic state
* @crtc: DRM crtc
*
* This function counts all connectors which will be connected to @crtc
* according to @state. Useful to recompute the enable state for @crtc.
*/
int
drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
struct drm_crtc *crtc)
{
int i, num_connected_connectors = 0;
for (i = 0; i < state->num_connector; i++) {
struct drm_connector_state *conn_state;
conn_state = state->connector_states[i];
if (conn_state && conn_state->crtc == crtc)
num_connected_connectors++;
}
DRM_DEBUG_KMS("State %p has %i connectors for [CRTC:%d]\n",
state, num_connected_connectors, crtc->base.id);
return num_connected_connectors;
}
EXPORT_SYMBOL(drm_atomic_connectors_for_crtc);
/**
* drm_atomic_legacy_backoff - locking backoff for legacy ioctls
* @state: atomic state
*
* This function should be used by legacy entry points which don't understand
* -EDEADLK semantics. For simplicity this one will grab all modeset locks after
* the slowpath completed.
*/
void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
{
int ret;
retry:
drm_modeset_backoff(state->acquire_ctx);
ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
state->acquire_ctx);
if (ret)
goto retry;
ret = drm_modeset_lock_all_crtcs(state->dev,
state->acquire_ctx);
if (ret)
goto retry;
}
EXPORT_SYMBOL(drm_atomic_legacy_backoff);
/**
* drm_atomic_check_only - check whether a given config would work
* @state: atomic configuration to check
*
* Note that this function can return -EDEADLK if the driver needed to acquire
* more locks but encountered a deadlock. The caller must then do the usual w/w
* backoff dance and restart. All other errors are fatal.
*
* Returns:
* 0 on success, negative error code on failure.
*/
int drm_atomic_check_only(struct drm_atomic_state *state)
{
struct drm_mode_config *config = &state->dev->mode_config;
DRM_DEBUG_KMS("checking %p\n", state);
if (config->funcs->atomic_check)
return config->funcs->atomic_check(state->dev, state);
else
return 0;
}
EXPORT_SYMBOL(drm_atomic_check_only);
/**
* drm_atomic_commit - commit configuration atomically
* @state: atomic configuration to check
*
* Note that this function can return -EDEADLK if the driver needed to acquire
* more locks but encountered a deadlock. The caller must then do the usual w/w
* backoff dance and restart. All other errors are fatal.
*
* Also note that on successful execution ownership of @state is transferred
* from the caller of this function to the function itself. The caller must not
* free or in any other way access @state. If the function fails then the caller
* must clean up @state itself.
*
* Returns:
* 0 on success, negative error code on failure.
*/
int drm_atomic_commit(struct drm_atomic_state *state)
{
struct drm_mode_config *config = &state->dev->mode_config;
int ret;
ret = drm_atomic_check_only(state);
if (ret)
return ret;
DRM_DEBUG_KMS("commiting %p\n", state);
return config->funcs->atomic_commit(state->dev, state, false);
}
EXPORT_SYMBOL(drm_atomic_commit);
/**
* drm_atomic_async_commit - atomic&async configuration commit
* @state: atomic configuration to check
*
* Note that this function can return -EDEADLK if the driver needed to acquire
* more locks but encountered a deadlock. The caller must then do the usual w/w
* backoff dance and restart. All other errors are fatal.
*
* Also note that on successful execution ownership of @state is transferred
* from the caller of this function to the function itself. The caller must not
* free or in any other way access @state. If the function fails then the caller
* must clean up @state itself.
*
* Returns:
* 0 on success, negative error code on failure.
*/
int drm_atomic_async_commit(struct drm_atomic_state *state)
{
struct drm_mode_config *config = &state->dev->mode_config;
int ret;
ret = drm_atomic_check_only(state);
if (ret)
return ret;
DRM_DEBUG_KMS("commiting %p asynchronously\n", state);
return config->funcs->atomic_commit(state->dev, state, true);
}
EXPORT_SYMBOL(drm_atomic_async_commit);
/**
* drm_atomic_helper_plane_duplicate_state - default state duplicate hook
* @plane: drm plane
*
* Default plane state duplicate hook for drivers which don't have their own
* subclassed plane state structure.
*/
struct drm_plane_state *
drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
{
struct drm_plane_state *state;
if (WARN_ON(!plane->state))
return NULL;
state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL);
if (state && state->fb)
drm_framebuffer_reference(state->fb);
return state;
}
EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
/**
* drm_atomic_helper_crtc_destroy_state - default state destroy hook
* @crtc: drm CRTC
* @state: CRTC state object to release
*
* Default CRTC state destroy hook for drivers which don't have their own
* subclassed CRTC state structure.
*/
void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
/**
* drm_atomic_helper_plane_destroy_state - default state destroy hook
* @plane: drm plane
* @state: plane state object to release
*
* Default plane state destroy hook for drivers which don't have their own
* subclassed plane state structure.
*/
void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
if (state->fb)
drm_framebuffer_unreference(state->fb);
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);

View File

@ -29,15 +29,10 @@
*/
#include <linux/export.h>
#include <linux/scatterlist.h>
#include <drm/drmP.h>
extern int x86_clflush_size;
static inline void clflush(volatile void *__p)
{
asm volatile("clflush %0" : "+m" (*(volatile char*)__p));
}
#if 0
static void

File diff suppressed because it is too large Load Diff

View File

@ -34,12 +34,35 @@
#include <linux/moduleparam.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
/**
* DOC: overview
*
* The CRTC modeset helper library provides a default set_config implementation
* in drm_crtc_helper_set_config(). Plus a few other convenience functions using
* the same callbacks which drivers can use to e.g. restore the modeset
* configuration on resume with drm_helper_resume_force_mode().
*
* The driver callbacks are mostly compatible with the atomic modeset helpers,
* except for the handling of the primary plane: Atomic helpers require that the
* primary plane is implemented as a real standalone plane and not directly tied
* to the CRTC state. For easier transition this library provides functions to
* implement the old semantics required by the CRTC helpers using the new plane
* and atomic helper callbacks.
*
* Drivers are strongly urged to convert to the atomic helpers (by way of first
* converting to the plane helpers). New drivers must not use these functions
* but need to implement the atomic interface instead, potentially using the
* atomic helpers for that.
*/
MODULE_AUTHOR("David Airlie, Jesse Barnes");
MODULE_DESCRIPTION("DRM KMS helper");
MODULE_LICENSE("GPL and additional rights");
@ -871,3 +894,112 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
drm_modeset_unlock_all(dev);
}
EXPORT_SYMBOL(drm_helper_resume_force_mode);
/**
* drm_helper_crtc_mode_set - mode_set implementation for atomic plane helpers
* @crtc: DRM CRTC
* @mode: DRM display mode which userspace requested
* @adjusted_mode: DRM display mode adjusted by ->mode_fixup callbacks
* @x: x offset of the CRTC scanout area on the underlying framebuffer
* @y: y offset of the CRTC scanout area on the underlying framebuffer
* @old_fb: previous framebuffer
*
* This function implements a callback useable as the ->mode_set callback
* required by the crtc helpers. Besides the atomic plane helper functions for
* the primary plane the driver must also provide the ->mode_set_nofb callback
* to set up the crtc.
*
* This is a transitional helper useful for converting drivers to the atomic
* interfaces.
*/
int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode, int x, int y,
struct drm_framebuffer *old_fb)
{
struct drm_crtc_state *crtc_state;
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
int ret;
if (crtc->funcs->atomic_duplicate_state)
crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
else if (crtc->state)
crtc_state = kmemdup(crtc->state, sizeof(*crtc_state),
GFP_KERNEL);
else
crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
if (!crtc_state)
return -ENOMEM;
crtc_state->enable = true;
crtc_state->planes_changed = true;
crtc_state->mode_changed = true;
drm_mode_copy(&crtc_state->mode, mode);
drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
if (crtc_funcs->atomic_check) {
ret = crtc_funcs->atomic_check(crtc, crtc_state);
if (ret) {
kfree(crtc_state);
return ret;
}
}
swap(crtc->state, crtc_state);
crtc_funcs->mode_set_nofb(crtc);
if (crtc_state) {
if (crtc->funcs->atomic_destroy_state)
crtc->funcs->atomic_destroy_state(crtc, crtc_state);
else
kfree(crtc_state);
}
return drm_helper_crtc_mode_set_base(crtc, x, y, old_fb);
}
EXPORT_SYMBOL(drm_helper_crtc_mode_set);
/**
* drm_helper_crtc_mode_set_base - mode_set_base implementation for atomic plane helpers
* @crtc: DRM CRTC
* @x: x offset of the CRTC scanout area on the underlying framebuffer
* @y: y offset of the CRTC scanout area on the underlying framebuffer
* @old_fb: previous framebuffer
*
* This function implements a callback useable as the ->mode_set_base used
* required by the crtc helpers. The driver must provide the atomic plane helper
* functions for the primary plane.
*
* This is a transitional helper useful for converting drivers to the atomic
* interfaces.
*/
int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
struct drm_plane_state *plane_state;
struct drm_plane *plane = crtc->primary;
if (plane->funcs->atomic_duplicate_state)
plane_state = plane->funcs->atomic_duplicate_state(plane);
else if (plane->state)
plane_state = drm_atomic_helper_plane_duplicate_state(plane);
else
plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
if (!plane_state)
return -ENOMEM;
plane_state->crtc = crtc;
drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
plane_state->crtc_x = 0;
plane_state->crtc_y = 0;
plane_state->crtc_h = crtc->mode.vdisplay;
plane_state->crtc_w = crtc->mode.hdisplay;
plane_state->src_x = x << 16;
plane_state->src_y = y << 16;
plane_state->src_h = crtc->mode.vdisplay << 16;
plane_state->src_w = crtc->mode.hdisplay << 16;
return drm_plane_helper_commit(plane, plane_state, old_fb);
}
EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);

View File

@ -27,8 +27,8 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/i2c.h>
#include <drm/drmP.h>
#include <drm/drm_dp_helper.h>
#include <drm/drmP.h>
/**
* DOC: dp helpers
@ -39,198 +39,6 @@
* blocks, ...
*/
/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
static int
i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
uint8_t write_byte, uint8_t *read_byte)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
int ret;
ret = (*algo_data->aux_ch)(adapter, mode,
write_byte, read_byte);
return ret;
}
/*
* I2C over AUX CH
*/
/*
* Send the address. If the I2C link is running, this 'restarts'
* the connection with the new address, this is used for doing
* a write followed by a read (as needed for DDC)
*/
static int
i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
int mode = MODE_I2C_START;
int ret;
if (reading)
mode |= MODE_I2C_READ;
else
mode |= MODE_I2C_WRITE;
algo_data->address = address;
algo_data->running = true;
ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
return ret;
}
/*
* Stop the I2C transaction. This closes out the link, sending
* a bare address packet with the MOT bit turned off
*/
static void
i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
int mode = MODE_I2C_STOP;
if (reading)
mode |= MODE_I2C_READ;
else
mode |= MODE_I2C_WRITE;
if (algo_data->running) {
(void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
algo_data->running = false;
}
}
/*
* Write a single byte to the current I2C address, the
* the I2C link must be running or this returns -EIO
*/
static int
i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
int ret;
if (!algo_data->running)
return -EIO;
ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL);
return ret;
}
/*
* Read a single byte from the current I2C address, the
* I2C link must be running or this returns -EIO
*/
static int
i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
{
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
int ret;
if (!algo_data->running)
return -EIO;
ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret);
return ret;
}
static int
i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs,
int num)
{
int ret = 0;
bool reading = false;
int m;
int b;
for (m = 0; m < num; m++) {
u16 len = msgs[m].len;
u8 *buf = msgs[m].buf;
reading = (msgs[m].flags & I2C_M_RD) != 0;
ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading);
if (ret < 0)
break;
if (reading) {
for (b = 0; b < len; b++) {
ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]);
if (ret < 0)
break;
}
} else {
for (b = 0; b < len; b++) {
ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]);
if (ret < 0)
break;
}
}
if (ret < 0)
break;
}
if (ret >= 0)
ret = num;
i2c_algo_dp_aux_stop(adapter, reading);
DRM_DEBUG_KMS("dp_aux_xfer return %d\n", ret);
return ret;
}
static u32
i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
I2C_FUNC_SMBUS_READ_BLOCK_DATA |
I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
I2C_FUNC_10BIT_ADDR;
}
static const struct i2c_algorithm i2c_dp_aux_algo = {
.master_xfer = i2c_algo_dp_aux_xfer,
.functionality = i2c_algo_dp_aux_functionality,
};
static void
i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
{
(void) i2c_algo_dp_aux_address(adapter, 0, false);
(void) i2c_algo_dp_aux_stop(adapter, false);
}
static int
i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
{
adapter->algo = &i2c_dp_aux_algo;
adapter->retries = 3;
i2c_dp_aux_reset_bus(adapter);
return 0;
}
/**
* i2c_dp_aux_add_bus() - register an i2c adapter using the aux ch helper
* @adapter: i2c adapter to register
*
* This registers an i2c adapter that uses dp aux channel as it's underlaying
* transport. The driver needs to fill out the &i2c_algo_dp_aux_data structure
* and store it in the algo_data member of the @adapter argument. This will be
* used by the i2c over dp aux algorithm to drive the hardware.
*
* RETURNS:
* 0 on success, -ERRNO on failure.
*
* IMPORTANT:
* This interface is deprecated, please switch to the new dp aux helpers and
* drm_dp_aux_register().
*/
int
i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
{
int error;
error = i2c_dp_aux_prepare_bus(adapter);
if (error)
return error;
error = i2c_add_adapter(adapter);
return error;
}
EXPORT_SYMBOL(i2c_dp_aux_add_bus);
/* Helpers for DP link training */
static u8 dp_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
{
@ -378,10 +186,11 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
/*
* The specification doesn't give any recommendation on how often to
* retry native transactions, so retry 7 times like for I2C-over-AUX
* transactions.
* retry native transactions. We used to retry 7 times like for
* aux i2c transactions but real world devices this wasn't
* sufficient, bump to 32 which makes Dell 4k monitors happier.
*/
for (retry = 0; retry < 7; retry++) {
for (retry = 0; retry < 32; retry++) {
mutex_lock(&aux->hw_mutex);
err = aux->transfer(aux, &msg);

View File

@ -689,7 +689,7 @@ static int build_allocate_payload(struct drm_dp_sideband_msg_tx *msg, int port_n
static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_vcpi *vcpi)
{
int ret;
int ret, vcpi_ret;
mutex_lock(&mgr->payload_lock);
ret = find_first_zero_bit(&mgr->payload_mask, mgr->max_payloads + 1);
@ -699,8 +699,16 @@ static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
goto out_unlock;
}
vcpi_ret = find_first_zero_bit(&mgr->vcpi_mask, mgr->max_payloads + 1);
if (vcpi_ret > mgr->max_payloads) {
ret = -EINVAL;
DRM_DEBUG_KMS("out of vcpi ids %d\n", ret);
goto out_unlock;
}
set_bit(ret, &mgr->payload_mask);
vcpi->vcpi = ret;
set_bit(vcpi_ret, &mgr->vcpi_mask);
vcpi->vcpi = vcpi_ret + 1;
mgr->proposed_vcpis[ret - 1] = vcpi;
out_unlock:
mutex_unlock(&mgr->payload_lock);
@ -708,15 +716,23 @@ out_unlock:
}
static void drm_dp_mst_put_payload_id(struct drm_dp_mst_topology_mgr *mgr,
int id)
int vcpi)
{
if (id == 0)
int i;
if (vcpi == 0)
return;
mutex_lock(&mgr->payload_lock);
DRM_DEBUG_KMS("putting payload %d\n", id);
clear_bit(id, &mgr->payload_mask);
mgr->proposed_vcpis[id - 1] = NULL;
DRM_DEBUG_KMS("putting payload %d\n", vcpi);
clear_bit(vcpi - 1, &mgr->vcpi_mask);
for (i = 0; i < mgr->max_payloads; i++) {
if (mgr->proposed_vcpis[i])
if (mgr->proposed_vcpis[i]->vcpi == vcpi) {
mgr->proposed_vcpis[i] = NULL;
clear_bit(i + 1, &mgr->payload_mask);
}
}
mutex_unlock(&mgr->payload_lock);
}
@ -830,6 +846,8 @@ static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb)
static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt)
{
struct drm_dp_mst_branch *mstb;
switch (old_pdt) {
case DP_PEER_DEVICE_DP_LEGACY_CONV:
case DP_PEER_DEVICE_SST_SINK:
@ -837,8 +855,9 @@ static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt)
drm_dp_mst_unregister_i2c_bus(&port->aux);
break;
case DP_PEER_DEVICE_MST_BRANCHING:
drm_dp_put_mst_branch_device(port->mstb);
mstb = port->mstb;
port->mstb = NULL;
drm_dp_put_mst_branch_device(mstb);
break;
}
}
@ -849,6 +868,8 @@ static void drm_dp_destroy_port(struct kref *kref)
struct drm_dp_mst_topology_mgr *mgr = port->mgr;
if (!port->input) {
port->vcpi.num_slots = 0;
kfree(port->cached_edid);
if (port->connector)
(*port->mgr->cbs->destroy_connector)(mgr, port->connector);
drm_dp_port_teardown_pdt(port, port->pdt);
@ -1002,19 +1023,20 @@ static void drm_dp_check_port_guid(struct drm_dp_mst_branch *mstb,
static void build_mst_prop_path(struct drm_dp_mst_port *port,
struct drm_dp_mst_branch *mstb,
char *proppath)
char *proppath,
size_t proppath_size)
{
int i;
char temp[8];
snprintf(proppath, 255, "mst:%d", mstb->mgr->conn_base_id);
snprintf(proppath, proppath_size, "mst:%d", mstb->mgr->conn_base_id);
for (i = 0; i < (mstb->lct - 1); i++) {
int shift = (i % 2) ? 0 : 4;
int port_num = mstb->rad[i / 2] >> shift;
snprintf(temp, 8, "-%d", port_num);
strncat(proppath, temp, 255);
snprintf(temp, sizeof(temp), "-%d", port_num);
strlcat(proppath, temp, proppath_size);
}
snprintf(temp, 8, "-%d", port->port_num);
strncat(proppath, temp, 255);
snprintf(temp, sizeof(temp), "-%d", port->port_num);
strlcat(proppath, temp, proppath_size);
}
static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
@ -1085,8 +1107,12 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
if (created && !port->input) {
char proppath[255];
build_mst_prop_path(port, mstb, proppath);
build_mst_prop_path(port, mstb, proppath, sizeof(proppath));
port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath);
if (port->port_num >= 8) {
port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
}
}
/* put reference to this port */
@ -1570,7 +1596,7 @@ static int drm_dp_destroy_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
}
drm_dp_dpcd_write_payload(mgr, id, payload);
payload->payload_state = 0;
payload->payload_state = DP_PAYLOAD_DELETE_LOCAL;
return 0;
}
@ -1597,7 +1623,7 @@ static int drm_dp_destroy_payload_step2(struct drm_dp_mst_topology_mgr *mgr,
*/
int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
{
int i;
int i, j;
int cur_slots = 1;
struct drm_dp_payload req_payload;
struct drm_dp_mst_port *port;
@ -1614,26 +1640,46 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
port = NULL;
req_payload.num_slots = 0;
}
if (mgr->payloads[i].start_slot != req_payload.start_slot) {
mgr->payloads[i].start_slot = req_payload.start_slot;
}
/* work out what is required to happen with this payload */
if (mgr->payloads[i].start_slot != req_payload.start_slot ||
mgr->payloads[i].num_slots != req_payload.num_slots) {
if (mgr->payloads[i].num_slots != req_payload.num_slots) {
/* need to push an update for this payload */
if (req_payload.num_slots) {
drm_dp_create_payload_step1(mgr, i + 1, &req_payload);
drm_dp_create_payload_step1(mgr, mgr->proposed_vcpis[i]->vcpi, &req_payload);
mgr->payloads[i].num_slots = req_payload.num_slots;
} else if (mgr->payloads[i].num_slots) {
mgr->payloads[i].num_slots = 0;
drm_dp_destroy_payload_step1(mgr, port, i + 1, &mgr->payloads[i]);
drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]);
req_payload.payload_state = mgr->payloads[i].payload_state;
} else
req_payload.payload_state = 0;
mgr->payloads[i].start_slot = req_payload.start_slot;
mgr->payloads[i].start_slot = 0;
}
mgr->payloads[i].payload_state = req_payload.payload_state;
}
cur_slots += req_payload.num_slots;
}
for (i = 0; i < mgr->max_payloads; i++) {
if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) {
DRM_DEBUG_KMS("removing payload %d\n", i);
for (j = i; j < mgr->max_payloads - 1; j++) {
memcpy(&mgr->payloads[j], &mgr->payloads[j + 1], sizeof(struct drm_dp_payload));
mgr->proposed_vcpis[j] = mgr->proposed_vcpis[j + 1];
if (mgr->proposed_vcpis[j] && mgr->proposed_vcpis[j]->num_slots) {
set_bit(j + 1, &mgr->payload_mask);
} else {
clear_bit(j + 1, &mgr->payload_mask);
}
}
memset(&mgr->payloads[mgr->max_payloads - 1], 0, sizeof(struct drm_dp_payload));
mgr->proposed_vcpis[mgr->max_payloads - 1] = NULL;
clear_bit(mgr->max_payloads, &mgr->payload_mask);
}
}
mutex_unlock(&mgr->payload_lock);
return 0;
@ -1664,9 +1710,9 @@ int drm_dp_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr)
DRM_DEBUG_KMS("payload %d %d\n", i, mgr->payloads[i].payload_state);
if (mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL) {
ret = drm_dp_create_payload_step2(mgr, port, i + 1, &mgr->payloads[i]);
ret = drm_dp_create_payload_step2(mgr, port, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]);
} else if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) {
ret = drm_dp_destroy_payload_step2(mgr, i + 1, &mgr->payloads[i]);
ret = drm_dp_destroy_payload_step2(mgr, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]);
}
if (ret) {
mutex_unlock(&mgr->payload_lock);
@ -1769,17 +1815,27 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr,
return 0;
}
static int drm_dp_get_vc_payload_bw(int dp_link_bw, int dp_link_count)
static bool drm_dp_get_vc_payload_bw(int dp_link_bw,
int dp_link_count,
int *out)
{
switch (dp_link_bw) {
default:
DRM_DEBUG_KMS("invalid link bandwidth in DPCD: %x (link count: %d)\n",
dp_link_bw, dp_link_count);
return false;
case DP_LINK_BW_1_62:
return 3 * dp_link_count;
*out = 3 * dp_link_count;
break;
case DP_LINK_BW_2_7:
return 5 * dp_link_count;
*out = 5 * dp_link_count;
break;
case DP_LINK_BW_5_4:
return 10 * dp_link_count;
*out = 10 * dp_link_count;
break;
}
return 0;
return true;
}
/**
@ -1811,7 +1867,13 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
goto out_unlock;
}
mgr->pbn_div = drm_dp_get_vc_payload_bw(mgr->dpcd[1], mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK);
if (!drm_dp_get_vc_payload_bw(mgr->dpcd[1],
mgr->dpcd[2] & DP_MAX_LANE_COUNT_MASK,
&mgr->pbn_div)) {
ret = -EINVAL;
goto out_unlock;
}
mgr->total_pbn = 2560;
mgr->total_slots = DIV_ROUND_UP(mgr->total_pbn, mgr->pbn_div);
mgr->avail_slots = mgr->total_slots;
@ -1868,6 +1930,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
memset(mgr->payloads, 0, mgr->max_payloads * sizeof(struct drm_dp_payload));
mgr->payload_mask = 0;
set_bit(0, &mgr->payload_mask);
mgr->vcpi_mask = 0;
}
out_unlock:
@ -2078,6 +2141,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
* drm_dp_mst_hpd_irq() - MST hotplug IRQ notify
* @mgr: manager to notify irq for.
* @esi: 4 bytes from SINK_COUNT_ESI
* @handled: whether the hpd interrupt was consumed or not
*
* This should be called from the driver when it detects a short IRQ,
* along with the value of the DEVICE_SERVICE_IRQ_VECTOR_ESI0. The
@ -2119,7 +2183,8 @@ EXPORT_SYMBOL(drm_dp_mst_hpd_irq);
* This returns the current connection state for a port. It validates the
* port pointer still exists so the caller doesn't require a reference
*/
enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector,
struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
{
enum drm_connector_status status = connector_status_disconnected;
@ -2138,6 +2203,10 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr
case DP_PEER_DEVICE_SST_SINK:
status = connector_status_connected;
/* for logical ports - cache the EDID */
if (port->port_num >= 8 && !port->cached_edid) {
port->cached_edid = drm_get_edid(connector, &port->aux.ddc);
}
break;
case DP_PEER_DEVICE_DP_LEGACY_CONV:
if (port->ldps)
@ -2169,7 +2238,12 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
if (!port)
return NULL;
if (port->cached_edid)
edid = drm_edid_duplicate(port->cached_edid);
else
edid = drm_get_edid(connector, &port->aux.ddc);
drm_mode_connector_set_tile_property(connector);
drm_dp_put_port(port);
return edid;
}

View File

@ -34,6 +34,7 @@
#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_edid.h>
#include <drm/drm_displayid.h>
#define version_greater(edid, maj, min) \
(((edid)->version > (maj)) || \
@ -632,27 +633,27 @@ static const struct drm_display_mode edid_cea_modes[] = {
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
DRM_MODE_FLAG_INTERLACE),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 6 - 1440x480i@60Hz */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
/* 6 - 720(1440)x480i@60Hz */
{ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
801, 858, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
/* 7 - 1440x480i@60Hz */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
/* 7 - 720(1440)x480i@60Hz */
{ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
801, 858, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 8 - 1440x240@60Hz */
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 240, 244, 247, 262, 0,
/* 8 - 720(1440)x240@60Hz */
{ DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
801, 858, 0, 240, 244, 247, 262, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_DBLCLK),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
/* 9 - 1440x240@60Hz */
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 240, 244, 247, 262, 0,
/* 9 - 720(1440)x240@60Hz */
{ DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
801, 858, 0, 240, 244, 247, 262, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_DBLCLK),
.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
@ -714,27 +715,27 @@ static const struct drm_display_mode edid_cea_modes[] = {
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
DRM_MODE_FLAG_INTERLACE),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 21 - 1440x576i@50Hz */
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
/* 21 - 720(1440)x576i@50Hz */
{ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
795, 864, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
/* 22 - 1440x576i@50Hz */
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
/* 22 - 720(1440)x576i@50Hz */
{ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
795, 864, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 23 - 1440x288@50Hz */
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 288, 290, 293, 312, 0,
/* 23 - 720(1440)x288@50Hz */
{ DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
795, 864, 0, 288, 290, 293, 312, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_DBLCLK),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
/* 24 - 1440x288@50Hz */
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 288, 290, 293, 312, 0,
/* 24 - 720(1440)x288@50Hz */
{ DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
795, 864, 0, 288, 290, 293, 312, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_DBLCLK),
.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
@ -837,17 +838,17 @@ static const struct drm_display_mode edid_cea_modes[] = {
796, 864, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 44 - 1440x576i@100Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
/* 44 - 720(1440)x576i@100Hz */
{ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
795, 864, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_DBLCLK),
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
/* 45 - 1440x576i@100Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
/* 45 - 720(1440)x576i@100Hz */
{ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
795, 864, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_DBLCLK),
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 46 - 1920x1080i@120Hz */
{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
@ -870,15 +871,15 @@ static const struct drm_display_mode edid_cea_modes[] = {
798, 858, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 50 - 1440x480i@120Hz */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
/* 50 - 720(1440)x480i@120Hz */
{ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 27000, 720, 739,
801, 858, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
/* 51 - 1440x480i@120Hz */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
/* 51 - 720(1440)x480i@120Hz */
{ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 27000, 720, 739,
801, 858, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
@ -892,15 +893,15 @@ static const struct drm_display_mode edid_cea_modes[] = {
796, 864, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
.vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 54 - 1440x576i@200Hz */
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
/* 54 - 720(1440)x576i@200Hz */
{ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
795, 864, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
/* 55 - 1440x576i@200Hz */
{ DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
/* 55 - 720(1440)x576i@200Hz */
{ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
795, 864, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
@ -914,15 +915,15 @@ static const struct drm_display_mode edid_cea_modes[] = {
798, 858, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
.vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
/* 58 - 1440x480i@240 */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
/* 58 - 720(1440)x480i@240 */
{ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 54000, 720, 739,
801, 858, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
/* 59 - 1440x480i@240 */
{ DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
/* 59 - 720(1440)x480i@240 */
{ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 54000, 720, 739,
801, 858, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
.vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
@ -1014,6 +1015,27 @@ module_param_named(edid_fixup, edid_fixup, int, 0400);
MODULE_PARM_DESC(edid_fixup,
"Minimum number of valid EDID header bytes (0-8, default 6)");
static void drm_get_displayid(struct drm_connector *connector,
struct edid *edid);
static int drm_edid_block_checksum(const u8 *raw_edid)
{
int i;
u8 csum = 0;
for (i = 0; i < EDID_LENGTH; i++)
csum += raw_edid[i];
return csum;
}
static bool drm_edid_is_zero(const u8 *in_edid, int length)
{
if (memchr_inv(in_edid, 0, length))
return false;
return true;
}
/**
* drm_edid_block_valid - Sanity check the EDID block (base or extension)
* @raw_edid: pointer to raw EDID block
@ -1027,8 +1049,7 @@ MODULE_PARM_DESC(edid_fixup,
*/
bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
{
int i;
u8 csum = 0;
u8 csum;
struct edid *edid = (struct edid *)raw_edid;
if (WARN_ON(!raw_edid))
@ -1048,8 +1069,7 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
}
}
for (i = 0; i < EDID_LENGTH; i++)
csum += raw_edid[i];
csum = drm_edid_block_checksum(raw_edid);
if (csum) {
if (print_bad_edid) {
DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
@ -1080,10 +1100,14 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
bad:
if (print_bad_edid) {
if (drm_edid_is_zero(raw_edid, EDID_LENGTH)) {
printk(KERN_ERR "EDID block is all zeroes\n");
} else {
printk(KERN_ERR "Raw EDID:\n");
print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1,
raw_edid, EDID_LENGTH, false);
}
}
return false;
}
EXPORT_SYMBOL(drm_edid_block_valid);
@ -1115,7 +1139,7 @@ EXPORT_SYMBOL(drm_edid_is_valid);
#define DDC_SEGMENT_ADDR 0x30
/**
* drm_do_probe_ddc_edid() - get EDID information via I2C
* @adapter: I2C device adaptor
* @data: I2C device adapter
* @buf: EDID data buffer to be filled
* @block: 128 byte EDID block to start fetching from
* @len: EDID data buffer length to fetch
@ -1125,9 +1149,9 @@ EXPORT_SYMBOL(drm_edid_is_valid);
* Return: 0 on success or -1 on failure.
*/
static int
drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
int block, int len)
drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len)
{
struct i2c_adapter *adapter = data;
unsigned char start = block * EDID_LENGTH;
unsigned char segment = block >> 1;
unsigned char xfers = segment ? 3 : 2;
@ -1176,16 +1200,26 @@ drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf,
return ret == xfers ? 0 : -1;
}
static bool drm_edid_is_zero(u8 *in_edid, int length)
{
if (memchr_inv(in_edid, 0, length))
return false;
return true;
}
static u8 *
drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
/**
* drm_do_get_edid - get EDID data using a custom EDID block read function
* @connector: connector we're probing
* @get_edid_block: EDID block read function
* @data: private data passed to the block read function
*
* When the I2C adapter connected to the DDC bus is hidden behind a device that
* exposes a different interface to read EDID blocks this function can be used
* to get EDID data using a custom block read function.
*
* As in the general case the DDC bus is accessible by the kernel at the I2C
* level, drivers must make all reasonable efforts to expose it as an I2C
* adapter and use drm_get_edid() instead of abusing this function.
*
* Return: Pointer to valid EDID or NULL if we couldn't find any.
*/
struct edid *drm_do_get_edid(struct drm_connector *connector,
int (*get_edid_block)(void *data, u8 *buf, unsigned int block,
size_t len),
void *data)
{
int i, j = 0, valid_extensions = 0;
u8 *block, *new;
@ -1196,7 +1230,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
/* base block fetch */
for (i = 0; i < 4; i++) {
if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH))
if (get_edid_block(data, block, 0, EDID_LENGTH))
goto out;
if (drm_edid_block_valid(block, 0, print_bad_edid))
break;
@ -1210,7 +1244,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
/* if there's no extensions, we're done */
if (block[0x7e] == 0)
return block;
return (struct edid *)block;
new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL);
if (!new)
@ -1219,7 +1253,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
for (j = 1; j <= block[0x7e]; j++) {
for (i = 0; i < 4; i++) {
if (drm_do_probe_ddc_edid(adapter,
if (get_edid_block(data,
block + (valid_extensions + 1) * EDID_LENGTH,
j, EDID_LENGTH))
goto out;
@ -1247,7 +1281,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
block = new;
}
return block;
return (struct edid *)block;
carp:
if (print_bad_edid) {
@ -1260,6 +1294,7 @@ out:
kfree(block);
return NULL;
}
EXPORT_SYMBOL_GPL(drm_do_get_edid);
/**
* drm_probe_ddc() - probe DDC presence
@ -1289,11 +1324,14 @@ EXPORT_SYMBOL(drm_probe_ddc);
struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter)
{
struct edid *edid = NULL;
struct edid *edid;
if (drm_probe_ddc(adapter))
edid = (struct edid *)drm_do_get_edid(connector, adapter);
if (!drm_probe_ddc(adapter))
return NULL;
edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
if (edid)
drm_get_displayid(connector, edid);
return edid;
}
EXPORT_SYMBOL(drm_get_edid);
@ -2103,7 +2141,8 @@ static int
add_inferred_modes(struct drm_connector *connector, struct edid *edid)
{
struct detailed_mode_closure closure = {
connector, edid, 0, 0, 0
.connector = connector,
.edid = edid,
};
if (version_greater(edid, 1, 0))
@ -2169,7 +2208,8 @@ add_established_modes(struct drm_connector *connector, struct edid *edid)
((edid->established_timings.mfg_rsvd & 0x80) << 9);
int i, modes = 0;
struct detailed_mode_closure closure = {
connector, edid, 0, 0, 0
.connector = connector,
.edid = edid,
};
for (i = 0; i <= EDID_EST_TIMINGS; i++) {
@ -2227,7 +2267,8 @@ add_standard_modes(struct drm_connector *connector, struct edid *edid)
{
int i, modes = 0;
struct detailed_mode_closure closure = {
connector, edid, 0, 0, 0
.connector = connector,
.edid = edid,
};
for (i = 0; i < EDID_STD_TIMINGS; i++) {
@ -2313,7 +2354,8 @@ static int
add_cvt_modes(struct drm_connector *connector, struct edid *edid)
{
struct detailed_mode_closure closure = {
connector, edid, 0, 0, 0
.connector = connector,
.edid = edid,
};
if (version_greater(edid, 1, 2))
@ -2357,11 +2399,10 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
u32 quirks)
{
struct detailed_mode_closure closure = {
connector,
edid,
1,
quirks,
0
.connector = connector,
.edid = edid,
.preferred = 1,
.quirks = quirks,
};
if (closure.preferred && !version_greater(edid, 1, 3))
@ -2386,7 +2427,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
/*
* Search EDID for CEA extension block.
*/
static u8 *drm_find_cea_extension(struct edid *edid)
static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
{
u8 *edid_ext = NULL;
int i;
@ -2398,7 +2439,7 @@ static u8 *drm_find_cea_extension(struct edid *edid)
/* Find CEA extension */
for (i = 0; i < edid->extensions; i++) {
edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
if (edid_ext[0] == CEA_EXT)
if (edid_ext[0] == ext_id)
break;
}
@ -2408,6 +2449,16 @@ static u8 *drm_find_cea_extension(struct edid *edid)
return edid_ext;
}
static u8 *drm_find_cea_extension(struct edid *edid)
{
return drm_find_edid_extension(edid, CEA_EXT);
}
static u8 *drm_find_displayid_extension(struct edid *edid)
{
return drm_find_edid_extension(edid, DISPLAYID_EXT);
}
/*
* Calculate the alternate clock for the CEA mode
* (60Hz vs. 59.94Hz etc.)
@ -2737,12 +2788,12 @@ static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
newmode = drm_display_mode_from_vic_index(connector, video_db,
video_len,
video_index);
if (newmode) {
if (newmode) {
newmode->flags |= DRM_MODE_FLAG_3D_FRAME_PACKING;
drm_mode_probed_add(connector, newmode);
modes++;
}
drm_mode_probed_add(connector, newmode);
modes++;
}
}
if (structure & (1 << 6)) {
newmode = drm_display_mode_from_vic_index(connector, video_db,
video_len,
@ -2986,7 +3037,7 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
hdmi = db;
hdmi_len = dbl;
}
}
}
}
/*
@ -3125,9 +3176,12 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
}
}
eld[5] |= sad_count << 4;
eld[2] = (20 + mnl + sad_count * 3 + 3) / 4;
DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", (int)eld[2], sad_count);
eld[DRM_ELD_BASELINE_ELD_LEN] =
DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4);
DRM_DEBUG_KMS("ELD size %d, SAD count %d\n",
drm_eld_size(eld), sad_count);
}
EXPORT_SYMBOL(drm_edid_to_eld);
@ -3433,10 +3487,10 @@ EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
/**
* drm_assign_hdmi_deep_color_info - detect whether monitor supports
* hdmi deep color modes and update drm_display_info if so.
*
* @edid: monitor EDID information
* @info: Updated with maximum supported deep color bpc and color format
* if deep color supported.
* @connector: DRM connector, used only for debug output
*
* Parse the CEA extension according to CEA-861-B.
* Return true if HDMI deep color supported, false if not or unknown.
@ -3865,3 +3919,123 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
return 0;
}
EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode);
static int drm_parse_display_id(struct drm_connector *connector,
u8 *displayid, int length,
bool is_edid_extension)
{
/* if this is an EDID extension the first byte will be 0x70 */
int idx = 0;
struct displayid_hdr *base;
struct displayid_block *block;
u8 csum = 0;
int i;
if (is_edid_extension)
idx = 1;
base = (struct displayid_hdr *)&displayid[idx];
DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
base->rev, base->bytes, base->prod_id, base->ext_count);
if (base->bytes + 5 > length - idx)
return -EINVAL;
for (i = idx; i <= base->bytes + 5; i++) {
csum += displayid[i];
}
if (csum) {
DRM_ERROR("DisplayID checksum invalid, remainder is %d\n", csum);
return -EINVAL;
}
block = (struct displayid_block *)&displayid[idx + 4];
DRM_DEBUG_KMS("block id %d, rev %d, len %d\n",
block->tag, block->rev, block->num_bytes);
switch (block->tag) {
case DATA_BLOCK_TILED_DISPLAY: {
struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block;
u16 w, h;
u8 tile_v_loc, tile_h_loc;
u8 num_v_tile, num_h_tile;
struct drm_tile_group *tg;
w = tile->tile_size[0] | tile->tile_size[1] << 8;
h = tile->tile_size[2] | tile->tile_size[3] << 8;
num_v_tile = (tile->topo[0] & 0xf) | (tile->topo[2] & 0x30);
num_h_tile = (tile->topo[0] >> 4) | ((tile->topo[2] >> 2) & 0x30);
tile_v_loc = (tile->topo[1] & 0xf) | ((tile->topo[2] & 0x3) << 4);
tile_h_loc = (tile->topo[1] >> 4) | (((tile->topo[2] >> 2) & 0x3) << 4);
connector->has_tile = true;
if (tile->tile_cap & 0x80)
connector->tile_is_single_monitor = true;
connector->num_h_tile = num_h_tile + 1;
connector->num_v_tile = num_v_tile + 1;
connector->tile_h_loc = tile_h_loc;
connector->tile_v_loc = tile_v_loc;
connector->tile_h_size = w + 1;
connector->tile_v_size = h + 1;
DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap);
DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1);
DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n",
num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc);
DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]);
tg = drm_mode_get_tile_group(connector->dev, tile->topology_id);
if (!tg) {
tg = drm_mode_create_tile_group(connector->dev, tile->topology_id);
}
if (!tg)
return -ENOMEM;
if (connector->tile_group != tg) {
/* if we haven't got a pointer,
take the reference, drop ref to old tile group */
if (connector->tile_group) {
drm_mode_put_tile_group(connector->dev, connector->tile_group);
}
connector->tile_group = tg;
} else
/* if same tile group, then release the ref we just took. */
drm_mode_put_tile_group(connector->dev, tg);
}
break;
default:
printk("unknown displayid tag %d\n", block->tag);
break;
}
return 0;
}
static void drm_get_displayid(struct drm_connector *connector,
struct edid *edid)
{
void *displayid = NULL;
int ret;
connector->has_tile = false;
displayid = drm_find_displayid_extension(edid);
if (!displayid) {
/* drop reference to any tile group we had */
goto out_drop_ref;
}
ret = drm_parse_display_id(connector, displayid, EDID_LENGTH, true);
if (ret < 0)
goto out_drop_ref;
if (!connector->has_tile)
goto out_drop_ref;
return;
out_drop_ref:
if (connector->tile_group) {
drm_mode_put_tile_group(connector->dev, connector->tile_group);
connector->tile_group = NULL;
}
return;
}

View File

@ -126,7 +126,7 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex));
if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) {
temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector) * (fb_helper->connector_count + 1), GFP_KERNEL);
temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL);
if (!temp)
return -ENOMEM;
@ -170,6 +170,7 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
return 0;
}
EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
{
uint16_t *r_base, *g_base, *b_base;
@ -210,10 +211,17 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper)
drm_warn_on_modeset_not_all_locked(dev);
list_for_each_entry(plane, &dev->mode_config.plane_list, head)
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
if (plane->type != DRM_PLANE_TYPE_PRIMARY)
drm_plane_force_disable(plane);
if (dev->mode_config.rotation_property) {
drm_mode_plane_set_obj_prop(plane,
dev->mode_config.rotation_property,
BIT(DRM_ROTATE_0));
}
}
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
struct drm_crtc *crtc = mode_set->crtc;
@ -243,6 +251,8 @@ bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
{
struct drm_device *dev = fb_helper->dev;
bool ret;
bool do_delayed = false;
drm_modeset_lock_all(dev);
ret = restore_fbdev_mode(fb_helper);
drm_modeset_unlock_all(dev);
@ -706,10 +716,6 @@ int drm_fb_helper_set_par(struct fb_info *info)
drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
if (fb_helper->delayed_hotplug) {
fb_helper->delayed_hotplug = false;
drm_fb_helper_hotplug_event(fb_helper);
}
return 0;
}
EXPORT_SYMBOL(drm_fb_helper_set_par);
@ -784,7 +790,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
struct drm_cmdline_mode *cmdline_mode;
cmdline_mode = &fb_helper_conn->cmdline_mode;
cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
if (cmdline_mode->bpp_specified) {
switch (cmdline_mode->bpp) {
@ -813,19 +819,21 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
crtc_count = 0;
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_display_mode *desired_mode;
int x, y;
desired_mode = fb_helper->crtc_info[i].desired_mode;
x = fb_helper->crtc_info[i].x;
y = fb_helper->crtc_info[i].y;
if (desired_mode) {
if (gamma_size == 0)
gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
if (desired_mode->hdisplay < sizes.fb_width)
sizes.fb_width = desired_mode->hdisplay;
if (desired_mode->vdisplay < sizes.fb_height)
sizes.fb_height = desired_mode->vdisplay;
if (desired_mode->hdisplay > sizes.surface_width)
sizes.surface_width = desired_mode->hdisplay;
if (desired_mode->vdisplay > sizes.surface_height)
sizes.surface_height = desired_mode->vdisplay;
if (desired_mode->hdisplay + x < sizes.fb_width)
sizes.fb_width = desired_mode->hdisplay + x;
if (desired_mode->vdisplay + y < sizes.fb_height)
sizes.fb_height = desired_mode->vdisplay + y;
if (desired_mode->hdisplay + x > sizes.surface_width)
sizes.surface_width = desired_mode->hdisplay + x;
if (desired_mode->vdisplay + y > sizes.surface_height)
sizes.surface_height = desired_mode->vdisplay + y;
crtc_count++;
}
}
@ -858,6 +866,8 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
info->var.pixclock = 0;
dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
info->node, info->fix.id);
list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
@ -1017,9 +1027,7 @@ EXPORT_SYMBOL(drm_has_preferred_mode);
static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
{
struct drm_cmdline_mode *cmdline_mode;
cmdline_mode = &fb_connector->cmdline_mode;
return cmdline_mode->specified;
return fb_connector->connector->cmdline_mode.specified;
}
struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
@ -1031,7 +1039,6 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
return NULL;
cmdline_mode = &fb_helper_conn->cmdline_mode;
if (cmdline_mode->specified == false)
return mode;
@ -1115,6 +1122,7 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
struct drm_display_mode **modes,
struct drm_fb_offset *offsets,
bool *enabled, int width, int height)
{
int count, i, j;
@ -1186,27 +1194,88 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
return false;
}
static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
struct drm_display_mode **modes,
struct drm_fb_offset *offsets,
int idx,
int h_idx, int v_idx)
{
struct drm_fb_helper_connector *fb_helper_conn;
int i;
int hoffset = 0, voffset = 0;
for (i = 0; i < fb_helper->connector_count; i++) {
fb_helper_conn = fb_helper->connector_info[i];
if (!fb_helper_conn->connector->has_tile)
continue;
if (!modes[i] && (h_idx || v_idx)) {
DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
fb_helper_conn->connector->base.id);
continue;
}
if (fb_helper_conn->connector->tile_h_loc < h_idx)
hoffset += modes[i]->hdisplay;
if (fb_helper_conn->connector->tile_v_loc < v_idx)
voffset += modes[i]->vdisplay;
}
offsets[idx].x = hoffset;
offsets[idx].y = voffset;
DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
return 0;
}
static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
struct drm_display_mode **modes,
struct drm_fb_offset *offsets,
bool *enabled, int width, int height)
{
struct drm_fb_helper_connector *fb_helper_conn;
int i;
uint64_t conn_configured = 0, mask;
int tile_pass = 0;
mask = (1 << fb_helper->connector_count) - 1;
retry:
for (i = 0; i < fb_helper->connector_count; i++) {
fb_helper_conn = fb_helper->connector_info[i];
if (enabled[i] == false)
if (conn_configured & (1 << i))
continue;
if (enabled[i] == false) {
conn_configured |= (1 << i);
continue;
}
/* first pass over all the untiled connectors */
if (tile_pass == 0 && fb_helper_conn->connector->has_tile)
continue;
if (tile_pass == 1) {
if (fb_helper_conn->connector->tile_h_loc != 0 ||
fb_helper_conn->connector->tile_v_loc != 0)
continue;
} else {
if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 &&
fb_helper_conn->connector->tile_v_loc != tile_pass - 1)
/* if this tile_pass doesn't cover any of the tiles - keep going */
continue;
/* find the tile offsets for this pass - need
to find all tiles left and above */
drm_get_tile_offsets(fb_helper, modes, offsets,
i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc);
}
DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
fb_helper_conn->connector->base.id);
/* got for command line mode first */
modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
if (!modes[i]) {
DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
fb_helper_conn->connector->base.id);
DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0);
modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
}
/* No preferred modes, pick one off the list */
@ -1216,6 +1285,12 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
}
DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
"none");
conn_configured |= (1 << i);
}
if ((conn_configured & mask) != mask) {
tile_pass++;
goto retry;
}
return true;
}
@ -1305,6 +1380,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
struct drm_device *dev = fb_helper->dev;
struct drm_fb_helper_crtc **crtcs;
struct drm_display_mode **modes;
struct drm_fb_offset *offsets;
struct drm_mode_set *modeset;
bool *enabled;
int width, height;
@ -1319,9 +1395,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
modes = kcalloc(dev->mode_config.num_connector,
sizeof(struct drm_display_mode *), GFP_KERNEL);
offsets = kcalloc(dev->mode_config.num_connector,
sizeof(struct drm_fb_offset), GFP_KERNEL);
enabled = kcalloc(dev->mode_config.num_connector,
sizeof(bool), GFP_KERNEL);
if (!crtcs || !modes || !enabled) {
if (!crtcs || !modes || !enabled || !offsets) {
DRM_ERROR("Memory allocation failed\n");
goto out;
}
@ -1331,14 +1409,16 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
if (!(fb_helper->funcs->initial_config &&
fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
offsets,
enabled, width, height))) {
memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0]));
memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0]));
memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0]));
if (!drm_target_cloned(fb_helper,
modes, enabled, width, height) &&
!drm_target_preferred(fb_helper,
modes, enabled, width, height))
if (!drm_target_cloned(fb_helper, modes, offsets,
enabled, width, height) &&
!drm_target_preferred(fb_helper, modes, offsets,
enabled, width, height))
DRM_ERROR("Unable to find initial modes\n");
DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
@ -1358,18 +1438,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
for (i = 0; i < fb_helper->connector_count; i++) {
struct drm_display_mode *mode = modes[i];
struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
struct drm_fb_offset *offset = &offsets[i];
modeset = &fb_crtc->mode_set;
if (mode && fb_crtc) {
DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
mode->name, fb_crtc->mode_set.crtc->base.id);
DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
fb_crtc->desired_mode = mode;
fb_crtc->x = offset->x;
fb_crtc->y = offset->y;
if (modeset->mode)
drm_mode_destroy(dev, modeset->mode);
modeset->mode = drm_mode_duplicate(dev,
fb_crtc->desired_mode);
modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
modeset->fb = fb_helper->fb;
modeset->x = offset->x;
modeset->y = offset->y;
}
}
@ -1378,7 +1463,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
modeset = &fb_helper->crtc_info[i].mode_set;
if (modeset->num_connectors == 0) {
BUG_ON(modeset->fb);
BUG_ON(modeset->num_connectors);
if (modeset->mode)
drm_mode_destroy(dev, modeset->mode);
modeset->mode = NULL;
@ -1387,6 +1471,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
out:
kfree(crtcs);
kfree(modes);
kfree(offsets);
kfree(enabled);
}
@ -1416,8 +1501,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
struct drm_device *dev = fb_helper->dev;
int count = 0;
// drm_fb_helper_parse_command_line(fb_helper);
mutex_lock(&dev->mode_config.mutex);
count = drm_fb_helper_probe_connector_modes(fb_helper,
dev->mode_config.max_width,

View File

@ -35,6 +35,8 @@
#include <linux/err.h>
#include <drm/drmP.h>
#include <drm/drm_vma_manager.h>
#include <drm/drm_gem.h>
#include "drm_internal.h"
/** @file drm_gem.c
*
@ -143,7 +145,7 @@ int drm_gem_object_init(struct drm_device *dev,
EXPORT_SYMBOL(drm_gem_object_init);
/**
* drm_gem_object_init - initialize an allocated private GEM object
* drm_gem_private_object_init - initialize an allocated private GEM object
* @dev: drm_device the object should be initialized for
* @obj: drm_gem_object to initialize
* @size: object size
@ -168,7 +170,7 @@ void drm_gem_private_object_init(struct drm_device *dev,
EXPORT_SYMBOL(drm_gem_private_object_init);
/**
* drm_gem_object_free - release resources bound to userspace handles
* drm_gem_object_handle_free - release resources bound to userspace handles
* @obj: GEM object to clean up.
*
* Called after the last handle to the object has been closed
@ -278,7 +280,7 @@ EXPORT_SYMBOL(drm_gem_dumb_destroy);
* drm_gem_handle_create_tail - internal functions to create a handle
* @file_priv: drm file-private structure to register the handle for
* @obj: object to register
* @handlep: pionter to return the created handle to the caller
* @handlep: pointer to return the created handle to the caller
*
* This expects the dev->object_name_lock to be held already and will drop it
* before returning. Used to avoid races in establishing new handles when
@ -331,7 +333,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
}
/**
* gem_handle_create - create a gem handle for an object
* drm_gem_handle_create - create a gem handle for an object
* @file_priv: drm file-private structure to register the handle for
* @obj: object to register
* @handlep: pionter to return the created handle to the caller
@ -340,8 +342,7 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
* to the object, which includes a regular reference count. Callers
* will likely want to dereference the object afterwards.
*/
int
drm_gem_handle_create(struct drm_file *file_priv,
int drm_gem_handle_create(struct drm_file *file_priv,
struct drm_gem_object *obj,
u32 *handlep)
{
@ -551,7 +552,7 @@ drm_gem_close_ioctl(struct drm_device *dev, void *data,
struct drm_gem_close *args = data;
int ret;
if (!(dev->driver->driver_features & DRIVER_GEM))
if (!drm_core_check_feature(dev, DRIVER_GEM))
return -ENODEV;
ret = drm_gem_handle_delete(file_priv, args->handle);
@ -578,7 +579,7 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
struct drm_gem_object *obj;
int ret;
if (!(dev->driver->driver_features & DRIVER_GEM))
if (!drm_core_check_feature(dev, DRIVER_GEM))
return -ENODEV;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
@ -631,7 +632,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
int ret;
u32 handle;
if (!(dev->driver->driver_features & DRIVER_GEM))
if (!drm_core_check_feature(dev, DRIVER_GEM))
return -ENODEV;
mutex_lock(&dev->object_name_lock);

View File

@ -0,0 +1,132 @@
/*
* Copyright © 2014 Intel Corporation
* Daniel Vetter <daniel.vetter@ffwll.ch>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/* drm_irq.c */
extern unsigned int drm_timestamp_monotonic;
/* drm_fops.c */
extern struct mutex drm_global_mutex;
int drm_lastclose(struct drm_device *dev);
/* drm_pci.c */
int drm_pci_set_unique(struct drm_device *dev,
struct drm_master *master,
struct drm_unique *u);
int drm_irq_by_busid(struct drm_device *dev, void *data,
struct drm_file *file_priv);
/* drm_vm.c */
int drm_vma_info(struct seq_file *m, void *data);
void drm_vm_open_locked(struct drm_device *dev, struct vm_area_struct *vma);
void drm_vm_close_locked(struct drm_device *dev, struct vm_area_struct *vma);
/* drm_prime.c */
int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv);
void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv,
struct dma_buf *dma_buf);
/* drm_info.c */
int drm_name_info(struct seq_file *m, void *data);
int drm_vm_info(struct seq_file *m, void *data);
int drm_bufs_info(struct seq_file *m, void *data);
int drm_vblank_info(struct seq_file *m, void *data);
int drm_clients_info(struct seq_file *m, void* data);
int drm_gem_name_info(struct seq_file *m, void *data);
/* drm_irq.c */
int drm_control(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int drm_modeset_ctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
/* drm_auth.c */
int drm_getmagic(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int drm_authmagic(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int drm_remove_magic(struct drm_master *master, drm_magic_t magic);
/* drm_sysfs.c */
extern struct class *drm_class;
struct class *drm_sysfs_create(struct module *owner, char *name);
void drm_sysfs_destroy(void);
struct device *drm_sysfs_minor_alloc(struct drm_minor *minor);
int drm_sysfs_connector_add(struct drm_connector *connector);
void drm_sysfs_connector_remove(struct drm_connector *connector);
/* drm_gem.c */
int drm_gem_init(struct drm_device *dev);
void drm_gem_destroy(struct drm_device *dev);
int drm_gem_handle_create_tail(struct drm_file *file_priv,
struct drm_gem_object *obj,
u32 *handlep);
int drm_gem_close_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int drm_gem_flink_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int drm_gem_open_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
void drm_gem_open(struct drm_device *dev, struct drm_file *file_private);
void drm_gem_release(struct drm_device *dev, struct drm_file *file_private);
/* drm_drv.c */
int drm_setmaster_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
struct drm_master *drm_master_create(struct drm_minor *minor);
/* drm_debugfs.c */
#if defined(CONFIG_DEBUG_FS)
int drm_debugfs_init(struct drm_minor *minor, int minor_id,
struct dentry *root);
int drm_debugfs_cleanup(struct drm_minor *minor);
int drm_debugfs_connector_add(struct drm_connector *connector);
void drm_debugfs_connector_remove(struct drm_connector *connector);
#else
static inline int drm_debugfs_init(struct drm_minor *minor, int minor_id,
struct dentry *root)
{
return 0;
}
static inline int drm_debugfs_cleanup(struct drm_minor *minor)
{
return 0;
}
static inline int drm_debugfs_connector_add(struct drm_connector *connector)
{
return 0;
}
static inline void drm_debugfs_connector_remove(struct drm_connector *connector)
{
}
#endif

View File

@ -33,13 +33,13 @@
*/
#include <drm/drmP.h>
#include <asm/div64.h>
//#include "drm_trace.h"
#include "drm_internal.h"
//#include <linux/interrupt.h> /* For task queue support */
#include <linux/slab.h>
//#include <linux/vgaarb.h>
#include <linux/vgaarb.h>
#include <linux/export.h>
/* Access macro for slots in vblank timestamp ringbuffer. */
@ -56,6 +56,12 @@
*/
#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
static bool
drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
struct timeval *tvblank, unsigned flags);
static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
/*
* Clear vblank timestamp buffer for a crtc.
*/
@ -86,11 +92,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
goto err;
for (i = 0; i < num_crtcs; i++) {
dev->vblank[i].dev = dev;
dev->vblank[i].crtc = i;
init_waitqueue_head(&dev->vblank[i].queue);
setup_timer(&dev->vblank[i].disable_timer, vblank_disable_fn,
(unsigned long)&dev->vblank[i]);
struct drm_vblank_crtc *vblank = &dev->vblank[i];
vblank->dev = dev;
vblank->crtc = i;
init_waitqueue_head(&vblank->queue);
setup_timer(&vblank->disable_timer, vblank_disable_fn,
(unsigned long)vblank);
}
DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n");
@ -106,7 +114,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
return 0;
err:
drm_vblank_cleanup(dev);
dev->num_crtcs = 0;
return ret;
}
EXPORT_SYMBOL(drm_vblank_init);
@ -178,7 +186,7 @@ int drm_irq_install(struct drm_device *dev, int irq)
dev->irq = irq;
}
u16_t cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4);
u16 cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4);
cmd&= ~(1<<10);
PciWrite16(dev->pdev->busnr, dev->pdev->devfn, 4, cmd);
@ -344,6 +352,159 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
}
EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
/**
* drm_vblank_get - get a reference count on vblank events
* @dev: DRM device
* @crtc: which CRTC to own
*
* Acquire a reference count on vblank events to avoid having them disabled
* while in use.
*
* This is the legacy version of drm_crtc_vblank_get().
*
* Returns:
* Zero on success, nonzero on failure.
*/
int drm_vblank_get(struct drm_device *dev, int crtc)
{
struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
unsigned long irqflags;
int ret = 0;
#if 0
if (WARN_ON(crtc >= dev->num_crtcs))
return -EINVAL;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* Going from 0->1 means we have to enable interrupts again */
if (atomic_add_return(1, &vblank->refcount) == 1) {
ret = drm_vblank_enable(dev, crtc);
} else {
if (!vblank->enabled) {
atomic_dec(&vblank->refcount);
ret = -EINVAL;
}
}
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
#endif
return ret;
}
EXPORT_SYMBOL(drm_vblank_get);
/**
* drm_crtc_vblank_get - get a reference count on vblank events
* @crtc: which CRTC to own
*
* Acquire a reference count on vblank events to avoid having them disabled
* while in use.
*
* This is the native kms version of drm_vblank_off().
*
* Returns:
* Zero on success, nonzero on failure.
*/
int drm_crtc_vblank_get(struct drm_crtc *crtc)
{
return drm_vblank_get(crtc->dev, drm_crtc_index(crtc));
}
EXPORT_SYMBOL(drm_crtc_vblank_get);
/**
* drm_vblank_put - give up ownership of vblank events
* @dev: DRM device
* @crtc: which counter to give up
*
* Release ownership of a given vblank counter, turning off interrupts
* if possible. Disable interrupts after drm_vblank_offdelay milliseconds.
*
* This is the legacy version of drm_crtc_vblank_put().
*/
void drm_vblank_put(struct drm_device *dev, int crtc)
{
#if 0
struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
if (WARN_ON(atomic_read(&vblank->refcount) == 0))
return;
if (WARN_ON(crtc >= dev->num_crtcs))
return;
/* Last user schedules interrupt disable */
if (atomic_dec_and_test(&vblank->refcount)) {
if (drm_vblank_offdelay == 0)
return;
else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0)
vblank_disable_fn((unsigned long)vblank);
else
mod_timer(&vblank->disable_timer,
jiffies + ((drm_vblank_offdelay * HZ)/1000));
}
#endif
}
EXPORT_SYMBOL(drm_vblank_put);
/**
* drm_crtc_vblank_put - give up ownership of vblank events
* @crtc: which counter to give up
*
* Release ownership of a given vblank counter, turning off interrupts
* if possible. Disable interrupts after drm_vblank_offdelay milliseconds.
*
* This is the native kms version of drm_vblank_put().
*/
void drm_crtc_vblank_put(struct drm_crtc *crtc)
{
drm_vblank_put(crtc->dev, drm_crtc_index(crtc));
}
EXPORT_SYMBOL(drm_crtc_vblank_put);
/**
* drm_wait_one_vblank - wait for one vblank
* @dev: DRM device
* @crtc: crtc index
*
* This waits for one vblank to pass on @crtc, using the irq driver interfaces.
* It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
* due to lack of driver support or because the crtc is off.
*/
void drm_wait_one_vblank(struct drm_device *dev, int crtc)
{
#if 0
int ret;
u32 last;
ret = drm_vblank_get(dev, crtc);
if (WARN(ret, "vblank not available on crtc %i, ret=%i\n", crtc, ret))
return;
last = drm_vblank_count(dev, crtc);
ret = wait_event_timeout(dev->vblank[crtc].queue,
last != drm_vblank_count(dev, crtc),
msecs_to_jiffies(100));
WARN(ret == 0, "vblank wait timed out on crtc %i\n", crtc);
drm_vblank_put(dev, crtc);
#endif
}
EXPORT_SYMBOL(drm_wait_one_vblank);
/**
* drm_crtc_wait_one_vblank - wait for one vblank
* @crtc: DRM crtc
*
* This waits for one vblank to pass on @crtc, using the irq driver interfaces.
* It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
* due to lack of driver support or because the crtc is off.
*/
void drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
{
drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc));
}
EXPORT_SYMBOL(drm_crtc_wait_one_vblank);
/**
* drm_vblank_off - disable vblank events on a CRTC
* @dev: DRM device
@ -360,6 +521,7 @@ EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
*/
void drm_vblank_off(struct drm_device *dev, int crtc)
{
struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
struct drm_pending_vblank_event *e, *t;
struct timeval now;
unsigned long irqflags;
@ -395,13 +557,14 @@ EXPORT_SYMBOL(drm_crtc_vblank_off);
*
* This functions restores the vblank interrupt state captured with
* drm_vblank_off() again. Note that calls to drm_vblank_on() and
* drm_vblank_off() can be unbalanced and so can also be unconditionaly called
* drm_vblank_off() can be unbalanced and so can also be unconditionally called
* in driver load code to reflect the current hardware state of the crtc.
*
* This is the legacy version of drm_crtc_vblank_on().
*/
void drm_vblank_on(struct drm_device *dev, int crtc)
{
struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
unsigned long irqflags;
}
@ -413,7 +576,7 @@ EXPORT_SYMBOL(drm_vblank_on);
*
* This functions restores the vblank interrupt state captured with
* drm_vblank_off() again. Note that calls to drm_vblank_on() and
* drm_vblank_off() can be unbalanced and so can also be unconditionaly called
* drm_vblank_off() can be unbalanced and so can also be unconditionally called
* in driver load code to reflect the current hardware state of the crtc.
*
* This is the native kms version of drm_vblank_on().
@ -453,6 +616,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
/* vblank is not initialized (IRQ not installed ?) */
if (!dev->num_crtcs)
return;
if (WARN_ON(crtc >= dev->num_crtcs))
return;
/*
* To avoid all the problems that might happen if interrupts
* were enabled/disabled around or between these calls, we just
@ -460,10 +627,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
* to avoid corrupting the count if multiple, mismatch calls occur),
* so that interrupts remain enabled in the interim.
*/
if (!dev->vblank[crtc].inmodeset) {
dev->vblank[crtc].inmodeset = 0x1;
if (!vblank->inmodeset) {
vblank->inmodeset = 0x1;
if (drm_vblank_get(dev, crtc) == 0)
dev->vblank[crtc].inmodeset |= 0x2;
vblank->inmodeset |= 0x2;
}
#endif
}
@ -486,16 +653,18 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
if (!dev->num_crtcs)
return;
if (dev->vblank[crtc].inmodeset) {
if (vblank->inmodeset) {
spin_lock_irqsave(&dev->vbl_lock, irqflags);
dev->vblank_disable_allowed = true;
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
if (dev->vblank[crtc].inmodeset & 0x2)
if (vblank->inmodeset & 0x2)
drm_vblank_put(dev, crtc);
dev->vblank[crtc].inmodeset = 0;
vblank->inmodeset = 0;
}
#endif
}
EXPORT_SYMBOL(drm_vblank_post_modeset);

View File

@ -0,0 +1,113 @@
#ifndef __DRM_LEGACY_H__
#define __DRM_LEGACY_H__
/*
* Copyright (c) 2014 David Herrmann <dh.herrmann@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* This file contains legacy interfaces that modern drm drivers
* should no longer be using. They cannot be removed as legacy
* drivers use them, and removing them are API breaks.
*/
#include <linux/list.h>
#include <drm/drm_legacy.h>
struct agp_memory;
struct drm_device;
struct drm_file;
/*
* Generic DRM Contexts
*/
#define DRM_KERNEL_CONTEXT 0
#define DRM_RESERVED_CONTEXTS 1
int drm_legacy_ctxbitmap_init(struct drm_device *dev);
void drm_legacy_ctxbitmap_cleanup(struct drm_device *dev);
void drm_legacy_ctxbitmap_free(struct drm_device *dev, int ctx_handle);
void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file);
int drm_legacy_resctx(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_addctx(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_getctx(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_switchctx(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_newctx(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_rmctx(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_setsareactx(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_getsareactx(struct drm_device *d, void *v, struct drm_file *f);
/*
* Generic Buffer Management
*/
#define DRM_MAP_HASH_OFFSET 0x10000000
int drm_legacy_addmap_ioctl(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_rmmap_ioctl(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_addbufs(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_infobufs(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_markbufs(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_freebufs(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_mapbufs(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_dma_ioctl(struct drm_device *d, void *v, struct drm_file *f);
void drm_legacy_vma_flush(struct drm_device *d);
/*
* AGP Support
*/
struct drm_agp_mem {
unsigned long handle;
struct agp_memory *memory;
unsigned long bound;
int pages;
struct list_head head;
};
/*
* Generic Userspace Locking-API
*/
int drm_legacy_i_have_hw_lock(struct drm_device *d, struct drm_file *f);
int drm_legacy_lock(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_unlock(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_lock_free(struct drm_lock_data *lock, unsigned int ctx);
/* DMA support */
int drm_legacy_dma_setup(struct drm_device *dev);
void drm_legacy_dma_takedown(struct drm_device *dev);
void drm_legacy_free_buffer(struct drm_device *dev,
struct drm_buf * buf);
void drm_legacy_reclaim_buffers(struct drm_device *dev,
struct drm_file *filp);
/* Scatter Gather Support */
void drm_legacy_sg_cleanup(struct drm_device *dev);
int drm_legacy_sg_alloc(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int drm_legacy_sg_free(struct drm_device *dev, void *data,
struct drm_file *file_priv);
#endif /* __DRM_LEGACY_H__ */

View File

@ -912,7 +912,7 @@ EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
*
* This function is a helper which can be used to validate modes against size
* limitations of the DRM device/connector. If a mode is too big its status
* memeber is updated with the appropriate validation failure code. The list
* member is updated with the appropriate validation failure code. The list
* itself is not changed.
*/
void drm_mode_validate_size(struct drm_device *dev,

View File

@ -35,7 +35,7 @@
* of extra utility/tracking out of our acquire-ctx. This is provided
* by drm_modeset_lock / drm_modeset_acquire_ctx.
*
* For basic principles of ww_mutex, see: Documentation/ww-mutex-design.txt
* For basic principles of ww_mutex, see: Documentation/locking/ww-mutex-design.txt
*
* The basic usage pattern is to:
*
@ -56,6 +56,230 @@
*/
/**
* __drm_modeset_lock_all - internal helper to grab all modeset locks
* @dev: DRM device
* @trylock: trylock mode for atomic contexts
*
* This is a special version of drm_modeset_lock_all() which can also be used in
* atomic contexts. Then @trylock must be set to true.
*
* Returns:
* 0 on success or negative error code on failure.
*/
int __drm_modeset_lock_all(struct drm_device *dev,
bool trylock)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx;
int ret;
ctx = kzalloc(sizeof(*ctx),
trylock ? GFP_ATOMIC : GFP_KERNEL);
if (!ctx)
return -ENOMEM;
if (trylock) {
if (!mutex_trylock(&config->mutex))
return -EBUSY;
} else {
mutex_lock(&config->mutex);
}
drm_modeset_acquire_init(ctx, 0);
ctx->trylock_only = trylock;
retry:
ret = drm_modeset_lock(&config->connection_mutex, ctx);
if (ret)
goto fail;
ret = drm_modeset_lock_all_crtcs(dev, ctx);
if (ret)
goto fail;
WARN_ON(config->acquire_ctx);
/* now we hold the locks, so now that it is safe, stash the
* ctx for drm_modeset_unlock_all():
*/
config->acquire_ctx = ctx;
drm_warn_on_modeset_not_all_locked(dev);
return 0;
fail:
if (ret == -EDEADLK) {
drm_modeset_backoff(ctx);
goto retry;
}
return ret;
}
EXPORT_SYMBOL(__drm_modeset_lock_all);
/**
* drm_modeset_lock_all - take all modeset locks
* @dev: drm device
*
* This function takes all modeset locks, suitable where a more fine-grained
* scheme isn't (yet) implemented. Locks must be dropped with
* drm_modeset_unlock_all.
*/
void drm_modeset_lock_all(struct drm_device *dev)
{
WARN_ON(__drm_modeset_lock_all(dev, false) != 0);
}
EXPORT_SYMBOL(drm_modeset_lock_all);
/**
* drm_modeset_unlock_all - drop all modeset locks
* @dev: device
*
* This function drop all modeset locks taken by drm_modeset_lock_all.
*/
void drm_modeset_unlock_all(struct drm_device *dev)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
if (WARN_ON(!ctx))
return;
config->acquire_ctx = NULL;
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);
kfree(ctx);
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_modeset_unlock_all);
/**
* drm_modeset_lock_crtc - lock crtc with hidden acquire ctx for a plane update
* @crtc: DRM CRTC
* @plane: DRM plane to be updated on @crtc
*
* This function locks the given crtc and plane (which should be either the
* primary or cursor plane) using a hidden acquire context. This is necessary so
* that drivers internally using the atomic interfaces can grab further locks
* with the lock acquire context.
*
* Note that @plane can be NULL, e.g. when the cursor support hasn't yet been
* converted to universal planes yet.
*/
void drm_modeset_lock_crtc(struct drm_crtc *crtc,
struct drm_plane *plane)
{
struct drm_modeset_acquire_ctx *ctx;
int ret;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (WARN_ON(!ctx))
return;
drm_modeset_acquire_init(ctx, 0);
retry:
ret = drm_modeset_lock(&crtc->mutex, ctx);
if (ret)
goto fail;
if (plane) {
ret = drm_modeset_lock(&plane->mutex, ctx);
if (ret)
goto fail;
if (plane->crtc) {
ret = drm_modeset_lock(&plane->crtc->mutex, ctx);
if (ret)
goto fail;
}
}
WARN_ON(crtc->acquire_ctx);
/* now we hold the locks, so now that it is safe, stash the
* ctx for drm_modeset_unlock_crtc():
*/
crtc->acquire_ctx = ctx;
return;
fail:
if (ret == -EDEADLK) {
drm_modeset_backoff(ctx);
goto retry;
}
}
EXPORT_SYMBOL(drm_modeset_lock_crtc);
/**
* drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls
* @crtc: drm crtc
*
* Legacy ioctl operations like cursor updates or page flips only have per-crtc
* locking, and store the acquire ctx in the corresponding crtc. All other
* legacy operations take all locks and use a global acquire context. This
* function grabs the right one.
*/
struct drm_modeset_acquire_ctx *
drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc)
{
if (crtc->acquire_ctx)
return crtc->acquire_ctx;
WARN_ON(!crtc->dev->mode_config.acquire_ctx);
return crtc->dev->mode_config.acquire_ctx;
}
EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx);
/**
* drm_modeset_unlock_crtc - drop crtc lock
* @crtc: drm crtc
*
* This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other
* locks acquired through the hidden context.
*/
void drm_modeset_unlock_crtc(struct drm_crtc *crtc)
{
struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx;
if (WARN_ON(!ctx))
return;
crtc->acquire_ctx = NULL;
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);
kfree(ctx);
}
EXPORT_SYMBOL(drm_modeset_unlock_crtc);
/**
* drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
* @dev: device
*
* Useful as a debug assert.
*/
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
{
struct drm_crtc *crtc;
/* Locking is currently fubar in the panic handler. */
// if (oops_in_progress)
// return;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
}
EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
/**
* drm_modeset_acquire_init - initialize acquire context
* @ctx: the acquire context
@ -108,7 +332,12 @@ static inline int modeset_lock(struct drm_modeset_lock *lock,
WARN_ON(ctx->contended);
if (interruptible && slow) {
if (ctx->trylock_only) {
if (!ww_mutex_trylock(&lock->mutex))
return -EBUSY;
else
return 0;
} else if (interruptible && slow) {
ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx);
} else if (interruptible) {
ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx);
@ -226,15 +455,14 @@ void drm_modeset_unlock(struct drm_modeset_lock *lock)
}
EXPORT_SYMBOL(drm_modeset_unlock);
/* Temporary.. until we have sufficiently fine grained locking, there
* are a couple scenarios where it is convenient to grab all crtc locks.
* It is planned to remove this:
*/
/* In some legacy codepaths it's convenient to just grab all the crtc and plane
* related locks. */
int drm_modeset_lock_all_crtcs(struct drm_device *dev,
struct drm_modeset_acquire_ctx *ctx)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_crtc *crtc;
struct drm_plane *plane;
int ret = 0;
list_for_each_entry(crtc, &config->crtc_list, head) {
@ -243,6 +471,12 @@ int drm_modeset_lock_all_crtcs(struct drm_device *dev,
return ret;
}
list_for_each_entry(plane, &config->plane_list, head) {
ret = drm_modeset_lock(&plane->mutex, ctx);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL(drm_modeset_lock_all_crtcs);

View File

@ -22,11 +22,12 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
//#include <linux/pci.h>
//#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include <drm/drmP.h>
#include "drm_legacy.h"
#include <syscall.h>
/**

View File

@ -27,10 +27,38 @@
#include <drm/drmP.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_rect.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_atomic_helper.h>
#define SUBPIXEL_MASK 0xffff
/**
* DOC: overview
*
* This helper library has two parts. The first part has support to implement
* primary plane support on top of the normal CRTC configuration interface.
* Since the legacy ->set_config interface ties the primary plane together with
* the CRTC state this does not allow userspace to disable the primary plane
* itself. To avoid too much duplicated code use
* drm_plane_helper_check_update() which can be used to enforce the same
* restrictions as primary planes had thus. The default primary plane only
* expose XRBG8888 and ARGB8888 as valid pixel formats for the attached
* framebuffer.
*
* Drivers are highly recommended to implement proper support for primary
* planes, and newly merged drivers must not rely upon these transitional
* helpers.
*
* The second part also implements transitional helpers which allow drivers to
* gradually switch to the atomic helper infrastructure for plane updates. Once
* that switch is complete drivers shouldn't use these any longer, instead using
* the proper legacy implementations for update and disable plane hooks provided
* by the atomic helpers.
*
* Again drivers are strongly urged to switch to the new interfaces.
*/
/*
* This is the minimal list of formats that seem to be safe for modeset use
* with all current DRM drivers. Most hardware can actually support more
@ -127,6 +155,11 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
return -ERANGE;
}
if (!fb) {
*visible = false;
return 0;
}
*visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale);
if (!*visible)
/*
@ -369,3 +402,171 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
}
EXPORT_SYMBOL(drm_crtc_init);
int drm_plane_helper_commit(struct drm_plane *plane,
struct drm_plane_state *plane_state,
struct drm_framebuffer *old_fb)
{
struct drm_plane_helper_funcs *plane_funcs;
struct drm_crtc *crtc[2];
struct drm_crtc_helper_funcs *crtc_funcs[2];
int i, ret = 0;
plane_funcs = plane->helper_private;
/* Since this is a transitional helper we can't assume that plane->state
* is always valid. Hence we need to use plane->crtc instead of
* plane->state->crtc as the old crtc. */
crtc[0] = plane->crtc;
crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
for (i = 0; i < 2; i++)
crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
if (plane_funcs->atomic_check) {
ret = plane_funcs->atomic_check(plane, plane_state);
if (ret)
goto out;
}
if (plane_funcs->prepare_fb && plane_state->fb) {
ret = plane_funcs->prepare_fb(plane, plane_state->fb);
if (ret)
goto out;
}
/* Point of no return, commit sw state. */
swap(plane->state, plane_state);
for (i = 0; i < 2; i++) {
if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
crtc_funcs[i]->atomic_begin(crtc[i]);
}
plane_funcs->atomic_update(plane, plane_state);
for (i = 0; i < 2; i++) {
if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
crtc_funcs[i]->atomic_flush(crtc[i]);
}
for (i = 0; i < 2; i++) {
if (!crtc[i])
continue;
/* There's no other way to figure out whether the crtc is running. */
ret = drm_crtc_vblank_get(crtc[i]);
if (ret == 0) {
drm_crtc_wait_one_vblank(crtc[i]);
drm_crtc_vblank_put(crtc[i]);
}
ret = 0;
}
if (plane_funcs->cleanup_fb && old_fb)
plane_funcs->cleanup_fb(plane, old_fb);
out:
if (plane_state) {
if (plane->funcs->atomic_destroy_state)
plane->funcs->atomic_destroy_state(plane, plane_state);
else
drm_atomic_helper_plane_destroy_state(plane, plane_state);
}
return ret;
}
/**
* drm_plane_helper_update() - Helper for primary plane update
* @plane: plane object to update
* @crtc: owning CRTC of owning plane
* @fb: framebuffer to flip onto plane
* @crtc_x: x offset of primary plane on crtc
* @crtc_y: y offset of primary plane on crtc
* @crtc_w: width of primary plane rectangle on crtc
* @crtc_h: height of primary plane rectangle on crtc
* @src_x: x offset of @fb for panning
* @src_y: y offset of @fb for panning
* @src_w: width of source rectangle in @fb
* @src_h: height of source rectangle in @fb
*
* Provides a default plane update handler using the atomic plane update
* functions. It is fully left to the driver to check plane constraints and
* handle corner-cases like a fully occluded or otherwise invisible plane.
*
* This is useful for piecewise transitioning of a driver to the atomic helpers.
*
* RETURNS:
* Zero on success, error code on failure
*/
int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
struct drm_plane_state *plane_state;
if (plane->funcs->atomic_duplicate_state)
plane_state = plane->funcs->atomic_duplicate_state(plane);
else if (plane->state)
plane_state = drm_atomic_helper_plane_duplicate_state(plane);
else
plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
if (!plane_state)
return -ENOMEM;
plane_state->crtc = crtc;
drm_atomic_set_fb_for_plane(plane_state, fb);
plane_state->crtc_x = crtc_x;
plane_state->crtc_y = crtc_y;
plane_state->crtc_h = crtc_h;
plane_state->crtc_w = crtc_w;
plane_state->src_x = src_x;
plane_state->src_y = src_y;
plane_state->src_h = src_h;
plane_state->src_w = src_w;
return drm_plane_helper_commit(plane, plane_state, plane->fb);
}
EXPORT_SYMBOL(drm_plane_helper_update);
/**
* drm_plane_helper_disable() - Helper for primary plane disable
* @plane: plane to disable
*
* Provides a default plane disable handler using the atomic plane update
* functions. It is fully left to the driver to check plane constraints and
* handle corner-cases like a fully occluded or otherwise invisible plane.
*
* This is useful for piecewise transitioning of a driver to the atomic helpers.
*
* RETURNS:
* Zero on success, error code on failure
*/
int drm_plane_helper_disable(struct drm_plane *plane)
{
struct drm_plane_state *plane_state;
/* crtc helpers love to call disable functions for already disabled hw
* functions. So cope with that. */
if (!plane->crtc)
return 0;
if (plane->funcs->atomic_duplicate_state)
plane_state = plane->funcs->atomic_duplicate_state(plane);
else if (plane->state)
plane_state = drm_atomic_helper_plane_duplicate_state(plane);
else
plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
if (!plane_state)
return -ENOMEM;
plane_state->crtc = NULL;
drm_atomic_set_fb_for_plane(plane_state, NULL);
return drm_plane_helper_commit(plane, plane_state, plane->fb);
}
EXPORT_SYMBOL(drm_plane_helper_disable);

View File

@ -102,7 +102,8 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
mode->status = MODE_UNVERIFIED;
if (connector->force) {
if (connector->force == DRM_FORCE_ON)
if (connector->force == DRM_FORCE_ON ||
connector->force == DRM_FORCE_ON_DIGITAL)
connector->status = connector_status_connected;
else
connector->status = connector_status_disconnected;

View File

@ -33,11 +33,6 @@
#include <drm/drmP.h>
#include <drm/drm_core.h>
struct va_format {
const char *fmt;
va_list *va;
};
unsigned int drm_debug = 0; /* 1 to enable debug output */
EXPORT_SYMBOL(drm_debug);
@ -61,22 +56,21 @@ EXPORT_SYMBOL(drm_timestamp_precision);
unsigned int drm_timestamp_monotonic = 1;
struct idr drm_minors_idr;
int drm_err(const char *func, const char *format, ...)
void drm_err(const char *format, ...)
{
struct va_format vaf;
va_list args;
int r;
struct va_format vaf;
va_list args;
va_start(args, format);
va_start(args, format);
vaf.fmt = format;
vaf.va = &args;
vaf.fmt = format;
vaf.va = &args;
r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
printk(KERN_ERR "[" DRM_NAME ":%pf] *ERROR* %pV",
__builtin_return_address(0), &vaf);
va_end(args);
return r;
va_end(args);
}
EXPORT_SYMBOL(drm_err);
@ -561,10 +555,6 @@ int drm_order(unsigned long size)
extern int x86_clflush_size;
static inline void clflush(volatile void *__p)
{
asm volatile("clflush %0" : "+m" (*(volatile char*)__p));
}
void drm_clflush_virt_range(void *addr, unsigned long length)
{

View File

@ -12,25 +12,19 @@
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
* ------------------------------------------------------------------------- */
/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
<kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
<kmalkki@cc.hut.fi> and Jean Delvare <jdelvare@suse.de> */
#include <types.h>
#include <list.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <syscall.h>
#include <linux/jiffies.h>
#include <errno.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <syscall.h>
#define I2C_FUNC_NOSTART 0x00000010 /* I2C_M_NOSTART */
@ -49,11 +43,11 @@
/* ----- global variables --------------------------------------------- */
static int bit_test = 0; /* see if the line-setting functions work */
static int bit_test; /* see if the line-setting functions work */
MODULE_PARM_DESC(bit_test, "lines testing - 0 off; 1 report; 2 fail if stuck");
#ifdef DEBUG
static int i2c_debug = 1;
module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(i2c_debug,
"debug level - 0 off; 1 normal; 2 verbose; 3 very verbose");
#endif
@ -97,14 +91,14 @@ static int sclhi(struct i2c_algo_bit_data *adap)
if (!adap->getscl)
goto done;
start = GetTimerTicks();
start = jiffies;
while (!getscl(adap)) {
/* This hw knows how to read the clock line, so we wait
* until it actually gets high. This is safer as some
* chips may hold it low ("clock stretching") while they
* are processing data internally.
*/
if (time_after(GetTimerTicks(), start + adap->timeout)) {
if (time_after(jiffies, start + adap->timeout)) {
/* Test one last time, as we may have been preempted
* between last check and timeout test.
*/
@ -112,8 +106,14 @@ static int sclhi(struct i2c_algo_bit_data *adap)
break;
return -ETIMEDOUT;
}
asm volatile("rep; nop" ::: "memory");
cpu_relax();
}
#ifdef DEBUG
if (jiffies != start && i2c_debug >= 3)
pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
"high\n", jiffies - start);
#endif
done:
udelay(adap->udelay);
return 0;
@ -650,3 +650,6 @@ int i2c_bit_add_bus(struct i2c_adapter *adap)
}
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
MODULE_LICENSE("GPL");

View File

@ -27,43 +27,13 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <list.h>
#include <errno.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <syscall.h>
#include <linux/jiffies.h>
#include <syscall.h>
@ -327,7 +297,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (ret != -EAGAIN)
break;
if (time_after(GetTimerTicks(), orig_jiffies + adap->timeout))
if (time_after((unsigned long)GetTimerTicks(), orig_jiffies + adap->timeout))
break;
delay(1);

View File

@ -1,21 +1,23 @@
CC = gcc
LD = ld
AS = as
FASM = fasm.exe
DEFINES = -D__KERNEL__ -DCONFIG_X86_32
DEFINES = -D__KERNEL__ -DCONFIG_X86_32 -DCONFIG_TINY_RCU -DCONFIG_X86_L1_CACHE_SHIFT=6
DEFINES += -DCONFIG_ARCH_HAS_CACHE_LINE_SIZE
DRV_TOPDIR = $(CURDIR)/../../..
DRM_TOPDIR = $(CURDIR)/..
DRV_INCLUDES = $(DRV_TOPDIR)/include
INCLUDES = -I$(DRV_INCLUDES) -I$(DRV_INCLUDES)/drm \
-I$(DRV_INCLUDES)/linux
INCLUDES = -I$(DRV_INCLUDES) \
-I$(DRV_INCLUDES)/asm \
-I$(DRV_INCLUDES)/uapi \
-I$(DRV_INCLUDES)/drm -I./ -I$(DRV_INCLUDES)
CFLAGS = -c -Os $(INCLUDES) $(DEFINES) -march=i686 -fomit-frame-pointer -fno-builtin-printf
CFLAGS= -c -O2 $(INCLUDES) $(DEFINES) -march=i686 -fno-ident -fomit-frame-pointer -fno-builtin-printf
CFLAGS+= -mno-stack-arg-probe -mpreferred-stack-boundary=2 -mincoming-stack-boundary=2 -mno-ms-bitfields
LIBPATH:= $(DRV_TOPDIR)/ddk
@ -30,7 +32,6 @@ NAME:= atikms
HFILES:= $(DRV_INCLUDES)/linux/types.h \
$(DRV_INCLUDES)/linux/list.h \
$(DRV_INCLUDES)/linux/pci.h \
$(DRV_INCLUDES)/drm/drm.h \
$(DRV_INCLUDES)/drm/drmP.h \
$(DRV_INCLUDES)/drm/drm_edid.h \
$(DRV_INCLUDES)/drm/drm_crtc.h \
@ -54,6 +55,7 @@ NAME_SRC= \
$(DRM_TOPDIR)/drm_crtc_helper.c \
$(DRM_TOPDIR)/drm_dp_helper.c \
$(DRM_TOPDIR)/drm_drv.c \
$(DRM_TOPDIR)/drm_atomic.c \
$(DRM_TOPDIR)/drm_edid.c \
$(DRM_TOPDIR)/drm_fb_helper.c \
$(DRM_TOPDIR)/drm_gem.c \
@ -123,6 +125,7 @@ NAME_SRC= \
radeon_ring.c \
radeon_sa.c \
radeon_semaphore.c \
radeon_sync.c \
radeon_test.c \
radeon_ttm.c \
radeon_ucode.c \
@ -139,7 +142,6 @@ NAME_SRC= \
rv740_dpm.c \
r520.c \
r600.c \
r600_audio.c \
r600_blit_shaders.c \
r600_cs.c \
r600_dma.c \

View File

@ -5,15 +5,17 @@ LD = ld
AS = as
FASM = fasm
DEFINES = -D__KERNEL__ -DCONFIG_X86_32
DEFINES = -D__KERNEL__ -DCONFIG_X86_32 -DCONFIG_TINY_RCU -DCONFIG_X86_L1_CACHE_SHIFT=6
DEFINES += -DCONFIG_ARCH_HAS_CACHE_LINE_SIZE
DDK_TOPDIR = d:\kos\kolibri\drivers\ddk
DRV_INCLUDES = /d/kos/kolibri/drivers/include
DRM_TOPDIR = $(CURDIR)/..
INCLUDES = -I$(DRV_INCLUDES)/linux/uapi -I$(DRV_INCLUDES)/linux \
-I$(DRV_INCLUDES)/linux/asm -I$(DRV_INCLUDES)/drm \
-I./ -I$(DRV_INCLUDES)
INCLUDES = -I$(DRV_INCLUDES) \
-I$(DRV_INCLUDES)/asm \
-I$(DRV_INCLUDES)/uapi \
-I$(DRV_INCLUDES)/drm -I./ -I$(DRV_INCLUDES)
CFLAGS_OPT = -Os -march=i686 -fno-ident -fomit-frame-pointer -fno-builtin-printf -mno-ms-bitfields
CFLAGS_OPT+= -mno-stack-arg-probe -mpreferred-stack-boundary=2 -mincoming-stack-boundary=2 -flto
@ -34,7 +36,6 @@ NAME:= atikms
HFILES:= $(DRV_INCLUDES)/linux/types.h \
$(DRV_INCLUDES)/linux/list.h \
$(DRV_INCLUDES)/linux/pci.h \
$(DRV_INCLUDES)/drm/drm.h \
$(DRV_INCLUDES)/drm/drmP.h \
$(DRV_INCLUDES)/drm/drm_edid.h \
$(DRV_INCLUDES)/drm/drm_crtc.h \
@ -58,6 +59,7 @@ NAME_SRC= \
$(DRM_TOPDIR)/drm_crtc_helper.c \
$(DRM_TOPDIR)/drm_dp_helper.c \
$(DRM_TOPDIR)/drm_drv.c \
$(DRM_TOPDIR)/drm_atomic.c \
$(DRM_TOPDIR)/drm_edid.c \
$(DRM_TOPDIR)/drm_fb_helper.c \
$(DRM_TOPDIR)/drm_gem.c \
@ -127,6 +129,7 @@ NAME_SRC= \
radeon_ring.c \
radeon_sa.c \
radeon_semaphore.c \
radeon_sync.c \
radeon_test.c \
radeon_ttm.c \
radeon_ucode.c \
@ -143,7 +146,6 @@ NAME_SRC= \
rv740_dpm.c \
r520.c \
r600.c \
r600_audio.c \
r600_blit_shaders.c \
r600_cs.c \
r600_dma.c \

View File

@ -1215,7 +1215,7 @@ free:
return ret;
}
int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
int atom_execute_table_scratch_unlocked(struct atom_context *ctx, int index, uint32_t * params)
{
int r;
@ -1236,6 +1236,15 @@ int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
return r;
}
int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
{
int r;
mutex_lock(&ctx->scratch_mutex);
r = atom_execute_table_scratch_unlocked(ctx, index, params);
mutex_unlock(&ctx->scratch_mutex);
return r;
}
static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
static void atom_index_iio(struct atom_context *ctx, int base)
@ -1344,7 +1353,7 @@ int atom_asic_init(struct atom_context *ctx)
void atom_destroy(struct atom_context *ctx)
{
kfree(ctx->iio);
kfree(ctx->iio);
kfree(ctx);
}

View File

@ -125,6 +125,7 @@ struct card_info {
struct atom_context {
struct card_info *card;
struct mutex mutex;
struct mutex scratch_mutex;
void *bios;
uint32_t cmd_table, data_table;
uint16_t *iio;
@ -145,6 +146,7 @@ extern int atom_debug;
struct atom_context *atom_parse(struct card_info *, void *);
int atom_execute_table(struct atom_context *, int, uint32_t *);
int atom_execute_table_scratch_unlocked(struct atom_context *, int, uint32_t *);
int atom_asic_init(struct atom_context *);
void atom_destroy(struct atom_context *);
bool atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size,

View File

@ -2039,6 +2039,7 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
atombios_crtc_set_base(crtc, x, y, old_fb);
atombios_overscan_setup(crtc, mode, adjusted_mode);
atombios_scaler_setup(crtc);
// radeon_cursor_reset(crtc);
/* update the hw version fpr dpm */
radeon_crtc->hw_mode = *adjusted_mode;

View File

@ -100,6 +100,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
memset(&args, 0, sizeof(args));
mutex_lock(&chan->mutex);
mutex_lock(&rdev->mode_info.atom_context->scratch_mutex);
base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);
@ -113,7 +114,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
if (ASIC_IS_DCE4(rdev))
args.v2.ucHPD_ID = chan->rec.hpd;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
atom_execute_table_scratch_unlocked(rdev->mode_info.atom_context, index, (uint32_t *)&args);
*ack = args.v1.ucReplyStatus;
@ -147,6 +148,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
r = recv_bytes;
done:
mutex_unlock(&rdev->mode_info.atom_context->scratch_mutex);
mutex_unlock(&chan->mutex);
return r;
@ -232,8 +234,8 @@ void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
/***** general DP utility functions *****/
#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200
#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPHASIS_9_5
#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_LEVEL_3
#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPH_LEVEL_3
static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count,

View File

@ -291,29 +291,6 @@ static void radeon_atom_backlight_exit(struct radeon_encoder *encoder)
bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
struct drm_display_mode *mode);
static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
case ENCODER_OBJECT_ID_INTERNAL_DDI:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
return true;
default:
return false;
}
}
static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)

View File

@ -48,6 +48,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
memset(&args, 0, sizeof(args));
mutex_lock(&chan->mutex);
mutex_lock(&rdev->mode_info.atom_context->scratch_mutex);
base = (unsigned char *)rdev->mode_info.atom_context->scratch;
@ -82,7 +83,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
args.ucSlaveAddr = slave_addr << 1;
args.ucLineNumber = chan->rec.i2c_id;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
atom_execute_table_scratch_unlocked(rdev->mode_info.atom_context, index, (uint32_t *)&args);
/* error */
if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) {
@ -95,6 +96,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan,
radeon_atom_copy_swap(buf, base, num, false);
done:
mutex_unlock(&rdev->mode_info.atom_context->scratch_mutex);
mutex_unlock(&chan->mutex);
return r;

View File

@ -24,6 +24,7 @@
#include "drmP.h"
#include "radeon.h"
#include "radeon_asic.h"
#include "btcd.h"
#include "r600_dpm.h"
#include "cypress_dpm.h"
@ -2099,7 +2100,6 @@ static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
bool disable_mclk_switching;
u32 mclk, sclk;
u16 vddc, vddci;
u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
btc_dpm_vblank_too_short(rdev))
@ -2141,39 +2141,6 @@ static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
ps->low.vddci = max_limits->vddci;
}
/* limit clocks to max supported clocks based on voltage dependency tables */
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
&max_sclk_vddc);
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
&max_mclk_vddci);
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
&max_mclk_vddc);
if (max_sclk_vddc) {
if (ps->low.sclk > max_sclk_vddc)
ps->low.sclk = max_sclk_vddc;
if (ps->medium.sclk > max_sclk_vddc)
ps->medium.sclk = max_sclk_vddc;
if (ps->high.sclk > max_sclk_vddc)
ps->high.sclk = max_sclk_vddc;
}
if (max_mclk_vddci) {
if (ps->low.mclk > max_mclk_vddci)
ps->low.mclk = max_mclk_vddci;
if (ps->medium.mclk > max_mclk_vddci)
ps->medium.mclk = max_mclk_vddci;
if (ps->high.mclk > max_mclk_vddci)
ps->high.mclk = max_mclk_vddci;
}
if (max_mclk_vddc) {
if (ps->low.mclk > max_mclk_vddc)
ps->low.mclk = max_mclk_vddc;
if (ps->medium.mclk > max_mclk_vddc)
ps->medium.mclk = max_mclk_vddc;
if (ps->high.mclk > max_mclk_vddc)
ps->high.mclk = max_mclk_vddc;
}
/* XXX validate the min clocks required for display */
if (disable_mclk_switching) {

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,8 @@
#define CISLANDS_MAX_HARDWARE_POWERLEVELS 2
#define CISLANDS_UNUSED_GPIO_PIN 0x7F
struct ci_pl {
u32 mclk;
u32 sclk;
@ -237,6 +239,7 @@ struct ci_power_info {
u32 sclk_dpm_key_disabled;
u32 mclk_dpm_key_disabled;
u32 pcie_dpm_key_disabled;
u32 thermal_sclk_dpm_enabled;
struct ci_pcie_perf_range pcie_gen_performance;
struct ci_pcie_perf_range pcie_lane_performance;
struct ci_pcie_perf_range pcie_gen_powersaving;
@ -264,6 +267,7 @@ struct ci_power_info {
bool caps_automatic_dc_transition;
bool caps_sclk_throttle_low_notification;
bool caps_dynamic_ac_timing;
bool caps_od_fuzzy_fan_control_support;
/* flags */
bool thermal_protection;
bool pcie_performance_request;
@ -285,6 +289,10 @@ struct ci_power_info {
struct ci_ps current_ps;
struct radeon_ps requested_rps;
struct ci_ps requested_ps;
/* fan control */
bool fan_ctrl_is_in_default_mode;
u32 t_min;
u32 fan_ctrl_default_mode;
};
#define CISLANDS_VOLTAGE_CONTROL_NONE 0x0

View File

@ -129,7 +129,7 @@ void ci_reset_smc(struct radeon_device *rdev)
int ci_program_jump_on_start(struct radeon_device *rdev)
{
static u8 data[] = { 0xE0, 0x00, 0x80, 0x40 };
static const u8 data[] = { 0xE0, 0x00, 0x80, 0x40 };
return ci_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
}

View File

@ -32,6 +32,7 @@
#include "cik_blit_shaders.h"
#include "radeon_ucode.h"
#include "clearstate_ci.h"
#include "radeon_kfd.h"
MODULE_FIRMWARE("radeon/BONAIRE_pfp.bin");
MODULE_FIRMWARE("radeon/BONAIRE_me.bin");
@ -1563,6 +1564,8 @@ static const u32 godavari_golden_registers[] =
static void cik_init_golden_registers(struct radeon_device *rdev)
{
/* Some of the registers might be dependent on GRBM_GFX_INDEX */
mutex_lock(&rdev->grbm_idx_mutex);
switch (rdev->family) {
case CHIP_BONAIRE:
radeon_program_register_sequence(rdev,
@ -1637,6 +1640,7 @@ static void cik_init_golden_registers(struct radeon_device *rdev)
default:
break;
}
mutex_unlock(&rdev->grbm_idx_mutex);
}
/**
@ -1806,7 +1810,7 @@ int ci_mc_load_microcode(struct radeon_device *rdev)
{
const __be32 *fw_data = NULL;
const __le32 *new_fw_data = NULL;
u32 running, blackout = 0;
u32 running, blackout = 0, tmp;
u32 *io_mc_regs = NULL;
const __le32 *new_io_mc_regs = NULL;
int i, regs_size, ucode_size;
@ -1866,6 +1870,15 @@ int ci_mc_load_microcode(struct radeon_device *rdev)
WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]);
}
}
tmp = RREG32(MC_SEQ_MISC0);
if ((rdev->pdev->device == 0x6649) && ((tmp & 0xff00) == 0x5600)) {
WREG32(MC_SEQ_IO_DEBUG_INDEX, 5);
WREG32(MC_SEQ_IO_DEBUG_DATA, 0x00000023);
WREG32(MC_SEQ_IO_DEBUG_INDEX, 9);
WREG32(MC_SEQ_IO_DEBUG_DATA, 0x000001f0);
}
/* load the MC ucode */
for (i = 0; i < ucode_size; i++) {
if (rdev->new_fw)
@ -3419,6 +3432,7 @@ static void cik_setup_rb(struct radeon_device *rdev,
u32 disabled_rbs = 0;
u32 enabled_rbs = 0;
mutex_lock(&rdev->grbm_idx_mutex);
for (i = 0; i < se_num; i++) {
for (j = 0; j < sh_per_se; j++) {
cik_select_se_sh(rdev, i, j);
@ -3430,6 +3444,7 @@ static void cik_setup_rb(struct radeon_device *rdev,
}
}
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
mutex_unlock(&rdev->grbm_idx_mutex);
mask = 1;
for (i = 0; i < max_rb_num_per_se * se_num; i++) {
@ -3440,6 +3455,7 @@ static void cik_setup_rb(struct radeon_device *rdev,
rdev->config.cik.backend_enable_mask = enabled_rbs;
mutex_lock(&rdev->grbm_idx_mutex);
for (i = 0; i < se_num; i++) {
cik_select_se_sh(rdev, i, 0xffffffff);
data = 0;
@ -3467,6 +3483,7 @@ static void cik_setup_rb(struct radeon_device *rdev,
WREG32(PA_SC_RASTER_CONFIG, data);
}
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
mutex_unlock(&rdev->grbm_idx_mutex);
}
/**
@ -3684,6 +3701,12 @@ static void cik_gpu_init(struct radeon_device *rdev)
/* set HW defaults for 3D engine */
WREG32(CP_MEQ_THRESHOLDS, MEQ1_START(0x30) | MEQ2_START(0x60));
mutex_lock(&rdev->grbm_idx_mutex);
/*
* making sure that the following register writes will be broadcasted
* to all the shaders
*/
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
WREG32(SX_DEBUG_1, 0x20);
WREG32(TA_CNTL_AUX, 0x00010000);
@ -3739,6 +3762,7 @@ static void cik_gpu_init(struct radeon_device *rdev)
WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3));
WREG32(PA_SC_ENHANCE, ENABLE_PA_SC_OUT_OF_ORDER);
mutex_unlock(&rdev->grbm_idx_mutex);
udelay(50);
}
@ -3959,41 +3983,38 @@ bool cik_semaphore_ring_emit(struct radeon_device *rdev,
* @src_offset: src GPU address
* @dst_offset: dst GPU address
* @num_gpu_pages: number of GPU pages to xfer
* @fence: radeon fence object
* @resv: reservation object to sync to
*
* Copy GPU paging using the CP DMA engine (CIK+).
* Used by the radeon ttm implementation to move pages if
* registered as the asic copy callback.
*/
int cik_copy_cpdma(struct radeon_device *rdev,
struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence)
struct reservation_object *resv)
{
struct radeon_semaphore *sem = NULL;
struct radeon_fence *fence;
struct radeon_sync sync;
int ring_index = rdev->asic->copy.blit_ring_index;
struct radeon_ring *ring = &rdev->ring[ring_index];
u32 size_in_bytes, cur_size_in_bytes, control;
int i, num_loops;
int r = 0;
r = radeon_semaphore_create(rdev, &sem);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
}
radeon_sync_create(&sync);
size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
r = radeon_ring_lock(rdev, ring, num_loops * 7 + 18);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
radeon_sync_free(rdev, &sync, NULL);
return ERR_PTR(r);
}
radeon_semaphore_sync_to(sem, *fence);
radeon_semaphore_sync_rings(rdev, sem, ring->idx);
radeon_sync_resv(rdev, &sync, resv, false);
radeon_sync_rings(rdev, &sync, ring->idx);
for (i = 0; i < num_loops; i++) {
cur_size_in_bytes = size_in_bytes;
@ -4014,17 +4035,17 @@ int cik_copy_cpdma(struct radeon_device *rdev,
dst_offset += cur_size_in_bytes;
}
r = radeon_fence_emit(rdev, fence, ring->idx);
r = radeon_fence_emit(rdev, &fence, ring->idx);
if (r) {
radeon_ring_unlock_undo(rdev, ring);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
radeon_sync_free(rdev, &sync, NULL);
return ERR_PTR(r);
}
radeon_ring_unlock_commit(rdev, ring, false);
radeon_semaphore_free(rdev, &sem, *fence);
radeon_sync_free(rdev, &sync, fence);
return r;
return fence;
}
/*
@ -4045,6 +4066,7 @@ int cik_copy_cpdma(struct radeon_device *rdev,
void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
{
struct radeon_ring *ring = &rdev->ring[ib->ring];
unsigned vm_id = ib->vm ? ib->vm->ids[ib->ring].id : 0;
u32 header, control = INDIRECT_BUFFER_VALID;
if (ib->is_const_ib) {
@ -4073,8 +4095,7 @@ void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
}
control |= ib->length_dw |
(ib->vm ? (ib->vm->id << 24) : 0);
control |= ib->length_dw | (vm_id << 24);
radeon_ring_write(ring, header);
radeon_ring_write(ring,
@ -4234,7 +4255,7 @@ static int cik_cp_gfx_load_microcode(struct radeon_device *rdev)
WREG32(CP_PFP_UCODE_ADDR, 0);
for (i = 0; i < fw_size; i++)
WREG32(CP_PFP_UCODE_DATA, le32_to_cpup(fw_data++));
WREG32(CP_PFP_UCODE_ADDR, 0);
WREG32(CP_PFP_UCODE_ADDR, le32_to_cpu(pfp_hdr->header.ucode_version));
/* CE */
fw_data = (const __le32 *)
@ -4243,7 +4264,7 @@ static int cik_cp_gfx_load_microcode(struct radeon_device *rdev)
WREG32(CP_CE_UCODE_ADDR, 0);
for (i = 0; i < fw_size; i++)
WREG32(CP_CE_UCODE_DATA, le32_to_cpup(fw_data++));
WREG32(CP_CE_UCODE_ADDR, 0);
WREG32(CP_CE_UCODE_ADDR, le32_to_cpu(ce_hdr->header.ucode_version));
/* ME */
fw_data = (const __be32 *)
@ -4252,7 +4273,8 @@ static int cik_cp_gfx_load_microcode(struct radeon_device *rdev)
WREG32(CP_ME_RAM_WADDR, 0);
for (i = 0; i < fw_size; i++)
WREG32(CP_ME_RAM_DATA, le32_to_cpup(fw_data++));
WREG32(CP_ME_RAM_WADDR, 0);
WREG32(CP_ME_RAM_WADDR, le32_to_cpu(me_hdr->header.ucode_version));
WREG32(CP_ME_RAM_RADDR, le32_to_cpu(me_hdr->header.ucode_version));
} else {
const __be32 *fw_data;
@ -4278,10 +4300,6 @@ static int cik_cp_gfx_load_microcode(struct radeon_device *rdev)
WREG32(CP_ME_RAM_WADDR, 0);
}
WREG32(CP_PFP_UCODE_ADDR, 0);
WREG32(CP_CE_UCODE_ADDR, 0);
WREG32(CP_ME_RAM_WADDR, 0);
WREG32(CP_ME_RAM_RADDR, 0);
return 0;
}
@ -4315,8 +4333,8 @@ static int cik_cp_gfx_start(struct radeon_device *rdev)
/* init the CE partitions. CE only used for gfx on CIK */
radeon_ring_write(ring, PACKET3(PACKET3_SET_BASE, 2));
radeon_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE));
radeon_ring_write(ring, 0xc000);
radeon_ring_write(ring, 0xc000);
radeon_ring_write(ring, 0x8000);
radeon_ring_write(ring, 0x8000);
/* setup clear context state */
radeon_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
@ -4563,7 +4581,7 @@ static int cik_cp_compute_load_microcode(struct radeon_device *rdev)
WREG32(CP_MEC_ME1_UCODE_ADDR, 0);
for (i = 0; i < fw_size; i++)
WREG32(CP_MEC_ME1_UCODE_DATA, le32_to_cpup(fw_data++));
WREG32(CP_MEC_ME1_UCODE_ADDR, 0);
WREG32(CP_MEC_ME1_UCODE_ADDR, le32_to_cpu(mec_hdr->header.ucode_version));
/* MEC2 */
if (rdev->family == CHIP_KAVERI) {
@ -4577,7 +4595,7 @@ static int cik_cp_compute_load_microcode(struct radeon_device *rdev)
WREG32(CP_MEC_ME2_UCODE_ADDR, 0);
for (i = 0; i < fw_size; i++)
WREG32(CP_MEC_ME2_UCODE_DATA, le32_to_cpup(fw_data++));
WREG32(CP_MEC_ME2_UCODE_ADDR, 0);
WREG32(CP_MEC_ME2_UCODE_ADDR, le32_to_cpu(mec2_hdr->header.ucode_version));
}
} else {
const __be32 *fw_data;
@ -4677,19 +4695,18 @@ static int cik_mec_init(struct radeon_device *rdev)
/*
* KV: 2 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 64 Queues total
* CI/KB: 1 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 32 Queues total
* Nonetheless, we assign only 1 pipe because all other pipes will
* be handled by KFD
*/
if (rdev->family == CHIP_KAVERI)
rdev->mec.num_mec = 2;
else
rdev->mec.num_mec = 1;
rdev->mec.num_pipe = 4;
rdev->mec.num_pipe = 1;
rdev->mec.num_queue = rdev->mec.num_mec * rdev->mec.num_pipe * 8;
if (rdev->mec.hpd_eop_obj == NULL) {
r = radeon_bo_create(rdev,
rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2,
PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, 0, NULL,
RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL,
&rdev->mec.hpd_eop_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create HDP EOP bo failed\n", r);
@ -4824,13 +4841,10 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
/* init the pipes */
mutex_lock(&rdev->srbm_mutex);
for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) {
int me = (i < 4) ? 1 : 2;
int pipe = (i < 4) ? i : (i - 4);
eop_gpu_addr = rdev->mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE * 2);
eop_gpu_addr = rdev->mec.hpd_eop_gpu_addr;
cik_srbm_select(rdev, me, pipe, 0, 0);
cik_srbm_select(rdev, 0, 0, 0, 0);
/* write the EOP addr */
WREG32(CP_HPD_EOP_BASE_ADDR, eop_gpu_addr >> 8);
@ -4844,8 +4858,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
tmp &= ~EOP_SIZE_MASK;
tmp |= order_base_2(MEC_HPD_SIZE / 8);
WREG32(CP_HPD_EOP_CONTROL, tmp);
}
cik_srbm_select(rdev, 0, 0, 0, 0);
mutex_unlock(&rdev->srbm_mutex);
/* init the queues. Just two for now. */
@ -4860,7 +4873,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
sizeof(struct bonaire_mqd),
PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, 0, NULL,
&rdev->ring[idx].mqd_obj);
NULL, &rdev->ring[idx].mqd_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create MQD bo failed\n", r);
return r;
@ -5899,8 +5912,13 @@ int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
*/
int cik_vm_init(struct radeon_device *rdev)
{
/* number of VMs */
rdev->vm_manager.nvm = 16;
/*
* number of VMs
* VMID 0 is reserved for System
* radeon graphics/compute will use VMIDs 1-7
* amdkfd will use VMIDs 8-15
*/
rdev->vm_manager.nvm = RADEON_NUM_OF_VMIDS;
/* base offset of vram pages */
if (rdev->flags & RADEON_IS_IGP) {
u64 tmp = RREG32(MC_VM_FB_OFFSET);
@ -5960,26 +5978,23 @@ static void cik_vm_decode_fault(struct radeon_device *rdev,
* Update the page table base and flush the VM TLB
* using the CP (CIK).
*/
void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
void cik_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr)
{
struct radeon_ring *ring = &rdev->ring[ridx];
int usepfp = (ridx == RADEON_RING_TYPE_GFX_INDEX);
if (vm == NULL)
return;
int usepfp = (ring->idx == RADEON_RING_TYPE_GFX_INDEX);
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
WRITE_DATA_DST_SEL(0)));
if (vm->id < 8) {
if (vm_id < 8) {
radeon_ring_write(ring,
(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2);
} else {
radeon_ring_write(ring,
(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm_id - 8) << 2)) >> 2);
}
radeon_ring_write(ring, 0);
radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
radeon_ring_write(ring, pd_addr >> 12);
/* update SH_MEM_* regs */
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
@ -5987,7 +6002,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
WRITE_DATA_DST_SEL(0)));
radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
radeon_ring_write(ring, 0);
radeon_ring_write(ring, VMID(vm->id));
radeon_ring_write(ring, VMID(vm_id));
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 6));
radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
@ -6008,7 +6023,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
radeon_ring_write(ring, VMID(0));
/* HDP flush */
cik_hdp_flush_cp_ring_emit(rdev, ridx);
cik_hdp_flush_cp_ring_emit(rdev, ring->idx);
/* bits 0-15 are the VM contexts0-15 */
radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
@ -6016,7 +6031,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
WRITE_DATA_DST_SEL(0)));
radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
radeon_ring_write(ring, 0);
radeon_ring_write(ring, 1 << vm->id);
radeon_ring_write(ring, 1 << vm_id);
/* compute doesn't have PFP */
if (usepfp) {
@ -6061,6 +6076,7 @@ static void cik_wait_for_rlc_serdes(struct radeon_device *rdev)
u32 i, j, k;
u32 mask;
mutex_lock(&rdev->grbm_idx_mutex);
for (i = 0; i < rdev->config.cik.max_shader_engines; i++) {
for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) {
cik_select_se_sh(rdev, i, j);
@ -6072,6 +6088,7 @@ static void cik_wait_for_rlc_serdes(struct radeon_device *rdev)
}
}
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
mutex_unlock(&rdev->grbm_idx_mutex);
mask = SE_MASTER_BUSY_MASK | GC_MASTER_BUSY | TC0_MASTER_BUSY | TC1_MASTER_BUSY;
for (k = 0; k < rdev->usec_timeout; k++) {
@ -6206,10 +6223,12 @@ static int cik_rlc_resume(struct radeon_device *rdev)
WREG32(RLC_LB_CNTR_INIT, 0);
WREG32(RLC_LB_CNTR_MAX, 0x00008000);
mutex_lock(&rdev->grbm_idx_mutex);
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff);
WREG32(RLC_LB_PARAMS, 0x00600408);
WREG32(RLC_LB_CNTL, 0x80000004);
mutex_unlock(&rdev->grbm_idx_mutex);
WREG32(RLC_MC_CNTL, 0);
WREG32(RLC_UCODE_CNTL, 0);
@ -6226,7 +6245,7 @@ static int cik_rlc_resume(struct radeon_device *rdev)
WREG32(RLC_GPM_UCODE_ADDR, 0);
for (i = 0; i < size; i++)
WREG32(RLC_GPM_UCODE_DATA, le32_to_cpup(fw_data++));
WREG32(RLC_GPM_UCODE_ADDR, 0);
WREG32(RLC_GPM_UCODE_ADDR, le32_to_cpu(hdr->header.ucode_version));
} else {
const __be32 *fw_data;
@ -6276,11 +6295,13 @@ static void cik_enable_cgcg(struct radeon_device *rdev, bool enable)
tmp = cik_halt_rlc(rdev);
mutex_lock(&rdev->grbm_idx_mutex);
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff);
WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff);
tmp2 = BPM_ADDR_MASK | CGCG_OVERRIDE_0 | CGLS_ENABLE;
WREG32(RLC_SERDES_WR_CTRL, tmp2);
mutex_unlock(&rdev->grbm_idx_mutex);
cik_update_rlc(rdev, tmp);
@ -6316,17 +6337,20 @@ static void cik_enable_mgcg(struct radeon_device *rdev, bool enable)
}
orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE);
data |= 0x00000001;
data &= 0xfffffffd;
if (orig != data)
WREG32(RLC_CGTT_MGCG_OVERRIDE, data);
tmp = cik_halt_rlc(rdev);
mutex_lock(&rdev->grbm_idx_mutex);
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff);
WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff);
data = BPM_ADDR_MASK | MGCG_OVERRIDE_0;
WREG32(RLC_SERDES_WR_CTRL, data);
mutex_unlock(&rdev->grbm_idx_mutex);
cik_update_rlc(rdev, tmp);
@ -6347,7 +6371,7 @@ static void cik_enable_mgcg(struct radeon_device *rdev, bool enable)
}
} else {
orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE);
data |= 0x00000002;
data |= 0x00000003;
if (orig != data)
WREG32(RLC_CGTT_MGCG_OVERRIDE, data);
@ -6370,11 +6394,13 @@ static void cik_enable_mgcg(struct radeon_device *rdev, bool enable)
tmp = cik_halt_rlc(rdev);
mutex_lock(&rdev->grbm_idx_mutex);
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
WREG32(RLC_SERDES_WR_CU_MASTER_MASK, 0xffffffff);
WREG32(RLC_SERDES_WR_NONCU_MASTER_MASK, 0xffffffff);
data = BPM_ADDR_MASK | MGCG_OVERRIDE_1;
WREG32(RLC_SERDES_WR_CTRL, data);
mutex_unlock(&rdev->grbm_idx_mutex);
cik_update_rlc(rdev, tmp);
}
@ -6803,10 +6829,12 @@ static u32 cik_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh)
u32 mask = 0, tmp, tmp1;
int i;
mutex_lock(&rdev->grbm_idx_mutex);
cik_select_se_sh(rdev, se, sh);
tmp = RREG32(CC_GC_SHADER_ARRAY_CONFIG);
tmp1 = RREG32(GC_USER_SHADER_ARRAY_CONFIG);
cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
mutex_unlock(&rdev->grbm_idx_mutex);
tmp &= 0xffff0000;
@ -7290,8 +7318,7 @@ static int cik_irq_init(struct radeon_device *rdev)
int cik_irq_set(struct radeon_device *rdev)
{
u32 cp_int_cntl;
u32 cp_m1p0, cp_m1p1, cp_m1p2, cp_m1p3;
u32 cp_m2p0, cp_m2p1, cp_m2p2, cp_m2p3;
u32 cp_m1p0;
u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
u32 grbm_int_cntl = 0;
@ -7325,13 +7352,6 @@ int cik_irq_set(struct radeon_device *rdev)
dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
cp_m1p0 = RREG32(CP_ME1_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
cp_m1p1 = RREG32(CP_ME1_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
cp_m1p2 = RREG32(CP_ME1_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
cp_m1p3 = RREG32(CP_ME1_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
cp_m2p0 = RREG32(CP_ME2_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
cp_m2p1 = RREG32(CP_ME2_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
cp_m2p2 = RREG32(CP_ME2_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
cp_m2p3 = RREG32(CP_ME2_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
if (rdev->flags & RADEON_IS_IGP)
thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL) &
@ -7353,33 +7373,6 @@ int cik_irq_set(struct radeon_device *rdev)
case 0:
cp_m1p0 |= TIME_STAMP_INT_ENABLE;
break;
case 1:
cp_m1p1 |= TIME_STAMP_INT_ENABLE;
break;
case 2:
cp_m1p2 |= TIME_STAMP_INT_ENABLE;
break;
case 3:
cp_m1p2 |= TIME_STAMP_INT_ENABLE;
break;
default:
DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe);
break;
}
} else if (ring->me == 2) {
switch (ring->pipe) {
case 0:
cp_m2p0 |= TIME_STAMP_INT_ENABLE;
break;
case 1:
cp_m2p1 |= TIME_STAMP_INT_ENABLE;
break;
case 2:
cp_m2p2 |= TIME_STAMP_INT_ENABLE;
break;
case 3:
cp_m2p2 |= TIME_STAMP_INT_ENABLE;
break;
default:
DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe);
break;
@ -7396,33 +7389,6 @@ int cik_irq_set(struct radeon_device *rdev)
case 0:
cp_m1p0 |= TIME_STAMP_INT_ENABLE;
break;
case 1:
cp_m1p1 |= TIME_STAMP_INT_ENABLE;
break;
case 2:
cp_m1p2 |= TIME_STAMP_INT_ENABLE;
break;
case 3:
cp_m1p2 |= TIME_STAMP_INT_ENABLE;
break;
default:
DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe);
break;
}
} else if (ring->me == 2) {
switch (ring->pipe) {
case 0:
cp_m2p0 |= TIME_STAMP_INT_ENABLE;
break;
case 1:
cp_m2p1 |= TIME_STAMP_INT_ENABLE;
break;
case 2:
cp_m2p2 |= TIME_STAMP_INT_ENABLE;
break;
case 3:
cp_m2p2 |= TIME_STAMP_INT_ENABLE;
break;
default:
DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe);
break;
@ -7511,13 +7477,6 @@ int cik_irq_set(struct radeon_device *rdev)
WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, dma_cntl1);
WREG32(CP_ME1_PIPE0_INT_CNTL, cp_m1p0);
WREG32(CP_ME1_PIPE1_INT_CNTL, cp_m1p1);
WREG32(CP_ME1_PIPE2_INT_CNTL, cp_m1p2);
WREG32(CP_ME1_PIPE3_INT_CNTL, cp_m1p3);
WREG32(CP_ME2_PIPE0_INT_CNTL, cp_m2p0);
WREG32(CP_ME2_PIPE1_INT_CNTL, cp_m2p1);
WREG32(CP_ME2_PIPE2_INT_CNTL, cp_m2p2);
WREG32(CP_ME2_PIPE3_INT_CNTL, cp_m2p3);
WREG32(GRBM_INT_CNTL, grbm_int_cntl);
@ -7834,6 +7793,10 @@ restart_ih:
while (rptr != wptr) {
/* wptr/rptr are in bytes! */
ring_index = rptr / 4;
// radeon_kfd_interrupt(rdev,
// (const void *) &rdev->ih.ring[ring_index]);
src_id = le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
ring_id = le32_to_cpu(rdev->ih.ring[ring_index + 2]) & 0xff;
@ -8457,6 +8420,10 @@ static int cik_startup(struct radeon_device *rdev)
return r;
}
// r = radeon_kfd_resume(rdev);
// if (r)
// return r;
return 0;
}
@ -9280,6 +9247,9 @@ void dce8_bandwidth_update(struct radeon_device *rdev)
u32 num_heads = 0, lb_size;
int i;
if (!rdev->mode_info.mode_config_initialized)
return;
radeon_update_display_priority(rdev);
for (i = 0; i < rdev->num_crtc; i++) {

View File

@ -147,4 +147,140 @@
#define CIK_LB_DESKTOP_HEIGHT 0x6b0c
#define CP_HQD_IQ_RPTR 0xC970u
#define AQL_ENABLE (1U << 0)
#define IDLE (1 << 2)
struct cik_mqd {
uint32_t header;
uint32_t compute_dispatch_initiator;
uint32_t compute_dim_x;
uint32_t compute_dim_y;
uint32_t compute_dim_z;
uint32_t compute_start_x;
uint32_t compute_start_y;
uint32_t compute_start_z;
uint32_t compute_num_thread_x;
uint32_t compute_num_thread_y;
uint32_t compute_num_thread_z;
uint32_t compute_pipelinestat_enable;
uint32_t compute_perfcount_enable;
uint32_t compute_pgm_lo;
uint32_t compute_pgm_hi;
uint32_t compute_tba_lo;
uint32_t compute_tba_hi;
uint32_t compute_tma_lo;
uint32_t compute_tma_hi;
uint32_t compute_pgm_rsrc1;
uint32_t compute_pgm_rsrc2;
uint32_t compute_vmid;
uint32_t compute_resource_limits;
uint32_t compute_static_thread_mgmt_se0;
uint32_t compute_static_thread_mgmt_se1;
uint32_t compute_tmpring_size;
uint32_t compute_static_thread_mgmt_se2;
uint32_t compute_static_thread_mgmt_se3;
uint32_t compute_restart_x;
uint32_t compute_restart_y;
uint32_t compute_restart_z;
uint32_t compute_thread_trace_enable;
uint32_t compute_misc_reserved;
uint32_t compute_user_data_0;
uint32_t compute_user_data_1;
uint32_t compute_user_data_2;
uint32_t compute_user_data_3;
uint32_t compute_user_data_4;
uint32_t compute_user_data_5;
uint32_t compute_user_data_6;
uint32_t compute_user_data_7;
uint32_t compute_user_data_8;
uint32_t compute_user_data_9;
uint32_t compute_user_data_10;
uint32_t compute_user_data_11;
uint32_t compute_user_data_12;
uint32_t compute_user_data_13;
uint32_t compute_user_data_14;
uint32_t compute_user_data_15;
uint32_t cp_compute_csinvoc_count_lo;
uint32_t cp_compute_csinvoc_count_hi;
uint32_t cp_mqd_base_addr_lo;
uint32_t cp_mqd_base_addr_hi;
uint32_t cp_hqd_active;
uint32_t cp_hqd_vmid;
uint32_t cp_hqd_persistent_state;
uint32_t cp_hqd_pipe_priority;
uint32_t cp_hqd_queue_priority;
uint32_t cp_hqd_quantum;
uint32_t cp_hqd_pq_base_lo;
uint32_t cp_hqd_pq_base_hi;
uint32_t cp_hqd_pq_rptr;
uint32_t cp_hqd_pq_rptr_report_addr_lo;
uint32_t cp_hqd_pq_rptr_report_addr_hi;
uint32_t cp_hqd_pq_wptr_poll_addr_lo;
uint32_t cp_hqd_pq_wptr_poll_addr_hi;
uint32_t cp_hqd_pq_doorbell_control;
uint32_t cp_hqd_pq_wptr;
uint32_t cp_hqd_pq_control;
uint32_t cp_hqd_ib_base_addr_lo;
uint32_t cp_hqd_ib_base_addr_hi;
uint32_t cp_hqd_ib_rptr;
uint32_t cp_hqd_ib_control;
uint32_t cp_hqd_iq_timer;
uint32_t cp_hqd_iq_rptr;
uint32_t cp_hqd_dequeue_request;
uint32_t cp_hqd_dma_offload;
uint32_t cp_hqd_sema_cmd;
uint32_t cp_hqd_msg_type;
uint32_t cp_hqd_atomic0_preop_lo;
uint32_t cp_hqd_atomic0_preop_hi;
uint32_t cp_hqd_atomic1_preop_lo;
uint32_t cp_hqd_atomic1_preop_hi;
uint32_t cp_hqd_hq_status0;
uint32_t cp_hqd_hq_control0;
uint32_t cp_mqd_control;
uint32_t cp_mqd_query_time_lo;
uint32_t cp_mqd_query_time_hi;
uint32_t cp_mqd_connect_start_time_lo;
uint32_t cp_mqd_connect_start_time_hi;
uint32_t cp_mqd_connect_end_time_lo;
uint32_t cp_mqd_connect_end_time_hi;
uint32_t cp_mqd_connect_end_wf_count;
uint32_t cp_mqd_connect_end_pq_rptr;
uint32_t cp_mqd_connect_end_pq_wptr;
uint32_t cp_mqd_connect_end_ib_rptr;
uint32_t reserved_96;
uint32_t reserved_97;
uint32_t reserved_98;
uint32_t reserved_99;
uint32_t iqtimer_pkt_header;
uint32_t iqtimer_pkt_dw0;
uint32_t iqtimer_pkt_dw1;
uint32_t iqtimer_pkt_dw2;
uint32_t iqtimer_pkt_dw3;
uint32_t iqtimer_pkt_dw4;
uint32_t iqtimer_pkt_dw5;
uint32_t iqtimer_pkt_dw6;
uint32_t reserved_108;
uint32_t reserved_109;
uint32_t reserved_110;
uint32_t reserved_111;
uint32_t queue_doorbell_id0;
uint32_t queue_doorbell_id1;
uint32_t queue_doorbell_id2;
uint32_t queue_doorbell_id3;
uint32_t queue_doorbell_id4;
uint32_t queue_doorbell_id5;
uint32_t queue_doorbell_id6;
uint32_t queue_doorbell_id7;
uint32_t queue_doorbell_id8;
uint32_t queue_doorbell_id9;
uint32_t queue_doorbell_id10;
uint32_t queue_doorbell_id11;
uint32_t queue_doorbell_id12;
uint32_t queue_doorbell_id13;
uint32_t queue_doorbell_id14;
uint32_t queue_doorbell_id15;
};
#endif

View File

@ -134,7 +134,7 @@ void cik_sdma_ring_ib_execute(struct radeon_device *rdev,
struct radeon_ib *ib)
{
struct radeon_ring *ring = &rdev->ring[ib->ring];
u32 extra_bits = (ib->vm ? ib->vm->id : 0) & 0xf;
u32 extra_bits = (ib->vm ? ib->vm->ids[ib->ring].id : 0) & 0xf;
if (rdev->wb.enabled) {
u32 next_rptr = ring->wptr + 5;
@ -530,41 +530,38 @@ void cik_sdma_fini(struct radeon_device *rdev)
* @src_offset: src GPU address
* @dst_offset: dst GPU address
* @num_gpu_pages: number of GPU pages to xfer
* @fence: radeon fence object
* @resv: reservation object to sync to
*
* Copy GPU paging using the DMA engine (CIK).
* Used by the radeon ttm implementation to move pages if
* registered as the asic copy callback.
*/
int cik_copy_dma(struct radeon_device *rdev,
struct radeon_fence *cik_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence)
struct reservation_object *resv)
{
struct radeon_semaphore *sem = NULL;
struct radeon_fence *fence;
struct radeon_sync sync;
int ring_index = rdev->asic->copy.dma_ring_index;
struct radeon_ring *ring = &rdev->ring[ring_index];
u32 size_in_bytes, cur_size_in_bytes;
int i, num_loops;
int r = 0;
r = radeon_semaphore_create(rdev, &sem);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
}
radeon_sync_create(&sync);
size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
r = radeon_ring_lock(rdev, ring, num_loops * 7 + 14);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
radeon_sync_free(rdev, &sync, NULL);
return ERR_PTR(r);
}
radeon_semaphore_sync_to(sem, *fence);
radeon_semaphore_sync_rings(rdev, sem, ring->idx);
radeon_sync_resv(rdev, &sync, resv, false);
radeon_sync_rings(rdev, &sync, ring->idx);
for (i = 0; i < num_loops; i++) {
cur_size_in_bytes = size_in_bytes;
@ -582,17 +579,17 @@ int cik_copy_dma(struct radeon_device *rdev,
dst_offset += cur_size_in_bytes;
}
r = radeon_fence_emit(rdev, fence, ring->idx);
r = radeon_fence_emit(rdev, &fence, ring->idx);
if (r) {
radeon_ring_unlock_undo(rdev, ring);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
radeon_sync_free(rdev, &sync, NULL);
return ERR_PTR(r);
}
radeon_ring_unlock_commit(rdev, ring, false);
radeon_semaphore_free(rdev, &sem, *fence);
radeon_sync_free(rdev, &sync, fence);
return r;
return fence;
}
/**
@ -666,17 +663,20 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
{
struct radeon_ib ib;
unsigned i;
unsigned index;
int r;
void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
u32 tmp = 0;
u64 gpu_addr;
if (!ptr) {
DRM_ERROR("invalid vram scratch pointer\n");
return -EINVAL;
}
if (ring->idx == R600_RING_TYPE_DMA_INDEX)
index = R600_WB_DMA_RING_TEST_OFFSET;
else
index = CAYMAN_WB_DMA1_RING_TEST_OFFSET;
gpu_addr = rdev->wb.gpu_addr + index;
tmp = 0xCAFEDEAD;
writel(tmp, ptr);
rdev->wb.wb[index/4] = cpu_to_le32(tmp);
r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
if (r) {
@ -685,8 +685,8 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
}
ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0);
ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc;
ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr);
ib.ptr[1] = lower_32_bits(gpu_addr);
ib.ptr[2] = upper_32_bits(gpu_addr);
ib.ptr[3] = 1;
ib.ptr[4] = 0xDEADBEEF;
ib.length_dw = 5;
@ -703,7 +703,7 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
return r;
}
for (i = 0; i < rdev->usec_timeout; i++) {
tmp = readl(ptr);
tmp = le32_to_cpu(rdev->wb.wb[index/4]);
if (tmp == 0xDEADBEEF)
break;
DRM_UDELAY(1);
@ -900,25 +900,21 @@ void cik_sdma_vm_pad_ib(struct radeon_ib *ib)
* Update the page table base and flush the VM TLB
* using sDMA (CIK).
*/
void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr)
{
struct radeon_ring *ring = &rdev->ring[ridx];
if (vm == NULL)
return;
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
if (vm->id < 8) {
radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
if (vm_id < 8) {
radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2);
} else {
radeon_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
radeon_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm_id - 8) << 2)) >> 2);
}
radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
radeon_ring_write(ring, pd_addr >> 12);
/* update SH_MEM_* regs */
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
radeon_ring_write(ring, VMID(vm->id));
radeon_ring_write(ring, VMID(vm_id));
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
radeon_ring_write(ring, SH_MEM_BASES >> 2);
@ -941,11 +937,11 @@ void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm
radeon_ring_write(ring, VMID(0));
/* flush HDP */
cik_sdma_hdp_flush_ring_emit(rdev, ridx);
cik_sdma_hdp_flush_ring_emit(rdev, ring->idx);
/* flush TLB */
radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
radeon_ring_write(ring, 1 << vm->id);
radeon_ring_write(ring, 1 << vm_id);
}

View File

@ -30,6 +30,8 @@
#define CIK_RB_BITMAP_WIDTH_PER_SH 2
#define HAWAII_RB_BITMAP_WIDTH_PER_SH 4
#define RADEON_NUM_OF_VMIDS 8
/* DIDT IND registers */
#define DIDT_SQ_CTRL0 0x0
# define DIDT_CTRL_EN (1 << 0)
@ -184,7 +186,10 @@
#define DIG_THERM_DPM(x) ((x) << 14)
#define DIG_THERM_DPM_MASK 0x003FC000
#define DIG_THERM_DPM_SHIFT 14
#define CG_THERMAL_STATUS 0xC0300008
#define FDO_PWM_DUTY(x) ((x) << 9)
#define FDO_PWM_DUTY_MASK (0xff << 9)
#define FDO_PWM_DUTY_SHIFT 9
#define CG_THERMAL_INT 0xC030000C
#define CI_DIG_THERM_INTH(x) ((x) << 8)
#define CI_DIG_THERM_INTH_MASK 0x0000FF00
@ -194,7 +199,10 @@
#define CI_DIG_THERM_INTL_SHIFT 16
#define THERM_INT_MASK_HIGH (1 << 24)
#define THERM_INT_MASK_LOW (1 << 25)
#define CG_MULT_THERMAL_CTRL 0xC0300010
#define TEMP_SEL(x) ((x) << 20)
#define TEMP_SEL_MASK (0xff << 20)
#define TEMP_SEL_SHIFT 20
#define CG_MULT_THERMAL_STATUS 0xC0300014
#define ASIC_MAX_TEMP(x) ((x) << 0)
#define ASIC_MAX_TEMP_MASK 0x000001ff
@ -203,6 +211,36 @@
#define CTF_TEMP_MASK 0x0003fe00
#define CTF_TEMP_SHIFT 9
#define CG_FDO_CTRL0 0xC0300064
#define FDO_STATIC_DUTY(x) ((x) << 0)
#define FDO_STATIC_DUTY_MASK 0x000000FF
#define FDO_STATIC_DUTY_SHIFT 0
#define CG_FDO_CTRL1 0xC0300068
#define FMAX_DUTY100(x) ((x) << 0)
#define FMAX_DUTY100_MASK 0x000000FF
#define FMAX_DUTY100_SHIFT 0
#define CG_FDO_CTRL2 0xC030006C
#define TMIN(x) ((x) << 0)
#define TMIN_MASK 0x000000FF
#define TMIN_SHIFT 0
#define FDO_PWM_MODE(x) ((x) << 11)
#define FDO_PWM_MODE_MASK (7 << 11)
#define FDO_PWM_MODE_SHIFT 11
#define TACH_PWM_RESP_RATE(x) ((x) << 25)
#define TACH_PWM_RESP_RATE_MASK (0x7f << 25)
#define TACH_PWM_RESP_RATE_SHIFT 25
#define CG_TACH_CTRL 0xC0300070
# define EDGE_PER_REV(x) ((x) << 0)
# define EDGE_PER_REV_MASK (0x7 << 0)
# define EDGE_PER_REV_SHIFT 0
# define TARGET_PERIOD(x) ((x) << 3)
# define TARGET_PERIOD_MASK 0xfffffff8
# define TARGET_PERIOD_SHIFT 3
#define CG_TACH_STATUS 0xC0300074
# define TACH_PERIOD(x) ((x) << 0)
# define TACH_PERIOD_MASK 0xffffffff
# define TACH_PERIOD_SHIFT 0
#define CG_ECLK_CNTL 0xC05000AC
# define ECLK_DIVIDER_MASK 0x7f
# define ECLK_DIR_CNTL_EN (1 << 8)
@ -1137,6 +1175,9 @@
#define SH_MEM_ALIGNMENT_MODE_UNALIGNED 3
#define DEFAULT_MTYPE(x) ((x) << 4)
#define APE1_MTYPE(x) ((x) << 7)
/* valid for both DEFAULT_MTYPE and APE1_MTYPE */
#define MTYPE_CACHED 0
#define MTYPE_NONCACHED 3
#define SX_DEBUG_1 0x9060
@ -1447,6 +1488,16 @@
#define CP_HQD_ACTIVE 0xC91C
#define CP_HQD_VMID 0xC920
#define CP_HQD_PERSISTENT_STATE 0xC924u
#define DEFAULT_CP_HQD_PERSISTENT_STATE (0x33U << 8)
#define CP_HQD_PIPE_PRIORITY 0xC928u
#define CP_HQD_QUEUE_PRIORITY 0xC92Cu
#define CP_HQD_QUANTUM 0xC930u
#define QUANTUM_EN 1U
#define QUANTUM_SCALE_1MS (1U << 4)
#define QUANTUM_DURATION(x) ((x) << 8)
#define CP_HQD_PQ_BASE 0xC934
#define CP_HQD_PQ_BASE_HI 0xC938
#define CP_HQD_PQ_RPTR 0xC93C
@ -1474,12 +1525,32 @@
#define PRIV_STATE (1 << 30)
#define KMD_QUEUE (1 << 31)
#define CP_HQD_IB_BASE_ADDR 0xC95Cu
#define CP_HQD_IB_BASE_ADDR_HI 0xC960u
#define CP_HQD_IB_RPTR 0xC964u
#define CP_HQD_IB_CONTROL 0xC968u
#define IB_ATC_EN (1U << 23)
#define DEFAULT_MIN_IB_AVAIL_SIZE (3U << 20)
#define CP_HQD_DEQUEUE_REQUEST 0xC974
#define DEQUEUE_REQUEST_DRAIN 1
#define DEQUEUE_REQUEST_RESET 2
#define CP_MQD_CONTROL 0xC99C
#define MQD_VMID(x) ((x) << 0)
#define MQD_VMID_MASK (0xf << 0)
#define CP_HQD_SEMA_CMD 0xC97Cu
#define CP_HQD_MSG_TYPE 0xC980u
#define CP_HQD_ATOMIC0_PREOP_LO 0xC984u
#define CP_HQD_ATOMIC0_PREOP_HI 0xC988u
#define CP_HQD_ATOMIC1_PREOP_LO 0xC98Cu
#define CP_HQD_ATOMIC1_PREOP_HI 0xC990u
#define CP_HQD_HQ_SCHEDULER0 0xC994u
#define CP_HQD_HQ_SCHEDULER1 0xC998u
#define SH_STATIC_MEM_CONFIG 0x9604u
#define DB_RENDER_CONTROL 0x28000
#define PA_SC_RASTER_CONFIG 0x28350
@ -2069,4 +2140,20 @@
#define VCE_CMD_IB_AUTO 0x00000005
#define VCE_CMD_SEMAPHORE 0x00000006
#define ATC_VMID0_PASID_MAPPING 0x339Cu
#define ATC_VMID_PASID_MAPPING_UPDATE_STATUS 0x3398u
#define ATC_VMID_PASID_MAPPING_VALID (1U << 31)
#define ATC_VM_APERTURE0_CNTL 0x3310u
#define ATS_ACCESS_MODE_NEVER 0
#define ATS_ACCESS_MODE_ALWAYS 1
#define ATC_VM_APERTURE0_CNTL2 0x3318u
#define ATC_VM_APERTURE0_HIGH_ADDR 0x3308u
#define ATC_VM_APERTURE0_LOW_ADDR 0x3300u
#define ATC_VM_APERTURE1_CNTL 0x3314u
#define ATC_VM_APERTURE1_CNTL2 0x331Cu
#define ATC_VM_APERTURE1_HIGH_ADDR 0x330Cu
#define ATC_VM_APERTURE1_LOW_ADDR 0x3304u
#endif

View File

@ -1,7 +1,5 @@
#include <drm/drmP.h>
#include <drm.h>
#include <drm_mm.h>
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "radeon_object.h"

View File

@ -24,6 +24,7 @@
#include "drmP.h"
#include "radeon.h"
#include "radeon_asic.h"
#include "evergreend.h"
#include "r600_dpm.h"
#include "cypress_dpm.h"

View File

@ -32,7 +32,7 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
u32 tmp;
u8 *sadb;
u8 *sadb = NULL;
int sad_count;
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
@ -165,7 +165,7 @@ void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *m
/* disable audio prior to setting up hw */
dig->afmt->pin = r600_audio_get_pin(rdev);
r600_audio_enable(rdev, dig->afmt->pin, false);
r600_audio_enable(rdev, dig->afmt->pin, 0);
r600_audio_set_dto(encoder, mode->clock);
@ -240,5 +240,5 @@ void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *m
r600_hdmi_audio_workaround(encoder);
/* enable audio after to setting up hw */
r600_audio_enable(rdev, dig->afmt->pin, true);
r600_audio_enable(rdev, dig->afmt->pin, 0xf);
}

View File

@ -155,7 +155,7 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
u32 offset, tmp;
u8 *sadb;
u8 *sadb = NULL;
int sad_count;
if (!dig || !dig->afmt || !dig->afmt->pin)
@ -284,13 +284,13 @@ static int dce6_audio_chipset_supported(struct radeon_device *rdev)
void dce6_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin,
bool enable)
u8 enable_mask)
{
if (!pin)
return;
WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL,
enable ? AUDIO_ENABLED : 0);
WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
enable_mask ? AUDIO_ENABLED : 0);
}
static const u32 pin_offsets[7] =

View File

@ -22,7 +22,6 @@
* Authors: Alex Deucher
*/
#include <linux/firmware.h>
//#include <linux/platform_device.h>
#include <linux/slab.h>
#include <drm/drmP.h>
#include "radeon.h"
@ -2346,6 +2345,9 @@ void evergreen_bandwidth_update(struct radeon_device *rdev)
u32 num_heads = 0, lb_size;
int i;
if (!rdev->mode_info.mode_config_initialized)
return;
radeon_update_display_priority(rdev);
for (i = 0; i < rdev->num_crtc; i++) {
@ -2553,6 +2555,7 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
tmp |= EVERGREEN_CRTC_BLANK_DATA_EN;
WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
}
} else {
tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
@ -3006,7 +3009,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
u32 vgt_cache_invalidation;
u32 hdp_host_path_cntl, tmp;
u32 disabled_rb_mask;
int i, j, num_shader_engines, ps_thread_count;
int i, j, ps_thread_count;
switch (rdev->family) {
case CHIP_CYPRESS:
@ -3304,8 +3307,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
rdev->config.evergreen.tile_config |=
((gb_addr_config & 0x30000000) >> 28) << 12;
num_shader_engines = (gb_addr_config & NUM_SHADER_ENGINES(3) >> 12) + 1;
if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK)) {
u32 efuse_straps_4;
u32 efuse_straps_3;
@ -4023,7 +4024,7 @@ int sumo_rlc_init(struct radeon_device *rdev)
if (rdev->rlc.save_restore_obj == NULL) {
r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL,
&rdev->rlc.save_restore_obj);
NULL, &rdev->rlc.save_restore_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create RLC sr bo failed\n", r);
return r;
@ -4102,7 +4103,7 @@ int sumo_rlc_init(struct radeon_device *rdev)
if (rdev->rlc.clear_state_obj == NULL) {
r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL,
&rdev->rlc.clear_state_obj);
NULL, &rdev->rlc.clear_state_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create RLC c bo failed\n", r);
sumo_rlc_fini(rdev);
@ -4179,7 +4180,7 @@ int sumo_rlc_init(struct radeon_device *rdev)
r = radeon_bo_create(rdev, rdev->rlc.cp_table_size,
PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL,
&rdev->rlc.cp_table_obj);
NULL, &rdev->rlc.cp_table_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create RLC cp table bo failed\n", r);
sumo_rlc_fini(rdev);
@ -5135,9 +5136,9 @@ restart_ih:
/* wptr/rptr are in bytes! */
rptr += 16;
rptr &= rdev->ih.ptr_mask;
WREG32(IH_RB_RPTR, rptr);
}
rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
atomic_set(&rdev->ih.lock, 0);
/* make sure wptr hasn't changed while processing */

View File

@ -35,7 +35,7 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
int r600_dma_cs_next_reloc(struct radeon_cs_parser *p,
struct radeon_cs_reloc **cs_reloc);
struct radeon_bo_list **cs_reloc);
struct evergreen_cs_track {
u32 group_size;
u32 nbanks;
@ -1094,7 +1094,7 @@ static int evergreen_cs_parse_packet0(struct radeon_cs_parser *p,
static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
{
struct evergreen_cs_track *track = (struct evergreen_cs_track *)p->track;
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
u32 last_reg;
u32 m, i, tmp, *ib;
int r;
@ -1792,7 +1792,7 @@ static bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
static int evergreen_packet3_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt)
{
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
struct evergreen_cs_track *track;
volatile u32 *ib;
unsigned idx;
@ -2661,7 +2661,7 @@ int evergreen_cs_parse(struct radeon_cs_parser *p)
p->track = NULL;
return r;
}
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
} while (p->idx < p->chunk_ib->length_dw);
#if 0
for (r = 0; r < p->ib.length_dw; r++) {
printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]);
@ -2684,8 +2684,8 @@ int evergreen_cs_parse(struct radeon_cs_parser *p)
**/
int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
{
struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx];
struct radeon_cs_reloc *src_reloc, *dst_reloc, *dst2_reloc;
struct radeon_cs_chunk *ib_chunk = p->chunk_ib;
struct radeon_bo_list *src_reloc, *dst_reloc, *dst2_reloc;
u32 header, cmd, count, sub_cmd;
volatile u32 *ib = p->ib.ptr;
u32 idx;
@ -3100,7 +3100,7 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
DRM_ERROR("Unknown packet type %d at %d !\n", cmd, idx);
return -EINVAL;
}
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
} while (p->idx < p->chunk_ib->length_dw);
#if 0
for (r = 0; r < p->ib->length_dw; r++) {
printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]);

View File

@ -104,35 +104,33 @@ void evergreen_dma_ring_ib_execute(struct radeon_device *rdev,
* Used by the radeon ttm implementation to move pages if
* registered as the asic copy callback.
*/
int evergreen_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence)
struct reservation_object *resv)
{
struct radeon_semaphore *sem = NULL;
struct radeon_fence *fence;
struct radeon_sync sync;
int ring_index = rdev->asic->copy.dma_ring_index;
struct radeon_ring *ring = &rdev->ring[ring_index];
u32 size_in_dw, cur_size_in_dw;
int i, num_loops;
int r = 0;
r = radeon_semaphore_create(rdev, &sem);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
}
radeon_sync_create(&sync);
size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
num_loops = DIV_ROUND_UP(size_in_dw, 0xfffff);
r = radeon_ring_lock(rdev, ring, num_loops * 5 + 11);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
radeon_sync_free(rdev, &sync, NULL);
return ERR_PTR(r);
}
radeon_semaphore_sync_to(sem, *fence);
radeon_semaphore_sync_rings(rdev, sem, ring->idx);
radeon_sync_resv(rdev, &sync, resv, false);
radeon_sync_rings(rdev, &sync, ring->idx);
for (i = 0; i < num_loops; i++) {
cur_size_in_dw = size_in_dw;
@ -148,17 +146,17 @@ int evergreen_copy_dma(struct radeon_device *rdev,
dst_offset += cur_size_in_dw * 4;
}
r = radeon_fence_emit(rdev, fence, ring->idx);
r = radeon_fence_emit(rdev, &fence, ring->idx);
if (r) {
radeon_ring_unlock_undo(rdev, ring);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
radeon_sync_free(rdev, &sync, NULL);
return ERR_PTR(r);
}
radeon_ring_unlock_commit(rdev, ring, false);
radeon_semaphore_free(rdev, &sem, *fence);
radeon_sync_free(rdev, &sync, fence);
return r;
return fence;
}
/**

View File

@ -38,6 +38,37 @@ extern void dce6_afmt_select_pin(struct drm_encoder *encoder);
extern void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
struct drm_display_mode *mode);
/* enable the audio stream */
static void dce4_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin,
u8 enable_mask)
{
u32 tmp = RREG32(AZ_HOT_PLUG_CONTROL);
if (!pin)
return;
if (enable_mask) {
tmp |= AUDIO_ENABLED;
if (enable_mask & 1)
tmp |= PIN0_AUDIO_ENABLED;
if (enable_mask & 2)
tmp |= PIN1_AUDIO_ENABLED;
if (enable_mask & 4)
tmp |= PIN2_AUDIO_ENABLED;
if (enable_mask & 8)
tmp |= PIN3_AUDIO_ENABLED;
} else {
tmp &= ~(AUDIO_ENABLED |
PIN0_AUDIO_ENABLED |
PIN1_AUDIO_ENABLED |
PIN2_AUDIO_ENABLED |
PIN3_AUDIO_ENABLED);
}
WREG32(AZ_HOT_PLUG_CONTROL, tmp);
}
/*
* update the N and CTS parameters for a given pixel clock rate
*/
@ -102,7 +133,7 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)
struct drm_connector *connector;
struct radeon_connector *radeon_connector = NULL;
u32 tmp;
u8 *sadb;
u8 *sadb = NULL;
int sad_count;
list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
@ -318,10 +349,10 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
/* disable audio prior to setting up hw */
if (ASIC_IS_DCE6(rdev)) {
dig->afmt->pin = dce6_audio_get_pin(rdev);
dce6_audio_enable(rdev, dig->afmt->pin, false);
dce6_audio_enable(rdev, dig->afmt->pin, 0);
} else {
dig->afmt->pin = r600_audio_get_pin(rdev);
r600_audio_enable(rdev, dig->afmt->pin, false);
dce4_audio_enable(rdev, dig->afmt->pin, 0);
}
evergreen_audio_set_dto(encoder, mode->clock);
@ -463,13 +494,15 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
/* enable audio after to setting up hw */
if (ASIC_IS_DCE6(rdev))
dce6_audio_enable(rdev, dig->afmt->pin, true);
dce6_audio_enable(rdev, dig->afmt->pin, 1);
else
r600_audio_enable(rdev, dig->afmt->pin, true);
dce4_audio_enable(rdev, dig->afmt->pin, 0xf);
}
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
@ -482,6 +515,14 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
if (!enable && !dig->afmt->enabled)
return;
if (!enable && dig->afmt->pin) {
if (ASIC_IS_DCE6(rdev))
dce6_audio_enable(rdev, dig->afmt->pin, 0);
else
dce4_audio_enable(rdev, dig->afmt->pin, 0);
dig->afmt->pin = NULL;
}
dig->afmt->enabled = enable;
DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",

View File

@ -2800,6 +2800,8 @@ void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
tmp = (RREG32_SMC(SMU_VOLTAGE_STATUS) & SMU_VOLTAGE_CURRENT_LEVEL_MASK) >>
SMU_VOLTAGE_CURRENT_LEVEL_SHIFT;
vddc = kv_convert_8bit_index_to_voltage(rdev, (u16)tmp);
seq_printf(m, "uvd %sabled\n", pi->uvd_power_gated ? "dis" : "en");
seq_printf(m, "vce %sabled\n", pi->vce_power_gated ? "dis" : "en");
seq_printf(m, "power level %d sclk: %u vddc: %u\n",
current_index, sclk, vddc);
}

View File

@ -29,7 +29,7 @@ struct drm_file *drm_file_handlers[256];
videomode_t usermode;
void cpu_detect();
void cpu_detect1();
int _stdcall display_handler(ioctl_t *io);
static char log[256];
@ -117,7 +117,7 @@ void ati_driver_thread()
asm volatile ("int $0x40"::"a"(-1));
}
u32_t __attribute__((externally_visible)) drvEntry(int action, char *cmdline)
u32 __attribute__((externally_visible)) drvEntry(int action, char *cmdline)
{
struct radeon_device *rdev = NULL;
@ -134,7 +134,7 @@ u32_t __attribute__((externally_visible)) drvEntry(int action, char *cmdline)
if( GetService("DISPLAY") != 0 )
return 0;
printf("Radeon v3.17-rc5 cmdline %s\n", cmdline);
printf("Radeon v3.19-rc1 cmdline %s\n", cmdline);
if( cmdline && *cmdline )
parse_cmdline(cmdline, &usermode, log, &radeon_modeset);
@ -145,7 +145,7 @@ u32_t __attribute__((externally_visible)) drvEntry(int action, char *cmdline)
return 0;
}
cpu_detect();
cpu_detect1();
err = enum_pci_devices();
if( unlikely(err != 0) )
@ -217,8 +217,8 @@ int r600_video_blit(uint64_t src_offset, int x, int y,
int _stdcall display_handler(ioctl_t *io)
{
int retval = -1;
u32_t *inp;
u32_t *outp;
u32 *inp;
u32 *outp;
inp = io->input;
outp = io->output;
@ -273,10 +273,10 @@ int _stdcall display_handler(ioctl_t *io)
#define PCI_CLASS_REVISION 0x08
#define PCI_CLASS_DISPLAY_VGA 0x0300
int pci_scan_filter(u32_t id, u32_t busnr, u32_t devfn)
int pci_scan_filter(u32 id, u32 busnr, u32 devfn)
{
u16_t vendor, device;
u32_t class;
u16 vendor, device;
u32 class;
int ret = 0;
vendor = id & 0xffff;

View File

@ -1366,6 +1366,7 @@ void cayman_fence_ring_emit(struct radeon_device *rdev,
void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
{
struct radeon_ring *ring = &rdev->ring[ib->ring];
unsigned vm_id = ib->vm ? ib->vm->ids[ib->ring].id : 0;
u32 cp_coher_cntl = PACKET3_FULL_CACHE_ENA | PACKET3_TC_ACTION_ENA |
PACKET3_SH_ACTION_ENA;
@ -1388,15 +1389,14 @@ void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
#endif
(ib->gpu_addr & 0xFFFFFFFC));
radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFF);
radeon_ring_write(ring, ib->length_dw |
(ib->vm ? (ib->vm->id << 24) : 0));
radeon_ring_write(ring, ib->length_dw | (vm_id << 24));
/* flush read cache over gart for this vmid */
radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
radeon_ring_write(ring, PACKET3_ENGINE_ME | cp_coher_cntl);
radeon_ring_write(ring, 0xFFFFFFFF);
radeon_ring_write(ring, 0);
radeon_ring_write(ring, ((ib->vm ? ib->vm->id : 0) << 24) | 10); /* poll interval */
radeon_ring_write(ring, (vm_id << 24) | 10); /* poll interval */
}
static void cayman_cp_enable(struct radeon_device *rdev, bool enable)
@ -1672,7 +1672,7 @@ static int cayman_cp_resume(struct radeon_device *rdev)
}
if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX)
radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
return 0;
}
@ -1903,7 +1903,7 @@ int cayman_asic_reset(struct radeon_device *rdev)
if (reset_mask)
evergreen_gpu_pci_config_reset(rdev);
r600_set_bios_scratch_engine_hung(rdev, false);
r600_set_bios_scratch_engine_hung(rdev, false);
return 0;
}
@ -1943,16 +1943,16 @@ static int cayman_startup(struct radeon_device *rdev)
/* scratch needs to be initialized before MC */
r = r600_vram_scratch_init(rdev);
if (r)
return r;
return r;
evergreen_mc_program(rdev);
if (!(rdev->flags & RADEON_IS_IGP) && !rdev->pm.dpm_enabled) {
r = ni_mc_load_microcode(rdev);
if (r) {
DRM_ERROR("Failed to load MC firmware!\n");
return r;
}
r = ni_mc_load_microcode(rdev);
if (r) {
DRM_ERROR("Failed to load MC firmware!\n");
return r;
}
}
r = cayman_pcie_gart_enable(rdev);
@ -2379,7 +2379,7 @@ void cayman_vm_decode_fault(struct radeon_device *rdev,
default:
block = "unknown";
break;
}
}
printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n",
protections, vmid, addr,
@ -2395,15 +2395,11 @@ void cayman_vm_decode_fault(struct radeon_device *rdev,
* Update the page table base and flush the VM TLB
* using the CP (cayman-si).
*/
void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr)
{
struct radeon_ring *ring = &rdev->ring[ridx];
if (vm == NULL)
return;
radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0));
radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2), 0));
radeon_ring_write(ring, pd_addr >> 12);
/* flush hdp cache */
radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0));
@ -2411,7 +2407,7 @@ void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
/* bits 0-7 are the VM contexts0-7 */
radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0));
radeon_ring_write(ring, 1 << vm->id);
radeon_ring_write(ring, 1 << vm_id);
/* sync PFP to ME, otherwise we might get invalid PFP reads */
radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));

View File

@ -123,6 +123,7 @@ void cayman_dma_ring_ib_execute(struct radeon_device *rdev,
struct radeon_ib *ib)
{
struct radeon_ring *ring = &rdev->ring[ib->ring];
unsigned vm_id = ib->vm ? ib->vm->ids[ib->ring].id : 0;
if (rdev->wb.enabled) {
u32 next_rptr = ring->wptr + 4;
@ -140,7 +141,7 @@ void cayman_dma_ring_ib_execute(struct radeon_device *rdev,
*/
while ((ring->wptr & 7) != 5)
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
radeon_ring_write(ring, DMA_IB_PACKET(DMA_PACKET_INDIRECT_BUFFER, ib->vm ? ib->vm->id : 0, 0));
radeon_ring_write(ring, DMA_IB_PACKET(DMA_PACKET_INDIRECT_BUFFER, vm_id, 0));
radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0));
radeon_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF));
@ -446,16 +447,12 @@ void cayman_dma_vm_pad_ib(struct radeon_ib *ib)
ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0);
}
void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
void cayman_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr)
{
struct radeon_ring *ring = &rdev->ring[ridx];
if (vm == NULL)
return;
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2));
radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
radeon_ring_write(ring, (0xf << 16) | ((VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2));
radeon_ring_write(ring, pd_addr >> 12);
/* flush hdp cache */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
@ -465,6 +462,6 @@ void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm
/* bits 0-7 are the VM contexts0-7 */
radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2));
radeon_ring_write(ring, 1 << vm->id);
radeon_ring_write(ring, 1 << vm_id);
}

View File

@ -23,6 +23,7 @@
#include "drmP.h"
#include "radeon.h"
#include "radeon_asic.h"
#include "nid.h"
#include "r600_dpm.h"
#include "ni_dpm.h"
@ -789,7 +790,6 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
bool disable_mclk_switching;
u32 mclk;
u16 vddci;
u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
int i;
if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
@ -816,29 +816,6 @@ static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
}
}
/* limit clocks to max supported clocks based on voltage dependency tables */
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
&max_sclk_vddc);
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
&max_mclk_vddci);
btc_get_max_clock_from_voltage_dependency_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
&max_mclk_vddc);
for (i = 0; i < ps->performance_level_count; i++) {
if (max_sclk_vddc) {
if (ps->performance_levels[i].sclk > max_sclk_vddc)
ps->performance_levels[i].sclk = max_sclk_vddc;
}
if (max_mclk_vddci) {
if (ps->performance_levels[i].mclk > max_mclk_vddci)
ps->performance_levels[i].mclk = max_mclk_vddci;
}
if (max_mclk_vddc) {
if (ps->performance_levels[i].mclk > max_mclk_vddc)
ps->performance_levels[i].mclk = max_mclk_vddc;
}
}
/* XXX validate the min clocks required for display */
/* adjust low state */

View File

@ -1,20 +1,12 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/mod_devicetable.h>
#include <errno-base.h>
#include <pci.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <syscall.h>
static inline __attribute__((const))
bool is_power_of_2(unsigned long n)
{
return (n != 0 && ((n & (n - 1)) == 0));
}
extern int pci_scan_filter(u32_t id, u32_t busnr, u32_t devfn);
extern int pci_scan_filter(u32 id, u32 busnr, u32 devfn);
static LIST_HEAD(devices);
@ -39,9 +31,9 @@ static inline unsigned int pci_calc_resource_flags(unsigned int flags)
}
static u32_t pci_size(u32_t base, u32_t maxbase, u32_t mask)
static u32 pci_size(u32 base, u32 maxbase, u32 mask)
{
u32_t size = mask & maxbase; /* Find the significant bits */
u32 size = mask & maxbase; /* Find the significant bits */
if (!size)
return 0;
@ -58,9 +50,9 @@ static u32_t pci_size(u32_t base, u32_t maxbase, u32_t mask)
return size;
}
static u64_t pci_size64(u64_t base, u64_t maxbase, u64_t mask)
static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
{
u64_t size = mask & maxbase; /* Find the significant bits */
u64 size = mask & maxbase; /* Find the significant bits */
if (!size)
return 0;
@ -77,7 +69,7 @@ static u64_t pci_size64(u64_t base, u64_t maxbase, u64_t mask)
return size;
}
static inline int is_64bit_memory(u32_t mask)
static inline int is_64bit_memory(u32 mask)
{
if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
(PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64))
@ -87,15 +79,15 @@ static inline int is_64bit_memory(u32_t mask)
static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
u32_t pos, reg, next;
u32_t l, sz;
u32 pos, reg, next;
u32 l, sz;
struct resource *res;
for(pos=0; pos < howmany; pos = next)
{
u64_t l64;
u64_t sz64;
u32_t raw_sz;
u64 l64;
u64 sz64;
u32 raw_sz;
next = pos + 1;
@ -117,7 +109,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
if ((l & PCI_BASE_ADDRESS_SPACE) ==
PCI_BASE_ADDRESS_SPACE_MEMORY)
{
sz = pci_size(l, sz, (u32_t)PCI_BASE_ADDRESS_MEM_MASK);
sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
/*
* For 64bit prefetchable memory sz could be 0, if the
* real size is bigger than 4G, so we need to check
@ -139,14 +131,14 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
res->flags |= pci_calc_resource_flags(l);
if (is_64bit_memory(l))
{
u32_t szhi, lhi;
u32 szhi, lhi;
lhi = PciRead32(dev->busnr, dev->devfn, reg+4);
PciWrite32(dev->busnr, dev->devfn, reg+4, ~0);
szhi = PciRead32(dev->busnr, dev->devfn, reg+4);
PciWrite32(dev->busnr, dev->devfn, reg+4, lhi);
sz64 = ((u64_t)szhi << 32) | raw_sz;
l64 = ((u64_t)lhi << 32) | l;
sz64 = ((u64)szhi << 32) | raw_sz;
l64 = ((u64)lhi << 32) | l;
sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
next++;
@ -170,7 +162,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
/* 64-bit wide address, treat as disabled */
PciWrite32(dev->busnr, dev->devfn, reg,
l & ~(u32_t)PCI_BASE_ADDRESS_MEM_MASK);
l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
PciWrite32(dev->busnr, dev->devfn, reg+4, 0);
res->start = 0;
res->end = sz;
@ -194,7 +186,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
if (sz && sz != 0xffffffff)
{
sz = pci_size(l, sz, (u32_t)PCI_ROM_ADDRESS_MASK);
sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK);
if (sz)
{
@ -210,7 +202,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
static void pci_read_irq(struct pci_dev *dev)
{
u8_t irq;
u8 irq;
irq = PciRead8(dev->busnr, dev->devfn, PCI_INTERRUPT_PIN);
dev->pin = irq;
@ -222,7 +214,7 @@ static void pci_read_irq(struct pci_dev *dev)
int pci_setup_device(struct pci_dev *dev)
{
u32_t class;
u32 class;
class = PciRead32(dev->busnr, dev->devfn, PCI_CLASS_REVISION);
dev->revision = class & 0xff;
@ -254,7 +246,7 @@ int pci_setup_device(struct pci_dev *dev)
*/
if (class == PCI_CLASS_STORAGE_IDE)
{
u8_t progif;
u8 progif;
progif = PciRead8(dev->busnr, dev->devfn,PCI_CLASS_PROG);
if ((progif & 1) == 0)
@ -319,12 +311,12 @@ int pci_setup_device(struct pci_dev *dev)
return 0;
};
static pci_dev_t* pci_scan_device(u32_t busnr, int devfn)
static pci_dev_t* pci_scan_device(u32 busnr, int devfn)
{
pci_dev_t *dev;
u32_t id;
u8_t hdr;
u32 id;
u8 hdr;
int timeout = 10;
@ -380,7 +372,7 @@ static pci_dev_t* pci_scan_device(u32_t busnr, int devfn)
int pci_scan_slot(u32_t bus, int devfn)
int pci_scan_slot(u32 bus, int devfn)
{
int func, nr = 0;
@ -488,8 +480,8 @@ int pci_find_capability(struct pci_dev *dev, int cap)
int enum_pci_devices()
{
pci_dev_t *dev;
u32_t last_bus;
u32_t bus = 0 , devfn = 0;
u32 last_bus;
u32 bus = 0 , devfn = 0;
last_bus = PciApi(1);
@ -672,11 +664,6 @@ void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
}
struct pci_bus_region {
resource_size_t start;
resource_size_t end;
};
static inline void
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res)
@ -775,21 +762,11 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
loff_t start;
void __iomem *rom;
// ENTER();
// dbgprintf("resource start %x end %x flags %x\n",
// res->start, res->end, res->flags);
/*
* IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy
* memory map if the VGA enable bit of the Bridge Control register is
* set for embedded VGA.
*/
start = (loff_t)0xC0000;
*size = 0x20000; /* cover C000:0 through E000:0 */
#if 0
if (res->flags & IORESOURCE_ROM_SHADOW) {
/* primary video rom always starts here */
start = (loff_t)0xC0000;
@ -801,21 +778,11 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
return (void __iomem *)(unsigned long)
pci_resource_start(pdev, PCI_ROM_RESOURCE);
} else {
/* assign the ROM an address if it doesn't have one */
// if (res->parent == NULL &&
// pci_assign_resource(pdev,PCI_ROM_RESOURCE))
return NULL;
// start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
// *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
// if (*size == 0)
// return NULL;
start = (loff_t)0xC0000;
*size = 0x20000; /* cover C000:0 through E000:0 */
/* Enable ROM space decodes */
// if (pci_enable_rom(pdev))
// return NULL;
}
}
#endif
rom = ioremap(start, *size);
if (!rom) {
@ -833,7 +800,6 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
* True size is important if the ROM is going to be copied.
*/
*size = pci_get_rom_size(pdev, rom, *size);
// LEAVE();
return rom;
}
@ -861,6 +827,8 @@ static void __pci_set_master(struct pci_dev *dev, bool enable)
else
cmd = old_cmd & ~PCI_COMMAND_MASTER;
if (cmd != old_cmd) {
dbgprintf("%s bus mastering\n",
enable ? "enabling" : "disabling");
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
dev->is_busmaster = enable;

View File

@ -56,6 +56,14 @@
#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40
#define FDO_MODE_HARDWARE 0
#define FDO_MODE_PIECE_WISE_LINEAR 1
enum FAN_CONTROL {
FAN_CONTROL_FUZZY,
FAN_CONTROL_TABLE
};
#define PPSMC_Result_OK ((uint8_t)0x01)
#define PPSMC_Result_Failed ((uint8_t)0xFF)
@ -79,6 +87,8 @@ typedef uint8_t PPSMC_Result;
#define PPSMC_MSG_DisableCac ((uint8_t)0x54)
#define PPSMC_TDPClampingActive ((uint8_t)0x59)
#define PPSMC_TDPClampingInactive ((uint8_t)0x5A)
#define PPSMC_StartFanControl ((uint8_t)0x5B)
#define PPSMC_StopFanControl ((uint8_t)0x5C)
#define PPSMC_MSG_NoDisplay ((uint8_t)0x5D)
#define PPSMC_MSG_HasDisplay ((uint8_t)0x5E)
#define PPSMC_MSG_UVDPowerOFF ((uint8_t)0x60)
@ -106,6 +116,7 @@ typedef uint8_t PPSMC_Result;
#define PPSMC_MSG_SAMUDPM_SetEnabledMask ((uint16_t) 0x130)
#define PPSMC_MSG_MCLKDPM_ForceState ((uint16_t) 0x131)
#define PPSMC_MSG_MCLKDPM_NoForcedLevel ((uint16_t) 0x132)
#define PPSMC_MSG_Thermal_Cntl_Disable ((uint16_t) 0x133)
#define PPSMC_MSG_Voltage_Cntl_Disable ((uint16_t) 0x135)
#define PPSMC_MSG_PCIeDPM_Enable ((uint16_t) 0x136)
#define PPSMC_MSG_PCIeDPM_Disable ((uint16_t) 0x13d)
@ -149,6 +160,10 @@ typedef uint8_t PPSMC_Result;
#define PPSMC_MSG_MASTER_DeepSleep_ON ((uint16_t) 0x18F)
#define PPSMC_MSG_MASTER_DeepSleep_OFF ((uint16_t) 0x190)
#define PPSMC_MSG_Remove_DC_Clamp ((uint16_t) 0x191)
#define PPSMC_MSG_SetFanPwmMax ((uint16_t) 0x19A)
#define PPSMC_MSG_ENABLE_THERMAL_DPM ((uint16_t) 0x19C)
#define PPSMC_MSG_DISABLE_THERMAL_DPM ((uint16_t) 0x19D)
#define PPSMC_MSG_API_GetSclkFrequency ((uint16_t) 0x200)
#define PPSMC_MSG_API_GetMclkFrequency ((uint16_t) 0x201)
@ -157,10 +172,11 @@ typedef uint8_t PPSMC_Result;
#define PPSMC_MSG_DPM_Config ((uint32_t) 0x102)
#define PPSMC_MSG_DPM_ForceState ((uint32_t) 0x104)
#define PPSMC_MSG_PG_SIMD_Config ((uint32_t) 0x108)
#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint32_t) 0x112)
#define PPSMC_MSG_Thermal_Cntl_Enable ((uint32_t) 0x10a)
#define PPSMC_MSG_Voltage_Cntl_Enable ((uint32_t) 0x109)
#define PPSMC_MSG_VCEPowerOFF ((uint32_t) 0x10e)
#define PPSMC_MSG_VCEPowerON ((uint32_t) 0x10f)
#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint32_t) 0x112)
#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint32_t) 0x11d)
#define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint32_t) 0x11e)
#define PPSMC_MSG_EnableBAPM ((uint32_t) 0x120)

View File

@ -96,6 +96,14 @@ typedef struct _ATOM_PPLIB_FANTABLE2
USHORT usTMax; // The max temperature
} ATOM_PPLIB_FANTABLE2;
typedef struct _ATOM_PPLIB_FANTABLE3
{
ATOM_PPLIB_FANTABLE2 basicTable2;
UCHAR ucFanControlMode;
USHORT usFanPWMMax;
USHORT usFanOutputSensitivity;
} ATOM_PPLIB_FANTABLE3;
typedef struct _ATOM_PPLIB_EXTENDEDHEADER
{
USHORT usSize;

View File

@ -869,13 +869,14 @@ bool r100_semaphore_ring_emit(struct radeon_device *rdev,
return false;
}
int r100_copy_blit(struct radeon_device *rdev,
struct radeon_fence *r100_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence)
struct reservation_object *resv)
{
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
struct radeon_fence *fence;
uint32_t cur_pages;
uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE;
uint32_t pitch;
@ -896,7 +897,7 @@ int r100_copy_blit(struct radeon_device *rdev,
r = radeon_ring_lock(rdev, ring, ndw);
if (r) {
DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw);
return -EINVAL;
return ERR_PTR(-EINVAL);
}
while (num_gpu_pages > 0) {
cur_pages = num_gpu_pages;
@ -936,11 +937,13 @@ int r100_copy_blit(struct radeon_device *rdev,
RADEON_WAIT_2D_IDLECLEAN |
RADEON_WAIT_HOST_IDLECLEAN |
RADEON_WAIT_DMA_GUI_IDLE);
if (fence) {
r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX);
r = radeon_fence_emit(rdev, &fence, RADEON_RING_TYPE_GFX_INDEX);
if (r) {
radeon_ring_unlock_undo(rdev, ring);
return ERR_PTR(r);
}
radeon_ring_unlock_commit(rdev, ring, false);
return r;
return fence;
}
static int r100_cp_wait_for_idle(struct radeon_device *rdev)
@ -1247,7 +1250,7 @@ int r100_reloc_pitch_offset(struct radeon_cs_parser *p,
int r;
u32 tile_flags = 0;
u32 tmp;
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
u32 value;
r = radeon_cs_packet_next_reloc(p, &reloc, 0);
@ -1286,7 +1289,7 @@ int r100_packet3_load_vbpntr(struct radeon_cs_parser *p,
int idx)
{
unsigned c, i;
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
struct r100_cs_track *track;
int r = 0;
volatile uint32_t *ib;
@ -1535,7 +1538,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt,
unsigned idx, unsigned reg)
{
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
struct r100_cs_track *track;
volatile uint32_t *ib;
uint32_t tmp;
@ -1894,7 +1897,7 @@ int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p,
static int r100_packet3_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt)
{
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
struct r100_cs_track *track;
unsigned idx;
volatile uint32_t *ib;
@ -2054,7 +2057,7 @@ int r100_cs_parse(struct radeon_cs_parser *p)
}
if (r)
return r;
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
} while (p->idx < p->chunk_ib->length_dw);
return 0;
}
@ -3200,6 +3203,9 @@ void r100_bandwidth_update(struct radeon_device *rdev)
uint32_t pixel_bytes1 = 0;
uint32_t pixel_bytes2 = 0;
if (!rdev->mode_info.mode_config_initialized)
return;
radeon_update_display_priority(rdev);
if (rdev->mode_info.crtcs[0]->base.enabled) {

View File

@ -80,13 +80,14 @@ static int r200_get_vtx_size_0(uint32_t vtx_fmt_0)
return vtx_size;
}
int r200_copy_dma(struct radeon_device *rdev,
struct radeon_fence *r200_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence)
struct reservation_object *resv)
{
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
struct radeon_fence *fence;
uint32_t size;
uint32_t cur_size;
int i, num_loops;
@ -98,7 +99,7 @@ int r200_copy_dma(struct radeon_device *rdev,
r = radeon_ring_lock(rdev, ring, num_loops * 4 + 64);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
return ERR_PTR(r);
}
/* Must wait for 2D idle & clean before DMA or hangs might happen */
radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0));
@ -118,11 +119,13 @@ int r200_copy_dma(struct radeon_device *rdev,
}
radeon_ring_write(ring, PACKET0(RADEON_WAIT_UNTIL, 0));
radeon_ring_write(ring, RADEON_WAIT_DMA_GUI_IDLE);
if (fence) {
r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX);
r = radeon_fence_emit(rdev, &fence, RADEON_RING_TYPE_GFX_INDEX);
if (r) {
radeon_ring_unlock_undo(rdev, ring);
return ERR_PTR(r);
}
radeon_ring_unlock_commit(rdev, ring, false);
return r;
return fence;
}
@ -143,7 +146,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt,
unsigned idx, unsigned reg)
{
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
struct r100_cs_track *track;
volatile uint32_t *ib;
uint32_t tmp;

View File

@ -598,7 +598,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt,
unsigned idx, unsigned reg)
{
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
struct r100_cs_track *track;
volatile uint32_t *ib;
uint32_t tmp, tile_flags = 0;
@ -1142,7 +1142,7 @@ fail:
static int r300_packet3_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt)
{
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
struct r100_cs_track *track;
volatile uint32_t *ib;
unsigned idx;
@ -1283,7 +1283,7 @@ int r300_cs_parse(struct radeon_cs_parser *p)
if (r) {
return r;
}
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
} while (p->idx < p->chunk_ib->length_dw);
return 0;
}

View File

@ -122,6 +122,94 @@ u32 r600_get_xclk(struct radeon_device *rdev)
int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
{
unsigned fb_div = 0, ref_div, vclk_div = 0, dclk_div = 0;
int r;
/* bypass vclk and dclk with bclk */
WREG32_P(CG_UPLL_FUNC_CNTL_2,
VCLK_SRC_SEL(1) | DCLK_SRC_SEL(1),
~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK));
/* assert BYPASS_EN, deassert UPLL_RESET, UPLL_SLEEP and UPLL_CTLREQ */
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_BYPASS_EN_MASK, ~(
UPLL_RESET_MASK | UPLL_SLEEP_MASK | UPLL_CTLREQ_MASK));
if (rdev->family >= CHIP_RS780)
WREG32_P(GFX_MACRO_BYPASS_CNTL, UPLL_BYPASS_CNTL,
~UPLL_BYPASS_CNTL);
if (!vclk || !dclk) {
/* keep the Bypass mode, put PLL to sleep */
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_SLEEP_MASK, ~UPLL_SLEEP_MASK);
return 0;
}
if (rdev->clock.spll.reference_freq == 10000)
ref_div = 34;
else
ref_div = 4;
r = radeon_uvd_calc_upll_dividers(rdev, vclk, dclk, 50000, 160000,
ref_div + 1, 0xFFF, 2, 30, ~0,
&fb_div, &vclk_div, &dclk_div);
if (r)
return r;
if (rdev->family >= CHIP_RV670 && rdev->family < CHIP_RS780)
fb_div >>= 1;
else
fb_div |= 1;
r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL);
if (r)
return r;
/* assert PLL_RESET */
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_RESET_MASK, ~UPLL_RESET_MASK);
/* For RS780 we have to choose ref clk */
if (rdev->family >= CHIP_RS780)
WREG32_P(CG_UPLL_FUNC_CNTL, UPLL_REFCLK_SRC_SEL_MASK,
~UPLL_REFCLK_SRC_SEL_MASK);
/* set the required fb, ref and post divder values */
WREG32_P(CG_UPLL_FUNC_CNTL,
UPLL_FB_DIV(fb_div) |
UPLL_REF_DIV(ref_div),
~(UPLL_FB_DIV_MASK | UPLL_REF_DIV_MASK));
WREG32_P(CG_UPLL_FUNC_CNTL_2,
UPLL_SW_HILEN(vclk_div >> 1) |
UPLL_SW_LOLEN((vclk_div >> 1) + (vclk_div & 1)) |
UPLL_SW_HILEN2(dclk_div >> 1) |
UPLL_SW_LOLEN2((dclk_div >> 1) + (dclk_div & 1)) |
UPLL_DIVEN_MASK | UPLL_DIVEN2_MASK,
~UPLL_SW_MASK);
/* give the PLL some time to settle */
mdelay(15);
/* deassert PLL_RESET */
WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_RESET_MASK);
mdelay(15);
/* deassert BYPASS EN */
WREG32_P(CG_UPLL_FUNC_CNTL, 0, ~UPLL_BYPASS_EN_MASK);
if (rdev->family >= CHIP_RS780)
WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~UPLL_BYPASS_CNTL);
r = radeon_uvd_send_upll_ctlreq(rdev, CG_UPLL_FUNC_CNTL);
if (r)
return r;
/* switch VCLK and DCLK selection */
WREG32_P(CG_UPLL_FUNC_CNTL_2,
VCLK_SRC_SEL(2) | DCLK_SRC_SEL(2),
~(VCLK_SRC_SEL_MASK | DCLK_SRC_SEL_MASK));
mdelay(100);
return 0;
}
@ -992,6 +1080,8 @@ static int r600_pcie_gart_enable(struct radeon_device *rdev)
WREG32(MC_VM_L1_TLB_MCB_WR_GFX_CNTL, tmp);
WREG32(MC_VM_L1_TLB_MCB_RD_PDMA_CNTL, tmp);
WREG32(MC_VM_L1_TLB_MCB_WR_PDMA_CNTL, tmp);
WREG32(MC_VM_L1_TLB_MCB_RD_UVD_CNTL, tmp);
WREG32(MC_VM_L1_TLB_MCB_WR_UVD_CNTL, tmp);
WREG32(MC_VM_L1_TLB_MCB_RD_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE);
WREG32(MC_VM_L1_TLB_MCB_WR_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE);
WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
@ -1042,6 +1132,8 @@ static void r600_pcie_gart_disable(struct radeon_device *rdev)
WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp);
WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp);
WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp);
WREG32(MC_VM_L1_TLB_MCB_RD_UVD_CNTL, tmp);
WREG32(MC_VM_L1_TLB_MCB_WR_UVD_CNTL, tmp);
radeon_gart_table_vram_unpin(rdev);
}
@ -1338,7 +1430,7 @@ int r600_vram_scratch_init(struct radeon_device *rdev)
if (rdev->vram_scratch.robj == NULL) {
r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE,
PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
0, NULL, &rdev->vram_scratch.robj);
0, NULL, NULL, &rdev->vram_scratch.robj);
if (r) {
return r;
}
@ -2792,35 +2884,32 @@ bool r600_semaphore_ring_emit(struct radeon_device *rdev,
* Used by the radeon ttm implementation to move pages if
* registered as the asic copy callback.
*/
int r600_copy_cpdma(struct radeon_device *rdev,
struct radeon_fence *r600_copy_cpdma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence)
struct reservation_object *resv)
{
struct radeon_semaphore *sem = NULL;
struct radeon_fence *fence;
struct radeon_sync sync;
int ring_index = rdev->asic->copy.blit_ring_index;
struct radeon_ring *ring = &rdev->ring[ring_index];
u32 size_in_bytes, cur_size_in_bytes, tmp;
int i, num_loops;
int r = 0;
r = radeon_semaphore_create(rdev, &sem);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
}
radeon_sync_create(&sync);
size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
r = radeon_ring_lock(rdev, ring, num_loops * 6 + 24);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
radeon_sync_free(rdev, &sync, NULL);
return ERR_PTR(r);
}
radeon_semaphore_sync_to(sem, *fence);
radeon_semaphore_sync_rings(rdev, sem, ring->idx);
radeon_sync_resv(rdev, &sync, resv, false);
radeon_sync_rings(rdev, &sync, ring->idx);
radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
@ -2846,17 +2935,17 @@ int r600_copy_cpdma(struct radeon_device *rdev,
radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
radeon_ring_write(ring, WAIT_CP_DMA_IDLE_bit);
r = radeon_fence_emit(rdev, fence, ring->idx);
r = radeon_fence_emit(rdev, &fence, ring->idx);
if (r) {
radeon_ring_unlock_undo(rdev, ring);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
radeon_sync_free(rdev, &sync, NULL);
return ERR_PTR(r);
}
radeon_ring_unlock_commit(rdev, ring, false);
radeon_semaphore_free(rdev, &sem, *fence);
radeon_sync_free(rdev, &sync, fence);
return r;
return fence;
}
int r600_set_surface_reg(struct radeon_device *rdev, int reg,
@ -3171,7 +3260,7 @@ int r600_ih_ring_alloc(struct radeon_device *rdev)
r = radeon_bo_create(rdev, rdev->ih.ring_size,
PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, 0,
NULL, &rdev->ih.ring_obj);
NULL, NULL, &rdev->ih.ring_obj);
if (r) {
DRM_ERROR("radeon: failed to create ih ring buffer (%d).\n", r);
return r;

View File

@ -969,7 +969,7 @@ static int r600_cs_parse_packet0(struct radeon_cs_parser *p,
static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
{
struct r600_cs_track *track = (struct r600_cs_track *)p->track;
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
u32 m, i, tmp, *ib;
int r;
@ -1626,7 +1626,7 @@ static bool r600_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
static int r600_packet3_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt)
{
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
struct r600_cs_track *track;
volatile u32 *ib;
unsigned idx;
@ -2316,7 +2316,7 @@ int r600_cs_parse(struct radeon_cs_parser *p)
p->track = NULL;
return r;
}
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
} while (p->idx < p->chunk_ib->length_dw);
#if 0
for (r = 0; r < p->ib.length_dw; r++) {
printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]);
@ -2351,10 +2351,10 @@ static void r600_cs_parser_fini(struct radeon_cs_parser *parser, int error)
static int r600_cs_parser_relocs_legacy(struct radeon_cs_parser *p)
{
if (p->chunk_relocs_idx == -1) {
if (p->chunk_relocs == NULL) {
return 0;
}
p->relocs = kzalloc(sizeof(struct radeon_cs_reloc), GFP_KERNEL);
p->relocs = kzalloc(sizeof(struct radeon_bo_list), GFP_KERNEL);
if (p->relocs == NULL) {
return -ENOMEM;
}
@ -2398,7 +2398,7 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
/* Copy the packet into the IB, the parser will read from the
* input memory (cached) and write to the IB (which can be
* uncached). */
ib_chunk = &parser.chunks[parser.chunk_ib_idx];
ib_chunk = parser.chunk_ib;
parser.ib.length_dw = ib_chunk->length_dw;
*l = parser.ib.length_dw;
if (copy_from_user(ib, ib_chunk->user_ptr, ib_chunk->length_dw * 4)) {
@ -2435,24 +2435,24 @@ void r600_cs_legacy_init(void)
* GPU offset using the provided start.
**/
int r600_dma_cs_next_reloc(struct radeon_cs_parser *p,
struct radeon_cs_reloc **cs_reloc)
struct radeon_bo_list **cs_reloc)
{
struct radeon_cs_chunk *relocs_chunk;
unsigned idx;
*cs_reloc = NULL;
if (p->chunk_relocs_idx == -1) {
if (p->chunk_relocs == NULL) {
DRM_ERROR("No relocation chunk !\n");
return -EINVAL;
}
relocs_chunk = &p->chunks[p->chunk_relocs_idx];
relocs_chunk = p->chunk_relocs;
idx = p->dma_reloc_idx;
if (idx >= p->nrelocs) {
DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
idx, p->nrelocs);
return -EINVAL;
}
*cs_reloc = p->relocs_ptr[idx];
*cs_reloc = &p->relocs[idx];
p->dma_reloc_idx++;
return 0;
}
@ -2472,8 +2472,8 @@ int r600_dma_cs_next_reloc(struct radeon_cs_parser *p,
**/
int r600_dma_cs_parse(struct radeon_cs_parser *p)
{
struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx];
struct radeon_cs_reloc *src_reloc, *dst_reloc;
struct radeon_cs_chunk *ib_chunk = p->chunk_ib;
struct radeon_bo_list *src_reloc, *dst_reloc;
u32 header, cmd, count, tiled;
volatile u32 *ib = p->ib.ptr;
u32 idx, idx_value;
@ -2619,7 +2619,7 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
DRM_ERROR("Unknown packet type %d at %d !\n", cmd, idx);
return -EINVAL;
}
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
} while (p->idx < p->chunk_ib->length_dw);
#if 0
for (r = 0; r < p->ib->length_dw; r++) {
printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]);

View File

@ -338,17 +338,17 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
{
struct radeon_ib ib;
unsigned i;
unsigned index;
int r;
void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
u32 tmp = 0;
u64 gpu_addr;
if (!ptr) {
DRM_ERROR("invalid vram scratch pointer\n");
return -EINVAL;
}
if (ring->idx == R600_RING_TYPE_DMA_INDEX)
index = R600_WB_DMA_RING_TEST_OFFSET;
else
index = CAYMAN_WB_DMA1_RING_TEST_OFFSET;
tmp = 0xCAFEDEAD;
writel(tmp, ptr);
gpu_addr = rdev->wb.gpu_addr + index;
r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
if (r) {
@ -357,8 +357,8 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
}
ib.ptr[0] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 1);
ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc;
ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff;
ib.ptr[1] = lower_32_bits(gpu_addr);
ib.ptr[2] = upper_32_bits(gpu_addr) & 0xff;
ib.ptr[3] = 0xDEADBEEF;
ib.length_dw = 4;
@ -374,7 +374,7 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
return r;
}
for (i = 0; i < rdev->usec_timeout; i++) {
tmp = readl(ptr);
tmp = le32_to_cpu(rdev->wb.wb[index/4]);
if (tmp == 0xDEADBEEF)
break;
DRM_UDELAY(1);
@ -430,41 +430,38 @@ void r600_dma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
* @src_offset: src GPU address
* @dst_offset: dst GPU address
* @num_gpu_pages: number of GPU pages to xfer
* @fence: radeon fence object
* @resv: reservation object to sync to
*
* Copy GPU paging using the DMA engine (r6xx).
* Used by the radeon ttm implementation to move pages if
* registered as the asic copy callback.
*/
int r600_copy_dma(struct radeon_device *rdev,
struct radeon_fence *r600_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence)
struct reservation_object *resv)
{
struct radeon_semaphore *sem = NULL;
struct radeon_fence *fence;
struct radeon_sync sync;
int ring_index = rdev->asic->copy.dma_ring_index;
struct radeon_ring *ring = &rdev->ring[ring_index];
u32 size_in_dw, cur_size_in_dw;
int i, num_loops;
int r = 0;
r = radeon_semaphore_create(rdev, &sem);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
}
radeon_sync_create(&sync);
size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFE);
r = radeon_ring_lock(rdev, ring, num_loops * 4 + 8);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
radeon_sync_free(rdev, &sync, NULL);
return ERR_PTR(r);
}
radeon_semaphore_sync_to(sem, *fence);
radeon_semaphore_sync_rings(rdev, sem, ring->idx);
radeon_sync_resv(rdev, &sync, resv, false);
radeon_sync_rings(rdev, &sync, ring->idx);
for (i = 0; i < num_loops; i++) {
cur_size_in_dw = size_in_dw;
@ -480,15 +477,15 @@ int r600_copy_dma(struct radeon_device *rdev,
dst_offset += cur_size_in_dw * 4;
}
r = radeon_fence_emit(rdev, fence, ring->idx);
r = radeon_fence_emit(rdev, &fence, ring->idx);
if (r) {
radeon_ring_unlock_undo(rdev, ring);
radeon_semaphore_free(rdev, &sem, NULL);
return r;
radeon_sync_free(rdev, &sync, NULL);
return ERR_PTR(r);
}
radeon_ring_unlock_commit(rdev, ring, false);
radeon_semaphore_free(rdev, &sem, *fence);
radeon_sync_free(rdev, &sync, fence);
return r;
return fence;
}

View File

@ -24,6 +24,7 @@
#include "drmP.h"
#include "radeon.h"
#include "radeon_asic.h"
#include "r600d.h"
#include "r600_dpm.h"
#include "atom.h"
@ -810,6 +811,7 @@ union power_info {
union fan_info {
struct _ATOM_PPLIB_FANTABLE fan;
struct _ATOM_PPLIB_FANTABLE2 fan2;
struct _ATOM_PPLIB_FANTABLE3 fan3;
};
static int r600_parse_clk_voltage_dep_table(struct radeon_clock_voltage_dependency_table *radeon_table,
@ -899,6 +901,14 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
else
rdev->pm.dpm.fan.t_max = 10900;
rdev->pm.dpm.fan.cycle_delay = 100000;
if (fan_info->fan.ucFanTableFormat >= 3) {
rdev->pm.dpm.fan.control_mode = fan_info->fan3.ucFanControlMode;
rdev->pm.dpm.fan.default_max_fan_pwm =
le16_to_cpu(fan_info->fan3.usFanPWMMax);
rdev->pm.dpm.fan.default_fan_output_sensitivity = 4836;
rdev->pm.dpm.fan.fan_output_sensitivity =
le16_to_cpu(fan_info->fan3.usFanOutputSensitivity);
}
rdev->pm.dpm.fan.ucode_fan_control = true;
}
}
@ -1255,7 +1265,7 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
(mode_info->atom_context->bios + data_offset +
le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
rdev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit =
ppt->usMaximumPowerDeliveryLimit;
le16_to_cpu(ppt->usMaximumPowerDeliveryLimit);
pt = &ppt->power_tune_table;
} else {
ATOM_PPLIB_POWERTUNE_Table *ppt = (ATOM_PPLIB_POWERTUNE_Table *)

View File

@ -96,6 +96,9 @@
#define R600_TEMP_RANGE_MIN (90 * 1000)
#define R600_TEMP_RANGE_MAX (120 * 1000)
#define FDO_PWM_MODE_STATIC 1
#define FDO_PWM_MODE_STATIC_RPM 5
enum r600_power_level {
R600_POWER_LEVEL_LOW = 0,
R600_POWER_LEVEL_MEDIUM = 1,

View File

@ -70,6 +70,169 @@ static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
};
/*
* check if the chipset is supported
*/
static int r600_audio_chipset_supported(struct radeon_device *rdev)
{
return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
}
static struct r600_audio_pin r600_audio_status(struct radeon_device *rdev)
{
struct r600_audio_pin status;
uint32_t value;
value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL);
/* number of channels */
status.channels = (value & 0x7) + 1;
/* bits per sample */
switch ((value & 0xF0) >> 4) {
case 0x0:
status.bits_per_sample = 8;
break;
case 0x1:
status.bits_per_sample = 16;
break;
case 0x2:
status.bits_per_sample = 20;
break;
case 0x3:
status.bits_per_sample = 24;
break;
case 0x4:
status.bits_per_sample = 32;
break;
default:
dev_err(rdev->dev, "Unknown bits per sample 0x%x, using 16\n",
(int)value);
status.bits_per_sample = 16;
}
/* current sampling rate in HZ */
if (value & 0x4000)
status.rate = 44100;
else
status.rate = 48000;
status.rate *= ((value >> 11) & 0x7) + 1;
status.rate /= ((value >> 8) & 0x7) + 1;
value = RREG32(R600_AUDIO_STATUS_BITS);
/* iec 60958 status bits */
status.status_bits = value & 0xff;
/* iec 60958 category code */
status.category_code = (value >> 8) & 0xff;
return status;
}
/*
* update all hdmi interfaces with current audio parameters
*/
void r600_audio_update_hdmi(struct work_struct *work)
{
struct radeon_device *rdev = container_of(work, struct radeon_device,
audio_work);
struct drm_device *dev = rdev->ddev;
struct r600_audio_pin audio_status = r600_audio_status(rdev);
struct drm_encoder *encoder;
bool changed = false;
if (rdev->audio.pin[0].channels != audio_status.channels ||
rdev->audio.pin[0].rate != audio_status.rate ||
rdev->audio.pin[0].bits_per_sample != audio_status.bits_per_sample ||
rdev->audio.pin[0].status_bits != audio_status.status_bits ||
rdev->audio.pin[0].category_code != audio_status.category_code) {
rdev->audio.pin[0] = audio_status;
changed = true;
}
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (!radeon_encoder_is_digital(encoder))
continue;
if (changed || r600_hdmi_buffer_status_changed(encoder))
r600_hdmi_update_audio_settings(encoder);
}
}
/* enable the audio stream */
void r600_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin,
u8 enable_mask)
{
u32 tmp = RREG32(AZ_HOT_PLUG_CONTROL);
if (!pin)
return;
if (enable_mask) {
tmp |= AUDIO_ENABLED;
if (enable_mask & 1)
tmp |= PIN0_AUDIO_ENABLED;
if (enable_mask & 2)
tmp |= PIN1_AUDIO_ENABLED;
if (enable_mask & 4)
tmp |= PIN2_AUDIO_ENABLED;
if (enable_mask & 8)
tmp |= PIN3_AUDIO_ENABLED;
} else {
tmp &= ~(AUDIO_ENABLED |
PIN0_AUDIO_ENABLED |
PIN1_AUDIO_ENABLED |
PIN2_AUDIO_ENABLED |
PIN3_AUDIO_ENABLED);
}
WREG32(AZ_HOT_PLUG_CONTROL, tmp);
}
/*
* initialize the audio vars
*/
int r600_audio_init(struct radeon_device *rdev)
{
if (!radeon_audio || !r600_audio_chipset_supported(rdev))
return 0;
rdev->audio.enabled = true;
rdev->audio.num_pins = 1;
rdev->audio.pin[0].channels = -1;
rdev->audio.pin[0].rate = -1;
rdev->audio.pin[0].bits_per_sample = -1;
rdev->audio.pin[0].status_bits = 0;
rdev->audio.pin[0].category_code = 0;
rdev->audio.pin[0].id = 0;
/* disable audio. it will be set up later */
r600_audio_enable(rdev, &rdev->audio.pin[0], 0);
return 0;
}
/*
* release the audio timer
* TODO: How to do this correctly on SMP systems?
*/
void r600_audio_fini(struct radeon_device *rdev)
{
if (!rdev->audio.enabled)
return;
r600_audio_enable(rdev, &rdev->audio.pin[0], 0);
rdev->audio.enabled = false;
}
struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev)
{
/* only one pin on 6xx-NI */
return &rdev->audio.pin[0];
}
/*
* calculate CTS and N values if they are not found in the table
*/
@ -356,7 +519,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
/* disable audio prior to setting up hw */
dig->afmt->pin = r600_audio_get_pin(rdev);
r600_audio_enable(rdev, dig->afmt->pin, false);
r600_audio_enable(rdev, dig->afmt->pin, 0xf);
r600_audio_set_dto(encoder, mode->clock);
@ -442,7 +605,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
/* enable audio after to setting up hw */
r600_audio_enable(rdev, dig->afmt->pin, true);
r600_audio_enable(rdev, dig->afmt->pin, 0xf);
}
/**
@ -527,6 +690,11 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
if (!enable && !dig->afmt->enabled)
return;
if (!enable && dig->afmt->pin) {
r600_audio_enable(rdev, dig->afmt->pin, 0);
dig->afmt->pin = NULL;
}
/* Older chipsets require setting HDMI and routing manually */
if (!ASIC_IS_DCE3(rdev)) {
if (enable)

View File

@ -323,11 +323,12 @@
#define HDP_TILING_CONFIG 0x2F3C
#define HDP_DEBUG1 0x2F34
#define MC_CONFIG 0x2000
#define MC_VM_AGP_TOP 0x2184
#define MC_VM_AGP_BOT 0x2188
#define MC_VM_AGP_BASE 0x218C
#define MC_VM_FB_LOCATION 0x2180
#define MC_VM_L1_TLB_MCD_RD_A_CNTL 0x219C
#define MC_VM_L1_TLB_MCB_RD_UVD_CNTL 0x2124
#define ENABLE_L1_TLB (1 << 0)
#define ENABLE_L1_FRAGMENT_PROCESSING (1 << 1)
#define ENABLE_L1_STRICT_ORDERING (1 << 2)
@ -347,12 +348,14 @@
#define EFFECTIVE_L1_QUEUE_SIZE(x) (((x) & 7) << 15)
#define EFFECTIVE_L1_QUEUE_SIZE_MASK 0x00038000
#define EFFECTIVE_L1_QUEUE_SIZE_SHIFT 15
#define MC_VM_L1_TLB_MCD_RD_A_CNTL 0x219C
#define MC_VM_L1_TLB_MCD_RD_B_CNTL 0x21A0
#define MC_VM_L1_TLB_MCB_RD_GFX_CNTL 0x21FC
#define MC_VM_L1_TLB_MCB_RD_HDP_CNTL 0x2204
#define MC_VM_L1_TLB_MCB_RD_PDMA_CNTL 0x2208
#define MC_VM_L1_TLB_MCB_RD_SEM_CNTL 0x220C
#define MC_VM_L1_TLB_MCB_RD_SYS_CNTL 0x2200
#define MC_VM_L1_TLB_MCB_WR_UVD_CNTL 0x212c
#define MC_VM_L1_TLB_MCD_WR_A_CNTL 0x21A4
#define MC_VM_L1_TLB_MCD_WR_B_CNTL 0x21A8
#define MC_VM_L1_TLB_MCB_WR_GFX_CNTL 0x2210
@ -366,6 +369,8 @@
#define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2194
#define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x2198
#define RS_DQ_RD_RET_CONF 0x2348
#define PA_CL_ENHANCE 0x8A14
#define CLIP_VTX_REORDER_ENA (1 << 0)
#define NUM_CLIP_SEQ(x) ((x) << 1)
@ -922,6 +927,23 @@
# define TARGET_LINK_SPEED_MASK (0xf << 0)
# define SELECTABLE_DEEMPHASIS (1 << 6)
/* Audio */
#define AZ_HOT_PLUG_CONTROL 0x7300
# define AZ_FORCE_CODEC_WAKE (1 << 0)
# define JACK_DETECTION_ENABLE (1 << 4)
# define UNSOLICITED_RESPONSE_ENABLE (1 << 8)
# define CODEC_HOT_PLUG_ENABLE (1 << 12)
# define AUDIO_ENABLED (1 << 31)
/* DCE3 adds */
# define PIN0_JACK_DETECTION_ENABLE (1 << 4)
# define PIN1_JACK_DETECTION_ENABLE (1 << 5)
# define PIN2_JACK_DETECTION_ENABLE (1 << 6)
# define PIN3_JACK_DETECTION_ENABLE (1 << 7)
# define PIN0_AUDIO_ENABLED (1 << 24)
# define PIN1_AUDIO_ENABLED (1 << 25)
# define PIN2_AUDIO_ENABLED (1 << 26)
# define PIN3_AUDIO_ENABLED (1 << 27)
/* Audio clocks DCE 2.0/3.0 */
#define AUDIO_DTO 0x7340
# define AUDIO_DTO_PHASE(x) (((x) & 0xffff) << 0)
@ -1476,6 +1498,7 @@
#define UVD_CGC_GATE 0xf4a8
#define UVD_LMI_CTRL2 0xf4f4
#define UVD_MASTINT_EN 0xf500
#define UVD_FW_START 0xf51C
#define UVD_LMI_ADDR_EXT 0xf594
#define UVD_LMI_CTRL 0xf598
#define UVD_LMI_SWAP_CNTL 0xf5b4
@ -1488,6 +1511,13 @@
#define UVD_MPC_SET_MUX 0xf5f4
#define UVD_MPC_SET_ALU 0xf5f8
#define UVD_VCPU_CACHE_OFFSET0 0xf608
#define UVD_VCPU_CACHE_SIZE0 0xf60c
#define UVD_VCPU_CACHE_OFFSET1 0xf610
#define UVD_VCPU_CACHE_SIZE1 0xf614
#define UVD_VCPU_CACHE_OFFSET2 0xf618
#define UVD_VCPU_CACHE_SIZE2 0xf61c
#define UVD_VCPU_CNTL 0xf660
#define UVD_SOFT_RESET 0xf680
#define RBC_SOFT_RESET (1<<0)
@ -1517,9 +1547,35 @@
#define UVD_CONTEXT_ID 0xf6f4
/* rs780 only */
#define GFX_MACRO_BYPASS_CNTL 0x30c0
#define SPLL_BYPASS_CNTL (1 << 0)
#define UPLL_BYPASS_CNTL (1 << 1)
#define CG_UPLL_FUNC_CNTL 0x7e0
# define UPLL_RESET_MASK 0x00000001
# define UPLL_SLEEP_MASK 0x00000002
# define UPLL_BYPASS_EN_MASK 0x00000004
# define UPLL_CTLREQ_MASK 0x00000008
# define UPLL_FB_DIV(x) ((x) << 4)
# define UPLL_FB_DIV_MASK 0x0000FFF0
# define UPLL_REF_DIV(x) ((x) << 16)
# define UPLL_REF_DIV_MASK 0x003F0000
# define UPLL_REFCLK_SRC_SEL_MASK 0x20000000
# define UPLL_CTLACK_MASK 0x40000000
# define UPLL_CTLACK2_MASK 0x80000000
#define CG_UPLL_FUNC_CNTL_2 0x7e4
# define UPLL_SW_HILEN(x) ((x) << 0)
# define UPLL_SW_LOLEN(x) ((x) << 4)
# define UPLL_SW_HILEN2(x) ((x) << 8)
# define UPLL_SW_LOLEN2(x) ((x) << 12)
# define UPLL_DIVEN_MASK 0x00010000
# define UPLL_DIVEN2_MASK 0x00020000
# define UPLL_SW_MASK 0x0003FFFF
# define VCLK_SRC_SEL(x) ((x) << 20)
# define VCLK_SRC_SEL_MASK 0x01F00000
# define DCLK_SRC_SEL(x) ((x) << 25)
# define DCLK_SRC_SEL_MASK 0x3E000000
/*
* PM4

View File

@ -60,12 +60,13 @@
* are considered as fatal)
*/
#include <asm/atomic.h>
#include <linux/atomic.h>
#include <linux/wait.h>
#include <linux/list.h>
#include <linux/kref.h>
#include <linux/interval_tree.h>
#include <asm/div64.h>
#include <linux/fence.h>
#include <ttm/ttm_bo_api.h>
#include <ttm/ttm_bo_driver.h>
@ -73,10 +74,10 @@
//#include <ttm/ttm_module.h>
#include <ttm/ttm_execbuf_util.h>
#include <linux/irqreturn.h>
#include <pci.h>
#include <drm/drm_gem.h>
#include <errno-base.h>
#include <linux/irqreturn.h>
#include <linux/pci.h>
#include "radeon_family.h"
#include "radeon_mode.h"
@ -154,9 +155,6 @@ static inline u32 ioread32(const volatile void __iomem *addr)
#define RADEONFB_CONN_LIMIT 4
#define RADEON_BIOS_NUM_SCRATCH 8
/* fence seq are set to this number when signaled */
#define RADEON_FENCE_SIGNALED_SEQ 0LL
/* internal ring indices */
/* r1xx+ has gfx CP ring */
#define RADEON_RING_TYPE_GFX_INDEX 0
@ -183,9 +181,6 @@ static inline u32 ioread32(const volatile void __iomem *addr)
/* number of hw syncs before falling back on blocking */
#define RADEON_NUM_SYNCS 4
/* number of hw syncs before falling back on blocking */
#define RADEON_NUM_SYNCS 4
/* hardcode those limit for now */
#define RADEON_VA_IB_OFFSET (1 << 20)
#define RADEON_VA_RESERVED_SIZE (8 << 20)
@ -384,28 +379,33 @@ extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
* Fences.
*/
struct radeon_fence_driver {
struct radeon_device *rdev;
uint32_t scratch_reg;
uint64_t gpu_addr;
volatile uint32_t *cpu_addr;
/* sync_seq is protected by ring emission lock */
uint64_t sync_seq[RADEON_NUM_RINGS];
atomic64_t last_seq;
bool initialized;
bool initialized, delayed_irq;
struct delayed_work lockup_work;
};
struct radeon_fence {
struct fence base;
struct radeon_device *rdev;
struct kref kref;
/* protected by radeon_fence.lock */
uint64_t seq;
/* RB, DMA, etc. */
unsigned ring;
bool is_vm_update;
wait_queue_t fence_wake;
};
int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring);
int radeon_fence_driver_init(struct radeon_device *rdev);
void radeon_fence_driver_fini(struct radeon_device *rdev);
void radeon_fence_driver_force_completion(struct radeon_device *rdev);
void radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring);
int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring);
void radeon_fence_process(struct radeon_device *rdev, int ring);
bool radeon_fence_signaled(struct radeon_fence *fence);
@ -481,12 +481,22 @@ struct radeon_mman {
#endif
};
struct radeon_bo_list {
struct radeon_bo *robj;
struct ttm_validate_buffer tv;
uint64_t gpu_offset;
unsigned prefered_domains;
unsigned allowed_domains;
uint32_t tiling_flags;
};
/* bo virtual address in a specific vm */
struct radeon_bo_va {
/* protected by bo being reserved */
struct list_head bo_list;
uint32_t flags;
uint64_t addr;
struct radeon_fence *last_pt_update;
unsigned ref_count;
/* protected by vm mutex */
@ -503,7 +513,7 @@ struct radeon_bo {
struct list_head list;
/* Protected by tbo.reserved */
u32 initial_domain;
u32 placements[3];
struct ttm_place placements[4];
struct ttm_placement placement;
struct ttm_buffer_object tbo;
struct ttm_bo_kmap_obj kmap;
@ -522,6 +532,8 @@ struct radeon_bo {
struct drm_gem_object gem_base;
pid_t pid;
struct radeon_mn *mn;
};
#define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base)
@ -604,7 +616,6 @@ struct radeon_semaphore {
struct radeon_sa_bo *sa_bo;
signed waiters;
uint64_t gpu_addr;
struct radeon_fence *sync_to[RADEON_NUM_RINGS];
};
int radeon_semaphore_create(struct radeon_device *rdev,
@ -613,15 +624,32 @@ bool radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring,
struct radeon_semaphore *semaphore);
bool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,
struct radeon_semaphore *semaphore);
void radeon_semaphore_sync_to(struct radeon_semaphore *semaphore,
struct radeon_fence *fence);
int radeon_semaphore_sync_rings(struct radeon_device *rdev,
struct radeon_semaphore *semaphore,
int waiting_ring);
void radeon_semaphore_free(struct radeon_device *rdev,
struct radeon_semaphore **semaphore,
struct radeon_fence *fence);
/*
* Synchronization
*/
struct radeon_sync {
struct radeon_semaphore *semaphores[RADEON_NUM_SYNCS];
struct radeon_fence *sync_to[RADEON_NUM_RINGS];
struct radeon_fence *last_vm_update;
};
void radeon_sync_create(struct radeon_sync *sync);
void radeon_sync_fence(struct radeon_sync *sync,
struct radeon_fence *fence);
int radeon_sync_resv(struct radeon_device *rdev,
struct radeon_sync *sync,
struct reservation_object *resv,
bool shared);
int radeon_sync_rings(struct radeon_device *rdev,
struct radeon_sync *sync,
int waiting_ring);
void radeon_sync_free(struct radeon_device *rdev, struct radeon_sync *sync,
struct radeon_fence *fence);
/*
* GART structures, functions & helpers
*/
@ -722,6 +750,10 @@ struct radeon_doorbell {
int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
void radeon_doorbell_get_kfd_info(struct radeon_device *rdev,
phys_addr_t *aperture_base,
size_t *aperture_size,
size_t *start_offset);
/*
* IRQS.
@ -801,6 +833,7 @@ struct radeon_irq {
int radeon_irq_kms_init(struct radeon_device *rdev);
void radeon_irq_kms_fini(struct radeon_device *rdev);
void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring);
bool radeon_irq_kms_sw_irq_get_delayed(struct radeon_device *rdev, int ring);
void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev, int ring);
void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc);
void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc);
@ -822,7 +855,7 @@ struct radeon_ib {
struct radeon_fence *fence;
struct radeon_vm *vm;
bool is_const_ib;
struct radeon_semaphore *semaphore;
struct radeon_sync sync;
};
struct radeon_ring {
@ -899,9 +932,22 @@ struct radeon_vm_pt {
uint64_t addr;
};
struct radeon_vm_id {
unsigned id;
uint64_t pd_gpu_addr;
/* last flushed PD/PT update */
struct radeon_fence *flushed_updates;
/* last use of vmid */
struct radeon_fence *last_id_use;
};
struct radeon_vm {
struct mutex mutex;
struct rb_root va;
unsigned id;
/* protecting invalidated and freed */
spinlock_t status_lock;
/* BOs moved, but not yet updated in the PT */
struct list_head invalidated;
@ -911,7 +957,6 @@ struct radeon_vm {
/* contains the page directory */
struct radeon_bo *page_directory;
uint64_t pd_gpu_addr;
unsigned max_pde_used;
/* array of page tables, one for each page directory entry */
@ -919,13 +964,8 @@ struct radeon_vm {
struct radeon_bo_va *ib_bo_va;
struct mutex mutex;
/* last fence for cs using this vm */
struct radeon_fence *fence;
/* last flush or NULL if we still need to flush */
struct radeon_fence *last_flush;
/* last use of vmid */
struct radeon_fence *last_id_use;
/* for id and flush management per ring */
struct radeon_vm_id ids[RADEON_NUM_RINGS];
};
struct radeon_vm_manager {
@ -1033,19 +1073,7 @@ void cayman_dma_fini(struct radeon_device *rdev);
/*
* CS.
*/
struct radeon_cs_reloc {
struct drm_gem_object *gobj;
struct radeon_bo *robj;
struct ttm_validate_buffer tv;
uint64_t gpu_offset;
unsigned prefered_domains;
unsigned allowed_domains;
uint32_t tiling_flags;
uint32_t handle;
};
struct radeon_cs_chunk {
uint32_t chunk_id;
uint32_t length_dw;
uint32_t *kdata;
void __user *user_ptr;
@ -1063,16 +1091,15 @@ struct radeon_cs_parser {
unsigned idx;
/* relocations */
unsigned nrelocs;
struct radeon_cs_reloc *relocs;
struct radeon_cs_reloc **relocs_ptr;
struct radeon_cs_reloc *vm_bos;
struct radeon_bo_list *relocs;
struct radeon_bo_list *vm_bos;
struct list_head validated;
unsigned dma_reloc_idx;
/* indices of various chunks */
int chunk_ib_idx;
int chunk_relocs_idx;
int chunk_flags_idx;
int chunk_const_ib_idx;
struct radeon_cs_chunk *chunk_ib;
struct radeon_cs_chunk *chunk_relocs;
struct radeon_cs_chunk *chunk_flags;
struct radeon_cs_chunk *chunk_const_ib;
struct radeon_ib ib;
struct radeon_ib const_ib;
void *track;
@ -1086,7 +1113,7 @@ struct radeon_cs_parser {
static inline u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx)
{
struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx];
struct radeon_cs_chunk *ibc = p->chunk_ib;
if (ibc->kdata)
return ibc->kdata[idx];
@ -1498,6 +1525,10 @@ struct radeon_dpm_fan {
u8 t_hyst;
u32 cycle_delay;
u16 t_max;
u8 control_mode;
u16 default_max_fan_pwm;
u16 default_fan_output_sensitivity;
u16 fan_output_sensitivity;
bool ucode_fan_control;
};
@ -1631,6 +1662,11 @@ struct radeon_pm {
/* internal thermal controller on rv6xx+ */
enum radeon_int_thermal_type int_thermal_type;
struct device *int_hwmon_dev;
/* fan control parameters */
bool no_fan;
u8 fan_pulses_per_revolution;
u8 fan_min_rpm;
u8 fan_max_rpm;
/* dpm */
bool dpm_enabled;
struct radeon_dpm dpm;
@ -1665,7 +1701,8 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
uint32_t handle, struct radeon_fence **fence);
int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
uint32_t handle, struct radeon_fence **fence);
void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo);
void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo,
uint32_t allowed_domains);
void radeon_uvd_free_handles(struct radeon_device *rdev,
struct drm_file *filp);
int radeon_uvd_cs_parse(struct radeon_cs_parser *parser);
@ -1754,6 +1791,11 @@ void radeon_test_ring_sync(struct radeon_device *rdev,
struct radeon_ring *cpB);
void radeon_test_syncing(struct radeon_device *rdev);
/*
* MMU Notifier
*/
int radeon_mn_register(struct radeon_bo *bo, unsigned long addr);
void radeon_mn_unregister(struct radeon_bo *bo);
/*
* Debugfs
@ -1787,7 +1829,8 @@ struct radeon_asic_ring {
void (*hdp_flush)(struct radeon_device *rdev, struct radeon_ring *ring);
bool (*emit_semaphore)(struct radeon_device *rdev, struct radeon_ring *cp,
struct radeon_semaphore *semaphore, bool emit_wait);
void (*vm_flush)(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
void (*vm_flush)(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr);
/* testing functions */
int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp);
@ -1868,24 +1911,24 @@ struct radeon_asic {
} display;
/* copy functions for bo handling */
struct {
int (*blit)(struct radeon_device *rdev,
struct radeon_fence *(*blit)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
struct reservation_object *resv);
u32 blit_ring_index;
int (*dma)(struct radeon_device *rdev,
struct radeon_fence *(*dma)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
struct reservation_object *resv);
u32 dma_ring_index;
/* method used for bo copy */
int (*copy)(struct radeon_device *rdev,
struct radeon_fence *(*copy)(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
struct reservation_object *resv);
/* ring used for bo copies */
u32 copy_ring_index;
} copy;
@ -2291,6 +2334,7 @@ struct radeon_device {
struct radeon_mman mman;
struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS];
wait_queue_head_t fence_queue;
unsigned fence_context;
struct mutex ring_lock;
struct radeon_ring ring[RADEON_NUM_RINGS];
bool ib_pool_ready;
@ -2309,7 +2353,7 @@ struct radeon_device {
bool need_dma32;
bool accel_working;
bool fastfb_working; /* IGP feature*/
bool needs_reset;
bool needs_reset, in_reset;
struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES];
const struct firmware *me_fw; /* all family ME firmware */
const struct firmware *pfp_fw; /* r6/700 PFP firmware */
@ -2330,7 +2374,6 @@ struct radeon_device {
struct radeon_mec mec;
struct work_struct hotplug_work;
struct work_struct audio_work;
struct work_struct reset_work;
int num_crtc; /* number of crtcs */
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
bool has_uvd;
@ -2355,6 +2398,8 @@ struct radeon_device {
struct radeon_atcs atcs;
/* srbm instance registers */
struct mutex srbm_mutex;
/* GRBM index mutex. Protects concurrents access to GRBM index */
struct mutex grbm_idx_mutex;
/* clock, powergating flags */
u32 cg_flags;
u32 pg_flags;
@ -2366,6 +2411,7 @@ struct radeon_device {
/* tracking pinned memory */
u64 vram_pin_size;
u64 gart_pin_size;
struct mutex mn_lock;
};
bool radeon_is_px(struct drm_device *dev);
@ -2421,7 +2467,17 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v);
/*
* Cast helper
*/
#define to_radeon_fence(p) ((struct radeon_fence *)(p))
extern const struct fence_ops radeon_fence_ops;
static inline struct radeon_fence *to_radeon_fence(struct fence *f)
{
struct radeon_fence *__f = container_of(f, struct radeon_fence, base);
if (__f->base.ops == &radeon_fence_ops)
return __f;
return NULL;
}
/*
* Registers read & write functions.
@ -2741,18 +2797,25 @@ void radeon_atombios_fini(struct radeon_device *rdev);
/*
* RING helpers.
*/
#if DRM_DEBUG_CODE == 0
/**
* radeon_ring_write - write a value to the ring
*
* @ring: radeon_ring structure holding ring information
* @v: dword (dw) value to write
*
* Write a value to the requested ring buffer (all asics).
*/
static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
{
if (ring->count_dw <= 0)
DRM_ERROR("radeon: writing more dwords to the ring than expected!\n");
ring->ring[ring->wptr++] = v;
ring->wptr &= ring->ptr_mask;
ring->count_dw--;
ring->ring_free_dw--;
}
#else
/* With debugging this is just too big to inline */
void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
#endif
/*
* ASICs macro.
@ -2778,7 +2841,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
#define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)]->ib_execute((rdev), (ib))
#define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)]->ib_parse((rdev), (ib))
#define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)]->is_lockup((rdev), (cp))
#define radeon_ring_vm_flush(rdev, r, vm) (rdev)->asic->ring[(r)]->vm_flush((rdev), (r), (vm))
#define radeon_ring_vm_flush(rdev, r, vm_id, pd_addr) (rdev)->asic->ring[(r)->idx]->vm_flush((rdev), (r), (vm_id), (pd_addr))
#define radeon_ring_get_rptr(rdev, r) (rdev)->asic->ring[(r)->idx]->get_rptr((rdev), (r))
#define radeon_ring_get_wptr(rdev, r) (rdev)->asic->ring[(r)->idx]->get_wptr((rdev), (r))
#define radeon_ring_set_wptr(rdev, r) (rdev)->asic->ring[(r)->idx]->set_wptr((rdev), (r))
@ -2791,9 +2854,9 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
#define radeon_hdmi_setmode(rdev, e, m) (rdev)->asic->display.hdmi_setmode((e), (m))
#define radeon_fence_ring_emit(rdev, r, fence) (rdev)->asic->ring[(r)]->emit_fence((rdev), (fence))
#define radeon_semaphore_ring_emit(rdev, r, cp, semaphore, emit_wait) (rdev)->asic->ring[(r)]->emit_semaphore((rdev), (cp), (semaphore), (emit_wait))
#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (f))
#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy.dma((rdev), (s), (d), (np), (f))
#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy.copy((rdev), (s), (d), (np), (f))
#define radeon_copy_blit(rdev, s, d, np, resv) (rdev)->asic->copy.blit((rdev), (s), (d), (np), (resv))
#define radeon_copy_dma(rdev, s, d, np, resv) (rdev)->asic->copy.dma((rdev), (s), (d), (np), (resv))
#define radeon_copy(rdev, s, d, np, resv) (rdev)->asic->copy.copy((rdev), (s), (d), (np), (resv))
#define radeon_copy_blit_ring_index(rdev) (rdev)->asic->copy.blit_ring_index
#define radeon_copy_dma_ring_index(rdev) (rdev)->asic->copy.dma_ring_index
#define radeon_copy_ring_index(rdev) (rdev)->asic->copy.copy_ring_index
@ -2867,6 +2930,10 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl
extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
extern int radeon_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
uint32_t flags);
extern bool radeon_ttm_tt_has_userptr(struct ttm_tt *ttm);
extern bool radeon_ttm_tt_is_readonly(struct ttm_tt *ttm);
extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
extern int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon);
@ -2883,14 +2950,14 @@ int radeon_vm_manager_init(struct radeon_device *rdev);
void radeon_vm_manager_fini(struct radeon_device *rdev);
int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm);
void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm);
struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev,
struct radeon_bo_list *radeon_vm_get_bos(struct radeon_device *rdev,
struct radeon_vm *vm,
struct list_head *head);
struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
struct radeon_vm *vm, int ring);
void radeon_vm_flush(struct radeon_device *rdev,
struct radeon_vm *vm,
int ring);
int ring, struct radeon_fence *fence);
void radeon_vm_fence(struct radeon_device *rdev,
struct radeon_vm *vm,
struct radeon_fence *fence);
@ -2924,10 +2991,10 @@ struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev);
struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev);
void r600_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin,
bool enable);
u8 enable_mask);
void dce6_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin,
bool enable);
u8 enable_mask);
/*
* R600 vram scratch functions
@ -2997,7 +3064,7 @@ bool radeon_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p);
void radeon_cs_dump_packet(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt);
int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p,
struct radeon_cs_reloc **cs_reloc,
struct radeon_bo_list **cs_reloc,
int nomm);
int r600_cs_common_vline_parse(struct radeon_cs_parser *p,
uint32_t *vline_start_end,
@ -3005,7 +3072,7 @@ int r600_cs_common_vline_parse(struct radeon_cs_parser *p,
#include "radeon_object.h"
#define DRM_UDELAY(d) udelay(d)
#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159
resource_size_t
drm_get_resource_start(struct drm_device *dev, unsigned int resource);

View File

@ -2294,6 +2294,14 @@ int radeon_asic_init(struct radeon_device *rdev)
case CHIP_RS780:
case CHIP_RS880:
rdev->asic = &rs780_asic;
/* 760G/780V/880V don't have UVD */
if ((rdev->pdev->device == 0x9616)||
(rdev->pdev->device == 0x9611)||
(rdev->pdev->device == 0x9613)||
(rdev->pdev->device == 0x9711)||
(rdev->pdev->device == 0x9713))
rdev->has_uvd = false;
else
rdev->has_uvd = true;
break;
case CHIP_RV770:

View File

@ -81,11 +81,11 @@ bool r100_semaphore_ring_emit(struct radeon_device *rdev,
int r100_cs_parse(struct radeon_cs_parser *p);
void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg);
int r100_copy_blit(struct radeon_device *rdev,
struct radeon_fence *r100_copy_blit(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
struct reservation_object *resv);
int r100_set_surface_reg(struct radeon_device *rdev, int reg,
uint32_t tiling_flags, uint32_t pitch,
uint32_t offset, uint32_t obj_size);
@ -152,11 +152,11 @@ void r100_gfx_set_wptr(struct radeon_device *rdev,
/*
* r200,rv250,rs300,rv280
*/
extern int r200_copy_dma(struct radeon_device *rdev,
struct radeon_fence *r200_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
struct reservation_object *resv);
void r200_set_safe_registers(struct radeon_device *rdev);
/*
@ -340,12 +340,14 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
int r600_dma_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
int r600_copy_cpdma(struct radeon_device *rdev,
struct radeon_fence *r600_copy_cpdma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages, struct radeon_fence **fence);
int r600_copy_dma(struct radeon_device *rdev,
unsigned num_gpu_pages,
struct reservation_object *resv);
struct radeon_fence *r600_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages, struct radeon_fence **fence);
unsigned num_gpu_pages,
struct reservation_object *resv);
void r600_hpd_init(struct radeon_device *rdev);
void r600_hpd_fini(struct radeon_device *rdev);
bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
@ -389,7 +391,6 @@ void r600_disable_interrupts(struct radeon_device *rdev);
void r600_rlc_stop(struct radeon_device *rdev);
/* r600 audio */
int r600_audio_init(struct radeon_device *rdev);
struct r600_audio_pin r600_audio_status(struct radeon_device *rdev);
void r600_audio_fini(struct radeon_device *rdev);
void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock);
void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
@ -461,10 +462,10 @@ bool rv770_page_flip_pending(struct radeon_device *rdev, int crtc);
void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
void r700_cp_stop(struct radeon_device *rdev);
void r700_cp_fini(struct radeon_device *rdev);
int rv770_copy_dma(struct radeon_device *rdev,
struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
struct reservation_object *resv);
u32 rv770_get_xclk(struct radeon_device *rdev);
int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
int rv770_get_temp(struct radeon_device *rdev);
@ -535,10 +536,10 @@ void evergreen_dma_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence);
void evergreen_dma_ring_ib_execute(struct radeon_device *rdev,
struct radeon_ib *ib);
int evergreen_copy_dma(struct radeon_device *rdev,
struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
struct reservation_object *resv);
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
int evergreen_get_temp(struct radeon_device *rdev);
@ -598,7 +599,8 @@ int cayman_asic_reset(struct radeon_device *rdev);
void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int cayman_vm_init(struct radeon_device *rdev);
void cayman_vm_fini(struct radeon_device *rdev);
void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr);
uint32_t cayman_vm_page_flags(struct radeon_device *rdev, uint32_t flags);
int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
int evergreen_dma_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
@ -623,7 +625,8 @@ void cayman_dma_vm_set_pages(struct radeon_device *rdev,
uint32_t incr, uint32_t flags);
void cayman_dma_vm_pad_ib(struct radeon_ib *ib);
void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
void cayman_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr);
u32 cayman_gfx_get_rptr(struct radeon_device *rdev,
struct radeon_ring *ring);
@ -698,12 +701,13 @@ int si_irq_set(struct radeon_device *rdev);
int si_irq_process(struct radeon_device *rdev);
int si_vm_init(struct radeon_device *rdev);
void si_vm_fini(struct radeon_device *rdev);
void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
void si_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr);
int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
int si_copy_dma(struct radeon_device *rdev,
struct radeon_fence *si_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
struct reservation_object *resv);
void si_dma_vm_copy_pages(struct radeon_device *rdev,
struct radeon_ib *ib,
@ -720,7 +724,8 @@ void si_dma_vm_set_pages(struct radeon_device *rdev,
uint64_t addr, unsigned count,
uint32_t incr, uint32_t flags);
void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr);
u32 si_get_xclk(struct radeon_device *rdev);
uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev);
int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
@ -759,14 +764,14 @@ bool cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,
struct radeon_semaphore *semaphore,
bool emit_wait);
void cik_sdma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int cik_copy_dma(struct radeon_device *rdev,
struct radeon_fence *cik_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
int cik_copy_cpdma(struct radeon_device *rdev,
struct reservation_object *resv);
struct radeon_fence *cik_copy_cpdma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct radeon_fence **fence);
struct reservation_object *resv);
int cik_sdma_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
@ -792,7 +797,8 @@ int cik_irq_set(struct radeon_device *rdev);
int cik_irq_process(struct radeon_device *rdev);
int cik_vm_init(struct radeon_device *rdev);
void cik_vm_fini(struct radeon_device *rdev);
void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
void cik_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr);
void cik_sdma_vm_copy_pages(struct radeon_device *rdev,
struct radeon_ib *ib,
@ -810,7 +816,8 @@ void cik_sdma_vm_set_pages(struct radeon_device *rdev,
uint32_t incr, uint32_t flags);
void cik_sdma_vm_pad_ib(struct radeon_ib *ib);
void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
unsigned vm_id, uint64_t pd_addr);
int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
u32 cik_gfx_get_rptr(struct radeon_device *rdev,
struct radeon_ring *ring);
@ -882,6 +889,7 @@ uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev,
struct radeon_ring *ring);
void uvd_v1_0_set_wptr(struct radeon_device *rdev,
struct radeon_ring *ring);
int uvd_v1_0_resume(struct radeon_device *rdev);
int uvd_v1_0_init(struct radeon_device *rdev);
void uvd_v1_0_fini(struct radeon_device *rdev);
@ -889,6 +897,8 @@ int uvd_v1_0_start(struct radeon_device *rdev);
void uvd_v1_0_stop(struct radeon_device *rdev);
int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
void uvd_v1_0_fence_emit(struct radeon_device *rdev,
struct radeon_fence *fence);
int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev,
struct radeon_ring *ring,

View File

@ -196,7 +196,7 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev)
}
}
static struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev,
struct radeon_gpio_rec radeon_atombios_lookup_gpio(struct radeon_device *rdev,
u8 id)
{
struct atom_context *ctx = rdev->mode_info.atom_context;
@ -221,6 +221,7 @@ static struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev,
if (id == pin->ucGPIO_ID) {
gpio.id = pin->ucGPIO_ID;
gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4;
gpio.shift = pin->ucGpioPinBitShift;
gpio.mask = (1 << pin->ucGpioPinBitShift);
gpio.valid = true;
break;
@ -458,7 +459,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
return true;
}
const int supported_devices_connector_convert[] = {
static const int supported_devices_connector_convert[] = {
DRM_MODE_CONNECTOR_Unknown,
DRM_MODE_CONNECTOR_VGA,
DRM_MODE_CONNECTOR_DVII,
@ -477,7 +478,7 @@ const int supported_devices_connector_convert[] = {
DRM_MODE_CONNECTOR_DisplayPort
};
const uint16_t supported_devices_connector_object_id_convert[] = {
static const uint16_t supported_devices_connector_object_id_convert[] = {
CONNECTOR_OBJECT_ID_NONE,
CONNECTOR_OBJECT_ID_VGA,
CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I, /* not all boards support DL */
@ -494,7 +495,7 @@ const uint16_t supported_devices_connector_object_id_convert[] = {
CONNECTOR_OBJECT_ID_SVIDEO
};
const int object_connector_convert[] = {
static const int object_connector_convert[] = {
DRM_MODE_CONNECTOR_Unknown,
DRM_MODE_CONNECTOR_DVII,
DRM_MODE_CONNECTOR_DVII,
@ -801,7 +802,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
hpd_record =
(ATOM_HPD_INT_RECORD *)
record;
gpio = radeon_lookup_gpio(rdev,
gpio = radeon_atombios_lookup_gpio(rdev,
hpd_record->ucHPDIntGPIOID);
hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
hpd.plugged_state = hpd_record->ucPlugged_PinState;
@ -2128,7 +2129,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_GPIO;
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
radeon_lookup_gpio(rdev,
radeon_atombios_lookup_gpio(rdev,
power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex);
if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
@ -2164,7 +2165,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_GPIO;
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
radeon_lookup_gpio(rdev,
radeon_atombios_lookup_gpio(rdev,
power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
@ -2200,7 +2201,7 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_GPIO;
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
radeon_lookup_gpio(rdev,
radeon_atombios_lookup_gpio(rdev,
power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex);
if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
@ -2248,6 +2249,14 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r
/* add the i2c bus for thermal/fan chip */
if (controller->ucType > 0) {
if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN)
rdev->pm.no_fan = true;
rdev->pm.fan_pulses_per_revolution =
controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
if (rdev->pm.fan_pulses_per_revolution) {
rdev->pm.fan_min_rpm = controller->ucFanMinRPM;
rdev->pm.fan_max_rpm = controller->ucFanMaxRPM;
}
if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
DRM_INFO("Internal thermal controller %s fan control\n",
(controller->ucFanParameters &

View File

@ -45,33 +45,29 @@ static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size,
for (i = 0; i < n; i++) {
switch (flag) {
case RADEON_BENCHMARK_COPY_DMA:
r = radeon_copy_dma(rdev, saddr, daddr,
fence = radeon_copy_dma(rdev, saddr, daddr,
size / RADEON_GPU_PAGE_SIZE,
&fence);
NULL);
break;
case RADEON_BENCHMARK_COPY_BLIT:
r = radeon_copy_blit(rdev, saddr, daddr,
fence = radeon_copy_blit(rdev, saddr, daddr,
size / RADEON_GPU_PAGE_SIZE,
&fence);
NULL);
break;
default:
DRM_ERROR("Unknown copy method\n");
r = -EINVAL;
return -EINVAL;
}
if (r)
goto exit_do_move;
if (IS_ERR(fence))
return PTR_ERR(fence);
r = radeon_fence_wait(fence, false);
if (r)
goto exit_do_move;
radeon_fence_unref(&fence);
if (r)
return r;
}
end_jiffies = jiffies;
r = jiffies_to_msecs(end_jiffies - start_jiffies);
exit_do_move:
if (fence)
radeon_fence_unref(&fence);
return r;
return jiffies_to_msecs(end_jiffies - start_jiffies);
}
@ -100,7 +96,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size,
ENTER();
n = RADEON_BENCHMARK_ITERATIONS;
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, 0, NULL, &sobj);
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, 0, NULL, NULL, &sobj);
if (r) {
goto out_cleanup;
}
@ -112,7 +108,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size,
if (r) {
goto out_cleanup;
}
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, ddomain, 0, NULL, &dobj);
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, ddomain, 0, NULL, NULL, &dobj);
if (r) {
goto out_cleanup;
}

View File

@ -116,7 +116,7 @@ enum radeon_combios_connector {
CONNECTOR_UNSUPPORTED_LEGACY
};
const int legacy_connector_convert[] = {
static const int legacy_connector_convert[] = {
DRM_MODE_CONNECTOR_Unknown,
DRM_MODE_CONNECTOR_DVID,
DRM_MODE_CONNECTOR_VGA,

View File

@ -322,6 +322,12 @@ static void radeon_connector_get_edid(struct drm_connector *connector)
}
if (!radeon_connector->edid) {
/* don't fetch the edid from the vbios if ddc fails and runpm is
* enabled so we report disconnected.
*/
if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0))
return;
if (rdev->is_atom_bios) {
/* some laptops provide a hardcoded edid in rom for LCDs */
if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) ||
@ -826,6 +832,8 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector,
static enum drm_connector_status
radeon_lvds_detect(struct drm_connector *connector, bool force)
{
struct drm_device *dev = connector->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct drm_encoder *encoder = radeon_best_single_encoder(connector);
enum drm_connector_status ret = connector_status_disconnected;

View File

@ -84,21 +84,18 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
struct drm_device *ddev = p->rdev->ddev;
struct radeon_cs_chunk *chunk;
struct radeon_cs_buckets buckets;
unsigned i, j;
bool duplicate;
unsigned i;
bool need_mmap_lock = false;
int r;
if (p->chunk_relocs_idx == -1) {
if (p->chunk_relocs == NULL) {
return 0;
}
chunk = &p->chunks[p->chunk_relocs_idx];
chunk = p->chunk_relocs;
p->dma_reloc_idx = 0;
/* FIXME: we assume that each relocs use 4 dwords */
p->nrelocs = chunk->length_dw / 4;
p->relocs_ptr = kcalloc(p->nrelocs, sizeof(void *), GFP_KERNEL);
if (p->relocs_ptr == NULL) {
return -ENOMEM;
}
p->relocs = kcalloc(p->nrelocs, sizeof(struct radeon_cs_reloc), GFP_KERNEL);
p->relocs = kcalloc(p->nrelocs, sizeof(struct radeon_bo_list), GFP_KERNEL);
if (p->relocs == NULL) {
return -ENOMEM;
}
@ -107,31 +104,17 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
for (i = 0; i < p->nrelocs; i++) {
struct drm_radeon_cs_reloc *r;
struct drm_gem_object *gobj;
unsigned priority;
duplicate = false;
r = (struct drm_radeon_cs_reloc *)&chunk->kdata[i*4];
for (j = 0; j < i; j++) {
if (r->handle == p->relocs[j].handle) {
p->relocs_ptr[i] = &p->relocs[j];
duplicate = true;
break;
}
}
if (duplicate) {
p->relocs[i].handle = 0;
continue;
}
p->relocs[i].gobj = drm_gem_object_lookup(ddev, p->filp,
r->handle);
if (p->relocs[i].gobj == NULL) {
gobj = drm_gem_object_lookup(ddev, p->filp, r->handle);
if (gobj == NULL) {
DRM_ERROR("gem object lookup failed 0x%x\n",
r->handle);
return -ENOENT;
}
p->relocs_ptr[i] = &p->relocs[i];
p->relocs[i].robj = gem_to_radeon_bo(p->relocs[i].gobj);
p->relocs[i].robj = gem_to_radeon_bo(gobj);
/* The userspace buffer priorities are from 0 to 15. A higher
* number means the buffer is more important.
@ -143,10 +126,13 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
+ !!r->write_domain;
/* the first reloc of an UVD job is the msg and that must be in
VRAM, also but everything into VRAM on AGP cards to avoid
image corruptions */
VRAM, also but everything into VRAM on AGP cards and older
IGP chips to avoid image corruptions */
if (p->ring == R600_RING_TYPE_UVD_INDEX &&
(i == 0 || drm_pci_device_is_agp(p->rdev->ddev))) {
(i == 0 || drm_pci_device_is_agp(p->rdev->ddev) ||
p->rdev->family == CHIP_RS780 ||
p->rdev->family == CHIP_RS880)) {
/* TODO: is this still needed for NI+ ? */
p->relocs[i].prefered_domains =
RADEON_GEM_DOMAIN_VRAM;
@ -171,9 +157,22 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
domain |= RADEON_GEM_DOMAIN_GTT;
p->relocs[i].allowed_domains = domain;
}
/*
if (radeon_ttm_tt_has_userptr(p->relocs[i].robj->tbo.ttm)) {
uint32_t domain = p->relocs[i].prefered_domains;
if (!(domain & RADEON_GEM_DOMAIN_GTT)) {
DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is "
"allowed for userptr BOs\n");
return -EINVAL;
}
need_mmap_lock = true;
domain = RADEON_GEM_DOMAIN_GTT;
p->relocs[i].prefered_domains = domain;
p->relocs[i].allowed_domains = domain;
}
*/
p->relocs[i].tv.bo = &p->relocs[i].robj->tbo;
p->relocs[i].handle = r->handle;
p->relocs[i].tv.shared = !r->write_domain;
radeon_cs_buckets_add(&buckets, &p->relocs[i].tv.head,
priority);
@ -184,8 +183,15 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
if (p->cs_flags & RADEON_CS_USE_VM)
p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm,
&p->validated);
// if (need_mmap_lock)
// down_read(&current->mm->mmap_sem);
return radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
r = radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
// if (need_mmap_lock)
// up_read(&current->mm->mmap_sem);
return r;
}
static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority)
@ -231,17 +237,21 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
return 0;
}
static void radeon_cs_sync_rings(struct radeon_cs_parser *p)
static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
{
int i;
struct radeon_bo_list *reloc;
int r;
for (i = 0; i < p->nrelocs; i++) {
if (!p->relocs[i].robj)
continue;
list_for_each_entry(reloc, &p->validated, tv.head) {
struct reservation_object *resv;
radeon_semaphore_sync_to(p->ib.semaphore,
p->relocs[i].robj->tbo.sync_obj);
resv = reloc->robj->tbo.resv;
r = radeon_sync_resv(p->rdev, &p->ib.sync, resv,
reloc->tv.shared);
if (r)
return r;
}
return 0;
}
/* XXX: note that this is called from the legacy UMS CS ioctl as well */
@ -260,13 +270,11 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
INIT_LIST_HEAD(&p->validated);
p->idx = 0;
p->ib.sa_bo = NULL;
p->ib.semaphore = NULL;
p->const_ib.sa_bo = NULL;
p->const_ib.semaphore = NULL;
p->chunk_ib_idx = -1;
p->chunk_relocs_idx = -1;
p->chunk_flags_idx = -1;
p->chunk_const_ib_idx = -1;
p->chunk_ib = NULL;
p->chunk_relocs = NULL;
p->chunk_flags = NULL;
p->chunk_const_ib = NULL;
p->chunks_array = kcalloc(cs->num_chunks, sizeof(uint64_t), GFP_KERNEL);
if (p->chunks_array == NULL) {
return -ENOMEM;
@ -293,24 +301,23 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
return -EFAULT;
}
p->chunks[i].length_dw = user_chunk.length_dw;
p->chunks[i].chunk_id = user_chunk.chunk_id;
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) {
p->chunk_relocs_idx = i;
if (user_chunk.chunk_id == RADEON_CHUNK_ID_RELOCS) {
p->chunk_relocs = &p->chunks[i];
}
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_IB) {
p->chunk_ib_idx = i;
if (user_chunk.chunk_id == RADEON_CHUNK_ID_IB) {
p->chunk_ib = &p->chunks[i];
/* zero length IB isn't useful */
if (p->chunks[i].length_dw == 0)
return -EINVAL;
}
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_CONST_IB) {
p->chunk_const_ib_idx = i;
if (user_chunk.chunk_id == RADEON_CHUNK_ID_CONST_IB) {
p->chunk_const_ib = &p->chunks[i];
/* zero length CONST IB isn't useful */
if (p->chunks[i].length_dw == 0)
return -EINVAL;
}
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS) {
p->chunk_flags_idx = i;
if (user_chunk.chunk_id == RADEON_CHUNK_ID_FLAGS) {
p->chunk_flags = &p->chunks[i];
/* zero length flags aren't useful */
if (p->chunks[i].length_dw == 0)
return -EINVAL;
@ -319,10 +326,10 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
size = p->chunks[i].length_dw;
cdata = (void __user *)(unsigned long)user_chunk.chunk_data;
p->chunks[i].user_ptr = cdata;
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_CONST_IB)
if (user_chunk.chunk_id == RADEON_CHUNK_ID_CONST_IB)
continue;
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_IB) {
if (user_chunk.chunk_id == RADEON_CHUNK_ID_IB) {
if (!p->rdev || !(p->rdev->flags & RADEON_IS_AGP))
continue;
}
@ -335,7 +342,7 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
if (copy_from_user(p->chunks[i].kdata, cdata, size)) {
return -EFAULT;
}
if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS) {
if (user_chunk.chunk_id == RADEON_CHUNK_ID_FLAGS) {
p->cs_flags = p->chunks[i].kdata[0];
if (p->chunks[i].length_dw > 1)
ring = p->chunks[i].kdata[1];
@ -376,8 +383,8 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
static int cmp_size_smaller_first(void *priv, struct list_head *a,
struct list_head *b)
{
struct radeon_cs_reloc *la = list_entry(a, struct radeon_cs_reloc, tv.head);
struct radeon_cs_reloc *lb = list_entry(b, struct radeon_cs_reloc, tv.head);
struct radeon_bo_list *la = list_entry(a, struct radeon_bo_list, tv.head);
struct radeon_bo_list *lb = list_entry(b, struct radeon_bo_list, tv.head);
/* Sort A before B if A is smaller. */
return (int)la->robj->tbo.num_pages - (int)lb->robj->tbo.num_pages;
@ -410,7 +417,7 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo
ttm_eu_fence_buffer_objects(&parser->ticket,
&parser->validated,
parser->ib.fence);
&parser->ib.fence->base);
} else if (backoff) {
ttm_eu_backoff_reservation(&parser->ticket,
&parser->validated);
@ -418,14 +425,16 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo
if (parser->relocs != NULL) {
for (i = 0; i < parser->nrelocs; i++) {
if (parser->relocs[i].gobj)
drm_gem_object_unreference_unlocked(parser->relocs[i].gobj);
struct radeon_bo *bo = parser->relocs[i].robj;
if (bo == NULL)
continue;
drm_gem_object_unreference_unlocked(&bo->gem_base);
}
}
kfree(parser->track);
kfree(parser->relocs);
kfree(parser->relocs_ptr);
kfree(parser->vm_bos);
drm_free_large(parser->vm_bos);
for (i = 0; i < parser->nchunks; i++)
drm_free_large(parser->chunks[i].kdata);
kfree(parser->chunks);
@ -439,7 +448,7 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
{
int r;
if (parser->chunk_ib_idx == -1)
if (parser->chunk_ib == NULL)
return 0;
if (parser->cs_flags & RADEON_CS_USE_VM)
@ -451,13 +460,19 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
return r;
}
r = radeon_cs_sync_rings(parser);
if (r) {
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to sync rings: %i\n", r);
return r;
}
if (parser->ring == R600_RING_TYPE_UVD_INDEX)
radeon_uvd_note_usage(rdev);
else if ((parser->ring == TN_RING_TYPE_VCE1_INDEX) ||
(parser->ring == TN_RING_TYPE_VCE2_INDEX))
radeon_vce_note_usage(rdev);
radeon_cs_sync_rings(parser);
r = radeon_ib_schedule(rdev, &parser->ib, NULL, true);
if (r) {
DRM_ERROR("Failed to schedule IB !\n");
@ -493,10 +508,6 @@ static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p,
for (i = 0; i < p->nrelocs; i++) {
struct radeon_bo *bo;
/* ignore duplicates */
if (p->relocs_ptr[i] != &p->relocs[i])
continue;
bo = p->relocs[i].robj;
bo_va = radeon_vm_bo_find(vm, bo);
if (bo_va == NULL) {
@ -507,6 +518,8 @@ static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p,
r = radeon_vm_bo_update(rdev, bo_va, &bo->tbo.mem);
if (r)
return r;
radeon_sync_fence(&p->ib.sync, bo_va->last_pt_update);
}
return radeon_vm_clear_invalids(rdev, vm);
@ -519,7 +532,7 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
struct radeon_vm *vm = &fpriv->vm;
int r;
if (parser->chunk_ib_idx == -1)
if (parser->chunk_ib == NULL)
return 0;
if ((parser->cs_flags & RADEON_CS_USE_VM) == 0)
return 0;
@ -544,11 +557,16 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
if (r) {
goto out;
}
radeon_cs_sync_rings(parser);
radeon_semaphore_sync_to(parser->ib.semaphore, vm->fence);
r = radeon_cs_sync_rings(parser);
if (r) {
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to sync rings: %i\n", r);
goto out;
}
if ((rdev->family >= CHIP_TAHITI) &&
(parser->chunk_const_ib_idx != -1)) {
(parser->chunk_const_ib != NULL)) {
r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib, true);
} else {
r = radeon_ib_schedule(rdev, &parser->ib, NULL, true);
@ -575,7 +593,7 @@ static int radeon_cs_ib_fill(struct radeon_device *rdev, struct radeon_cs_parser
struct radeon_vm *vm = NULL;
int r;
if (parser->chunk_ib_idx == -1)
if (parser->chunk_ib == NULL)
return 0;
if (parser->cs_flags & RADEON_CS_USE_VM) {
@ -583,8 +601,8 @@ static int radeon_cs_ib_fill(struct radeon_device *rdev, struct radeon_cs_parser
vm = &fpriv->vm;
if ((rdev->family >= CHIP_TAHITI) &&
(parser->chunk_const_ib_idx != -1)) {
ib_chunk = &parser->chunks[parser->chunk_const_ib_idx];
(parser->chunk_const_ib != NULL)) {
ib_chunk = parser->chunk_const_ib;
if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) {
DRM_ERROR("cs IB CONST too big: %d\n", ib_chunk->length_dw);
return -EINVAL;
@ -603,13 +621,13 @@ static int radeon_cs_ib_fill(struct radeon_device *rdev, struct radeon_cs_parser
return -EFAULT;
}
ib_chunk = &parser->chunks[parser->chunk_ib_idx];
ib_chunk = parser->chunk_ib;
if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) {
DRM_ERROR("cs IB too big: %d\n", ib_chunk->length_dw);
return -EINVAL;
}
}
ib_chunk = &parser->chunks[parser->chunk_ib_idx];
ib_chunk = parser->chunk_ib;
r = radeon_ib_get(rdev, parser->ring, &parser->ib,
vm, ib_chunk->length_dw * 4);
@ -694,7 +712,7 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt,
unsigned idx)
{
struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx];
struct radeon_cs_chunk *ib_chunk = p->chunk_ib;
struct radeon_device *rdev = p->rdev;
uint32_t header;
@ -788,7 +806,7 @@ void radeon_cs_dump_packet(struct radeon_cs_parser *p,
* GPU offset using the provided start.
**/
int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p,
struct radeon_cs_reloc **cs_reloc,
struct radeon_bo_list **cs_reloc,
int nomm)
{
struct radeon_cs_chunk *relocs_chunk;
@ -796,12 +814,12 @@ int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p,
unsigned idx;
int r;
if (p->chunk_relocs_idx == -1) {
if (p->chunk_relocs == NULL) {
DRM_ERROR("No relocation chunk !\n");
return -EINVAL;
}
*cs_reloc = NULL;
relocs_chunk = &p->chunks[p->chunk_relocs_idx];
relocs_chunk = p->chunk_relocs;
r = radeon_cs_packet_parse(p, &p3reloc, p->idx);
if (r)
return r;
@ -827,6 +845,6 @@ int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p,
(u64)relocs_chunk->kdata[idx + 3] << 32;
(*cs_reloc)->gpu_offset |= relocs_chunk->kdata[idx + 0];
} else
*cs_reloc = p->relocs_ptr[(idx / 4)];
*cs_reloc = &p->relocs[(idx / 4)];
return 0;
}

View File

@ -71,7 +71,7 @@ int radeon_deep_color = 0;
int radeon_use_pflipirq = 2;
int irq_override = 0;
int radeon_bapm = -1;
int radeon_backlight = 0;
int radeon_backlight = 0;
extern display_t *os_display;
extern struct drm_device *main_device;
@ -82,7 +82,7 @@ void parse_cmdline(char *cmdline, videomode_t *mode, char *log, int *kms);
int init_display(struct radeon_device *rdev, videomode_t *mode);
int init_display_kms(struct drm_device *dev, videomode_t *usermode);
int get_modes(videomode_t *mode, u32_t *count);
int get_modes(videomode_t *mode, u32 *count);
int set_user_mode(videomode_t *mode);
int r100_2D_test(struct radeon_device *rdev);
@ -437,6 +437,37 @@ void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
__clear_bit(doorbell, rdev->doorbell.used);
}
/**
* radeon_doorbell_get_kfd_info - Report doorbell configuration required to
* setup KFD
*
* @rdev: radeon_device pointer
* @aperture_base: output returning doorbell aperture base physical address
* @aperture_size: output returning doorbell aperture size in bytes
* @start_offset: output returning # of doorbell bytes reserved for radeon.
*
* Radeon and the KFD share the doorbell aperture. Radeon sets it up,
* takes doorbells required for its own rings and reports the setup to KFD.
* Radeon reserved doorbells are at the start of the doorbell aperture.
*/
void radeon_doorbell_get_kfd_info(struct radeon_device *rdev,
phys_addr_t *aperture_base,
size_t *aperture_size,
size_t *start_offset)
{
/* The first num_doorbells are used by radeon.
* KFD takes whatever's left in the aperture. */
if (rdev->doorbell.size > rdev->doorbell.num_doorbells * sizeof(u32)) {
*aperture_base = rdev->doorbell.base;
*aperture_size = rdev->doorbell.size;
*start_offset = rdev->doorbell.num_doorbells * sizeof(u32);
} else {
*aperture_base = 0;
*aperture_size = 0;
*start_offset = 0;
}
}
/*
* radeon_wb_*()
* Writeback is the the method by which the the GPU updates special pages
@ -494,7 +525,7 @@ int radeon_wb_init(struct radeon_device *rdev)
if (rdev->wb.wb_obj == NULL) {
r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, 0, NULL,
RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL,
&rdev->wb.wb_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
@ -998,6 +1029,7 @@ int radeon_atombios_init(struct radeon_device *rdev)
}
mutex_init(&rdev->mode_info.atom_context->mutex);
mutex_init(&rdev->mode_info.atom_context->scratch_mutex);
radeon_atom_initialize_bios_scratch_regs(rdev->ddev);
atom_allocate_fb_scratch(rdev->mode_info.atom_context);
return 0;
@ -1234,6 +1266,7 @@ int radeon_device_init(struct radeon_device *rdev,
for (i = 0; i < RADEON_NUM_RINGS; i++) {
rdev->ring[i].idx = i;
}
rdev->fence_context = fence_context_alloc(RADEON_NUM_RINGS);
DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n",
radeon_family_name[rdev->family], pdev->vendor, pdev->device,
@ -1248,9 +1281,13 @@ int radeon_device_init(struct radeon_device *rdev,
mutex_init(&rdev->pm.mutex);
mutex_init(&rdev->gpu_clock_mutex);
mutex_init(&rdev->srbm_mutex);
mutex_init(&rdev->grbm_idx_mutex);
// init_rwsem(&rdev->pm.mclk_lock);
// init_rwsem(&rdev->exclusive_lock);
init_waitqueue_head(&rdev->irq.vblank_queue);
mutex_init(&rdev->mn_lock);
// hash_init(rdev->mn_hash);
r = radeon_gem_init(rdev);
if (r)
return r;
@ -1362,9 +1399,6 @@ int radeon_device_init(struct radeon_device *rdev,
if (r)
return r;
r = radeon_ib_ring_tests(rdev);
if (r)
DRM_ERROR("ib ring test failed (%d).\n", r);
if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) {
@ -1379,6 +1413,10 @@ int radeon_device_init(struct radeon_device *rdev,
return r;
}
// r = radeon_ib_ring_tests(rdev);
// if (r)
// DRM_ERROR("ib ring test failed (%d).\n", r);
if ((radeon_testing & 1)) {
if (rdev->accel_working)
radeon_test_moves(rdev);
@ -1436,7 +1474,6 @@ int radeon_gpu_reset(struct radeon_device *rdev)
}
}
retry:
r = radeon_asic_reset(rdev);
if (!r) {
dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n");
@ -1445,25 +1482,12 @@ retry:
radeon_restore_bios_scratch_regs(rdev);
if (!r) {
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (!r && ring_data[i]) {
radeon_ring_restore(rdev, &rdev->ring[i],
ring_sizes[i], ring_data[i]);
ring_sizes[i] = 0;
ring_data[i] = NULL;
}
// r = radeon_ib_ring_tests(rdev);
// if (r) {
// dev_err(rdev->dev, "ib ring test failed (%d).\n", r);
// if (saved) {
// saved = false;
// radeon_suspend(rdev);
// goto retry;
// }
// }
} else {
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
radeon_fence_driver_force_completion(rdev, i);
kfree(ring_data[i]);
}
}

View File

@ -1537,7 +1537,7 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl
/* In vblank? */
if (in_vbl)
ret |= DRM_SCANOUTPOS_INVBL;
ret |= DRM_SCANOUTPOS_IN_VBLANK;
/* Is vpos outside nominal vblank area, but less than
* 1/100 of a frame height away from start of vblank?

View File

@ -179,6 +179,9 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder,
(rdev->pdev->subsystem_vendor == 0x1734) &&
(rdev->pdev->subsystem_device == 0x1107))
use_bl = false;
/* disable native backlight control on older asics */
else if (rdev->family < CHIP_R600)
use_bl = false;
else
use_bl = true;
}
@ -410,3 +413,24 @@ bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
}
}
bool radeon_encoder_is_digital(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
case ENCODER_OBJECT_ID_INTERNAL_DDI:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
return true;
default:
return false;
}
}

View File

@ -184,7 +184,8 @@ out_unref:
static int radeonfb_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper;
struct radeon_fbdev *rfbdev =
container_of(helper, struct radeon_fbdev, helper);
struct radeon_device *rdev = rfbdev->rdev;
struct fb_info *info;
struct drm_framebuffer *fb = NULL;

View File

@ -29,9 +29,8 @@
* Dave Airlie
*/
#include <linux/seq_file.h>
#include <asm/atomic.h>
#include <linux/atomic.h>
#include <linux/wait.h>
#include <linux/list.h>
#include <linux/kref.h>
#include <linux/slab.h>
#include <drm/drmP.h>
@ -111,30 +110,70 @@ int radeon_fence_emit(struct radeon_device *rdev,
struct radeon_fence **fence,
int ring)
{
u64 seq = ++rdev->fence_drv[ring].sync_seq[ring];
/* we are protected by the ring emission mutex */
*fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL);
if ((*fence) == NULL) {
return -ENOMEM;
}
kref_init(&((*fence)->kref));
(*fence)->rdev = rdev;
(*fence)->seq = ++rdev->fence_drv[ring].sync_seq[ring];
(*fence)->seq = seq;
(*fence)->ring = ring;
(*fence)->is_vm_update = false;
fence_init(&(*fence)->base, &radeon_fence_ops,
&rdev->fence_queue.lock, rdev->fence_context + ring, seq);
radeon_fence_ring_emit(rdev, ring, *fence);
trace_radeon_fence_emit(rdev->ddev, ring, (*fence)->seq);
return 0;
}
/**
* radeon_fence_process - process a fence
* radeon_fence_check_signaled - callback from fence_queue
*
* this function is called with fence_queue lock held, which is also used
* for the fence locking itself, so unlocked variants are used for
* fence_signal, and remove_wait_queue.
*/
static int radeon_fence_check_signaled(wait_queue_t *wait, unsigned mode, int flags, void *key)
{
struct radeon_fence *fence;
u64 seq;
fence = container_of(wait, struct radeon_fence, fence_wake);
/*
* We cannot use radeon_fence_process here because we're already
* in the waitqueue, in a call from wake_up_all.
*/
seq = atomic64_read(&fence->rdev->fence_drv[fence->ring].last_seq);
if (seq >= fence->seq) {
int ret = fence_signal_locked(&fence->base);
if (!ret)
FENCE_TRACE(&fence->base, "signaled from irq context\n");
else
FENCE_TRACE(&fence->base, "was already signaled\n");
radeon_irq_kms_sw_irq_put(fence->rdev, fence->ring);
// __remove_wait_queue(&fence->rdev->fence_queue, &fence->fence_wake);
fence_put(&fence->base);
} else
FENCE_TRACE(&fence->base, "pending\n");
return 0;
}
/**
* radeon_fence_activity - check for fence activity
*
* @rdev: radeon_device pointer
* @ring: ring index the fence is associated with
*
* Checks the current fence value and wakes the fence queue
* if the sequence number has increased (all asics).
* Checks the current fence value and calculates the last
* signalled fence value. Returns true if activity occured
* on the ring, and the fence_queue should be waken up.
*/
void radeon_fence_process(struct radeon_device *rdev, int ring)
static bool radeon_fence_activity(struct radeon_device *rdev, int ring)
{
uint64_t seq, last_seq, last_emitted;
unsigned count_loop = 0;
@ -190,23 +229,77 @@ void radeon_fence_process(struct radeon_device *rdev, int ring)
}
} while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq);
if (wake)
wake_up_all(&rdev->fence_queue);
// if (seq < last_emitted)
// radeon_fence_schedule_check(rdev, ring);
return wake;
}
/**
* radeon_fence_destroy - destroy a fence
* radeon_fence_check_lockup - check for hardware lockup
*
* @kref: fence kref
* @work: delayed work item
*
* Frees the fence object (all asics).
* Checks for fence activity and if there is none probe
* the hardware if a lockup occured.
*/
static void radeon_fence_destroy(struct kref *kref)
static void radeon_fence_check_lockup(struct work_struct *work)
{
struct radeon_fence *fence;
struct radeon_fence_driver *fence_drv;
struct radeon_device *rdev;
int ring;
fence = container_of(kref, struct radeon_fence, kref);
kfree(fence);
fence_drv = container_of(work, struct radeon_fence_driver,
lockup_work.work);
rdev = fence_drv->rdev;
ring = fence_drv - &rdev->fence_drv[0];
// if (!down_read_trylock(&rdev->exclusive_lock)) {
// /* just reschedule the check if a reset is going on */
// radeon_fence_schedule_check(rdev, ring);
// return;
// }
if (fence_drv->delayed_irq && rdev->ddev->irq_enabled) {
unsigned long irqflags;
fence_drv->delayed_irq = false;
spin_lock_irqsave(&rdev->irq.lock, irqflags);
radeon_irq_set(rdev);
spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
}
if (radeon_fence_activity(rdev, ring))
wake_up_all(&rdev->fence_queue);
else if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) {
/* good news we believe it's a lockup */
dev_warn(rdev->dev, "GPU lockup (current fence id "
"0x%016llx last fence id 0x%016llx on ring %d)\n",
(uint64_t)atomic64_read(&fence_drv->last_seq),
fence_drv->sync_seq[ring], ring);
/* remember that we need an reset */
rdev->needs_reset = true;
wake_up_all(&rdev->fence_queue);
}
// up_read(&rdev->exclusive_lock);
}
/**
* radeon_fence_process - process a fence
*
* @rdev: radeon_device pointer
* @ring: ring index the fence is associated with
*
* Checks the current fence value and wakes the fence queue
* if the sequence number has increased (all asics).
*/
void radeon_fence_process(struct radeon_device *rdev, int ring)
{
if (radeon_fence_activity(rdev, ring))
wake_up_all(&rdev->fence_queue);
}
/**
@ -237,6 +330,77 @@ static bool radeon_fence_seq_signaled(struct radeon_device *rdev,
return false;
}
static bool radeon_fence_is_signaled(struct fence *f)
{
struct radeon_fence *fence = to_radeon_fence(f);
struct radeon_device *rdev = fence->rdev;
unsigned ring = fence->ring;
u64 seq = fence->seq;
if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) {
return true;
}
// if (down_read_trylock(&rdev->exclusive_lock))
{
radeon_fence_process(rdev, ring);
// up_read(&rdev->exclusive_lock);
if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) {
return true;
}
}
return false;
}
/**
* radeon_fence_enable_signaling - enable signalling on fence
* @fence: fence
*
* This function is called with fence_queue lock held, and adds a callback
* to fence_queue that checks if this fence is signaled, and if so it
* signals the fence and removes itself.
*/
static bool radeon_fence_enable_signaling(struct fence *f)
{
struct radeon_fence *fence = to_radeon_fence(f);
struct radeon_device *rdev = fence->rdev;
if (atomic64_read(&rdev->fence_drv[fence->ring].last_seq) >= fence->seq)
return false;
// if (down_read_trylock(&rdev->exclusive_lock))
{
radeon_irq_kms_sw_irq_get(rdev, fence->ring);
// if (radeon_fence_activity(rdev, fence->ring))
// wake_up_all_locked(&rdev->fence_queue);
/* did fence get signaled after we enabled the sw irq? */
if (atomic64_read(&rdev->fence_drv[fence->ring].last_seq) >= fence->seq) {
radeon_irq_kms_sw_irq_put(rdev, fence->ring);
// up_read(&rdev->exclusive_lock);
return false;
}
// up_read(&rdev->exclusive_lock);
// } else {
/* we're probably in a lockup, lets not fiddle too much */
// if (radeon_irq_kms_sw_irq_get_delayed(rdev, fence->ring))
// rdev->fence_drv[fence->ring].delayed_irq = true;
// radeon_fence_schedule_check(rdev, fence->ring);
}
// fence->fence_wake.flags = 0;
// fence->fence_wake.private = NULL;
fence->fence_wake.func = radeon_fence_check_signaled;
__add_wait_queue(&rdev->fence_queue, &fence->fence_wake);
fence_get(f);
FENCE_TRACE(&fence->base, "armed on ring %i!\n", fence->ring);
return true;
}
/**
* radeon_fence_signaled - check if a fence has signaled
*
@ -247,14 +411,15 @@ static bool radeon_fence_seq_signaled(struct radeon_device *rdev,
*/
bool radeon_fence_signaled(struct radeon_fence *fence)
{
if (!fence) {
if (!fence)
return true;
}
if (fence->seq == RADEON_FENCE_SIGNALED_SEQ) {
return true;
}
if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) {
fence->seq = RADEON_FENCE_SIGNALED_SEQ;
int ret;
ret = fence_signal(&fence->base);
if (!ret)
FENCE_TRACE(&fence->base, "signaled from radeon_fence_signaled\n");
return true;
}
return false;
@ -283,49 +448,54 @@ static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq)
}
/**
* radeon_fence_wait_seq - wait for a specific sequence numbers
* radeon_fence_wait_seq_timeout - wait for a specific sequence numbers
*
* @rdev: radeon device pointer
* @target_seq: sequence number(s) we want to wait for
* @intr: use interruptable sleep
* @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite wait
*
* Wait for the requested sequence number(s) to be written by any ring
* (all asics). Sequnce number array is indexed by ring id.
* @intr selects whether to use interruptable (true) or non-interruptable
* (false) sleep when waiting for the sequence number. Helper function
* for radeon_fence_wait_*().
* Returns 0 if the sequence number has passed, error for all other cases.
* Returns remaining time if the sequence number has passed, 0 when
* the wait timeout, or an error for all other cases.
* -EDEADLK is returned when a GPU lockup has been detected.
*/
static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
bool intr)
static long radeon_fence_wait_seq_timeout(struct radeon_device *rdev,
u64 *target_seq, bool intr,
long timeout)
{
uint64_t last_seq[RADEON_NUM_RINGS];
bool signaled;
int i, r;
long r;
int i;
while (!radeon_fence_any_seq_signaled(rdev, target_seq)) {
if (radeon_fence_any_seq_signaled(rdev, target_seq))
return timeout;
/* Save current sequence values, used to check for GPU lockups */
/* enable IRQs and tracing */
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (!target_seq[i])
continue;
last_seq[i] = atomic64_read(&rdev->fence_drv[i].last_seq);
trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]);
radeon_irq_kms_sw_irq_get(rdev, i);
}
if (intr) {
r = wait_event_interruptible_timeout(rdev->fence_queue, (
(signaled = radeon_fence_any_seq_signaled(rdev, target_seq))
|| rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT);
radeon_fence_any_seq_signaled(rdev, target_seq)
|| rdev->needs_reset), timeout);
} else {
r = wait_event_timeout(rdev->fence_queue, (
(signaled = radeon_fence_any_seq_signaled(rdev, target_seq))
|| rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT);
radeon_fence_any_seq_signaled(rdev, target_seq)
|| rdev->needs_reset), timeout);
}
if (rdev->needs_reset)
r = -EDEADLK;
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (!target_seq[i])
continue;
@ -334,59 +504,14 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]);
}
if (unlikely(r < 0))
return r;
if (unlikely(!signaled)) {
if (rdev->needs_reset)
return -EDEADLK;
/* we were interrupted for some reason and fence
* isn't signaled yet, resume waiting */
if (r)
continue;
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (!target_seq[i])
continue;
if (last_seq[i] != atomic64_read(&rdev->fence_drv[i].last_seq))
break;
}
if (i != RADEON_NUM_RINGS)
continue;
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (!target_seq[i])
continue;
if (radeon_ring_is_lockup(rdev, i, &rdev->ring[i]))
break;
}
if (i < RADEON_NUM_RINGS) {
/* good news we believe it's a lockup */
dev_warn(rdev->dev, "GPU lockup (waiting for "
"0x%016llx last fence id 0x%016llx on"
" ring %d)\n",
target_seq[i], last_seq[i], i);
/* remember that we need an reset */
rdev->needs_reset = true;
wake_up_all(&rdev->fence_queue);
return -EDEADLK;
}
}
}
return 0;
}
/**
* radeon_fence_wait - wait for a fence to signal
*
* @fence: radeon fence object
* @intr: use interruptable sleep
* @intr: use interruptible sleep
*
* Wait for the requested fence to signal (all asics).
* @intr selects whether to use interruptable (true) or non-interruptable
@ -396,22 +521,26 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
int radeon_fence_wait(struct radeon_fence *fence, bool intr)
{
uint64_t seq[RADEON_NUM_RINGS] = {};
int r;
long r;
if (fence == NULL) {
WARN(1, "Querying an invalid fence : %p !\n", fence);
return -EINVAL;
}
/*
* This function should not be called on !radeon fences.
* If this is the case, it would mean this function can
* also be called on radeon fences belonging to another card.
* exclusive_lock is not held in that case.
*/
if (WARN_ON_ONCE(!to_radeon_fence(&fence->base)))
return fence_wait(&fence->base, intr);
seq[fence->ring] = fence->seq;
if (seq[fence->ring] == RADEON_FENCE_SIGNALED_SEQ)
return 0;
r = radeon_fence_wait_seq(fence->rdev, seq, intr);
if (r)
r = radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, MAX_SCHEDULE_TIMEOUT);
if (r < 0) {
return r;
}
fence->seq = RADEON_FENCE_SIGNALED_SEQ;
r = fence_signal(&fence->base);
if (!r)
FENCE_TRACE(&fence->base, "signaled from fence_wait\n");
return 0;
}
@ -434,7 +563,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev,
{
uint64_t seq[RADEON_NUM_RINGS];
unsigned i, num_rings = 0;
int r;
long r;
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
seq[i] = 0;
@ -445,18 +574,14 @@ int radeon_fence_wait_any(struct radeon_device *rdev,
seq[i] = fences[i]->seq;
++num_rings;
/* test if something was allready signaled */
if (seq[i] == RADEON_FENCE_SIGNALED_SEQ)
return 0;
}
/* nothing to wait for ? */
if (num_rings == 0)
return -ENOENT;
r = radeon_fence_wait_seq(rdev, seq, intr);
if (r) {
r = radeon_fence_wait_seq_timeout(rdev, seq, intr, MAX_SCHEDULE_TIMEOUT);
if (r < 0) {
return r;
}
return 0;
@ -475,6 +600,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev,
int radeon_fence_wait_next(struct radeon_device *rdev, int ring)
{
uint64_t seq[RADEON_NUM_RINGS] = {};
long r;
seq[ring] = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL;
if (seq[ring] >= rdev->fence_drv[ring].sync_seq[ring]) {
@ -482,7 +608,10 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring)
already the last emited fence */
return -ENOENT;
}
return radeon_fence_wait_seq(rdev, seq, false);
r = radeon_fence_wait_seq_timeout(rdev, seq, false, MAX_SCHEDULE_TIMEOUT);
if (r < 0)
return r;
return 0;
}
/**
@ -498,18 +627,18 @@ int radeon_fence_wait_next(struct radeon_device *rdev, int ring)
int radeon_fence_wait_empty(struct radeon_device *rdev, int ring)
{
uint64_t seq[RADEON_NUM_RINGS] = {};
int r;
long r;
seq[ring] = rdev->fence_drv[ring].sync_seq[ring];
if (!seq[ring])
return 0;
r = radeon_fence_wait_seq(rdev, seq, false);
if (r) {
r = radeon_fence_wait_seq_timeout(rdev, seq, false, MAX_SCHEDULE_TIMEOUT);
if (r < 0) {
if (r == -EDEADLK)
return -EDEADLK;
dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n",
dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%ld)\n",
ring, r);
}
return 0;
@ -525,7 +654,7 @@ int radeon_fence_wait_empty(struct radeon_device *rdev, int ring)
*/
struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence)
{
kref_get(&fence->kref);
fence_get(&fence->base);
return fence;
}
@ -542,7 +671,7 @@ void radeon_fence_unref(struct radeon_fence **fence)
*fence = NULL;
if (tmp) {
kref_put(&tmp->kref, radeon_fence_destroy);
fence_put(&tmp->base);
}
}
@ -711,6 +840,9 @@ static void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring)
rdev->fence_drv[ring].sync_seq[i] = 0;
atomic64_set(&rdev->fence_drv[ring].last_seq, 0);
rdev->fence_drv[ring].initialized = false;
INIT_DELAYED_WORK(&rdev->fence_drv[ring].lockup_work,
radeon_fence_check_lockup);
rdev->fence_drv[ring].rdev = rdev;
}
/**
@ -758,7 +890,7 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)
r = radeon_fence_wait_empty(rdev, ring);
if (r) {
/* no need to trigger GPU reset as we are unloading */
radeon_fence_driver_force_completion(rdev);
radeon_fence_driver_force_completion(rdev, ring);
}
wake_up_all(&rdev->fence_queue);
radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg);
@ -771,17 +903,14 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)
* radeon_fence_driver_force_completion - force all fence waiter to complete
*
* @rdev: radeon device pointer
* @ring: the ring to complete
*
* In case of GPU reset failure make sure no process keep waiting on fence
* that will never complete.
*/
void radeon_fence_driver_force_completion(struct radeon_device *rdev)
void radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring)
{
int ring;
for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
if (!rdev->fence_drv[ring].initialized)
continue;
if (rdev->fence_drv[ring].initialized) {
radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring);
}
}
@ -833,6 +962,7 @@ static int radeon_debugfs_gpu_reset(struct seq_file *m, void *data)
down_read(&rdev->exclusive_lock);
seq_printf(m, "%d\n", rdev->needs_reset);
rdev->needs_reset = true;
wake_up_all(&rdev->fence_queue);
up_read(&rdev->exclusive_lock);
return 0;
@ -852,3 +982,72 @@ int radeon_debugfs_fence_init(struct radeon_device *rdev)
return 0;
#endif
}
static const char *radeon_fence_get_driver_name(struct fence *fence)
{
return "radeon";
}
static const char *radeon_fence_get_timeline_name(struct fence *f)
{
struct radeon_fence *fence = to_radeon_fence(f);
switch (fence->ring) {
case RADEON_RING_TYPE_GFX_INDEX: return "radeon.gfx";
case CAYMAN_RING_TYPE_CP1_INDEX: return "radeon.cp1";
case CAYMAN_RING_TYPE_CP2_INDEX: return "radeon.cp2";
case R600_RING_TYPE_DMA_INDEX: return "radeon.dma";
case CAYMAN_RING_TYPE_DMA1_INDEX: return "radeon.dma1";
case R600_RING_TYPE_UVD_INDEX: return "radeon.uvd";
case TN_RING_TYPE_VCE1_INDEX: return "radeon.vce1";
case TN_RING_TYPE_VCE2_INDEX: return "radeon.vce2";
default: WARN_ON_ONCE(1); return "radeon.unk";
}
}
static inline bool radeon_test_signaled(struct radeon_fence *fence)
{
return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags);
}
static signed long radeon_fence_default_wait(struct fence *f, bool intr,
signed long t)
{
struct radeon_fence *fence = to_radeon_fence(f);
struct radeon_device *rdev = fence->rdev;
bool signaled;
fence_enable_sw_signaling(&fence->base);
/*
* This function has to return -EDEADLK, but cannot hold
* exclusive_lock during the wait because some callers
* may already hold it. This means checking needs_reset without
* lock, and not fiddling with any gpu internals.
*
* The callback installed with fence_enable_sw_signaling will
* run before our wait_event_*timeout call, so we will see
* both the signaled fence and the changes to needs_reset.
*/
if (intr)
t = wait_event_interruptible_timeout(rdev->fence_queue,
((signaled = radeon_test_signaled(fence)) ||
rdev->needs_reset), t);
else
t = wait_event_timeout(rdev->fence_queue,
((signaled = radeon_test_signaled(fence)) ||
rdev->needs_reset), t);
if (t > 0 && !signaled)
return -EDEADLK;
return t;
}
const struct fence_ops radeon_fence_ops = {
.get_driver_name = radeon_fence_get_driver_name,
.get_timeline_name = radeon_fence_get_timeline_name,
.enable_signaling = radeon_fence_enable_signaling,
.signaled = radeon_fence_is_signaled,
.wait = radeon_fence_default_wait,
.release = NULL,
};

View File

@ -137,7 +137,7 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev)
if (rdev->gart.robj == NULL) {
r = radeon_bo_create(rdev, rdev->gart.table_size,
PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
0, NULL, &rdev->gart.robj);
0, NULL, NULL, &rdev->gart.robj);
if (r) {
return r;
}

View File

@ -65,7 +65,7 @@ int radeon_gem_object_create(struct radeon_device *rdev, unsigned long size,
retry:
r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain,
flags, NULL, &robj);
flags, NULL, NULL, &robj);
if (r) {
if (r != -ERESTARTSYS) {
if (initial_domain == RADEON_GEM_DOMAIN_VRAM) {
@ -91,7 +91,7 @@ static int radeon_gem_set_domain(struct drm_gem_object *gobj,
{
struct radeon_bo *robj;
uint32_t domain;
int r;
long r;
/* FIXME: reeimplement */
robj = gem_to_radeon_bo(gobj);
@ -229,9 +229,10 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
return r;
}
int radeon_mode_dumb_mmap(struct drm_file *filp,
static int radeon_mode_mmap(struct drm_file *filp,
struct drm_device *dev,
uint32_t handle, uint64_t *offset_p)
uint32_t handle, bool dumb,
uint64_t *offset_p)
{
struct drm_gem_object *gobj;
struct radeon_bo *robj;
@ -240,6 +241,14 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
if (gobj == NULL) {
return -ENOENT;
}
/*
* We don't allow dumb mmaps on objects created using another
* interface.
*/
WARN_ONCE(dumb && !(gobj->dumb || gobj->import_attach),
"Illegal dumb map of GPU buffer.\n");
robj = gem_to_radeon_bo(gobj);
*offset_p = radeon_bo_mmap_offset(robj);
drm_gem_object_unreference_unlocked(gobj);
@ -251,7 +260,8 @@ int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
{
struct drm_radeon_gem_mmap *args = data;
return radeon_mode_dumb_mmap(filp, dev, args->handle, &args->addr_ptr);
return radeon_mode_mmap(filp, dev, args->handle, false,
&args->addr_ptr);
}
int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
@ -283,8 +293,9 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
struct drm_radeon_gem_wait_idle *args = data;
struct drm_gem_object *gobj;
struct radeon_bo *robj;
int r;
int r = 0;
uint32_t cur_placement = 0;
long ret;
gobj = drm_gem_object_lookup(dev, filp, args->handle);
if (gobj == NULL) {

View File

@ -64,10 +64,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
return r;
}
r = radeon_semaphore_create(rdev, &ib->semaphore);
if (r) {
return r;
}
radeon_sync_create(&ib->sync);
ib->ring = ring;
ib->fence = NULL;
@ -96,7 +93,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
*/
void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib)
{
radeon_semaphore_free(rdev, &ib->semaphore, ib->fence);
radeon_sync_free(rdev, &ib->sync, ib->fence);
radeon_sa_bo_free(rdev, &ib->sa_bo, ib->fence);
radeon_fence_unref(&ib->fence);
}
@ -145,11 +142,11 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
if (ib->vm) {
struct radeon_fence *vm_id_fence;
vm_id_fence = radeon_vm_grab_id(rdev, ib->vm, ib->ring);
radeon_semaphore_sync_to(ib->semaphore, vm_id_fence);
radeon_sync_fence(&ib->sync, vm_id_fence);
}
/* sync with other rings */
r = radeon_semaphore_sync_rings(rdev, ib->semaphore, ib->ring);
r = radeon_sync_rings(rdev, &ib->sync, ib->ring);
if (r) {
dev_err(rdev->dev, "failed to sync rings (%d)\n", r);
radeon_ring_unlock_undo(rdev, ring);
@ -157,11 +154,12 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
}
if (ib->vm)
radeon_vm_flush(rdev, ib->vm, ib->ring);
radeon_vm_flush(rdev, ib->vm, ib->ring,
ib->sync.last_vm_update);
if (const_ib) {
radeon_ring_ib_execute(rdev, const_ib->ring, const_ib);
radeon_semaphore_free(rdev, &const_ib->semaphore, NULL);
radeon_sync_free(rdev, &const_ib->sync, NULL);
}
radeon_ring_ib_execute(rdev, ib->ring, ib);
r = radeon_fence_emit(rdev, &ib->fence, ib->ring);
@ -269,6 +267,7 @@ int radeon_ib_ring_tests(struct radeon_device *rdev)
r = radeon_ib_test(rdev, i, ring);
if (r) {
radeon_fence_driver_force_completion(rdev, i);
ring->ready = false;
rdev->needs_reset = false;

View File

@ -205,6 +205,21 @@ void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev, int ring)
}
}
/**
* radeon_irq_kms_sw_irq_get_delayed - enable software interrupt
*
* @rdev: radeon device pointer
* @ring: ring whose interrupt you want to enable
*
* Enables the software interrupt for a specific ring (all asics).
* The software interrupt is generally used to signal a fence on
* a particular ring.
*/
bool radeon_irq_kms_sw_irq_get_delayed(struct radeon_device *rdev, int ring)
{
return atomic_inc_return(&rdev->irq.ring_int[ring]) == 1;
}
/**
* radeon_irq_kms_sw_irq_put - disable software interrupt
*

View File

@ -0,0 +1,47 @@
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* radeon_kfd.h defines the private interface between the
* AMD kernel graphics drivers and the AMD KFD.
*/
#ifndef RADEON_KFD_H_INCLUDED
#define RADEON_KFD_H_INCLUDED
#include <linux/types.h>
//#include "../amd/include/kgd_kfd_interface.h"
struct radeon_device;
bool radeon_kfd_init(void);
void radeon_kfd_fini(void);
void radeon_kfd_suspend(struct radeon_device *rdev);
int radeon_kfd_resume(struct radeon_device *rdev);
void radeon_kfd_interrupt(struct radeon_device *rdev,
const void *ih_ring_entry);
void radeon_kfd_device_probe(struct radeon_device *rdev);
void radeon_kfd_device_init(struct radeon_device *rdev);
void radeon_kfd_device_fini(struct radeon_device *rdev);
#endif /* RADEON_KFD_H_INCLUDED */

View File

@ -321,6 +321,10 @@ struct radeon_crtc {
uint32_t crtc_offset;
struct drm_gem_object *cursor_bo;
uint64_t cursor_addr;
int cursor_x;
int cursor_y;
int cursor_hot_x;
int cursor_hot_y;
int cursor_width;
int cursor_height;
int max_cursor_width;
@ -462,6 +466,7 @@ struct radeon_gpio_rec {
u8 id;
u32 reg;
u32 mask;
u32 shift;
};
struct radeon_hpd {
@ -748,6 +753,8 @@ extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
struct radeon_atom_ss *ss,
int id, u32 clock);
extern struct radeon_gpio_rec radeon_atombios_lookup_gpio(struct radeon_device *rdev,
u8 id);
extern void radeon_compute_pll_legacy(struct radeon_pll *pll,
uint64_t freq,
@ -777,6 +784,7 @@ extern void atombios_digital_setup(struct drm_encoder *encoder, int action);
extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
extern bool atombios_set_edp_panel_power(struct drm_connector *connector, int action);
extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
extern bool radeon_encoder_is_digital(struct drm_encoder *encoder);
extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
@ -801,13 +809,16 @@ extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
extern int radeon_crtc_do_set_base(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int x, int y, int atomic);
extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
extern int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
struct drm_file *file_priv,
uint32_t handle,
uint32_t width,
uint32_t height);
uint32_t height,
int32_t hot_x,
int32_t hot_y);
extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
int x, int y);
extern void radeon_cursor_reset(struct drm_crtc *crtc);
extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
unsigned int flags,

View File

@ -96,40 +96,83 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
{
u32 c = 0, i;
rbo->placement.fpfn = 0;
rbo->placement.lpfn = 0;
rbo->placement.placement = rbo->placements;
rbo->placement.busy_placement = rbo->placements;
if (domain & RADEON_GEM_DOMAIN_VRAM)
rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
if (domain & RADEON_GEM_DOMAIN_VRAM) {
/* Try placing BOs which don't need CPU access outside of the
* CPU accessible part of VRAM
*/
if ((rbo->flags & RADEON_GEM_NO_CPU_ACCESS) &&
rbo->rdev->mc.visible_vram_size < rbo->rdev->mc.real_vram_size) {
rbo->placements[c].fpfn =
rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
rbo->placements[c++].flags = TTM_PL_FLAG_WC |
TTM_PL_FLAG_UNCACHED |
TTM_PL_FLAG_VRAM;
}
rbo->placements[c].fpfn = 0;
rbo->placements[c++].flags = TTM_PL_FLAG_WC |
TTM_PL_FLAG_UNCACHED |
TTM_PL_FLAG_VRAM;
}
if (domain & RADEON_GEM_DOMAIN_GTT) {
if (rbo->flags & RADEON_GEM_GTT_UC) {
rbo->placements[c++] = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_TT;
rbo->placements[c].fpfn = 0;
rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED |
TTM_PL_FLAG_TT;
} else if ((rbo->flags & RADEON_GEM_GTT_WC) ||
(rbo->rdev->flags & RADEON_IS_AGP)) {
rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
rbo->placements[c].fpfn = 0;
rbo->placements[c++].flags = TTM_PL_FLAG_WC |
TTM_PL_FLAG_UNCACHED |
TTM_PL_FLAG_TT;
} else {
rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT;
rbo->placements[c].fpfn = 0;
rbo->placements[c++].flags = TTM_PL_FLAG_CACHED |
TTM_PL_FLAG_TT;
}
}
if (domain & RADEON_GEM_DOMAIN_CPU) {
if (rbo->flags & RADEON_GEM_GTT_UC) {
rbo->placements[c++] = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_SYSTEM;
rbo->placements[c].fpfn = 0;
rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED |
TTM_PL_FLAG_SYSTEM;
} else if ((rbo->flags & RADEON_GEM_GTT_WC) ||
rbo->rdev->flags & RADEON_IS_AGP) {
rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
rbo->placements[c].fpfn = 0;
rbo->placements[c++].flags = TTM_PL_FLAG_WC |
TTM_PL_FLAG_UNCACHED |
TTM_PL_FLAG_SYSTEM;
} else {
rbo->placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM;
rbo->placements[c].fpfn = 0;
rbo->placements[c++].flags = TTM_PL_FLAG_CACHED |
TTM_PL_FLAG_SYSTEM;
}
}
if (!c)
rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
if (!c) {
rbo->placements[c].fpfn = 0;
rbo->placements[c++].flags = TTM_PL_MASK_CACHING |
TTM_PL_FLAG_SYSTEM;
}
rbo->placement.num_placement = c;
rbo->placement.num_busy_placement = c;
for (i = 0; i < c; ++i) {
if ((rbo->flags & RADEON_GEM_CPU_ACCESS) &&
(rbo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
!rbo->placements[i].fpfn)
rbo->placements[i].lpfn =
rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
else
rbo->placements[i].lpfn = 0;
}
/*
* Use two-ended allocation depending on the buffer size to
* improve fragmentation quality.
@ -137,14 +180,16 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
*/
if (rbo->tbo.mem.size > 512 * 1024) {
for (i = 0; i < c; i++) {
rbo->placements[i] |= TTM_PL_FLAG_TOPDOWN;
rbo->placements[i].flags |= TTM_PL_FLAG_TOPDOWN;
}
}
}
int radeon_bo_create(struct radeon_device *rdev,
unsigned long size, int byte_align, bool kernel, u32 domain,
u32 flags, struct sg_table *sg, struct radeon_bo **bo_ptr)
unsigned long size, int byte_align, bool kernel,
u32 domain, u32 flags, struct sg_table *sg,
struct reservation_object *resv,
struct radeon_bo **bo_ptr)
{
struct radeon_bo *bo;
enum ttm_bo_type type;
@ -187,18 +232,19 @@ int radeon_bo_create(struct radeon_device *rdev,
if (!(rdev->flags & RADEON_IS_PCIE))
bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
// printf("%s rdev->flags %x bo->flags %x\n",
// __FUNCTION__, bo->flags);
if(flags & RADEON_GEM_GTT_WC)
bo->flags&= ~RADEON_GEM_GTT_WC;
#ifdef CONFIG_X86_32
/* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit
* See https://bugs.freedesktop.org/show_bug.cgi?id=84627
*/
bo->flags &= ~RADEON_GEM_GTT_WC;
#endif
radeon_ttm_placement_from_domain(bo, domain);
/* Kernel allocation are uninterruptible */
// down_read(&rdev->pm.mclk_lock);
r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
&bo->placement, page_align, !kernel, NULL,
acc_size, sg, &radeon_ttm_bo_destroy);
acc_size, sg, resv, &radeon_ttm_bo_destroy);
// up_read(&rdev->pm.mclk_lock);
if (unlikely(r != 0)) {
return r;
@ -289,21 +335,19 @@ int radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
return 0;
}
radeon_ttm_placement_from_domain(bo, domain);
if (domain == RADEON_GEM_DOMAIN_VRAM) {
for (i = 0; i < bo->placement.num_placement; i++) {
/* force to pin into visible video ram */
bo->placement.lpfn = bo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
}
if (max_offset) {
u64 lpfn = max_offset >> PAGE_SHIFT;
if ((bo->placements[i].flags & TTM_PL_FLAG_VRAM) &&
!(bo->flags & RADEON_GEM_NO_CPU_ACCESS) &&
(!max_offset || max_offset > bo->rdev->mc.visible_vram_size))
bo->placements[i].lpfn =
bo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
else
bo->placements[i].lpfn = max_offset >> PAGE_SHIFT;
if (!bo->placement.lpfn)
bo->placement.lpfn = bo->rdev->mc.gtt_size >> PAGE_SHIFT;
if (lpfn < bo->placement.lpfn)
bo->placement.lpfn = lpfn;
bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
}
for (i = 0; i < bo->placement.num_placement; i++)
bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
if (likely(r == 0)) {
bo->pin_count = 1;
@ -335,8 +379,10 @@ int radeon_bo_unpin(struct radeon_bo *bo)
bo->pin_count--;
if (bo->pin_count)
return 0;
for (i = 0; i < bo->placement.num_placement; i++)
bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
for (i = 0; i < bo->placement.num_placement; i++) {
bo->placements[i].lpfn = 0;
bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
}
r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
if (likely(r == 0)) {
if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
@ -422,24 +468,29 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
struct ww_acquire_ctx *ticket,
struct list_head *head, int ring)
{
struct radeon_cs_reloc *lobj;
struct radeon_bo *bo;
struct radeon_bo_list *lobj;
struct list_head duplicates;
int r;
u64 bytes_moved = 0, initial_bytes_moved;
u64 bytes_moved_threshold = radeon_bo_get_threshold_for_moves(rdev);
r = ttm_eu_reserve_buffers(ticket, head);
INIT_LIST_HEAD(&duplicates);
r = ttm_eu_reserve_buffers(ticket, head, true, &duplicates);
if (unlikely(r != 0)) {
return r;
}
list_for_each_entry(lobj, head, tv.head) {
bo = lobj->robj;
struct radeon_bo *bo = lobj->robj;
if (!bo->pin_count) {
u32 domain = lobj->prefered_domains;
u32 allowed = lobj->allowed_domains;
u32 current_domain =
radeon_mem_type_to_domain(bo->tbo.mem.mem_type);
WARN_ONCE(bo->gem_base.dumb,
"GPU use of dumb buffer is illegal.\n");
/* Check if this buffer will be moved and don't move it
* if we have moved too many buffers for this IB already.
*
@ -448,7 +499,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
* into account. We don't want to disallow buffer moves
* completely.
*/
if ((lobj->allowed_domains & current_domain) != 0 &&
if ((allowed & current_domain) != 0 &&
(domain & current_domain) == 0 && /* will be moved */
bytes_moved > bytes_moved_threshold) {
/* don't move it */
@ -458,7 +509,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
retry:
radeon_ttm_placement_from_domain(bo, domain);
if (ring == R600_RING_TYPE_UVD_INDEX)
radeon_uvd_force_into_uvd_segment(bo);
radeon_uvd_force_into_uvd_segment(bo, allowed);
initial_bytes_moved = atomic64_read(&rdev->num_bytes_moved);
r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
@ -478,6 +529,12 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
lobj->gpu_offset = radeon_bo_gpu_offset(bo);
lobj->tiling_flags = bo->tiling_flags;
}
list_for_each_entry(lobj, &duplicates, tv.head) {
lobj->gpu_offset = radeon_bo_gpu_offset(lobj->robj);
lobj->tiling_flags = lobj->robj->tiling_flags;
}
return 0;
}
@ -678,12 +735,29 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait)
r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, NULL);
if (unlikely(r != 0))
return r;
spin_lock(&bo->tbo.bdev->fence_lock);
if (mem_type)
*mem_type = bo->tbo.mem.mem_type;
if (bo->tbo.sync_obj)
r = ttm_bo_wait(&bo->tbo, true, true, no_wait);
spin_unlock(&bo->tbo.bdev->fence_lock);
ttm_bo_unreserve(&bo->tbo);
return r;
}
/**
* radeon_bo_fence - add fence to buffer object
*
* @bo: buffer object in question
* @fence: fence to add
* @shared: true if fence should be added shared
*
*/
void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
bool shared)
{
struct reservation_object *resv = bo->tbo.resv;
if (shared)
reservation_object_add_shared_fence(resv, &fence->base);
else
reservation_object_add_excl_fence(resv, &fence->base);
}

View File

@ -126,6 +126,7 @@ extern int radeon_bo_create(struct radeon_device *rdev,
unsigned long size, int byte_align,
bool kernel, u32 domain, u32 flags,
struct sg_table *sg,
struct reservation_object *resv,
struct radeon_bo **bo_ptr);
extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr);
extern void radeon_bo_kunmap(struct radeon_bo *bo);
@ -154,6 +155,8 @@ extern void radeon_bo_move_notify(struct ttm_buffer_object *bo,
struct ttm_mem_reg *new_mem);
extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
extern int radeon_bo_get_surface_reg(struct radeon_bo *bo);
extern void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
bool shared);
/*
* sub allocation

View File

@ -1479,7 +1479,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
if (rdev->pm.active_crtcs & (1 << crtc)) {
vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL);
if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
!(vbl_status & DRM_SCANOUTPOS_INVBL))
!(vbl_status & DRM_SCANOUTPOS_IN_VBLANK))
in_vbl = false;
}
}

View File

@ -44,27 +44,6 @@
*/
static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring);
/**
* radeon_ring_write - write a value to the ring
*
* @ring: radeon_ring structure holding ring information
* @v: dword (dw) value to write
*
* Write a value to the requested ring buffer (all asics).
*/
void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
{
#if DRM_DEBUG_CODE
if (ring->count_dw <= 0) {
DRM_ERROR("radeon: writing more dwords to the ring than expected!\n");
}
#endif
ring->ring[ring->wptr++] = v;
ring->wptr &= ring->ptr_mask;
ring->count_dw--;
ring->ring_free_dw--;
}
/**
* radeon_ring_supports_scratch_reg - check if the ring supports
* writing to scratch registers
@ -404,7 +383,7 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
/* Allocate ring buffer */
if (ring->ring_obj == NULL) {
r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, 0,
RADEON_GEM_DOMAIN_GTT, 0, NULL,
NULL, &ring->ring_obj);
if (r) {
dev_err(rdev->dev, "(%d) ring create failed\n", r);

View File

@ -65,7 +65,7 @@ int radeon_sa_bo_manager_init(struct radeon_device *rdev,
}
r = radeon_bo_create(rdev, size, align, true,
domain, flags, NULL, &sa_manager->bo);
domain, flags, NULL, NULL, &sa_manager->bo);
if (r) {
dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r);
return r;

View File

@ -34,15 +34,14 @@
int radeon_semaphore_create(struct radeon_device *rdev,
struct radeon_semaphore **semaphore)
{
uint64_t *cpu_addr;
int i, r;
int r;
*semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);
if (*semaphore == NULL) {
return -ENOMEM;
}
r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &(*semaphore)->sa_bo,
8 * RADEON_NUM_SYNCS, 8);
r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo,
&(*semaphore)->sa_bo, 8, 8);
if (r) {
kfree(*semaphore);
*semaphore = NULL;
@ -51,12 +50,7 @@ int radeon_semaphore_create(struct radeon_device *rdev,
(*semaphore)->waiters = 0;
(*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo);
cpu_addr = radeon_sa_bo_cpu_addr((*semaphore)->sa_bo);
for (i = 0; i < RADEON_NUM_SYNCS; ++i)
cpu_addr[i] = 0;
for (i = 0; i < RADEON_NUM_RINGS; ++i)
(*semaphore)->sync_to[i] = NULL;
*((uint64_t *)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
return 0;
}
@ -95,99 +89,6 @@ bool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ridx,
return false;
}
/**
* radeon_semaphore_sync_to - use the semaphore to sync to a fence
*
* @semaphore: semaphore object to add fence to
* @fence: fence to sync to
*
* Sync to the fence using this semaphore object
*/
void radeon_semaphore_sync_to(struct radeon_semaphore *semaphore,
struct radeon_fence *fence)
{
struct radeon_fence *other;
if (!fence)
return;
other = semaphore->sync_to[fence->ring];
semaphore->sync_to[fence->ring] = radeon_fence_later(fence, other);
}
/**
* radeon_semaphore_sync_rings - sync ring to all registered fences
*
* @rdev: radeon_device pointer
* @semaphore: semaphore object to use for sync
* @ring: ring that needs sync
*
* Ensure that all registered fences are signaled before letting
* the ring continue. The caller must hold the ring lock.
*/
int radeon_semaphore_sync_rings(struct radeon_device *rdev,
struct radeon_semaphore *semaphore,
int ring)
{
unsigned count = 0;
int i, r;
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
struct radeon_fence *fence = semaphore->sync_to[i];
/* check if we really need to sync */
if (!radeon_fence_need_sync(fence, ring))
continue;
/* prevent GPU deadlocks */
if (!rdev->ring[i].ready) {
dev_err(rdev->dev, "Syncing to a disabled ring!");
return -EINVAL;
}
if (++count > RADEON_NUM_SYNCS) {
/* not enough room, wait manually */
r = radeon_fence_wait(fence, false);
if (r)
return r;
continue;
}
/* allocate enough space for sync command */
r = radeon_ring_alloc(rdev, &rdev->ring[i], 16);
if (r) {
return r;
}
/* emit the signal semaphore */
if (!radeon_semaphore_emit_signal(rdev, i, semaphore)) {
/* signaling wasn't successful wait manually */
radeon_ring_undo(&rdev->ring[i]);
r = radeon_fence_wait(fence, false);
if (r)
return r;
continue;
}
/* we assume caller has already allocated space on waiters ring */
if (!radeon_semaphore_emit_wait(rdev, ring, semaphore)) {
/* waiting wasn't successful wait manually */
radeon_ring_undo(&rdev->ring[i]);
r = radeon_fence_wait(fence, false);
if (r)
return r;
continue;
}
radeon_ring_commit(rdev, &rdev->ring[i], false);
radeon_fence_note_sync(fence, ring);
semaphore->gpu_addr += 8;
}
return 0;
}
void radeon_semaphore_free(struct radeon_device *rdev,
struct radeon_semaphore **semaphore,
struct radeon_fence *fence)

View File

@ -0,0 +1,220 @@
/*
* Copyright 2014 Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*/
/*
* Authors:
* Christian König <christian.koenig@amd.com>
*/
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_trace.h"
/**
* radeon_sync_create - zero init sync object
*
* @sync: sync object to initialize
*
* Just clear the sync object for now.
*/
void radeon_sync_create(struct radeon_sync *sync)
{
unsigned i;
for (i = 0; i < RADEON_NUM_SYNCS; ++i)
sync->semaphores[i] = NULL;
for (i = 0; i < RADEON_NUM_RINGS; ++i)
sync->sync_to[i] = NULL;
sync->last_vm_update = NULL;
}
/**
* radeon_sync_fence - use the semaphore to sync to a fence
*
* @sync: sync object to add fence to
* @fence: fence to sync to
*
* Sync to the fence using the semaphore objects
*/
void radeon_sync_fence(struct radeon_sync *sync,
struct radeon_fence *fence)
{
struct radeon_fence *other;
if (!fence)
return;
other = sync->sync_to[fence->ring];
sync->sync_to[fence->ring] = radeon_fence_later(fence, other);
if (fence->is_vm_update) {
other = sync->last_vm_update;
sync->last_vm_update = radeon_fence_later(fence, other);
}
}
/**
* radeon_sync_resv - use the semaphores to sync to a reservation object
*
* @sync: sync object to add fences from reservation object to
* @resv: reservation object with embedded fence
* @shared: true if we should only sync to the exclusive fence
*
* Sync to the fence using the semaphore objects
*/
int radeon_sync_resv(struct radeon_device *rdev,
struct radeon_sync *sync,
struct reservation_object *resv,
bool shared)
{
struct reservation_object_list *flist;
struct fence *f;
struct radeon_fence *fence;
unsigned i;
int r = 0;
/* always sync to the exclusive fence */
f = reservation_object_get_excl(resv);
fence = f ? to_radeon_fence(f) : NULL;
if (fence && fence->rdev == rdev)
radeon_sync_fence(sync, fence);
else if (f)
r = fence_wait(f, true);
flist = reservation_object_get_list(resv);
if (shared || !flist || r)
return r;
for (i = 0; i < flist->shared_count; ++i) {
f = rcu_dereference_protected(flist->shared[i],
reservation_object_held(resv));
fence = to_radeon_fence(f);
if (fence && fence->rdev == rdev)
radeon_sync_fence(sync, fence);
else
r = fence_wait(f, true);
if (r)
break;
}
return r;
}
/**
* radeon_sync_rings - sync ring to all registered fences
*
* @rdev: radeon_device pointer
* @sync: sync object to use
* @ring: ring that needs sync
*
* Ensure that all registered fences are signaled before letting
* the ring continue. The caller must hold the ring lock.
*/
int radeon_sync_rings(struct radeon_device *rdev,
struct radeon_sync *sync,
int ring)
{
unsigned count = 0;
int i, r;
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
struct radeon_fence *fence = sync->sync_to[i];
struct radeon_semaphore *semaphore;
/* check if we really need to sync */
if (!radeon_fence_need_sync(fence, ring))
continue;
/* prevent GPU deadlocks */
if (!rdev->ring[i].ready) {
dev_err(rdev->dev, "Syncing to a disabled ring!");
return -EINVAL;
}
if (count >= RADEON_NUM_SYNCS) {
/* not enough room, wait manually */
r = radeon_fence_wait(fence, false);
if (r)
return r;
continue;
}
r = radeon_semaphore_create(rdev, &semaphore);
if (r)
return r;
sync->semaphores[count++] = semaphore;
/* allocate enough space for sync command */
r = radeon_ring_alloc(rdev, &rdev->ring[i], 16);
if (r)
return r;
/* emit the signal semaphore */
if (!radeon_semaphore_emit_signal(rdev, i, semaphore)) {
/* signaling wasn't successful wait manually */
radeon_ring_undo(&rdev->ring[i]);
r = radeon_fence_wait(fence, false);
if (r)
return r;
continue;
}
/* we assume caller has already allocated space on waiters ring */
if (!radeon_semaphore_emit_wait(rdev, ring, semaphore)) {
/* waiting wasn't successful wait manually */
radeon_ring_undo(&rdev->ring[i]);
r = radeon_fence_wait(fence, false);
if (r)
return r;
continue;
}
radeon_ring_commit(rdev, &rdev->ring[i], false);
radeon_fence_note_sync(fence, ring);
}
return 0;
}
/**
* radeon_sync_free - free the sync object
*
* @rdev: radeon_device pointer
* @sync: sync object to use
* @fence: fence to use for the free
*
* Free the sync object by freeing all semaphores in it.
*/
void radeon_sync_free(struct radeon_device *rdev,
struct radeon_sync *sync,
struct radeon_fence *fence)
{
unsigned i;
for (i = 0; i < RADEON_NUM_SYNCS; ++i)
radeon_semaphore_free(rdev, &sync->semaphores[i], fence);
}

View File

@ -67,7 +67,7 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
}
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
0, NULL, &vram_obj);
0, NULL, NULL, &vram_obj);
if (r) {
DRM_ERROR("Failed to create VRAM object\n");
goto out_cleanup;
@ -87,7 +87,8 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
struct radeon_fence *fence = NULL;
r = radeon_bo_create(rdev, size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, 0, NULL, gtt_obj + i);
RADEON_GEM_DOMAIN_GTT, 0, NULL, NULL,
gtt_obj + i);
if (r) {
DRM_ERROR("Failed to create GTT object %d\n", i);
goto out_lclean;
@ -116,11 +117,16 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
radeon_bo_kunmap(gtt_obj[i]);
if (ring == R600_RING_TYPE_DMA_INDEX)
r = radeon_copy_dma(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, &fence);
fence = radeon_copy_dma(rdev, gtt_addr, vram_addr,
size / RADEON_GPU_PAGE_SIZE,
NULL);
else
r = radeon_copy_blit(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, &fence);
if (r) {
fence = radeon_copy_blit(rdev, gtt_addr, vram_addr,
size / RADEON_GPU_PAGE_SIZE,
NULL);
if (IS_ERR(fence)) {
DRM_ERROR("Failed GTT->VRAM copy %d\n", i);
r = PTR_ERR(fence);
goto out_lclean_unpin;
}
@ -162,11 +168,16 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
radeon_bo_kunmap(vram_obj);
if (ring == R600_RING_TYPE_DMA_INDEX)
r = radeon_copy_dma(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, &fence);
fence = radeon_copy_dma(rdev, vram_addr, gtt_addr,
size / RADEON_GPU_PAGE_SIZE,
NULL);
else
r = radeon_copy_blit(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, &fence);
if (r) {
fence = radeon_copy_blit(rdev, vram_addr, gtt_addr,
size / RADEON_GPU_PAGE_SIZE,
NULL);
if (IS_ERR(fence)) {
DRM_ERROR("Failed VRAM->GTT copy %d\n", i);
r = PTR_ERR(fence);
goto out_lclean_unpin;
}
@ -222,7 +233,7 @@ out_lclean:
radeon_bo_unreserve(gtt_obj[i]);
radeon_bo_unref(&gtt_obj[i]);
}
if (fence)
if (fence && !IS_ERR(fence))
radeon_fence_unref(&fence);
break;
}

View File

@ -166,12 +166,15 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
static void radeon_evict_flags(struct ttm_buffer_object *bo,
struct ttm_placement *placement)
{
static struct ttm_place placements = {
.fpfn = 0,
.lpfn = 0,
.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM
};
struct radeon_bo *rbo;
static u32 placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
if (!radeon_ttm_bo_is_radeon_bo(bo)) {
placement->fpfn = 0;
placement->lpfn = 0;
placement->placement = &placements;
placement->busy_placement = &placements;
placement->num_placement = 1;
@ -181,9 +184,32 @@ static void radeon_evict_flags(struct ttm_buffer_object *bo,
rbo = container_of(bo, struct radeon_bo, tbo);
switch (bo->mem.mem_type) {
case TTM_PL_VRAM:
if (rbo->rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready == false)
if (rbo->rdev->ring[radeon_copy_ring_index(rbo->rdev)].ready == false)
radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_CPU);
else
else if (rbo->rdev->mc.visible_vram_size < rbo->rdev->mc.real_vram_size &&
bo->mem.start < (rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT)) {
unsigned fpfn = rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
int i;
/* Try evicting to the CPU inaccessible part of VRAM
* first, but only set GTT as busy placement, so this
* BO will be evicted to GTT rather than causing other
* BOs to be evicted from VRAM
*/
radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM |
RADEON_GEM_DOMAIN_GTT);
rbo->placement.num_busy_placement = 0;
for (i = 0; i < rbo->placement.num_placement; i++) {
if (rbo->placements[i].flags & TTM_PL_FLAG_VRAM) {
if (rbo->placements[0].fpfn < fpfn)
rbo->placements[0].fpfn = fpfn;
} else {
rbo->placement.busy_placement =
&rbo->placements[i];
rbo->placement.num_busy_placement = 1;
}
}
} else
radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT);
break;
case TTM_PL_TT:
@ -216,6 +242,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
struct radeon_device *rdev;
uint64_t old_start, new_start;
struct radeon_fence *fence;
unsigned num_pages;
int r, ridx;
rdev = radeon_get_rdev(bo->bdev);
@ -252,13 +279,12 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0);
/* sync other rings */
fence = bo->sync_obj;
r = radeon_copy(rdev, old_start, new_start,
new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE), /* GPU pages */
&fence);
/* FIXME: handle copy error */
r = ttm_bo_move_accel_cleanup(bo, (void *)fence,
num_pages = new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
fence = radeon_copy(rdev, old_start, new_start, num_pages, bo->resv);
if (IS_ERR(fence))
return PTR_ERR(fence);
r = ttm_bo_move_accel_cleanup(bo, &fence->base,
evict, no_wait_gpu, new_mem);
radeon_fence_unref(&fence);
return r;
@ -272,20 +298,20 @@ static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
struct radeon_device *rdev;
struct ttm_mem_reg *old_mem = &bo->mem;
struct ttm_mem_reg tmp_mem;
u32 placements;
struct ttm_place placements;
struct ttm_placement placement;
int r;
rdev = radeon_get_rdev(bo->bdev);
tmp_mem = *new_mem;
tmp_mem.mm_node = NULL;
placement.fpfn = 0;
placement.lpfn = 0;
placement.num_placement = 1;
placement.placement = &placements;
placement.num_busy_placement = 1;
placement.busy_placement = &placements;
placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
placements.fpfn = 0;
placements.lpfn = 0;
placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
r = ttm_bo_mem_space(bo, &placement, &tmp_mem,
interruptible, no_wait_gpu);
if (unlikely(r)) {
@ -320,19 +346,19 @@ static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem = &bo->mem;
struct ttm_mem_reg tmp_mem;
struct ttm_placement placement;
u32 placements;
struct ttm_place placements;
int r;
rdev = radeon_get_rdev(bo->bdev);
tmp_mem = *new_mem;
tmp_mem.mm_node = NULL;
placement.fpfn = 0;
placement.lpfn = 0;
placement.num_placement = 1;
placement.placement = &placements;
placement.num_busy_placement = 1;
placement.busy_placement = &placements;
placements = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
placements.fpfn = 0;
placements.lpfn = 0;
placements.flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_TT;
r = ttm_bo_mem_space(bo, &placement, &tmp_mem,
interruptible, no_wait_gpu);
if (unlikely(r)) {
@ -471,31 +497,6 @@ static void radeon_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_re
{
}
static int radeon_sync_obj_wait(void *sync_obj, bool lazy, bool interruptible)
{
return radeon_fence_wait((struct radeon_fence *)sync_obj, interruptible);
}
static int radeon_sync_obj_flush(void *sync_obj)
{
return 0;
}
static void radeon_sync_obj_unref(void **sync_obj)
{
radeon_fence_unref((struct radeon_fence **)sync_obj);
}
static void *radeon_sync_obj_ref(void *sync_obj)
{
return radeon_fence_ref((struct radeon_fence *)sync_obj);
}
static bool radeon_sync_obj_signaled(void *sync_obj)
{
return radeon_fence_signaled((struct radeon_fence *)sync_obj);
}
/*
* TTM backend functions.
*/
@ -503,6 +504,10 @@ struct radeon_ttm_tt {
struct ttm_dma_tt ttm;
struct radeon_device *rdev;
u64 offset;
uint64_t userptr;
struct mm_struct *usermm;
uint32_t userflags;
};
static int radeon_ttm_backend_bind(struct ttm_tt *ttm,
@ -580,10 +585,17 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev,
return &gtt->ttm.ttm;
}
static struct radeon_ttm_tt *radeon_ttm_tt_to_gtt(struct ttm_tt *ttm)
{
if (!ttm || ttm->func != &radeon_backend_func)
return NULL;
return (struct radeon_ttm_tt *)ttm;
}
static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
{
struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
struct radeon_device *rdev;
struct radeon_ttm_tt *gtt = (void *)ttm;
unsigned i;
int r;
bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
@ -628,7 +640,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
{
struct radeon_device *rdev;
struct radeon_ttm_tt *gtt = (void *)ttm;
struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(ttm);
unsigned i;
bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
@ -663,11 +675,6 @@ static struct ttm_bo_driver radeon_bo_driver = {
.evict_flags = &radeon_evict_flags,
.move = &radeon_bo_move,
.verify_access = &radeon_verify_access,
.sync_obj_signaled = &radeon_sync_obj_signaled,
.sync_obj_wait = &radeon_sync_obj_wait,
.sync_obj_flush = &radeon_sync_obj_flush,
.sync_obj_unref = &radeon_sync_obj_unref,
.sync_obj_ref = &radeon_sync_obj_ref,
.move_notify = &radeon_bo_move_notify,
// .fault_reserve_notify = &radeon_bo_fault_reserve_notify,
.io_mem_reserve = &radeon_ttm_io_mem_reserve,
@ -703,8 +710,8 @@ int radeon_ttm_init(struct radeon_device *rdev)
/* Change the size here instead of the init above so only lpfn is affected */
radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
r = radeon_bo_create(rdev, 16*1024*1024, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0,
r = radeon_bo_create(rdev, 16 * 1024 * 1024, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL,
NULL, &rdev->stollen_vga_memory);
if (r) {
return r;

View File

@ -46,6 +46,9 @@
#define FIRMWARE_TAHITI "radeon/TAHITI_uvd.bin"
#define FIRMWARE_BONAIRE "radeon/BONAIRE_uvd.bin"
MODULE_FIRMWARE(FIRMWARE_R600);
MODULE_FIRMWARE(FIRMWARE_RS780);
MODULE_FIRMWARE(FIRMWARE_RV770);
MODULE_FIRMWARE(FIRMWARE_RV710);
MODULE_FIRMWARE(FIRMWARE_CYPRESS);
MODULE_FIRMWARE(FIRMWARE_SUMO);
@ -115,9 +118,11 @@ int radeon_uvd_init(struct radeon_device *rdev)
}
bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) +
RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE;
RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE +
RADEON_GPU_PAGE_SIZE;
r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL, &rdev->uvd.vcpu_bo);
RADEON_GEM_DOMAIN_VRAM, 0, NULL,
NULL, &rdev->uvd.vcpu_bo);
if (r) {
dev_err(rdev->dev, "(%d) failed to allocate UVD bo\n", r);
return r;
@ -231,10 +236,30 @@ int radeon_uvd_resume(struct radeon_device *rdev)
return 0;
}
void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo)
void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo,
uint32_t allowed_domains)
{
rbo->placement.fpfn = 0 >> PAGE_SHIFT;
rbo->placement.lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
int i;
for (i = 0; i < rbo->placement.num_placement; ++i) {
rbo->placements[i].fpfn = 0 >> PAGE_SHIFT;
rbo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
}
/* If it must be in VRAM it must be in the first segment as well */
if (allowed_domains == RADEON_GEM_DOMAIN_VRAM)
return;
/* abort if we already have more than one placement */
if (rbo->placement.num_placement > 1)
return;
/* add another 256MB segment */
rbo->placements[1] = rbo->placements[0];
rbo->placements[1].fpfn += (256 * 1024 * 1024) >> PAGE_SHIFT;
rbo->placements[1].lpfn += (256 * 1024 * 1024) >> PAGE_SHIFT;
rbo->placement.num_placement++;
rbo->placement.num_busy_placement++;
}
void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp)
@ -356,6 +381,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
{
int32_t *msg, msg_type, handle;
unsigned img_size = 0;
struct fence *f;
void *ptr;
int i, r;
@ -365,8 +391,9 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
return -EINVAL;
}
if (bo->tbo.sync_obj) {
r = radeon_fence_wait(bo->tbo.sync_obj, false);
f = reservation_object_get_excl(bo->tbo.resv);
if (f) {
r = radeon_fence_wait((struct radeon_fence *)f, false);
if (r) {
DRM_ERROR("Failed waiting for UVD message (%d)!\n", r);
return r;
@ -441,12 +468,12 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
unsigned buf_sizes[], bool *has_msg_cmd)
{
struct radeon_cs_chunk *relocs_chunk;
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
unsigned idx, cmd, offset;
uint64_t start, end;
int r;
relocs_chunk = &p->chunks[p->chunk_relocs_idx];
relocs_chunk = p->chunk_relocs;
offset = radeon_get_ib_value(p, data0);
idx = radeon_get_ib_value(p, data1);
if (idx >= relocs_chunk->length_dw) {
@ -455,7 +482,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
return -EINVAL;
}
reloc = p->relocs_ptr[(idx / 4)];
reloc = &p->relocs[(idx / 4)];
start = reloc->gpu_offset;
end = start + radeon_bo_size(reloc->robj);
start += offset;
@ -563,13 +590,13 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
[0x00000003] = 2048,
};
if (p->chunks[p->chunk_ib_idx].length_dw % 16) {
if (p->chunk_ib->length_dw % 16) {
DRM_ERROR("UVD IB length (%d) not 16 dwords aligned!\n",
p->chunks[p->chunk_ib_idx].length_dw);
p->chunk_ib->length_dw);
return -EINVAL;
}
if (p->chunk_relocs_idx == -1) {
if (p->chunk_relocs == NULL) {
DRM_ERROR("No relocation chunk !\n");
return -EINVAL;
}
@ -593,7 +620,7 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
DRM_ERROR("Unknown packet type %d !\n", pkt.type);
return -EINVAL;
}
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
} while (p->idx < p->chunk_ib->length_dw);
if (!has_msg_cmd) {
DRM_ERROR("UVD-IBs need a msg command!\n");
@ -604,38 +631,16 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
}
static int radeon_uvd_send_msg(struct radeon_device *rdev,
int ring, struct radeon_bo *bo,
int ring, uint64_t addr,
struct radeon_fence **fence)
{
struct ttm_validate_buffer tv;
struct ww_acquire_ctx ticket;
struct list_head head;
struct radeon_ib ib;
uint64_t addr;
int i, r;
memset(&tv, 0, sizeof(tv));
tv.bo = &bo->tbo;
INIT_LIST_HEAD(&head);
list_add(&tv.head, &head);
r = ttm_eu_reserve_buffers(&ticket, &head);
if (r)
return r;
radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_VRAM);
radeon_uvd_force_into_uvd_segment(bo);
r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
if (r)
goto err;
r = radeon_ib_get(rdev, ring, &ib, NULL, 64);
if (r)
goto err;
return r;
addr = radeon_bo_gpu_offset(bo);
ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0);
ib.ptr[1] = addr;
ib.ptr[2] = PACKET0(UVD_GPCOM_VCPU_DATA1, 0);
@ -647,19 +652,11 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
ib.length_dw = 16;
r = radeon_ib_schedule(rdev, &ib, NULL, false);
if (r)
goto err;
ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence);
if (fence)
*fence = radeon_fence_ref(ib.fence);
radeon_ib_free(rdev, &ib);
radeon_bo_unref(&bo);
return 0;
err:
ttm_eu_backoff_reservation(&ticket, &head);
return r;
}
@ -669,28 +666,19 @@ err:
int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
uint32_t handle, struct radeon_fence **fence)
{
struct radeon_bo *bo;
uint32_t *msg;
/* we use the last page of the vcpu bo for the UVD message */
uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) -
RADEON_GPU_PAGE_SIZE;
uint32_t *msg = rdev->uvd.cpu_addr + offs;
uint64_t addr = rdev->uvd.gpu_addr + offs;
int r, i;
r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL, &bo);
r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true);
if (r)
return r;
r = radeon_bo_reserve(bo, false);
if (r) {
radeon_bo_unref(&bo);
return r;
}
r = radeon_bo_kmap(bo, (void **)&msg);
if (r) {
radeon_bo_unreserve(bo);
radeon_bo_unref(&bo);
return r;
}
/* stitch together an UVD create msg */
msg[0] = cpu_to_le32(0x00000de4);
msg[1] = cpu_to_le32(0x00000000);
@ -706,37 +694,27 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
for (i = 11; i < 1024; ++i)
msg[i] = cpu_to_le32(0x0);
radeon_bo_kunmap(bo);
radeon_bo_unreserve(bo);
return radeon_uvd_send_msg(rdev, ring, bo, fence);
r = radeon_uvd_send_msg(rdev, ring, addr, fence);
radeon_bo_unreserve(rdev->uvd.vcpu_bo);
return r;
}
int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
uint32_t handle, struct radeon_fence **fence)
{
struct radeon_bo *bo;
uint32_t *msg;
/* we use the last page of the vcpu bo for the UVD message */
uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) -
RADEON_GPU_PAGE_SIZE;
uint32_t *msg = rdev->uvd.cpu_addr + offs;
uint64_t addr = rdev->uvd.gpu_addr + offs;
int r, i;
r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL, &bo);
r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true);
if (r)
return r;
r = radeon_bo_reserve(bo, false);
if (r) {
radeon_bo_unref(&bo);
return r;
}
r = radeon_bo_kmap(bo, (void **)&msg);
if (r) {
radeon_bo_unreserve(bo);
radeon_bo_unref(&bo);
return r;
}
/* stitch together an UVD destroy msg */
msg[0] = cpu_to_le32(0x00000de4);
msg[1] = cpu_to_le32(0x00000002);
@ -745,10 +723,9 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
for (i = 4; i < 1024; ++i)
msg[i] = cpu_to_le32(0x0);
radeon_bo_kunmap(bo);
radeon_bo_unreserve(bo);
return radeon_uvd_send_msg(rdev, ring, bo, fence);
r = radeon_uvd_send_msg(rdev, ring, addr, fence);
radeon_bo_unreserve(rdev->uvd.vcpu_bo);
return r;
}
/**

View File

@ -126,7 +126,8 @@ int radeon_vce_init(struct radeon_device *rdev)
size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size) +
RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE;
r = radeon_bo_create(rdev, size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL, &rdev->vce.vcpu_bo);
RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL,
&rdev->vce.vcpu_bo);
if (r) {
dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r);
return r;
@ -452,11 +453,11 @@ int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi,
unsigned size)
{
struct radeon_cs_chunk *relocs_chunk;
struct radeon_cs_reloc *reloc;
struct radeon_bo_list *reloc;
uint64_t start, end, offset;
unsigned idx;
relocs_chunk = &p->chunks[p->chunk_relocs_idx];
relocs_chunk = p->chunk_relocs;
offset = radeon_get_ib_value(p, lo);
idx = radeon_get_ib_value(p, hi);
@ -466,7 +467,7 @@ int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi,
return -EINVAL;
}
reloc = p->relocs_ptr[(idx / 4)];
reloc = &p->relocs[(idx / 4)];
start = reloc->gpu_offset;
end = start + radeon_bo_size(reloc->robj);
start += offset;
@ -533,7 +534,7 @@ int radeon_vce_cs_parse(struct radeon_cs_parser *p)
uint32_t *size = &tmp;
int i, r;
while (p->idx < p->chunks[p->chunk_ib_idx].length_dw) {
while (p->idx < p->chunk_ib->length_dw) {
uint32_t len = radeon_get_ib_value(p, p->idx);
uint32_t cmd = radeon_get_ib_value(p, p->idx + 1);

View File

@ -125,39 +125,37 @@ void radeon_vm_manager_fini(struct radeon_device *rdev)
* Add the page directory to the list of BOs to
* validate for command submission (cayman+).
*/
struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev,
struct radeon_bo_list *radeon_vm_get_bos(struct radeon_device *rdev,
struct radeon_vm *vm,
struct list_head *head)
{
struct radeon_cs_reloc *list;
struct radeon_bo_list *list;
unsigned i, idx;
list = kmalloc_array(vm->max_pde_used + 2,
sizeof(struct radeon_cs_reloc), GFP_KERNEL);
sizeof(struct radeon_bo_list), GFP_KERNEL);
if (!list)
return NULL;
/* add the vm page table to the list */
list[0].gobj = NULL;
list[0].robj = vm->page_directory;
list[0].prefered_domains = RADEON_GEM_DOMAIN_VRAM;
list[0].allowed_domains = RADEON_GEM_DOMAIN_VRAM;
list[0].tv.bo = &vm->page_directory->tbo;
list[0].tv.shared = true;
list[0].tiling_flags = 0;
list[0].handle = 0;
list_add(&list[0].tv.head, head);
for (i = 0, idx = 1; i <= vm->max_pde_used; i++) {
if (!vm->page_tables[i].bo)
continue;
list[idx].gobj = NULL;
list[idx].robj = vm->page_tables[i].bo;
list[idx].prefered_domains = RADEON_GEM_DOMAIN_VRAM;
list[idx].allowed_domains = RADEON_GEM_DOMAIN_VRAM;
list[idx].tv.bo = &list[idx].robj->tbo;
list[idx].tv.shared = true;
list[idx].tiling_flags = 0;
list[idx].handle = 0;
list_add(&list[idx++].tv.head, head);
}
@ -180,15 +178,18 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
struct radeon_vm *vm, int ring)
{
struct radeon_fence *best[RADEON_NUM_RINGS] = {};
struct radeon_vm_id *vm_id = &vm->ids[ring];
unsigned choices[2] = {};
unsigned i;
/* check if the id is still valid */
if (vm->last_id_use && vm->last_id_use == rdev->vm_manager.active[vm->id])
if (vm_id->id && vm_id->last_id_use &&
vm_id->last_id_use == rdev->vm_manager.active[vm_id->id])
return NULL;
/* we definately need to flush */
radeon_fence_unref(&vm->last_flush);
vm_id->pd_gpu_addr = ~0ll;
/* skip over VMID 0, since it is the system VM */
for (i = 1; i < rdev->vm_manager.nvm; ++i) {
@ -196,8 +197,8 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
if (fence == NULL) {
/* found a free one */
vm->id = i;
trace_radeon_vm_grab_id(vm->id, ring);
vm_id->id = i;
trace_radeon_vm_grab_id(i, ring);
return NULL;
}
@ -209,8 +210,8 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
for (i = 0; i < 2; ++i) {
if (choices[i]) {
vm->id = choices[i];
trace_radeon_vm_grab_id(vm->id, ring);
vm_id->id = choices[i];
trace_radeon_vm_grab_id(choices[i], ring);
return rdev->vm_manager.active[choices[i]];
}
}
@ -226,6 +227,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
* @rdev: radeon_device pointer
* @vm: vm we want to flush
* @ring: ring to use for flush
* @updates: last vm update that is waited for
*
* Flush the vm (cayman+).
*
@ -233,15 +235,21 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
*/
void radeon_vm_flush(struct radeon_device *rdev,
struct radeon_vm *vm,
int ring)
int ring, struct radeon_fence *updates)
{
uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory);
struct radeon_vm_id *vm_id = &vm->ids[ring];
if (pd_addr != vm_id->pd_gpu_addr || !vm_id->flushed_updates ||
radeon_fence_is_earlier(vm_id->flushed_updates, updates)) {
trace_radeon_vm_flush(pd_addr, ring, vm->ids[ring].id);
radeon_fence_unref(&vm_id->flushed_updates);
vm_id->flushed_updates = radeon_fence_ref(updates);
vm_id->pd_gpu_addr = pd_addr;
radeon_ring_vm_flush(rdev, &rdev->ring[ring],
vm_id->id, vm_id->pd_gpu_addr);
/* if we can't remember our last VM flush then flush now! */
if (!vm->last_flush || pd_addr != vm->pd_gpu_addr) {
trace_radeon_vm_flush(pd_addr, ring, vm->id);
vm->pd_gpu_addr = pd_addr;
radeon_ring_vm_flush(rdev, ring, vm);
}
}
@ -261,18 +269,13 @@ void radeon_vm_fence(struct radeon_device *rdev,
struct radeon_vm *vm,
struct radeon_fence *fence)
{
radeon_fence_unref(&vm->fence);
vm->fence = radeon_fence_ref(fence);
unsigned vm_id = vm->ids[fence->ring].id;
radeon_fence_unref(&rdev->vm_manager.active[vm->id]);
rdev->vm_manager.active[vm->id] = radeon_fence_ref(fence);
radeon_fence_unref(&rdev->vm_manager.active[vm_id]);
rdev->vm_manager.active[vm_id] = radeon_fence_ref(fence);
radeon_fence_unref(&vm->last_id_use);
vm->last_id_use = radeon_fence_ref(fence);
/* we just flushed the VM, remember that */
if (!vm->last_flush)
vm->last_flush = radeon_fence_ref(fence);
radeon_fence_unref(&vm->ids[fence->ring].last_id_use);
vm->ids[fence->ring].last_id_use = radeon_fence_ref(fence);
}
/**
@ -385,34 +388,25 @@ static void radeon_vm_set_pages(struct radeon_device *rdev,
static int radeon_vm_clear_bo(struct radeon_device *rdev,
struct radeon_bo *bo)
{
struct ttm_validate_buffer tv;
struct ww_acquire_ctx ticket;
struct list_head head;
struct radeon_ib ib;
unsigned entries;
uint64_t addr;
int r;
memset(&tv, 0, sizeof(tv));
tv.bo = &bo->tbo;
INIT_LIST_HEAD(&head);
list_add(&tv.head, &head);
r = ttm_eu_reserve_buffers(&ticket, &head);
r = radeon_bo_reserve(bo, false);
if (r)
return r;
r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
if (r)
goto error;
goto error_unreserve;
addr = radeon_bo_gpu_offset(bo);
entries = radeon_bo_size(bo) / 8;
r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, 256);
if (r)
goto error;
goto error_unreserve;
ib.length_dw = 0;
@ -422,15 +416,16 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev,
r = radeon_ib_schedule(rdev, &ib, NULL, false);
if (r)
goto error;
goto error_free;
ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence);
ib.fence->is_vm_update = true;
radeon_bo_fence(bo, ib.fence, false);
error_free:
radeon_ib_free(rdev, &ib);
return 0;
error:
ttm_eu_backoff_reservation(&ticket, &head);
error_unreserve:
radeon_bo_unreserve(bo);
return r;
}
@ -446,7 +441,7 @@ error:
* Validate and set the offset requested within the vm address space.
* Returns 0 for success, error for failure.
*
* Object has to be reserved!
* Object has to be reserved and gets unreserved by this function!
*/
int radeon_vm_bo_set_addr(struct radeon_device *rdev,
struct radeon_bo_va *bo_va,
@ -492,7 +487,9 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
tmp->vm = vm;
tmp->addr = bo_va->addr;
tmp->bo = radeon_bo_ref(bo_va->bo);
spin_lock(&vm->status_lock);
list_add(&tmp->vm_status, &vm->freed);
spin_unlock(&vm->status_lock);
}
interval_tree_remove(&bo_va->it, &vm->va);
@ -545,7 +542,8 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
r = radeon_bo_create(rdev, RADEON_VM_PTE_COUNT * 8,
RADEON_GPU_PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL, &pt);
RADEON_GEM_DOMAIN_VRAM, 0,
NULL, NULL, &pt);
if (r)
return r;
@ -571,7 +569,7 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
}
mutex_unlock(&vm->mutex);
return radeon_bo_reserve(bo_va->bo, false);
return 0;
}
/**
@ -694,17 +692,16 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev,
if (ib.length_dw != 0) {
radeon_asic_vm_pad_ib(rdev, &ib);
radeon_semaphore_sync_to(ib.semaphore, pd->tbo.sync_obj);
radeon_semaphore_sync_to(ib.semaphore, vm->last_id_use);
radeon_sync_resv(rdev, &ib.sync, pd->tbo.resv, true);
WARN_ON(ib.length_dw > ndw);
r = radeon_ib_schedule(rdev, &ib, NULL, false);
if (r) {
radeon_ib_free(rdev, &ib);
return r;
}
radeon_fence_unref(&vm->fence);
vm->fence = radeon_fence_ref(ib.fence);
radeon_fence_unref(&vm->last_flush);
ib.fence->is_vm_update = true;
radeon_bo_fence(pd, ib.fence, false);
}
radeon_ib_free(rdev, &ib);
@ -803,7 +800,7 @@ static void radeon_vm_frag_ptes(struct radeon_device *rdev,
*
* Global and local mutex must be locked!
*/
static void radeon_vm_update_ptes(struct radeon_device *rdev,
static int radeon_vm_update_ptes(struct radeon_device *rdev,
struct radeon_vm *vm,
struct radeon_ib *ib,
uint64_t start, uint64_t end,
@ -820,8 +817,12 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev,
struct radeon_bo *pt = vm->page_tables[pt_idx].bo;
unsigned nptes;
uint64_t pte;
int r;
radeon_semaphore_sync_to(ib->semaphore, pt->tbo.sync_obj);
radeon_sync_resv(rdev, &ib->sync, pt->tbo.resv, true);
r = reservation_object_reserve_shared(pt->tbo.resv);
if (r)
return r;
if ((addr & ~mask) == (end & ~mask))
nptes = end - addr;
@ -855,6 +856,33 @@ static void radeon_vm_update_ptes(struct radeon_device *rdev,
last_pte + 8 * count,
last_dst, flags);
}
return 0;
}
/**
* radeon_vm_fence_pts - fence page tables after an update
*
* @vm: requested vm
* @start: start of GPU address range
* @end: end of GPU address range
* @fence: fence to use
*
* Fence the page tables in the range @start - @end (cayman+).
*
* Global and local mutex must be locked!
*/
static void radeon_vm_fence_pts(struct radeon_vm *vm,
uint64_t start, uint64_t end,
struct radeon_fence *fence)
{
unsigned i;
start >>= radeon_vm_block_size;
end >>= radeon_vm_block_size;
for (i = start; i <= end; ++i)
radeon_bo_fence(vm->page_tables[i].bo, fence, true);
}
/**
@ -887,11 +915,16 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
return -EINVAL;
}
spin_lock(&vm->status_lock);
list_del_init(&bo_va->vm_status);
spin_unlock(&vm->status_lock);
bo_va->flags &= ~RADEON_VM_PAGE_VALID;
bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM;
bo_va->flags &= ~RADEON_VM_PAGE_SNOOPED;
// if (bo_va->bo && radeon_ttm_tt_is_readonly(bo_va->bo->tbo.ttm))
// bo_va->flags &= ~RADEON_VM_PAGE_WRITEABLE;
if (mem) {
addr = mem->start << PAGE_SHIFT;
if (mem->mem_type != TTM_PL_SYSTEM) {
@ -953,23 +986,34 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
return r;
ib.length_dw = 0;
radeon_vm_update_ptes(rdev, vm, &ib, bo_va->it.start,
if (!(bo_va->flags & RADEON_VM_PAGE_VALID)) {
unsigned i;
for (i = 0; i < RADEON_NUM_RINGS; ++i)
radeon_sync_fence(&ib.sync, vm->ids[i].last_id_use);
}
r = radeon_vm_update_ptes(rdev, vm, &ib, bo_va->it.start,
bo_va->it.last + 1, addr,
radeon_vm_page_flags(bo_va->flags));
if (r) {
radeon_ib_free(rdev, &ib);
return r;
}
radeon_asic_vm_pad_ib(rdev, &ib);
WARN_ON(ib.length_dw > ndw);
radeon_semaphore_sync_to(ib.semaphore, vm->fence);
r = radeon_ib_schedule(rdev, &ib, NULL, false);
if (r) {
radeon_ib_free(rdev, &ib);
return r;
}
radeon_fence_unref(&vm->fence);
vm->fence = radeon_fence_ref(ib.fence);
ib.fence->is_vm_update = true;
radeon_vm_fence_pts(vm, bo_va->it.start, bo_va->it.last + 1, ib.fence);
radeon_fence_unref(&bo_va->last_pt_update);
bo_va->last_pt_update = radeon_fence_ref(ib.fence);
radeon_ib_free(rdev, &ib);
radeon_fence_unref(&vm->last_flush);
return 0;
}
@ -988,16 +1032,25 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
int radeon_vm_clear_freed(struct radeon_device *rdev,
struct radeon_vm *vm)
{
struct radeon_bo_va *bo_va, *tmp;
struct radeon_bo_va *bo_va;
int r;
list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) {
spin_lock(&vm->status_lock);
while (!list_empty(&vm->freed)) {
bo_va = list_first_entry(&vm->freed,
struct radeon_bo_va, vm_status);
spin_unlock(&vm->status_lock);
r = radeon_vm_bo_update(rdev, bo_va, NULL);
radeon_bo_unref(&bo_va->bo);
radeon_fence_unref(&bo_va->last_pt_update);
kfree(bo_va);
if (r)
return r;
spin_lock(&vm->status_lock);
}
spin_unlock(&vm->status_lock);
return 0;
}
@ -1016,14 +1069,23 @@ int radeon_vm_clear_freed(struct radeon_device *rdev,
int radeon_vm_clear_invalids(struct radeon_device *rdev,
struct radeon_vm *vm)
{
struct radeon_bo_va *bo_va, *tmp;
struct radeon_bo_va *bo_va;
int r;
list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, vm_status) {
spin_lock(&vm->status_lock);
while (!list_empty(&vm->invalidated)) {
bo_va = list_first_entry(&vm->invalidated,
struct radeon_bo_va, vm_status);
spin_unlock(&vm->status_lock);
r = radeon_vm_bo_update(rdev, bo_va, NULL);
if (r)
return r;
spin_lock(&vm->status_lock);
}
spin_unlock(&vm->status_lock);
return 0;
}
@ -1046,14 +1108,17 @@ void radeon_vm_bo_rmv(struct radeon_device *rdev,
mutex_lock(&vm->mutex);
interval_tree_remove(&bo_va->it, &vm->va);
spin_lock(&vm->status_lock);
list_del(&bo_va->vm_status);
if (bo_va->addr) {
bo_va->bo = radeon_bo_ref(bo_va->bo);
list_add(&bo_va->vm_status, &vm->freed);
} else {
radeon_fence_unref(&bo_va->last_pt_update);
kfree(bo_va);
}
spin_unlock(&vm->status_lock);
mutex_unlock(&vm->mutex);
}
@ -1074,10 +1139,10 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev,
list_for_each_entry(bo_va, &bo->va, bo_list) {
if (bo_va->addr) {
mutex_lock(&bo_va->vm->mutex);
spin_lock(&bo_va->vm->status_lock);
list_del(&bo_va->vm_status);
list_add(&bo_va->vm_status, &bo_va->vm->invalidated);
mutex_unlock(&bo_va->vm->mutex);
spin_unlock(&bo_va->vm->status_lock);
}
}
}
@ -1095,15 +1160,17 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
const unsigned align = min(RADEON_VM_PTB_ALIGN_SIZE,
RADEON_VM_PTE_COUNT * 8);
unsigned pd_size, pd_entries, pts_size;
int r;
int i, r;
vm->id = 0;
vm->ib_bo_va = NULL;
vm->fence = NULL;
vm->last_flush = NULL;
vm->last_id_use = NULL;
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
vm->ids[i].id = 0;
vm->ids[i].flushed_updates = NULL;
vm->ids[i].last_id_use = NULL;
}
mutex_init(&vm->mutex);
vm->va = RB_ROOT;
spin_lock_init(&vm->status_lock);
INIT_LIST_HEAD(&vm->invalidated);
INIT_LIST_HEAD(&vm->freed);
@ -1120,7 +1187,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
r = radeon_bo_create(rdev, pd_size, align, true,
RADEON_GEM_DOMAIN_VRAM, 0, NULL,
&vm->page_directory);
NULL, &vm->page_directory);
if (r)
return r;
@ -1157,11 +1224,13 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
if (!r) {
list_del_init(&bo_va->bo_list);
radeon_bo_unreserve(bo_va->bo);
radeon_fence_unref(&bo_va->last_pt_update);
kfree(bo_va);
}
}
list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) {
radeon_bo_unref(&bo_va->bo);
radeon_fence_unref(&bo_va->last_pt_update);
kfree(bo_va);
}
@ -1171,9 +1240,10 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
radeon_bo_unref(&vm->page_directory);
radeon_fence_unref(&vm->fence);
radeon_fence_unref(&vm->last_flush);
radeon_fence_unref(&vm->last_id_use);
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
radeon_fence_unref(&vm->ids[i].flushed_updates);
radeon_fence_unref(&vm->ids[i].last_id_use);
}
mutex_destroy(&vm->mutex);
}

View File

@ -1,8 +1,6 @@
#include <drm/drmP.h>
#include <drm/radeon_drm.h>
#include <drm.h>
#include <drm_mm.h>
#include "radeon.h"
#include "radeon_object.h"
#include "bitmap.h"
@ -34,7 +32,7 @@ int init_cursor(cursor_t *cursor)
rdev = (struct radeon_device *)os_display->ddev->dev_private;
r = radeon_bo_create(rdev, CURSOR_WIDTH*CURSOR_HEIGHT*4,
PAGE_SIZE, false, RADEON_GEM_DOMAIN_VRAM, 0, NULL, &cursor->robj);
4096, false, RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL, &cursor->robj);
if (unlikely(r != 0))
return r;
@ -227,9 +225,9 @@ bool init_display(struct radeon_device *rdev, videomode_t *usermode)
{
struct drm_device *dev;
cursor_t *cursor;
bool retval = true;
u32_t ifl;
cursor_t *cursor;
bool retval = true;
u32 ifl;
ENTER();

View File

@ -1,8 +1,6 @@
#include <drm/drmP.h>
#include <drm/radeon_drm.h>
#include <drm.h>
#include <drm_mm.h>
#include "radeon.h"
#include "radeon_object.h"
#include "drm_fb_helper.h"
@ -406,8 +404,8 @@ int init_display_kms(struct drm_device *dev, videomode_t *usermode)
struct drm_crtc *crtc = NULL;
struct drm_framebuffer *fb;
cursor_t *cursor;
u32_t ifl;
cursor_t *cursor;
u32 ifl;
int ret;
mutex_lock(&dev->mode_config.mutex);

View File

@ -840,6 +840,9 @@ void rs600_bandwidth_update(struct radeon_device *rdev)
u32 d1mode_priority_a_cnt, d2mode_priority_a_cnt;
/* FIXME: implement full support */
if (!rdev->mode_info.mode_config_initialized)
return;
radeon_update_display_priority(rdev);
if (rdev->mode_info.crtcs[0]->base.enabled)

View File

@ -579,6 +579,9 @@ void rs690_bandwidth_update(struct radeon_device *rdev)
u32 d1mode_priority_a_cnt, d1mode_priority_b_cnt;
u32 d2mode_priority_a_cnt, d2mode_priority_b_cnt;
if (!rdev->mode_info.mode_config_initialized)
return;
radeon_update_display_priority(rdev);
if (rdev->mode_info.crtcs[0]->base.enabled)

View File

@ -24,6 +24,7 @@
#include "drmP.h"
#include "radeon.h"
#include "radeon_asic.h"
#include "rs780d.h"
#include "r600_dpm.h"
#include "rs780_dpm.h"

View File

@ -1214,6 +1214,9 @@ void rv515_bandwidth_update(struct radeon_device *rdev)
struct drm_display_mode *mode0 = NULL;
struct drm_display_mode *mode1 = NULL;
if (!rdev->mode_info.mode_config_initialized)
return;
radeon_update_display_priority(rdev);
if (rdev->mode_info.crtcs[0]->base.enabled)

View File

@ -24,6 +24,7 @@
#include "drmP.h"
#include "radeon.h"
#include "radeon_asic.h"
#include "rv6xxd.h"
#include "r600_dpm.h"
#include "rv6xx_dpm.h"

Some files were not shown because too many files have changed in this diff Show More