UAPI Changes:
 
  * drm/panfrost: Export AFBC_FEATURES register to userspace
 
 Cross-subsystem Changes:
 
  * dma-buf: Fix debug printing; Rename dma_resv_*() functions + changes
    in callers; Cleanups
 
 Core Changes:
 
  * Add prefetching memcpy for WC
 
  * Avoid circular dependency on CONFIG_FB
 
  * Cleanups
 
  * Documentation fixes throughout DRM
 
  * ttm: Make struct ttm_resource the base of all managers + changes
    in all users of TTM; Add a generic memcpy for page-based iomem; Remove
    use of VM_MIXEDMAP; Cleanups
 
 Driver Changes:
 
  * drm/bridge: Add TI SN65DSI83 and SN65DSI84 + DT bindings
 
  * drm/hyperv: Add DRM driver for HyperV graphics output
 
  * drm/msm: Fix module dependencies
 
  * drm/panel: KD53T133: Support rotation
 
  * drm/pl111: Fix module dependencies
 
  * drm/qxl: Fixes
 
  * drm/stm: Cleanups
 
  * drm/sun4i: Be explicit about format modifiers
 
  * drm/vc4: Use struct gpio_desc; Cleanups
 
  * drm/vgem: Cleanups
 
  * drm/vmwgfx: Use ttm_bo_move_null() if there's nothing to copy
 
  * fbdev/mach64: Cleanups
 
  * fbdev/mb862xx: Use DEVICE_ATTR_RO
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAmDAcD0ACgkQaA3BHVML
 eiMkvwf8CwJk2XBHwejx07UKR09jXD2fdHqXElPSsPCwz/L+zIIAr5NqswQupnKl
 n8WAPgrXAGGpQuQEdkjYbukpL6kWIbg+nqdynWSS7Zf6h0SdZMqdYxGdJ9ciarVs
 Aoc56RLJaD97CaxPD5PmkQxUuRyXlMHINjUGevjWqIcGG3CMmh+AdCGx5RChMG4K
 MiIMgdzdg09AGGmlWTe56y7ihH1RWSfgyh/BHsMJ+bxhIpLQzm7Yul5zMSh/hQY5
 qJdDAdKGOKj99Z+UL9C8ZTU3sAMHfqZR0DyqlFTd7cYvT6ZnFoF1mGJ+Tkpz/DB2
 r4/CX2B6x39sNV1lOF7qKQ1kQLgEBw==
 =VT2X
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2021-06-09' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for 5.14:

UAPI Changes:

 * drm/panfrost: Export AFBC_FEATURES register to userspace

Cross-subsystem Changes:

 * dma-buf: Fix debug printing; Rename dma_resv_*() functions + changes
   in callers; Cleanups

Core Changes:

 * Add prefetching memcpy for WC

 * Avoid circular dependency on CONFIG_FB

 * Cleanups

 * Documentation fixes throughout DRM

 * ttm: Make struct ttm_resource the base of all managers + changes
   in all users of TTM; Add a generic memcpy for page-based iomem; Remove
   use of VM_MIXEDMAP; Cleanups

Driver Changes:

 * drm/bridge: Add TI SN65DSI83 and SN65DSI84 + DT bindings

 * drm/hyperv: Add DRM driver for HyperV graphics output

 * drm/msm: Fix module dependencies

 * drm/panel: KD53T133: Support rotation

 * drm/pl111: Fix module dependencies

 * drm/qxl: Fixes

 * drm/stm: Cleanups

 * drm/sun4i: Be explicit about format modifiers

 * drm/vc4: Use struct gpio_desc; Cleanups

 * drm/vgem: Cleanups

 * drm/vmwgfx: Use ttm_bo_move_null() if there's nothing to copy

 * fbdev/mach64: Cleanups

 * fbdev/mb862xx: Use DEVICE_ATTR_RO

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/YMBw3DF2b9udByfT@linux-uq9g
This commit is contained in:
Dave Airlie 2021-06-10 11:03:50 +10:00
Родитель 5745d647d5 5b7a2c92b6
Коммит 09b020bb05
154 изменённых файлов: 3856 добавлений и 1266 удалений

Просмотреть файл

@ -0,0 +1,159 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/bridge/ti,sn65dsi83.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: SN65DSI83 and SN65DSI84 DSI to LVDS bridge chip
maintainers:
- Marek Vasut <marex@denx.de>
description: |
Texas Instruments SN65DSI83 1x Single-link MIPI DSI
to 1x Single-link LVDS
https://www.ti.com/lit/gpn/sn65dsi83
Texas Instruments SN65DSI84 1x Single-link MIPI DSI
to 1x Dual-link or 2x Single-link LVDS
https://www.ti.com/lit/gpn/sn65dsi84
properties:
compatible:
enum:
- ti,sn65dsi83
- ti,sn65dsi84
reg:
enum:
- 0x2c
- 0x2d
enable-gpios:
maxItems: 1
description: GPIO specifier for bridge_en pin (active high).
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: /schemas/graph.yaml#/properties/port
description: Video port for MIPI DSI Channel-A input
properties:
endpoint:
$ref: /schemas/media/video-interfaces.yaml#
unevaluatedProperties: false
properties:
data-lanes:
description: array of physical DSI data lane indexes.
minItems: 1
maxItems: 4
items:
- const: 1
- const: 2
- const: 3
- const: 4
port@1:
$ref: /schemas/graph.yaml#/properties/port
description: Video port for MIPI DSI Channel-B input
properties:
endpoint:
$ref: /schemas/media/video-interfaces.yaml#
unevaluatedProperties: false
properties:
data-lanes:
description: array of physical DSI data lane indexes.
minItems: 1
maxItems: 4
items:
- const: 1
- const: 2
- const: 3
- const: 4
port@2:
$ref: /schemas/graph.yaml#/properties/port
description: Video port for LVDS Channel-A output (panel or bridge).
port@3:
$ref: /schemas/graph.yaml#/properties/port
description: Video port for LVDS Channel-B output (panel or bridge).
required:
- port@0
- port@2
required:
- compatible
- reg
- enable-gpios
- ports
allOf:
- if:
properties:
compatible:
contains:
const: ti,sn65dsi83
then:
properties:
ports:
properties:
port@1: false
port@3: false
- if:
properties:
compatible:
contains:
const: ti,sn65dsi84
then:
properties:
ports:
properties:
port@1: false
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
bridge@2d {
compatible = "ti,sn65dsi83";
reg = <0x2d>;
enable-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
endpoint {
remote-endpoint = <&dsi0_out>;
data-lanes = <1 2 3 4>;
};
};
port@2 {
reg = <2>;
endpoint {
remote-endpoint = <&panel_in_lvds>;
};
};
};
};
};

Просмотреть файл

@ -178,6 +178,15 @@ DMA Fence Array
.. kernel-doc:: include/linux/dma-fence-array.h
:internal:
DMA Fence Chain
~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/dma-buf/dma-fence-chain.c
:export:
.. kernel-doc:: include/linux/dma-fence-chain.h
:internal:
DMA Fence uABI/Sync File
~~~~~~~~~~~~~~~~~~~~~~~~

Просмотреть файл

@ -469,8 +469,8 @@ DRM MM Range Allocator Function References
.. kernel-doc:: drivers/gpu/drm/drm_mm.c
:export:
DRM Cache Handling
==================
DRM Cache Handling and Fast WC memcpy()
=======================================
.. kernel-doc:: drivers/gpu/drm/drm_cache.c
:export:

Просмотреть файл

@ -6084,6 +6084,14 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
F: Documentation/devicetree/bindings/display/hisilicon/
F: drivers/gpu/drm/hisilicon/
DRM DRIVER FOR HYPERV SYNTHETIC VIDEO DEVICE
M: Deepak Rawat <drawat.floss@gmail.com>
L: linux-hyperv@vger.kernel.org
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc
F: drivers/gpu/drm/hyperv
DRM DRIVERS FOR LIMA
M: Qiang Yu <yuq825@gmail.com>
L: dri-devel@lists.freedesktop.org

Просмотреть файл

@ -234,7 +234,7 @@ retry:
shared_count = fobj->shared_count;
else
shared_count = 0;
fence_excl = rcu_dereference(resv->fence_excl);
fence_excl = dma_resv_excl_fence(resv);
if (read_seqcount_retry(&resv->seq, seq)) {
rcu_read_unlock();
goto retry;
@ -1147,8 +1147,7 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
long ret;
/* Wait on any implicit rendering fences */
ret = dma_resv_wait_timeout_rcu(resv, write, true,
MAX_SCHEDULE_TIMEOUT);
ret = dma_resv_wait_timeout(resv, write, true, MAX_SCHEDULE_TIMEOUT);
if (ret < 0)
return ret;
@ -1349,15 +1348,14 @@ EXPORT_SYMBOL_GPL(dma_buf_vunmap);
#ifdef CONFIG_DEBUG_FS
static int dma_buf_debug_show(struct seq_file *s, void *unused)
{
int ret;
struct dma_buf *buf_obj;
struct dma_buf_attachment *attach_obj;
struct dma_resv *robj;
struct dma_resv_list *fobj;
struct dma_fence *fence;
unsigned seq;
int count = 0, attach_count, shared_count, i;
size_t size = 0;
int ret;
ret = mutex_lock_interruptible(&db_list.lock);
@ -1383,33 +1381,24 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
buf_obj->name ?: "");
robj = buf_obj->resv;
while (true) {
seq = read_seqcount_begin(&robj->seq);
rcu_read_lock();
fobj = rcu_dereference(robj->fence);
shared_count = fobj ? fobj->shared_count : 0;
fence = rcu_dereference(robj->fence_excl);
if (!read_seqcount_retry(&robj->seq, seq))
break;
rcu_read_unlock();
}
fence = dma_resv_excl_fence(robj);
if (fence)
seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n",
fence->ops->get_driver_name(fence),
fence->ops->get_timeline_name(fence),
dma_fence_is_signaled(fence) ? "" : "un");
fobj = rcu_dereference_protected(robj->fence,
dma_resv_held(robj));
shared_count = fobj ? fobj->shared_count : 0;
for (i = 0; i < shared_count; i++) {
fence = rcu_dereference(fobj->shared[i]);
if (!dma_fence_get_rcu(fence))
continue;
fence = rcu_dereference_protected(fobj->shared[i],
dma_resv_held(robj));
seq_printf(s, "\tShared fence: %s %s %ssignalled\n",
fence->ops->get_driver_name(fence),
fence->ops->get_timeline_name(fence),
dma_fence_is_signaled(fence) ? "" : "un");
dma_fence_put(fence);
}
rcu_read_unlock();
seq_puts(s, "\tAttached Devices:\n");
attach_count = 0;

Просмотреть файл

@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT
/*
* Copyright (C) 2012-2014 Canonical Ltd (Maarten Lankhorst)
*
@ -92,49 +93,6 @@ static void dma_resv_list_free(struct dma_resv_list *list)
kfree_rcu(list, rcu);
}
#if IS_ENABLED(CONFIG_LOCKDEP)
static int __init dma_resv_lockdep(void)
{
struct mm_struct *mm = mm_alloc();
struct ww_acquire_ctx ctx;
struct dma_resv obj;
struct address_space mapping;
int ret;
if (!mm)
return -ENOMEM;
dma_resv_init(&obj);
address_space_init_once(&mapping);
mmap_read_lock(mm);
ww_acquire_init(&ctx, &reservation_ww_class);
ret = dma_resv_lock(&obj, &ctx);
if (ret == -EDEADLK)
dma_resv_lock_slow(&obj, &ctx);
fs_reclaim_acquire(GFP_KERNEL);
/* for unmap_mapping_range on trylocked buffer objects in shrinkers */
i_mmap_lock_write(&mapping);
i_mmap_unlock_write(&mapping);
#ifdef CONFIG_MMU_NOTIFIER
lock_map_acquire(&__mmu_notifier_invalidate_range_start_map);
__dma_fence_might_wait();
lock_map_release(&__mmu_notifier_invalidate_range_start_map);
#else
__dma_fence_might_wait();
#endif
fs_reclaim_release(GFP_KERNEL);
ww_mutex_unlock(&obj.lock);
ww_acquire_fini(&ctx);
mmap_read_unlock(mm);
mmput(mm);
return 0;
}
subsys_initcall(dma_resv_lockdep);
#endif
/**
* dma_resv_init - initialize a reservation object
* @obj: the reservation object
@ -191,14 +149,11 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
dma_resv_assert_held(obj);
old = dma_resv_get_list(obj);
old = dma_resv_shared_list(obj);
if (old && old->shared_max) {
if ((old->shared_count + num_fences) <= old->shared_max)
return 0;
else
max = max(old->shared_count + num_fences,
old->shared_max * 2);
max = max(old->shared_count + num_fences, old->shared_max * 2);
} else {
max = max(4ul, roundup_pow_of_two(num_fences));
}
@ -252,6 +207,28 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
}
EXPORT_SYMBOL(dma_resv_reserve_shared);
#ifdef CONFIG_DEBUG_MUTEXES
/**
* dma_resv_reset_shared_max - reset shared fences for debugging
* @obj: the dma_resv object to reset
*
* Reset the number of pre-reserved shared slots to test that drivers do
* correct slot allocation using dma_resv_reserve_shared(). See also
* &dma_resv_list.shared_max.
*/
void dma_resv_reset_shared_max(struct dma_resv *obj)
{
struct dma_resv_list *fences = dma_resv_shared_list(obj);
dma_resv_assert_held(obj);
/* Test shared fence slot reservation */
if (fences)
fences->shared_max = fences->shared_count;
}
EXPORT_SYMBOL(dma_resv_reset_shared_max);
#endif
/**
* dma_resv_add_shared_fence - Add a fence to a shared slot
* @obj: the reservation object
@ -270,7 +247,7 @@ void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
dma_resv_assert_held(obj);
fobj = dma_resv_get_list(obj);
fobj = dma_resv_shared_list(obj);
count = fobj->shared_count;
write_seqcount_begin(&obj->seq);
@ -307,13 +284,13 @@ EXPORT_SYMBOL(dma_resv_add_shared_fence);
*/
void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
{
struct dma_fence *old_fence = dma_resv_get_excl(obj);
struct dma_fence *old_fence = dma_resv_excl_fence(obj);
struct dma_resv_list *old;
u32 i = 0;
dma_resv_assert_held(obj);
old = dma_resv_get_list(obj);
old = dma_resv_shared_list(obj);
if (old)
i = old->shared_count;
@ -337,26 +314,26 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
EXPORT_SYMBOL(dma_resv_add_excl_fence);
/**
* dma_resv_copy_fences - Copy all fences from src to dst.
* @dst: the destination reservation object
* @src: the source reservation object
*
* Copy all fences from src to dst. dst-lock must be held.
*/
* dma_resv_copy_fences - Copy all fences from src to dst.
* @dst: the destination reservation object
* @src: the source reservation object
*
* Copy all fences from src to dst. dst-lock must be held.
*/
int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
{
struct dma_resv_list *src_list, *dst_list;
struct dma_fence *old, *new;
unsigned i;
unsigned int i;
dma_resv_assert_held(dst);
rcu_read_lock();
src_list = rcu_dereference(src->fence);
src_list = dma_resv_shared_list(src);
retry:
if (src_list) {
unsigned shared_count = src_list->shared_count;
unsigned int shared_count = src_list->shared_count;
rcu_read_unlock();
@ -365,7 +342,7 @@ retry:
return -ENOMEM;
rcu_read_lock();
src_list = rcu_dereference(src->fence);
src_list = dma_resv_shared_list(src);
if (!src_list || src_list->shared_count > shared_count) {
kfree(dst_list);
goto retry;
@ -373,6 +350,7 @@ retry:
dst_list->shared_count = 0;
for (i = 0; i < src_list->shared_count; ++i) {
struct dma_fence __rcu **dst;
struct dma_fence *fence;
fence = rcu_dereference(src_list->shared[i]);
@ -382,7 +360,7 @@ retry:
if (!dma_fence_get_rcu(fence)) {
dma_resv_list_free(dst_list);
src_list = rcu_dereference(src->fence);
src_list = dma_resv_shared_list(src);
goto retry;
}
@ -391,7 +369,8 @@ retry:
continue;
}
rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], fence);
dst = &dst_list->shared[dst_list->shared_count++];
rcu_assign_pointer(*dst, fence);
}
} else {
dst_list = NULL;
@ -400,8 +379,8 @@ retry:
new = dma_fence_get_rcu_safe(&src->fence_excl);
rcu_read_unlock();
src_list = dma_resv_get_list(dst);
old = dma_resv_get_excl(dst);
src_list = dma_resv_shared_list(dst);
old = dma_resv_excl_fence(dst);
write_seqcount_begin(&dst->seq);
/* write_seqcount_begin provides the necessary memory barrier */
@ -417,7 +396,7 @@ retry:
EXPORT_SYMBOL(dma_resv_copy_fences);
/**
* dma_resv_get_fences_rcu - Get an object's shared and exclusive
* dma_resv_get_fences - Get an object's shared and exclusive
* fences without update side lock held
* @obj: the reservation object
* @pfence_excl: the returned exclusive fence (or NULL)
@ -429,10 +408,9 @@ EXPORT_SYMBOL(dma_resv_copy_fences);
* exclusive fence is not specified the fence is put into the array of the
* shared fences as well. Returns either zero or -ENOMEM.
*/
int dma_resv_get_fences_rcu(struct dma_resv *obj,
struct dma_fence **pfence_excl,
unsigned *pshared_count,
struct dma_fence ***pshared)
int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl,
unsigned int *pshared_count,
struct dma_fence ***pshared)
{
struct dma_fence **shared = NULL;
struct dma_fence *fence_excl;
@ -449,11 +427,11 @@ int dma_resv_get_fences_rcu(struct dma_resv *obj,
rcu_read_lock();
seq = read_seqcount_begin(&obj->seq);
fence_excl = rcu_dereference(obj->fence_excl);
fence_excl = dma_resv_excl_fence(obj);
if (fence_excl && !dma_fence_get_rcu(fence_excl))
goto unlock;
fobj = rcu_dereference(obj->fence);
fobj = dma_resv_shared_list(obj);
if (fobj)
sz += sizeof(*shared) * fobj->shared_max;
@ -515,27 +493,28 @@ unlock:
*pshared = shared;
return ret;
}
EXPORT_SYMBOL_GPL(dma_resv_get_fences_rcu);
EXPORT_SYMBOL_GPL(dma_resv_get_fences);
/**
* dma_resv_wait_timeout_rcu - Wait on reservation's objects
* dma_resv_wait_timeout - Wait on reservation's objects
* shared and/or exclusive fences.
* @obj: the reservation object
* @wait_all: if true, wait on all fences, else wait on just exclusive fence
* @intr: if true, do interruptible wait
* @timeout: timeout value in jiffies or zero to return immediately
*
* Callers are not required to hold specific locks, but maybe hold
* dma_resv_lock() already
* RETURNS
* Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
* greater than zer on success.
*/
long dma_resv_wait_timeout_rcu(struct dma_resv *obj,
bool wait_all, bool intr,
unsigned long timeout)
long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr,
unsigned long timeout)
{
struct dma_fence *fence;
unsigned seq, shared_count;
long ret = timeout ? timeout : 1;
unsigned int seq, shared_count;
struct dma_fence *fence;
int i;
retry:
@ -544,7 +523,7 @@ retry:
rcu_read_lock();
i = -1;
fence = rcu_dereference(obj->fence_excl);
fence = dma_resv_excl_fence(obj);
if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
if (!dma_fence_get_rcu(fence))
goto unlock_retry;
@ -559,14 +538,15 @@ retry:
}
if (wait_all) {
struct dma_resv_list *fobj = rcu_dereference(obj->fence);
struct dma_resv_list *fobj = dma_resv_shared_list(obj);
if (fobj)
shared_count = fobj->shared_count;
for (i = 0; !fence && i < shared_count; ++i) {
struct dma_fence *lfence = rcu_dereference(fobj->shared[i]);
struct dma_fence *lfence;
lfence = rcu_dereference(fobj->shared[i]);
if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
&lfence->flags))
continue;
@ -602,7 +582,7 @@ unlock_retry:
rcu_read_unlock();
goto retry;
}
EXPORT_SYMBOL_GPL(dma_resv_wait_timeout_rcu);
EXPORT_SYMBOL_GPL(dma_resv_wait_timeout);
static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence)
@ -622,18 +602,20 @@ static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence)
}
/**
* dma_resv_test_signaled_rcu - Test if a reservation object's
* fences have been signaled.
* dma_resv_test_signaled - Test if a reservation object's fences have been
* signaled.
* @obj: the reservation object
* @test_all: if true, test all fences, otherwise only test the exclusive
* fence
*
* Callers are not required to hold specific locks, but maybe hold
* dma_resv_lock() already
* RETURNS
* true if all fences signaled, else false
*/
bool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool test_all)
bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all)
{
unsigned seq, shared_count;
unsigned int seq, shared_count;
int ret;
rcu_read_lock();
@ -643,16 +625,16 @@ retry:
seq = read_seqcount_begin(&obj->seq);
if (test_all) {
unsigned i;
struct dma_resv_list *fobj = rcu_dereference(obj->fence);
struct dma_resv_list *fobj = dma_resv_shared_list(obj);
unsigned int i;
if (fobj)
shared_count = fobj->shared_count;
for (i = 0; i < shared_count; ++i) {
struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
struct dma_fence *fence;
fence = rcu_dereference(fobj->shared[i]);
ret = dma_resv_test_signaled_single(fence);
if (ret < 0)
goto retry;
@ -665,7 +647,7 @@ retry:
}
if (!shared_count) {
struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl);
struct dma_fence *fence_excl = dma_resv_excl_fence(obj);
if (fence_excl) {
ret = dma_resv_test_signaled_single(fence_excl);
@ -680,4 +662,47 @@ retry:
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(dma_resv_test_signaled_rcu);
EXPORT_SYMBOL_GPL(dma_resv_test_signaled);
#if IS_ENABLED(CONFIG_LOCKDEP)
static int __init dma_resv_lockdep(void)
{
struct mm_struct *mm = mm_alloc();
struct ww_acquire_ctx ctx;
struct dma_resv obj;
struct address_space mapping;
int ret;
if (!mm)
return -ENOMEM;
dma_resv_init(&obj);
address_space_init_once(&mapping);
mmap_read_lock(mm);
ww_acquire_init(&ctx, &reservation_ww_class);
ret = dma_resv_lock(&obj, &ctx);
if (ret == -EDEADLK)
dma_resv_lock_slow(&obj, &ctx);
fs_reclaim_acquire(GFP_KERNEL);
/* for unmap_mapping_range on trylocked buffer objects in shrinkers */
i_mmap_lock_write(&mapping);
i_mmap_unlock_write(&mapping);
#ifdef CONFIG_MMU_NOTIFIER
lock_map_acquire(&__mmu_notifier_invalidate_range_start_map);
__dma_fence_might_wait();
lock_map_release(&__mmu_notifier_invalidate_range_start_map);
#else
__dma_fence_might_wait();
#endif
fs_reclaim_release(GFP_KERNEL);
ww_mutex_unlock(&obj.lock);
ww_acquire_fini(&ctx);
mmap_read_unlock(mm);
mmput(mm);
return 0;
}
subsys_initcall(dma_resv_lockdep);
#endif

Просмотреть файл

@ -98,8 +98,8 @@ config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
config DRM_FBDEV_EMULATION
bool "Enable legacy fbdev support for your modesetting driver"
depends on DRM
depends on FB
select DRM_KMS_HELPER
select FB
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@ -379,6 +379,19 @@ source "drivers/gpu/drm/xlnx/Kconfig"
source "drivers/gpu/drm/gud/Kconfig"
config DRM_HYPERV
tristate "DRM Support for Hyper-V synthetic video device"
depends on DRM && PCI && MMU && HYPERV
select DRM_KMS_HELPER
select DRM_GEM_SHMEM_HELPER
help
This is a KMS driver for Hyper-V synthetic video device. Choose this
option if you would like to enable drm driver for Hyper-V virtual
machine. Unselect Hyper-V framebuffer driver (CONFIG_FB_HYPERV) so
that DRM driver is used by default.
If M is selected the module will be called hyperv_drm.
# Keep legacy drivers last
menuconfig DRM_LEGACY

Просмотреть файл

@ -126,3 +126,4 @@ obj-$(CONFIG_DRM_MCDE) += mcde/
obj-$(CONFIG_DRM_TIDSS) += tidss/
obj-y += xlnx/
obj-y += gud/
obj-$(CONFIG_DRM_HYPERV) += hyperv/

Просмотреть файл

@ -247,7 +247,7 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
if (!ef)
return -EINVAL;
old = dma_resv_get_list(resv);
old = dma_resv_shared_list(resv);
if (!old)
return 0;
@ -1668,7 +1668,7 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
* the next restore worker
*/
if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) &&
bo->tbo.mem.mem_type == TTM_PL_SYSTEM)
bo->tbo.resource->mem_type == TTM_PL_SYSTEM)
is_invalid_userptr = true;
ret = vm_validate_pt_pd_bos(avm);

Просмотреть файл

@ -4127,9 +4127,9 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev)
list_for_each_entry(shadow, &adev->shadow_list, shadow_list) {
/* No need to recover an evicted BO */
if (shadow->tbo.mem.mem_type != TTM_PL_TT ||
shadow->tbo.mem.start == AMDGPU_BO_INVALID_OFFSET ||
shadow->parent->tbo.mem.mem_type != TTM_PL_VRAM)
if (shadow->tbo.resource->mem_type != TTM_PL_TT ||
shadow->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET ||
shadow->parent->tbo.resource->mem_type != TTM_PL_VRAM)
continue;
r = amdgpu_bo_restore_shadow(shadow, &next);

Просмотреть файл

@ -203,9 +203,8 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
goto unpin;
}
r = dma_resv_get_fences_rcu(new_abo->tbo.base.resv, &work->excl,
&work->shared_count,
&work->shared);
r = dma_resv_get_fences(new_abo->tbo.base.resv, &work->excl,
&work->shared_count, &work->shared);
if (unlikely(r != 0)) {
DRM_ERROR("failed to get fences for buffer\n");
goto unpin;

Просмотреть файл

@ -49,10 +49,10 @@ __dma_resv_make_exclusive(struct dma_resv *obj)
unsigned int count;
int r;
if (!dma_resv_get_list(obj)) /* no shared fences to convert */
if (!dma_resv_shared_list(obj)) /* no shared fences to convert */
return 0;
r = dma_resv_get_fences_rcu(obj, NULL, &count, &fences);
r = dma_resv_get_fences(obj, NULL, &count, &fences);
if (r)
return r;
@ -226,12 +226,12 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,
if (r)
return ERR_PTR(r);
} else if (!(amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type) &
} else if (!(amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type) &
AMDGPU_GEM_DOMAIN_GTT)) {
return ERR_PTR(-EBUSY);
}
switch (bo->tbo.mem.mem_type) {
switch (bo->tbo.resource->mem_type) {
case TTM_PL_TT:
sgt = drm_prime_pages_to_sg(obj->dev,
bo->tbo.ttm->pages,
@ -245,8 +245,9 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,
break;
case TTM_PL_VRAM:
r = amdgpu_vram_mgr_alloc_sgt(adev, &bo->tbo.mem, 0,
bo->tbo.base.size, attach->dev, dir, &sgt);
r = amdgpu_vram_mgr_alloc_sgt(adev, bo->tbo.resource, 0,
bo->tbo.base.size, attach->dev,
dir, &sgt);
if (r)
return ERR_PTR(r);
break;
@ -436,7 +437,7 @@ amdgpu_dma_buf_move_notify(struct dma_buf_attachment *attach)
struct amdgpu_vm_bo_base *bo_base;
int r;
if (bo->tbo.mem.mem_type == TTM_PL_SYSTEM)
if (bo->tbo.resource->mem_type == TTM_PL_SYSTEM)
return;
r = ttm_bo_validate(&bo->tbo, &placement, &ctx);

Просмотреть файл

@ -226,7 +226,7 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj,
if (!amdgpu_vm_ready(vm))
goto out_unlock;
fence = dma_resv_get_excl(bo->tbo.base.resv);
fence = dma_resv_excl_fence(bo->tbo.base.resv);
if (fence) {
amdgpu_bo_fence(bo, fence, true);
fence = NULL;
@ -526,8 +526,7 @@ int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
return -ENOENT;
}
robj = gem_to_amdgpu_bo(gobj);
ret = dma_resv_wait_timeout_rcu(robj->tbo.base.resv, true, true,
timeout);
ret = dma_resv_wait_timeout(robj->tbo.base.resv, true, true, timeout);
/* ret == 0 means not signaled,
* ret > 0 means signaled

Просмотреть файл

@ -101,7 +101,7 @@ void amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level,
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
switch (bo->tbo.mem.mem_type) {
switch (bo->tbo.resource->mem_type) {
case TTM_PL_TT:
*addr = bo->tbo.ttm->dma_address[0];
break;
@ -112,7 +112,7 @@ void amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level,
*addr = 0;
break;
}
*flags = amdgpu_ttm_tt_pde_flags(bo->tbo.ttm, &bo->tbo.mem);
*flags = amdgpu_ttm_tt_pde_flags(bo->tbo.ttm, bo->tbo.resource);
amdgpu_gmc_get_vm_pde(adev, level, addr, flags);
}

Просмотреть файл

@ -22,18 +22,26 @@
* Authors: Christian König
*/
#include <drm/ttm/ttm_range_manager.h>
#include "amdgpu.h"
struct amdgpu_gtt_node {
struct ttm_buffer_object *tbo;
struct ttm_range_mgr_node base;
};
static inline struct amdgpu_gtt_mgr *
to_gtt_mgr(struct ttm_resource_manager *man)
{
return container_of(man, struct amdgpu_gtt_mgr, manager);
}
struct amdgpu_gtt_node {
struct drm_mm_node node;
struct ttm_buffer_object *tbo;
};
static inline struct amdgpu_gtt_node *
to_amdgpu_gtt_node(struct ttm_resource *res)
{
return container_of(res, struct amdgpu_gtt_node, base.base);
}
/**
* DOC: mem_info_gtt_total
@ -93,13 +101,15 @@ const struct attribute_group amdgpu_gtt_mgr_attr_group = {
/**
* amdgpu_gtt_mgr_has_gart_addr - Check if mem has address space
*
* @mem: the mem object to check
* @res: the mem object to check
*
* Check if a mem object has already address space allocated.
*/
bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem)
bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *res)
{
return mem->mm_node != NULL;
struct amdgpu_gtt_node *node = to_amdgpu_gtt_node(res);
return drm_mm_node_allocated(&node->base.mm_nodes[0]);
}
/**
@ -115,54 +125,57 @@ bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem)
static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *tbo,
const struct ttm_place *place,
struct ttm_resource *mem)
struct ttm_resource **res)
{
struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
uint32_t num_pages = PFN_UP(tbo->base.size);
struct amdgpu_gtt_node *node;
int r;
spin_lock(&mgr->lock);
if ((&tbo->mem == mem || tbo->mem.mem_type != TTM_PL_TT) &&
atomic64_read(&mgr->available) < mem->num_pages) {
if (tbo->resource && tbo->resource->mem_type != TTM_PL_TT &&
atomic64_read(&mgr->available) < num_pages) {
spin_unlock(&mgr->lock);
return -ENOSPC;
}
atomic64_sub(mem->num_pages, &mgr->available);
atomic64_sub(num_pages, &mgr->available);
spin_unlock(&mgr->lock);
if (!place->lpfn) {
mem->mm_node = NULL;
mem->start = AMDGPU_BO_INVALID_OFFSET;
return 0;
}
node = kzalloc(sizeof(*node), GFP_KERNEL);
node = kzalloc(struct_size(node, base.mm_nodes, 1), GFP_KERNEL);
if (!node) {
r = -ENOMEM;
goto err_out;
}
node->tbo = tbo;
ttm_resource_init(tbo, place, &node->base.base);
spin_lock(&mgr->lock);
r = drm_mm_insert_node_in_range(&mgr->mm, &node->node, mem->num_pages,
tbo->page_alignment, 0, place->fpfn,
place->lpfn, DRM_MM_INSERT_BEST);
spin_unlock(&mgr->lock);
if (place->lpfn) {
spin_lock(&mgr->lock);
r = drm_mm_insert_node_in_range(&mgr->mm,
&node->base.mm_nodes[0],
num_pages, tbo->page_alignment,
0, place->fpfn, place->lpfn,
DRM_MM_INSERT_BEST);
spin_unlock(&mgr->lock);
if (unlikely(r))
goto err_free;
if (unlikely(r))
goto err_free;
mem->mm_node = node;
mem->start = node->node.start;
node->base.base.start = node->base.mm_nodes[0].start;
} else {
node->base.mm_nodes[0].start = 0;
node->base.mm_nodes[0].size = node->base.base.num_pages;
node->base.base.start = AMDGPU_BO_INVALID_OFFSET;
}
*res = &node->base.base;
return 0;
err_free:
kfree(node);
err_out:
atomic64_add(mem->num_pages, &mgr->available);
atomic64_add(num_pages, &mgr->available);
return r;
}
@ -176,19 +189,18 @@ err_out:
* Free the allocated GTT again.
*/
static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
struct ttm_resource *mem)
struct ttm_resource *res)
{
struct amdgpu_gtt_node *node = to_amdgpu_gtt_node(res);
struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
struct amdgpu_gtt_node *node = mem->mm_node;
if (node) {
spin_lock(&mgr->lock);
drm_mm_remove_node(&node->node);
spin_unlock(&mgr->lock);
kfree(node);
}
spin_lock(&mgr->lock);
if (drm_mm_node_allocated(&node->base.mm_nodes[0]))
drm_mm_remove_node(&node->base.mm_nodes[0]);
spin_unlock(&mgr->lock);
atomic64_add(res->num_pages, &mgr->available);
atomic64_add(mem->num_pages, &mgr->available);
kfree(node);
}
/**
@ -224,7 +236,7 @@ int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man)
adev = container_of(mgr, typeof(*adev), mman.gtt_mgr);
spin_lock(&mgr->lock);
drm_mm_for_each_node(mm_node, &mgr->mm) {
node = container_of(mm_node, struct amdgpu_gtt_node, node);
node = container_of(mm_node, typeof(*node), base.mm_nodes[0]);
r = amdgpu_ttm_recover_gart(node->tbo);
if (r)
break;

Просмотреть файл

@ -112,7 +112,7 @@ void amdgpu_pasid_free_delayed(struct dma_resv *resv,
unsigned count;
int r;
r = dma_resv_get_fences_rcu(resv, NULL, &count, &fences);
r = dma_resv_get_fences(resv, NULL, &count, &fences);
if (r)
goto fallback;
@ -156,8 +156,7 @@ fallback:
/* Not enough memory for the delayed delete, as last resort
* block for all the fences to complete.
*/
dma_resv_wait_timeout_rcu(resv, true, false,
MAX_SCHEDULE_TIMEOUT);
dma_resv_wait_timeout(resv, true, false, MAX_SCHEDULE_TIMEOUT);
amdgpu_pasid_free(pasid);
}

Просмотреть файл

@ -75,8 +75,8 @@ static bool amdgpu_mn_invalidate_gfx(struct mmu_interval_notifier *mni,
mmu_interval_set_seq(mni, cur_seq);
r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, true, false,
MAX_SCHEDULE_TIMEOUT);
r = dma_resv_wait_timeout(bo->tbo.base.resv, true, false,
MAX_SCHEDULE_TIMEOUT);
mutex_unlock(&adev->notifier_lock);
if (r <= 0)
DRM_ERROR("(%ld) failed to wait for user bo\n", r);

Просмотреть файл

@ -364,14 +364,14 @@ int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev,
if (cpu_addr)
amdgpu_bo_kunmap(*bo_ptr);
ttm_resource_free(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem);
ttm_resource_free(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.resource);
for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) {
(*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT;
(*bo_ptr)->placements[i].lpfn = (offset + size) >> PAGE_SHIFT;
}
r = ttm_bo_mem_space(&(*bo_ptr)->tbo, &(*bo_ptr)->placement,
&(*bo_ptr)->tbo.mem, &ctx);
&(*bo_ptr)->tbo.resource, &ctx);
if (r)
goto error;
@ -575,15 +575,15 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
return r;
if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
bo->tbo.mem.mem_type == TTM_PL_VRAM &&
bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT)
bo->tbo.resource->mem_type == TTM_PL_VRAM &&
bo->tbo.resource->start < adev->gmc.visible_vram_size >> PAGE_SHIFT)
amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved,
ctx.bytes_moved);
else
amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, 0);
if (bp->flags & AMDGPU_GEM_CREATE_VRAM_CLEARED &&
bo->tbo.mem.mem_type == TTM_PL_VRAM) {
bo->tbo.resource->mem_type == TTM_PL_VRAM) {
struct dma_fence *fence;
r = amdgpu_fill_buffer(bo, 0, bo->tbo.base.resv, &fence);
@ -777,12 +777,12 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
return 0;
}
r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, false, false,
MAX_SCHEDULE_TIMEOUT);
r = dma_resv_wait_timeout(bo->tbo.base.resv, false, false,
MAX_SCHEDULE_TIMEOUT);
if (r < 0)
return r;
r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.mem.num_pages, &bo->kmap);
r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.resource->num_pages, &bo->kmap);
if (r)
return r;
@ -905,8 +905,8 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
domain = amdgpu_bo_get_preferred_pin_domain(adev, domain);
if (bo->tbo.pin_count) {
uint32_t mem_type = bo->tbo.mem.mem_type;
uint32_t mem_flags = bo->tbo.mem.placement;
uint32_t mem_type = bo->tbo.resource->mem_type;
uint32_t mem_flags = bo->tbo.resource->placement;
if (!(domain & amdgpu_mem_type_to_domain(mem_type)))
return -EINVAL;
@ -956,7 +956,7 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
ttm_bo_pin(&bo->tbo);
domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type);
if (domain == AMDGPU_GEM_DOMAIN_VRAM) {
atomic64_add(amdgpu_bo_size(bo), &adev->vram_pin_size);
atomic64_add(amdgpu_vram_mgr_bo_visible_size(bo),
@ -1008,11 +1008,11 @@ void amdgpu_bo_unpin(struct amdgpu_bo *bo)
if (bo->tbo.base.import_attach)
dma_buf_unpin(bo->tbo.base.import_attach);
if (bo->tbo.mem.mem_type == TTM_PL_VRAM) {
if (bo->tbo.resource->mem_type == TTM_PL_VRAM) {
atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size);
atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo),
&adev->visible_pin_size);
} else if (bo->tbo.mem.mem_type == TTM_PL_TT) {
} else if (bo->tbo.resource->mem_type == TTM_PL_TT) {
atomic64_sub(amdgpu_bo_size(bo), &adev->gart_pin_size);
}
}
@ -1245,7 +1245,7 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
struct amdgpu_bo *abo;
struct ttm_resource *old_mem = &bo->mem;
struct ttm_resource *old_mem = bo->resource;
if (!amdgpu_bo_is_amdgpu_bo(bo))
return;
@ -1256,7 +1256,7 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
amdgpu_bo_kunmap(abo);
if (abo->tbo.base.dma_buf && !abo->tbo.base.import_attach &&
bo->mem.mem_type != TTM_PL_SYSTEM)
bo->resource->mem_type != TTM_PL_SYSTEM)
dma_buf_move_notify(abo->tbo.base.dma_buf);
/* remember the eviction */
@ -1276,7 +1276,7 @@ void amdgpu_bo_get_memory(struct amdgpu_bo *bo, uint64_t *vram_mem,
{
unsigned int domain;
domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type);
switch (domain) {
case AMDGPU_GEM_DOMAIN_VRAM:
*vram_mem += amdgpu_bo_size(bo);
@ -1318,7 +1318,7 @@ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo)
if (bo->base.resv == &bo->base._resv)
amdgpu_amdkfd_remove_fence_on_pt_pd_bos(abo);
if (bo->mem.mem_type != TTM_PL_VRAM || !bo->mem.mm_node ||
if (bo->resource->mem_type != TTM_PL_VRAM ||
!(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE))
return;
@ -1355,10 +1355,10 @@ vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
/* Remember that this BO was accessed by the CPU */
abo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
if (bo->mem.mem_type != TTM_PL_VRAM)
if (bo->resource->mem_type != TTM_PL_VRAM)
return 0;
offset = bo->mem.start << PAGE_SHIFT;
offset = bo->resource->start << PAGE_SHIFT;
if ((offset + bo->base.size) <= adev->gmc.visible_vram_size)
return 0;
@ -1381,9 +1381,9 @@ vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
else if (unlikely(r))
return VM_FAULT_SIGBUS;
offset = bo->mem.start << PAGE_SHIFT;
offset = bo->resource->start << PAGE_SHIFT;
/* this should never happen */
if (bo->mem.mem_type == TTM_PL_VRAM &&
if (bo->resource->mem_type == TTM_PL_VRAM &&
(offset + bo->base.size) > adev->gmc.visible_vram_size)
return VM_FAULT_SIGBUS;
@ -1468,11 +1468,11 @@ int amdgpu_bo_sync_wait(struct amdgpu_bo *bo, void *owner, bool intr)
*/
u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
{
WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM);
WARN_ON_ONCE(bo->tbo.resource->mem_type == TTM_PL_SYSTEM);
WARN_ON_ONCE(!dma_resv_is_locked(bo->tbo.base.resv) &&
!bo->tbo.pin_count && bo->tbo.type != ttm_bo_type_kernel);
WARN_ON_ONCE(bo->tbo.mem.start == AMDGPU_BO_INVALID_OFFSET);
WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_VRAM &&
WARN_ON_ONCE(bo->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET);
WARN_ON_ONCE(bo->tbo.resource->mem_type == TTM_PL_VRAM &&
!(bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS));
return amdgpu_bo_gpu_offset_no_check(bo);
@ -1490,8 +1490,8 @@ u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo)
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
uint64_t offset;
offset = (bo->tbo.mem.start << PAGE_SHIFT) +
amdgpu_ttm_domain_start(adev, bo->tbo.mem.mem_type);
offset = (bo->tbo.resource->start << PAGE_SHIFT) +
amdgpu_ttm_domain_start(adev, bo->tbo.resource->mem_type);
return amdgpu_gmc_sign_extend(offset);
}
@ -1544,7 +1544,7 @@ u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m)
unsigned int pin_count;
u64 size;
domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type);
switch (domain) {
case AMDGPU_GEM_DOMAIN_VRAM:
placement = "VRAM";

Просмотреть файл

@ -223,10 +223,10 @@ static inline bool amdgpu_bo_in_cpu_visible_vram(struct amdgpu_bo *bo)
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
struct amdgpu_res_cursor cursor;
if (bo->tbo.mem.mem_type != TTM_PL_VRAM)
if (bo->tbo.resource->mem_type != TTM_PL_VRAM)
return false;
amdgpu_res_first(&bo->tbo.mem, 0, amdgpu_bo_size(bo), &cursor);
amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &cursor);
while (cursor.remaining) {
if (cursor.start < adev->gmc.visible_vram_size)
return true;

Просмотреть файл

@ -66,14 +66,18 @@ static DEVICE_ATTR_RO(mem_info_preempt_used);
static int amdgpu_preempt_mgr_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *tbo,
const struct ttm_place *place,
struct ttm_resource *mem)
struct ttm_resource **res)
{
struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man);
atomic64_add(mem->num_pages, &mgr->used);
*res = kzalloc(sizeof(**res), GFP_KERNEL);
if (*res)
return -ENOMEM;
mem->mm_node = NULL;
mem->start = AMDGPU_BO_INVALID_OFFSET;
ttm_resource_init(tbo, place, *res);
(*res)->start = AMDGPU_BO_INVALID_OFFSET;
atomic64_add((*res)->num_pages, &mgr->used);
return 0;
}
@ -86,11 +90,12 @@ static int amdgpu_preempt_mgr_new(struct ttm_resource_manager *man,
* Free the allocated GTT again.
*/
static void amdgpu_preempt_mgr_del(struct ttm_resource_manager *man,
struct ttm_resource *mem)
struct ttm_resource *res)
{
struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man);
atomic64_sub(mem->num_pages, &mgr->used);
atomic64_sub(res->num_pages, &mgr->used);
kfree(res);
}
/**

Просмотреть файл

@ -28,6 +28,7 @@
#include <drm/drm_mm.h>
#include <drm/ttm/ttm_resource.h>
#include <drm/ttm/ttm_range_manager.h>
/* state back for walking over vram_mgr and gtt_mgr allocations */
struct amdgpu_res_cursor {
@ -53,7 +54,7 @@ static inline void amdgpu_res_first(struct ttm_resource *res,
{
struct drm_mm_node *node;
if (!res || !res->mm_node) {
if (!res) {
cur->start = start;
cur->size = size;
cur->remaining = size;
@ -63,7 +64,7 @@ static inline void amdgpu_res_first(struct ttm_resource *res,
BUG_ON(start + size > res->num_pages << PAGE_SHIFT);
node = res->mm_node;
node = to_ttm_range_mgr_node(res)->mm_nodes;
while (start >= node->size << PAGE_SHIFT)
start -= node++->size << PAGE_SHIFT;

Просмотреть файл

@ -210,10 +210,10 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync,
return -EINVAL;
/* always sync to the exclusive fence */
f = dma_resv_get_excl(resv);
f = dma_resv_excl_fence(resv);
r = amdgpu_sync_fence(sync, f);
flist = dma_resv_get_list(resv);
flist = dma_resv_shared_list(resv);
if (!flist || r)
return r;

Просмотреть файл

@ -127,8 +127,8 @@ TRACE_EVENT(amdgpu_bo_create,
TP_fast_assign(
__entry->bo = bo;
__entry->pages = bo->tbo.mem.num_pages;
__entry->type = bo->tbo.mem.mem_type;
__entry->pages = bo->tbo.resource->num_pages;
__entry->type = bo->tbo.resource->mem_type;
__entry->prefer = bo->preferred_domains;
__entry->allow = bo->allowed_domains;
__entry->visible = bo->flags;

Просмотреть файл

@ -45,6 +45,7 @@
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_range_manager.h>
#include <drm/amdgpu_drm.h>
@ -125,7 +126,8 @@ static void amdgpu_evict_flags(struct ttm_buffer_object *bo,
rcu_read_unlock();
return;
}
switch (bo->mem.mem_type) {
switch (bo->resource->mem_type) {
case AMDGPU_PL_GDS:
case AMDGPU_PL_GWS:
case AMDGPU_PL_OA:
@ -460,7 +462,7 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
{
struct amdgpu_device *adev;
struct amdgpu_bo *abo;
struct ttm_resource *old_mem = &bo->mem;
struct ttm_resource *old_mem = bo->resource;
int r;
if (new_mem->mem_type == TTM_PL_TT ||
@ -495,7 +497,7 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
return r;
amdgpu_ttm_backend_unbind(bo->bdev, bo->ttm);
ttm_resource_free(bo, &bo->mem);
ttm_resource_free(bo, &bo->resource);
ttm_bo_assign_mem(bo, new_mem);
goto out;
}
@ -605,7 +607,8 @@ static unsigned long amdgpu_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
struct amdgpu_res_cursor cursor;
amdgpu_res_first(&bo->mem, (u64)page_offset << PAGE_SHIFT, 0, &cursor);
amdgpu_res_first(bo->resource, (u64)page_offset << PAGE_SHIFT, 0,
&cursor);
return (adev->gmc.aper_base + cursor.start) >> PAGE_SHIFT;
}
@ -954,50 +957,50 @@ int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo)
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
struct ttm_operation_ctx ctx = { false, false };
struct amdgpu_ttm_tt *gtt = (void *)bo->ttm;
struct ttm_resource tmp;
struct ttm_placement placement;
struct ttm_place placements;
struct ttm_resource *tmp;
uint64_t addr, flags;
int r;
if (bo->mem.start != AMDGPU_BO_INVALID_OFFSET)
if (bo->resource->start != AMDGPU_BO_INVALID_OFFSET)
return 0;
addr = amdgpu_gmc_agp_addr(bo);
if (addr != AMDGPU_BO_INVALID_OFFSET) {
bo->mem.start = addr >> PAGE_SHIFT;
} else {
/* allocate GART space */
placement.num_placement = 1;
placement.placement = &placements;
placement.num_busy_placement = 1;
placement.busy_placement = &placements;
placements.fpfn = 0;
placements.lpfn = adev->gmc.gart_size >> PAGE_SHIFT;
placements.mem_type = TTM_PL_TT;
placements.flags = bo->mem.placement;
r = ttm_bo_mem_space(bo, &placement, &tmp, &ctx);
if (unlikely(r))
return r;
/* compute PTE flags for this buffer object */
flags = amdgpu_ttm_tt_pte_flags(adev, bo->ttm, &tmp);
/* Bind pages */
gtt->offset = (u64)tmp.start << PAGE_SHIFT;
r = amdgpu_ttm_gart_bind(adev, bo, flags);
if (unlikely(r)) {
ttm_resource_free(bo, &tmp);
return r;
}
amdgpu_gart_invalidate_tlb(adev);
ttm_resource_free(bo, &bo->mem);
bo->mem = tmp;
bo->resource->start = addr >> PAGE_SHIFT;
return 0;
}
/* allocate GART space */
placement.num_placement = 1;
placement.placement = &placements;
placement.num_busy_placement = 1;
placement.busy_placement = &placements;
placements.fpfn = 0;
placements.lpfn = adev->gmc.gart_size >> PAGE_SHIFT;
placements.mem_type = TTM_PL_TT;
placements.flags = bo->resource->placement;
r = ttm_bo_mem_space(bo, &placement, &tmp, &ctx);
if (unlikely(r))
return r;
/* compute PTE flags for this buffer object */
flags = amdgpu_ttm_tt_pte_flags(adev, bo->ttm, tmp);
/* Bind pages */
gtt->offset = (u64)tmp->start << PAGE_SHIFT;
r = amdgpu_ttm_gart_bind(adev, bo, flags);
if (unlikely(r)) {
ttm_resource_free(bo, &tmp);
return r;
}
amdgpu_gart_invalidate_tlb(adev);
ttm_resource_free(bo, &bo->resource);
ttm_bo_assign_mem(bo, tmp);
return 0;
}
@ -1016,7 +1019,7 @@ int amdgpu_ttm_recover_gart(struct ttm_buffer_object *tbo)
if (!tbo->ttm)
return 0;
flags = amdgpu_ttm_tt_pte_flags(adev, tbo->ttm, &tbo->mem);
flags = amdgpu_ttm_tt_pte_flags(adev, tbo->ttm, tbo->resource);
r = amdgpu_ttm_gart_bind(adev, tbo, flags);
return r;
@ -1330,12 +1333,16 @@ uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
const struct ttm_place *place)
{
unsigned long num_pages = bo->mem.num_pages;
unsigned long num_pages = bo->resource->num_pages;
struct amdgpu_res_cursor cursor;
struct dma_resv_list *flist;
struct dma_fence *f;
int i;
/* Swapout? */
if (bo->resource->mem_type == TTM_PL_SYSTEM)
return true;
if (bo->type == ttm_bo_type_kernel &&
!amdgpu_vm_evictable(ttm_to_amdgpu_bo(bo)))
return false;
@ -1344,7 +1351,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
* If true, then return false as any KFD process needs all its BOs to
* be resident to run successfully
*/
flist = dma_resv_get_list(bo->base.resv);
flist = dma_resv_shared_list(bo->base.resv);
if (flist) {
for (i = 0; i < flist->shared_count; ++i) {
f = rcu_dereference_protected(flist->shared[i],
@ -1354,7 +1361,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
}
}
switch (bo->mem.mem_type) {
switch (bo->resource->mem_type) {
case AMDGPU_PL_PREEMPT:
/* Preemptible BOs don't own system resources managed by the
* driver (pages, VRAM, GART space). They point to resources
@ -1372,7 +1379,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
case TTM_PL_VRAM:
/* Check each drm MM node individually */
amdgpu_res_first(&bo->mem, 0, (u64)num_pages << PAGE_SHIFT,
amdgpu_res_first(bo->resource, 0, (u64)num_pages << PAGE_SHIFT,
&cursor);
while (cursor.remaining) {
if (place->fpfn < PFN_DOWN(cursor.start + cursor.size)
@ -1414,10 +1421,10 @@ static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo,
uint32_t value = 0;
int ret = 0;
if (bo->mem.mem_type != TTM_PL_VRAM)
if (bo->resource->mem_type != TTM_PL_VRAM)
return -EIO;
amdgpu_res_first(&bo->mem, offset, len, &cursor);
amdgpu_res_first(bo->resource, offset, len, &cursor);
while (cursor.remaining) {
uint64_t aligned_pos = cursor.start & ~(uint64_t)3;
uint64_t bytes = 4 - (cursor.start & 3);
@ -1942,21 +1949,21 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
return -EINVAL;
}
if (bo->tbo.mem.mem_type == AMDGPU_PL_PREEMPT) {
if (bo->tbo.resource->mem_type == AMDGPU_PL_PREEMPT) {
DRM_ERROR("Trying to clear preemptible memory.\n");
return -EINVAL;
}
if (bo->tbo.mem.mem_type == TTM_PL_TT) {
if (bo->tbo.resource->mem_type == TTM_PL_TT) {
r = amdgpu_ttm_alloc_gart(&bo->tbo);
if (r)
return r;
}
num_bytes = bo->tbo.mem.num_pages << PAGE_SHIFT;
num_bytes = bo->tbo.resource->num_pages << PAGE_SHIFT;
num_loops = 0;
amdgpu_res_first(&bo->tbo.mem, 0, num_bytes, &cursor);
amdgpu_res_first(bo->tbo.resource, 0, num_bytes, &cursor);
while (cursor.remaining) {
num_loops += DIV_ROUND_UP_ULL(cursor.size, max_bytes);
amdgpu_res_next(&cursor, cursor.size);
@ -1981,12 +1988,13 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
}
}
amdgpu_res_first(&bo->tbo.mem, 0, num_bytes, &cursor);
amdgpu_res_first(bo->tbo.resource, 0, num_bytes, &cursor);
while (cursor.remaining) {
uint32_t cur_size = min_t(uint64_t, cursor.size, max_bytes);
uint64_t dst_addr = cursor.start;
dst_addr += amdgpu_ttm_domain_start(adev, bo->tbo.mem.mem_type);
dst_addr += amdgpu_ttm_domain_start(adev,
bo->tbo.resource->mem_type);
amdgpu_emit_fill_buffer(adev, &job->ibs[0], src_data, dst_addr,
cur_size);

Просмотреть файл

@ -1125,9 +1125,8 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo,
ib->length_dw = 16;
if (direct) {
r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv,
true, false,
msecs_to_jiffies(10));
r = dma_resv_wait_timeout(bo->tbo.base.resv, true, false,
msecs_to_jiffies(10));
if (r == 0)
r = -ETIMEDOUT;
if (r < 0)

Просмотреть файл

@ -342,7 +342,7 @@ static void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base,
amdgpu_vm_bo_idle(base);
if (bo->preferred_domains &
amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type))
amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type))
return;
/*
@ -658,10 +658,11 @@ void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev,
if (!bo->parent)
continue;
ttm_bo_move_to_lru_tail(&bo->tbo, &bo->tbo.mem,
ttm_bo_move_to_lru_tail(&bo->tbo, bo->tbo.resource,
&vm->lru_bulk_move);
if (shadow)
ttm_bo_move_to_lru_tail(&shadow->tbo, &shadow->tbo.mem,
ttm_bo_move_to_lru_tail(&shadow->tbo,
shadow->tbo.resource,
&vm->lru_bulk_move);
}
spin_unlock(&adev->mman.bdev.lru_lock);
@ -1858,10 +1859,10 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va,
struct drm_gem_object *gobj = dma_buf->priv;
struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj);
if (abo->tbo.mem.mem_type == TTM_PL_VRAM)
if (abo->tbo.resource->mem_type == TTM_PL_VRAM)
bo = gem_to_amdgpu_bo(gobj);
}
mem = &bo->tbo.mem;
mem = bo->tbo.resource;
if (mem->mem_type == TTM_PL_TT ||
mem->mem_type == AMDGPU_PL_PREEMPT)
pages_addr = bo->tbo.ttm->dma_address;
@ -1922,7 +1923,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va,
* next command submission.
*/
if (bo && bo->tbo.base.resv == vm->root.base.bo->tbo.base.resv) {
uint32_t mem_type = bo->tbo.mem.mem_type;
uint32_t mem_type = bo->tbo.resource->mem_type;
if (!(bo->preferred_domains &
amdgpu_mem_type_to_domain(mem_type)))
@ -2063,13 +2064,12 @@ static void amdgpu_vm_prt_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
unsigned i, shared_count;
int r;
r = dma_resv_get_fences_rcu(resv, &excl,
&shared_count, &shared);
r = dma_resv_get_fences(resv, &excl, &shared_count, &shared);
if (r) {
/* Not enough memory to grab the fence list, as last resort
* block for all the fences to complete.
*/
dma_resv_wait_timeout_rcu(resv, true, false,
dma_resv_wait_timeout(resv, true, false,
MAX_SCHEDULE_TIMEOUT);
return;
}
@ -2681,7 +2681,7 @@ bool amdgpu_vm_evictable(struct amdgpu_bo *bo)
return true;
/* Don't evict VM page tables while they are busy */
if (!dma_resv_test_signaled_rcu(bo->tbo.base.resv, true))
if (!dma_resv_test_signaled(bo->tbo.base.resv, true))
return false;
/* Try to block ongoing updates */
@ -2861,8 +2861,8 @@ void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t min_vm_size,
*/
long amdgpu_vm_wait_idle(struct amdgpu_vm *vm, long timeout)
{
timeout = dma_resv_wait_timeout_rcu(vm->root.base.bo->tbo.base.resv,
true, true, timeout);
timeout = dma_resv_wait_timeout(vm->root.base.bo->tbo.base.resv, true,
true, timeout);
if (timeout <= 0)
return timeout;

Просмотреть файл

@ -23,6 +23,8 @@
*/
#include <linux/dma-mapping.h>
#include <drm/ttm/ttm_range_manager.h>
#include "amdgpu.h"
#include "amdgpu_vm.h"
#include "amdgpu_res_cursor.h"
@ -217,19 +219,20 @@ static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
{
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
struct ttm_resource *mem = &bo->tbo.mem;
struct drm_mm_node *nodes = mem->mm_node;
unsigned pages = mem->num_pages;
struct ttm_resource *res = bo->tbo.resource;
unsigned pages = res->num_pages;
struct drm_mm_node *mm;
u64 usage;
if (amdgpu_gmc_vram_full_visible(&adev->gmc))
return amdgpu_bo_size(bo);
if (mem->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT)
if (res->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT)
return 0;
for (usage = 0; nodes && pages; pages -= nodes->size, nodes++)
usage += amdgpu_vram_mgr_vis_size(adev, nodes);
mm = &container_of(res, struct ttm_range_mgr_node, base)->mm_nodes[0];
for (usage = 0; pages; pages -= mm->size, mm++)
usage += amdgpu_vram_mgr_vis_size(adev, mm);
return usage;
}
@ -365,15 +368,15 @@ static void amdgpu_vram_mgr_virt_start(struct ttm_resource *mem,
static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *tbo,
const struct ttm_place *place,
struct ttm_resource *mem)
struct ttm_resource **res)
{
unsigned long lpfn, num_nodes, pages_per_node, pages_left, pages;
struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
struct amdgpu_device *adev = to_amdgpu_device(mgr);
uint64_t vis_usage = 0, mem_bytes, max_bytes;
struct ttm_range_mgr_node *node;
struct drm_mm *mm = &mgr->mm;
enum drm_mm_insert_mode mode;
struct drm_mm_node *nodes;
unsigned i;
int r;
@ -386,10 +389,10 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
max_bytes -= AMDGPU_VM_RESERVED_VRAM;
/* bail out quickly if there's likely not enough VRAM for this BO */
mem_bytes = (u64)mem->num_pages << PAGE_SHIFT;
mem_bytes = tbo->base.size;
if (atomic64_add_return(mem_bytes, &mgr->usage) > max_bytes) {
atomic64_sub(mem_bytes, &mgr->usage);
return -ENOSPC;
r = -ENOSPC;
goto error_sub;
}
if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
@ -404,22 +407,23 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
#endif
pages_per_node = max_t(uint32_t, pages_per_node,
tbo->page_alignment);
num_nodes = DIV_ROUND_UP(mem->num_pages, pages_per_node);
num_nodes = DIV_ROUND_UP(PFN_UP(mem_bytes), pages_per_node);
}
nodes = kvmalloc_array((uint32_t)num_nodes, sizeof(*nodes),
GFP_KERNEL | __GFP_ZERO);
if (!nodes) {
atomic64_sub(mem_bytes, &mgr->usage);
return -ENOMEM;
node = kvmalloc(struct_size(node, mm_nodes, num_nodes),
GFP_KERNEL | __GFP_ZERO);
if (!node) {
r = -ENOMEM;
goto error_sub;
}
ttm_resource_init(tbo, place, &node->base);
mode = DRM_MM_INSERT_BEST;
if (place->flags & TTM_PL_FLAG_TOPDOWN)
mode = DRM_MM_INSERT_HIGH;
mem->start = 0;
pages_left = mem->num_pages;
pages_left = node->base.num_pages;
/* Limit maximum size to 2GB due to SG table limitations */
pages = min(pages_left, 2UL << (30 - PAGE_SHIFT));
@ -432,8 +436,9 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
if (pages >= pages_per_node)
alignment = pages_per_node;
r = drm_mm_insert_node_in_range(mm, &nodes[i], pages, alignment,
0, place->fpfn, lpfn, mode);
r = drm_mm_insert_node_in_range(mm, &node->mm_nodes[i], pages,
alignment, 0, place->fpfn,
lpfn, mode);
if (unlikely(r)) {
if (pages > pages_per_node) {
if (is_power_of_2(pages))
@ -442,11 +447,11 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
pages = rounddown_pow_of_two(pages);
continue;
}
goto error;
goto error_free;
}
vis_usage += amdgpu_vram_mgr_vis_size(adev, &nodes[i]);
amdgpu_vram_mgr_virt_start(mem, &nodes[i]);
vis_usage += amdgpu_vram_mgr_vis_size(adev, &node->mm_nodes[i]);
amdgpu_vram_mgr_virt_start(&node->base, &node->mm_nodes[i]);
pages_left -= pages;
++i;
@ -456,19 +461,20 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
spin_unlock(&mgr->lock);
if (i == 1)
mem->placement |= TTM_PL_FLAG_CONTIGUOUS;
node->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
atomic64_add(vis_usage, &mgr->vis_usage);
mem->mm_node = nodes;
*res = &node->base;
return 0;
error:
error_free:
while (i--)
drm_mm_remove_node(&nodes[i]);
drm_mm_remove_node(&node->mm_nodes[i]);
spin_unlock(&mgr->lock);
atomic64_sub(mem->num_pages << PAGE_SHIFT, &mgr->usage);
kvfree(node);
kvfree(nodes);
error_sub:
atomic64_sub(mem_bytes, &mgr->usage);
return r;
}
@ -481,24 +487,22 @@ error:
* Free the allocated VRAM again.
*/
static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
struct ttm_resource *mem)
struct ttm_resource *res)
{
struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
struct amdgpu_device *adev = to_amdgpu_device(mgr);
struct drm_mm_node *nodes = mem->mm_node;
uint64_t usage = 0, vis_usage = 0;
unsigned pages = mem->num_pages;
if (!mem->mm_node)
return;
unsigned i, pages;
spin_lock(&mgr->lock);
while (pages) {
pages -= nodes->size;
drm_mm_remove_node(nodes);
usage += nodes->size << PAGE_SHIFT;
vis_usage += amdgpu_vram_mgr_vis_size(adev, nodes);
++nodes;
for (i = 0, pages = res->num_pages; pages;
pages -= node->mm_nodes[i].size, ++i) {
struct drm_mm_node *mm = &node->mm_nodes[i];
drm_mm_remove_node(mm);
usage += mm->size << PAGE_SHIFT;
vis_usage += amdgpu_vram_mgr_vis_size(adev, mm);
}
amdgpu_vram_mgr_do_reserve(man);
spin_unlock(&mgr->lock);
@ -506,8 +510,7 @@ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
atomic64_sub(usage, &mgr->usage);
atomic64_sub(vis_usage, &mgr->vis_usage);
kvfree(mem->mm_node);
mem->mm_node = NULL;
kvfree(node);
}
/**
@ -524,7 +527,7 @@ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
* Allocate and fill a sg table from a VRAM allocation.
*/
int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
struct ttm_resource *mem,
struct ttm_resource *res,
u64 offset, u64 length,
struct device *dev,
enum dma_data_direction dir,
@ -540,7 +543,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
return -ENOMEM;
/* Determine the number of DRM_MM nodes to export */
amdgpu_res_first(mem, offset, length, &cursor);
amdgpu_res_first(res, offset, length, &cursor);
while (cursor.remaining) {
num_entries++;
amdgpu_res_next(&cursor, cursor.size);
@ -560,7 +563,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
* and the number of bytes from it. Access the following
* DRM_MM node(s) if more buffer needs to exported
*/
amdgpu_res_first(mem, offset, length, &cursor);
amdgpu_res_first(res, offset, length, &cursor);
for_each_sgtable_sg((*sgt), sg, i) {
phys_addr_t phys = cursor.start + adev->gmc.aper_base;
size_t size = cursor.size;

Просмотреть файл

@ -29,6 +29,7 @@
#include "amdgpu_object.h"
#include "amdgpu_vm.h"
#include "amdgpu_mn.h"
#include "amdgpu_res_cursor.h"
#include "kfd_priv.h"
#include "kfd_svm.h"
#include "kfd_migrate.h"
@ -205,34 +206,6 @@ svm_migrate_copy_done(struct amdgpu_device *adev, struct dma_fence *mfence)
return r;
}
static uint64_t
svm_migrate_node_physical_addr(struct amdgpu_device *adev,
struct drm_mm_node **mm_node, uint64_t *offset)
{
struct drm_mm_node *node = *mm_node;
uint64_t pos = *offset;
if (node->start == AMDGPU_BO_INVALID_OFFSET) {
pr_debug("drm node is not validated\n");
return 0;
}
pr_debug("vram node start 0x%llx npages 0x%llx\n", node->start,
node->size);
if (pos >= node->size) {
do {
pos -= node->size;
node++;
} while (pos >= node->size);
*mm_node = node;
*offset = pos;
}
return (node->start + pos) << PAGE_SHIFT;
}
unsigned long
svm_migrate_addr_to_pfn(struct amdgpu_device *adev, unsigned long addr)
{
@ -297,11 +270,9 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
{
uint64_t npages = migrate->cpages;
struct device *dev = adev->dev;
struct drm_mm_node *node;
struct amdgpu_res_cursor cursor;
dma_addr_t *src;
uint64_t *dst;
uint64_t vram_addr;
uint64_t offset;
uint64_t i, j;
int r;
@ -317,19 +288,12 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
goto out;
}
node = prange->ttm_res->mm_node;
offset = prange->offset;
vram_addr = svm_migrate_node_physical_addr(adev, &node, &offset);
if (!vram_addr) {
WARN_ONCE(1, "vram node address is 0\n");
r = -ENOMEM;
goto out;
}
amdgpu_res_first(prange->ttm_res, prange->offset << PAGE_SHIFT,
npages << PAGE_SHIFT, &cursor);
for (i = j = 0; i < npages; i++) {
struct page *spage;
dst[i] = vram_addr + (j << PAGE_SHIFT);
dst[i] = cursor.start + (j << PAGE_SHIFT);
migrate->dst[i] = svm_migrate_addr_to_pfn(adev, dst[i]);
svm_migrate_get_vram_page(prange, migrate->dst[i]);
@ -354,18 +318,10 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
mfence);
if (r)
goto out_free_vram_pages;
offset += j;
vram_addr = (node->start + offset) << PAGE_SHIFT;
amdgpu_res_next(&cursor, j << PAGE_SHIFT);
j = 0;
} else {
offset++;
vram_addr += PAGE_SIZE;
}
if (offset >= node->size) {
node++;
pr_debug("next node size 0x%llx\n", node->size);
vram_addr = node->start << PAGE_SHIFT;
offset = 0;
amdgpu_res_next(&cursor, PAGE_SIZE);
}
continue;
}
@ -373,19 +329,15 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
pr_debug("dma mapping src to 0x%llx, page_to_pfn 0x%lx\n",
src[i] >> PAGE_SHIFT, page_to_pfn(spage));
if (j + offset >= node->size - 1 && i < npages - 1) {
if (j >= (cursor.size >> PAGE_SHIFT) - 1 && i < npages - 1) {
r = svm_migrate_copy_memory_gart(adev, src + i - j,
dst + i - j, j + 1,
FROM_RAM_TO_VRAM,
mfence);
if (r)
goto out_free_vram_pages;
node++;
pr_debug("next node size 0x%llx\n", node->size);
vram_addr = node->start << PAGE_SHIFT;
offset = 0;
j = 0;
amdgpu_res_next(&cursor, (j + 1) * PAGE_SIZE);
j= 0;
} else {
j++;
}

Просмотреть файл

@ -409,7 +409,7 @@ svm_range_validate_svm_bo(struct amdgpu_device *adev, struct svm_range *prange)
pr_debug("reuse old bo svms 0x%p [0x%lx 0x%lx]\n",
prange->svms, prange->start, prange->last);
prange->ttm_res = &prange->svm_bo->bo->tbo.mem;
prange->ttm_res = prange->svm_bo->bo->tbo.resource;
return true;
}
@ -515,7 +515,7 @@ svm_range_vram_node_new(struct amdgpu_device *adev, struct svm_range *prange,
svm_bo->bo = bo;
prange->svm_bo = svm_bo;
prange->ttm_res = &bo->tbo.mem;
prange->ttm_res = bo->tbo.resource;
prange->offset = 0;
spin_lock(&svm_bo->list_lock);

Просмотреть файл

@ -8447,9 +8447,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
* deadlock during GPU reset when this fence will not signal
* but we hold reservation lock for the BO.
*/
r = dma_resv_wait_timeout_rcu(abo->tbo.base.resv, true,
false,
msecs_to_jiffies(5000));
r = dma_resv_wait_timeout(abo->tbo.base.resv, true, false,
msecs_to_jiffies(5000));
if (unlikely(r <= 0))
DRM_ERROR("Waiting for fences timed out!");

Просмотреть файл

@ -285,6 +285,16 @@ config DRM_TI_TFP410
help
Texas Instruments TFP410 DVI/HDMI Transmitter driver
config DRM_TI_SN65DSI83
tristate "TI SN65DSI83 and SN65DSI84 DSI to LVDS bridge"
depends on OF
select DRM_KMS_HELPER
select REGMAP_I2C
select DRM_PANEL
select DRM_MIPI_DSI
help
Texas Instruments SN65DSI83 and SN65DSI84 DSI to LVDS Bridge driver
config DRM_TI_SN65DSI86
tristate "TI SN65DSI86 DSI to eDP bridge"
depends on OF

Просмотреть файл

@ -23,6 +23,7 @@ obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
obj-$(CONFIG_DRM_TOSHIBA_TC358768) += tc358768.o
obj-$(CONFIG_DRM_TOSHIBA_TC358775) += tc358775.o
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
obj-$(CONFIG_DRM_TI_SN65DSI83) += ti-sn65dsi83.o
obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o
obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
obj-$(CONFIG_DRM_TI_TPD12S015) += ti-tpd12s015.o

Просмотреть файл

@ -0,0 +1,709 @@
// SPDX-License-Identifier: GPL-2.0
/*
* TI SN65DSI83,84,85 driver
*
* Currently supported:
* - SN65DSI83
* = 1x Single-link DSI ~ 1x Single-link LVDS
* - Supported
* - Single-link LVDS mode tested
* - SN65DSI84
* = 1x Single-link DSI ~ 2x Single-link or 1x Dual-link LVDS
* - Supported
* - Dual-link LVDS mode tested
* - 2x Single-link LVDS mode unsupported
* (should be easy to add by someone who has the HW)
* - SN65DSI85
* = 2x Single-link or 1x Dual-link DSI ~ 2x Single-link or 1x Dual-link LVDS
* - Unsupported
* (should be easy to add by someone who has the HW)
*
* Copyright (C) 2021 Marek Vasut <marex@denx.de>
*
* Based on previous work of:
* Valentin Raevsky <valentin@compulab.co.il>
* Philippe Schenker <philippe.schenker@toradex.com>
*/
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/regmap.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
/* ID registers */
#define REG_ID(n) (0x00 + (n))
/* Reset and clock registers */
#define REG_RC_RESET 0x09
#define REG_RC_RESET_SOFT_RESET BIT(0)
#define REG_RC_LVDS_PLL 0x0a
#define REG_RC_LVDS_PLL_PLL_EN_STAT BIT(7)
#define REG_RC_LVDS_PLL_LVDS_CLK_RANGE(n) (((n) & 0x7) << 1)
#define REG_RC_LVDS_PLL_HS_CLK_SRC_DPHY BIT(0)
#define REG_RC_DSI_CLK 0x0b
#define REG_RC_DSI_CLK_DSI_CLK_DIVIDER(n) (((n) & 0x1f) << 3)
#define REG_RC_DSI_CLK_REFCLK_MULTIPLIER(n) ((n) & 0x3)
#define REG_RC_PLL_EN 0x0d
#define REG_RC_PLL_EN_PLL_EN BIT(0)
/* DSI registers */
#define REG_DSI_LANE 0x10
#define REG_DSI_LANE_LEFT_RIGHT_PIXELS BIT(7) /* DSI85-only */
#define REG_DSI_LANE_DSI_CHANNEL_MODE_DUAL 0 /* DSI85-only */
#define REG_DSI_LANE_DSI_CHANNEL_MODE_2SINGLE BIT(6) /* DSI85-only */
#define REG_DSI_LANE_DSI_CHANNEL_MODE_SINGLE BIT(5)
#define REG_DSI_LANE_CHA_DSI_LANES(n) (((n) & 0x3) << 3)
#define REG_DSI_LANE_CHB_DSI_LANES(n) (((n) & 0x3) << 1)
#define REG_DSI_LANE_SOT_ERR_TOL_DIS BIT(0)
#define REG_DSI_EQ 0x11
#define REG_DSI_EQ_CHA_DSI_DATA_EQ(n) (((n) & 0x3) << 6)
#define REG_DSI_EQ_CHA_DSI_CLK_EQ(n) (((n) & 0x3) << 2)
#define REG_DSI_CLK 0x12
#define REG_DSI_CLK_CHA_DSI_CLK_RANGE(n) ((n) & 0xff)
/* LVDS registers */
#define REG_LVDS_FMT 0x18
#define REG_LVDS_FMT_DE_NEG_POLARITY BIT(7)
#define REG_LVDS_FMT_HS_NEG_POLARITY BIT(6)
#define REG_LVDS_FMT_VS_NEG_POLARITY BIT(5)
#define REG_LVDS_FMT_LVDS_LINK_CFG BIT(4) /* 0:AB 1:A-only */
#define REG_LVDS_FMT_CHA_24BPP_MODE BIT(3)
#define REG_LVDS_FMT_CHB_24BPP_MODE BIT(2)
#define REG_LVDS_FMT_CHA_24BPP_FORMAT1 BIT(1)
#define REG_LVDS_FMT_CHB_24BPP_FORMAT1 BIT(0)
#define REG_LVDS_VCOM 0x19
#define REG_LVDS_VCOM_CHA_LVDS_VOCM BIT(6)
#define REG_LVDS_VCOM_CHB_LVDS_VOCM BIT(4)
#define REG_LVDS_VCOM_CHA_LVDS_VOD_SWING(n) (((n) & 0x3) << 2)
#define REG_LVDS_VCOM_CHB_LVDS_VOD_SWING(n) ((n) & 0x3)
#define REG_LVDS_LANE 0x1a
#define REG_LVDS_LANE_EVEN_ODD_SWAP BIT(6)
#define REG_LVDS_LANE_CHA_REVERSE_LVDS BIT(5)
#define REG_LVDS_LANE_CHB_REVERSE_LVDS BIT(4)
#define REG_LVDS_LANE_CHA_LVDS_TERM BIT(1)
#define REG_LVDS_LANE_CHB_LVDS_TERM BIT(0)
#define REG_LVDS_CM 0x1b
#define REG_LVDS_CM_CHA_LVDS_CM_ADJUST(n) (((n) & 0x3) << 4)
#define REG_LVDS_CM_CHB_LVDS_CM_ADJUST(n) ((n) & 0x3)
/* Video registers */
#define REG_VID_CHA_ACTIVE_LINE_LENGTH_LOW 0x20
#define REG_VID_CHA_ACTIVE_LINE_LENGTH_HIGH 0x21
#define REG_VID_CHA_VERTICAL_DISPLAY_SIZE_LOW 0x24
#define REG_VID_CHA_VERTICAL_DISPLAY_SIZE_HIGH 0x25
#define REG_VID_CHA_SYNC_DELAY_LOW 0x28
#define REG_VID_CHA_SYNC_DELAY_HIGH 0x29
#define REG_VID_CHA_HSYNC_PULSE_WIDTH_LOW 0x2c
#define REG_VID_CHA_HSYNC_PULSE_WIDTH_HIGH 0x2d
#define REG_VID_CHA_VSYNC_PULSE_WIDTH_LOW 0x30
#define REG_VID_CHA_VSYNC_PULSE_WIDTH_HIGH 0x31
#define REG_VID_CHA_HORIZONTAL_BACK_PORCH 0x34
#define REG_VID_CHA_VERTICAL_BACK_PORCH 0x36
#define REG_VID_CHA_HORIZONTAL_FRONT_PORCH 0x38
#define REG_VID_CHA_VERTICAL_FRONT_PORCH 0x3a
#define REG_VID_CHA_TEST_PATTERN 0x3c
/* IRQ registers */
#define REG_IRQ_GLOBAL 0xe0
#define REG_IRQ_GLOBAL_IRQ_EN BIT(0)
#define REG_IRQ_EN 0xe1
#define REG_IRQ_EN_CHA_SYNCH_ERR_EN BIT(7)
#define REG_IRQ_EN_CHA_CRC_ERR_EN BIT(6)
#define REG_IRQ_EN_CHA_UNC_ECC_ERR_EN BIT(5)
#define REG_IRQ_EN_CHA_COR_ECC_ERR_EN BIT(4)
#define REG_IRQ_EN_CHA_LLP_ERR_EN BIT(3)
#define REG_IRQ_EN_CHA_SOT_BIT_ERR_EN BIT(2)
#define REG_IRQ_EN_CHA_PLL_UNLOCK_EN BIT(0)
#define REG_IRQ_STAT 0xe5
#define REG_IRQ_STAT_CHA_SYNCH_ERR BIT(7)
#define REG_IRQ_STAT_CHA_CRC_ERR BIT(6)
#define REG_IRQ_STAT_CHA_UNC_ECC_ERR BIT(5)
#define REG_IRQ_STAT_CHA_COR_ECC_ERR BIT(4)
#define REG_IRQ_STAT_CHA_LLP_ERR BIT(3)
#define REG_IRQ_STAT_CHA_SOT_BIT_ERR BIT(2)
#define REG_IRQ_STAT_CHA_PLL_UNLOCK BIT(0)
enum sn65dsi83_model {
MODEL_SN65DSI83,
MODEL_SN65DSI84,
};
struct sn65dsi83 {
struct drm_bridge bridge;
struct drm_display_mode mode;
struct device *dev;
struct regmap *regmap;
struct device_node *host_node;
struct mipi_dsi_device *dsi;
struct drm_bridge *panel_bridge;
struct gpio_desc *enable_gpio;
int dsi_lanes;
bool lvds_dual_link;
bool lvds_dual_link_even_odd_swap;
bool lvds_format_24bpp;
bool lvds_format_jeida;
};
static const struct regmap_range sn65dsi83_readable_ranges[] = {
regmap_reg_range(REG_ID(0), REG_ID(8)),
regmap_reg_range(REG_RC_LVDS_PLL, REG_RC_DSI_CLK),
regmap_reg_range(REG_RC_PLL_EN, REG_RC_PLL_EN),
regmap_reg_range(REG_DSI_LANE, REG_DSI_CLK),
regmap_reg_range(REG_LVDS_FMT, REG_LVDS_CM),
regmap_reg_range(REG_VID_CHA_ACTIVE_LINE_LENGTH_LOW,
REG_VID_CHA_ACTIVE_LINE_LENGTH_HIGH),
regmap_reg_range(REG_VID_CHA_VERTICAL_DISPLAY_SIZE_LOW,
REG_VID_CHA_VERTICAL_DISPLAY_SIZE_HIGH),
regmap_reg_range(REG_VID_CHA_SYNC_DELAY_LOW,
REG_VID_CHA_SYNC_DELAY_HIGH),
regmap_reg_range(REG_VID_CHA_HSYNC_PULSE_WIDTH_LOW,
REG_VID_CHA_HSYNC_PULSE_WIDTH_HIGH),
regmap_reg_range(REG_VID_CHA_VSYNC_PULSE_WIDTH_LOW,
REG_VID_CHA_VSYNC_PULSE_WIDTH_HIGH),
regmap_reg_range(REG_VID_CHA_HORIZONTAL_BACK_PORCH,
REG_VID_CHA_HORIZONTAL_BACK_PORCH),
regmap_reg_range(REG_VID_CHA_VERTICAL_BACK_PORCH,
REG_VID_CHA_VERTICAL_BACK_PORCH),
regmap_reg_range(REG_VID_CHA_HORIZONTAL_FRONT_PORCH,
REG_VID_CHA_HORIZONTAL_FRONT_PORCH),
regmap_reg_range(REG_VID_CHA_VERTICAL_FRONT_PORCH,
REG_VID_CHA_VERTICAL_FRONT_PORCH),
regmap_reg_range(REG_VID_CHA_TEST_PATTERN, REG_VID_CHA_TEST_PATTERN),
regmap_reg_range(REG_IRQ_GLOBAL, REG_IRQ_EN),
regmap_reg_range(REG_IRQ_STAT, REG_IRQ_STAT),
};
static const struct regmap_access_table sn65dsi83_readable_table = {
.yes_ranges = sn65dsi83_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(sn65dsi83_readable_ranges),
};
static const struct regmap_range sn65dsi83_writeable_ranges[] = {
regmap_reg_range(REG_RC_RESET, REG_RC_DSI_CLK),
regmap_reg_range(REG_RC_PLL_EN, REG_RC_PLL_EN),
regmap_reg_range(REG_DSI_LANE, REG_DSI_CLK),
regmap_reg_range(REG_LVDS_FMT, REG_LVDS_CM),
regmap_reg_range(REG_VID_CHA_ACTIVE_LINE_LENGTH_LOW,
REG_VID_CHA_ACTIVE_LINE_LENGTH_HIGH),
regmap_reg_range(REG_VID_CHA_VERTICAL_DISPLAY_SIZE_LOW,
REG_VID_CHA_VERTICAL_DISPLAY_SIZE_HIGH),
regmap_reg_range(REG_VID_CHA_SYNC_DELAY_LOW,
REG_VID_CHA_SYNC_DELAY_HIGH),
regmap_reg_range(REG_VID_CHA_HSYNC_PULSE_WIDTH_LOW,
REG_VID_CHA_HSYNC_PULSE_WIDTH_HIGH),
regmap_reg_range(REG_VID_CHA_VSYNC_PULSE_WIDTH_LOW,
REG_VID_CHA_VSYNC_PULSE_WIDTH_HIGH),
regmap_reg_range(REG_VID_CHA_HORIZONTAL_BACK_PORCH,
REG_VID_CHA_HORIZONTAL_BACK_PORCH),
regmap_reg_range(REG_VID_CHA_VERTICAL_BACK_PORCH,
REG_VID_CHA_VERTICAL_BACK_PORCH),
regmap_reg_range(REG_VID_CHA_HORIZONTAL_FRONT_PORCH,
REG_VID_CHA_HORIZONTAL_FRONT_PORCH),
regmap_reg_range(REG_VID_CHA_VERTICAL_FRONT_PORCH,
REG_VID_CHA_VERTICAL_FRONT_PORCH),
regmap_reg_range(REG_VID_CHA_TEST_PATTERN, REG_VID_CHA_TEST_PATTERN),
regmap_reg_range(REG_IRQ_GLOBAL, REG_IRQ_EN),
regmap_reg_range(REG_IRQ_STAT, REG_IRQ_STAT),
};
static const struct regmap_access_table sn65dsi83_writeable_table = {
.yes_ranges = sn65dsi83_writeable_ranges,
.n_yes_ranges = ARRAY_SIZE(sn65dsi83_writeable_ranges),
};
static const struct regmap_range sn65dsi83_volatile_ranges[] = {
regmap_reg_range(REG_RC_RESET, REG_RC_RESET),
regmap_reg_range(REG_RC_LVDS_PLL, REG_RC_LVDS_PLL),
regmap_reg_range(REG_IRQ_STAT, REG_IRQ_STAT),
};
static const struct regmap_access_table sn65dsi83_volatile_table = {
.yes_ranges = sn65dsi83_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(sn65dsi83_volatile_ranges),
};
static const struct regmap_config sn65dsi83_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.rd_table = &sn65dsi83_readable_table,
.wr_table = &sn65dsi83_writeable_table,
.volatile_table = &sn65dsi83_volatile_table,
.cache_type = REGCACHE_RBTREE,
.max_register = REG_IRQ_STAT,
};
static struct sn65dsi83 *bridge_to_sn65dsi83(struct drm_bridge *bridge)
{
return container_of(bridge, struct sn65dsi83, bridge);
}
static int sn65dsi83_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
struct device *dev = ctx->dev;
struct mipi_dsi_device *dsi;
struct mipi_dsi_host *host;
int ret = 0;
const struct mipi_dsi_device_info info = {
.type = "sn65dsi83",
.channel = 0,
.node = NULL,
};
host = of_find_mipi_dsi_host_by_node(ctx->host_node);
if (!host) {
dev_err(dev, "failed to find dsi host\n");
return -EPROBE_DEFER;
}
dsi = mipi_dsi_device_register_full(host, &info);
if (IS_ERR(dsi)) {
return dev_err_probe(dev, PTR_ERR(dsi),
"failed to create dsi device\n");
}
ctx->dsi = dsi;
dsi->lanes = ctx->dsi_lanes;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST;
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err(dev, "failed to attach dsi to host\n");
goto err_dsi_attach;
}
return drm_bridge_attach(bridge->encoder, ctx->panel_bridge,
&ctx->bridge, flags);
err_dsi_attach:
mipi_dsi_device_unregister(dsi);
return ret;
}
static void sn65dsi83_pre_enable(struct drm_bridge *bridge)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
/*
* Reset the chip, pull EN line low for t_reset=10ms,
* then high for t_en=1ms.
*/
regcache_mark_dirty(ctx->regmap);
gpiod_set_value(ctx->enable_gpio, 0);
usleep_range(10000, 11000);
gpiod_set_value(ctx->enable_gpio, 1);
usleep_range(1000, 1100);
}
static u8 sn65dsi83_get_lvds_range(struct sn65dsi83 *ctx)
{
/*
* The encoding of the LVDS_CLK_RANGE is as follows:
* 000 - 25 MHz <= LVDS_CLK < 37.5 MHz
* 001 - 37.5 MHz <= LVDS_CLK < 62.5 MHz
* 010 - 62.5 MHz <= LVDS_CLK < 87.5 MHz
* 011 - 87.5 MHz <= LVDS_CLK < 112.5 MHz
* 100 - 112.5 MHz <= LVDS_CLK < 137.5 MHz
* 101 - 137.5 MHz <= LVDS_CLK <= 154 MHz
* which is a range of 12.5MHz..162.5MHz in 50MHz steps, except that
* the ends of the ranges are clamped to the supported range. Since
* sn65dsi83_mode_valid() already filters the valid modes and limits
* the clock to 25..154 MHz, the range calculation can be simplified
* as follows:
*/
int mode_clock = ctx->mode.clock;
if (ctx->lvds_dual_link)
mode_clock /= 2;
return (mode_clock - 12500) / 25000;
}
static u8 sn65dsi83_get_dsi_range(struct sn65dsi83 *ctx)
{
/*
* The encoding of the CHA_DSI_CLK_RANGE is as follows:
* 0x00 through 0x07 - Reserved
* 0x08 - 40 <= DSI_CLK < 45 MHz
* 0x09 - 45 <= DSI_CLK < 50 MHz
* ...
* 0x63 - 495 <= DSI_CLK < 500 MHz
* 0x64 - 500 MHz
* 0x65 through 0xFF - Reserved
* which is DSI clock in 5 MHz steps, clamped to 40..500 MHz.
* The DSI clock are calculated as:
* DSI_CLK = mode clock * bpp / dsi_data_lanes / 2
* the 2 is there because the bus is DDR.
*/
return DIV_ROUND_UP(clamp((unsigned int)ctx->mode.clock *
mipi_dsi_pixel_format_to_bpp(ctx->dsi->format) /
ctx->dsi_lanes / 2, 40000U, 500000U), 5000U);
}
static u8 sn65dsi83_get_dsi_div(struct sn65dsi83 *ctx)
{
/* The divider is (DSI_CLK / LVDS_CLK) - 1, which really is: */
unsigned int dsi_div = mipi_dsi_pixel_format_to_bpp(ctx->dsi->format);
dsi_div /= ctx->dsi_lanes;
if (!ctx->lvds_dual_link)
dsi_div /= 2;
return dsi_div - 1;
}
static void sn65dsi83_enable(struct drm_bridge *bridge)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
unsigned int pval;
u16 val;
int ret;
/* Clear reset, disable PLL */
regmap_write(ctx->regmap, REG_RC_RESET, 0x00);
regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00);
/* Reference clock derived from DSI link clock. */
regmap_write(ctx->regmap, REG_RC_LVDS_PLL,
REG_RC_LVDS_PLL_LVDS_CLK_RANGE(sn65dsi83_get_lvds_range(ctx)) |
REG_RC_LVDS_PLL_HS_CLK_SRC_DPHY);
regmap_write(ctx->regmap, REG_DSI_CLK,
REG_DSI_CLK_CHA_DSI_CLK_RANGE(sn65dsi83_get_dsi_range(ctx)));
regmap_write(ctx->regmap, REG_RC_DSI_CLK,
REG_RC_DSI_CLK_DSI_CLK_DIVIDER(sn65dsi83_get_dsi_div(ctx)));
/* Set number of DSI lanes and LVDS link config. */
regmap_write(ctx->regmap, REG_DSI_LANE,
REG_DSI_LANE_DSI_CHANNEL_MODE_SINGLE |
REG_DSI_LANE_CHA_DSI_LANES(~(ctx->dsi_lanes - 1)) |
/* CHB is DSI85-only, set to default on DSI83/DSI84 */
REG_DSI_LANE_CHB_DSI_LANES(3));
/* No equalization. */
regmap_write(ctx->regmap, REG_DSI_EQ, 0x00);
/* Set up sync signal polarity. */
val = (ctx->mode.flags & DRM_MODE_FLAG_NHSYNC ?
REG_LVDS_FMT_HS_NEG_POLARITY : 0) |
(ctx->mode.flags & DRM_MODE_FLAG_NVSYNC ?
REG_LVDS_FMT_VS_NEG_POLARITY : 0);
/* Set up bits-per-pixel, 18bpp or 24bpp. */
if (ctx->lvds_format_24bpp) {
val |= REG_LVDS_FMT_CHA_24BPP_MODE;
if (ctx->lvds_dual_link)
val |= REG_LVDS_FMT_CHB_24BPP_MODE;
}
/* Set up LVDS format, JEIDA/Format 1 or SPWG/Format 2 */
if (ctx->lvds_format_jeida) {
val |= REG_LVDS_FMT_CHA_24BPP_FORMAT1;
if (ctx->lvds_dual_link)
val |= REG_LVDS_FMT_CHB_24BPP_FORMAT1;
}
/* Set up LVDS output config (DSI84,DSI85) */
if (!ctx->lvds_dual_link)
val |= REG_LVDS_FMT_LVDS_LINK_CFG;
regmap_write(ctx->regmap, REG_LVDS_FMT, val);
regmap_write(ctx->regmap, REG_LVDS_VCOM, 0x05);
regmap_write(ctx->regmap, REG_LVDS_LANE,
(ctx->lvds_dual_link_even_odd_swap ?
REG_LVDS_LANE_EVEN_ODD_SWAP : 0) |
REG_LVDS_LANE_CHA_LVDS_TERM |
REG_LVDS_LANE_CHB_LVDS_TERM);
regmap_write(ctx->regmap, REG_LVDS_CM, 0x00);
val = cpu_to_le16(ctx->mode.hdisplay);
regmap_bulk_write(ctx->regmap, REG_VID_CHA_ACTIVE_LINE_LENGTH_LOW,
&val, 2);
val = cpu_to_le16(ctx->mode.vdisplay);
regmap_bulk_write(ctx->regmap, REG_VID_CHA_VERTICAL_DISPLAY_SIZE_LOW,
&val, 2);
/* 32 + 1 pixel clock to ensure proper operation */
val = cpu_to_le16(32 + 1);
regmap_bulk_write(ctx->regmap, REG_VID_CHA_SYNC_DELAY_LOW, &val, 2);
val = cpu_to_le16(ctx->mode.hsync_end - ctx->mode.hsync_start);
regmap_bulk_write(ctx->regmap, REG_VID_CHA_HSYNC_PULSE_WIDTH_LOW,
&val, 2);
val = cpu_to_le16(ctx->mode.vsync_end - ctx->mode.vsync_start);
regmap_bulk_write(ctx->regmap, REG_VID_CHA_VSYNC_PULSE_WIDTH_LOW,
&val, 2);
regmap_write(ctx->regmap, REG_VID_CHA_HORIZONTAL_BACK_PORCH,
ctx->mode.htotal - ctx->mode.hsync_end);
regmap_write(ctx->regmap, REG_VID_CHA_VERTICAL_BACK_PORCH,
ctx->mode.vtotal - ctx->mode.vsync_end);
regmap_write(ctx->regmap, REG_VID_CHA_HORIZONTAL_FRONT_PORCH,
ctx->mode.hsync_start - ctx->mode.hdisplay);
regmap_write(ctx->regmap, REG_VID_CHA_VERTICAL_FRONT_PORCH,
ctx->mode.vsync_start - ctx->mode.vdisplay);
regmap_write(ctx->regmap, REG_VID_CHA_TEST_PATTERN, 0x00);
/* Enable PLL */
regmap_write(ctx->regmap, REG_RC_PLL_EN, REG_RC_PLL_EN_PLL_EN);
usleep_range(3000, 4000);
ret = regmap_read_poll_timeout(ctx->regmap, REG_RC_LVDS_PLL, pval,
pval & REG_RC_LVDS_PLL_PLL_EN_STAT,
1000, 100000);
if (ret) {
dev_err(ctx->dev, "failed to lock PLL, ret=%i\n", ret);
/* On failure, disable PLL again and exit. */
regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00);
return;
}
/* Trigger reset after CSR register update. */
regmap_write(ctx->regmap, REG_RC_RESET, REG_RC_RESET_SOFT_RESET);
/* Clear all errors that got asserted during initialization. */
regmap_read(ctx->regmap, REG_IRQ_STAT, &pval);
regmap_write(ctx->regmap, REG_IRQ_STAT, pval);
}
static void sn65dsi83_disable(struct drm_bridge *bridge)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
/* Clear reset, disable PLL */
regmap_write(ctx->regmap, REG_RC_RESET, 0x00);
regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00);
}
static void sn65dsi83_post_disable(struct drm_bridge *bridge)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
/* Put the chip in reset, pull EN line low. */
gpiod_set_value(ctx->enable_gpio, 0);
}
static enum drm_mode_status
sn65dsi83_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
/* LVDS output clock range 25..154 MHz */
if (mode->clock < 25000)
return MODE_CLOCK_LOW;
if (mode->clock > 154000)
return MODE_CLOCK_HIGH;
return MODE_OK;
}
static void sn65dsi83_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
const struct drm_display_mode *adj)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
ctx->mode = *adj;
}
static bool sn65dsi83_mode_fixup(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
struct drm_display_mode *adj)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
u32 input_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
struct drm_encoder *encoder = bridge->encoder;
struct drm_device *ddev = encoder->dev;
struct drm_connector *connector;
/* The DSI format is always RGB888_1X24 */
list_for_each_entry(connector, &ddev->mode_config.connector_list, head) {
switch (connector->display_info.bus_formats[0]) {
case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
ctx->lvds_format_24bpp = false;
ctx->lvds_format_jeida = true;
break;
case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
ctx->lvds_format_24bpp = true;
ctx->lvds_format_jeida = true;
break;
case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
ctx->lvds_format_24bpp = true;
ctx->lvds_format_jeida = false;
break;
default:
/*
* Some bridges still don't set the correct
* LVDS bus pixel format, use SPWG24 default
* format until those are fixed.
*/
ctx->lvds_format_24bpp = true;
ctx->lvds_format_jeida = false;
dev_warn(ctx->dev,
"Unsupported LVDS bus format 0x%04x, please check output bridge driver. Falling back to SPWG24.\n",
connector->display_info.bus_formats[0]);
break;
}
drm_display_info_set_bus_formats(&connector->display_info,
&input_bus_format, 1);
}
return true;
}
static const struct drm_bridge_funcs sn65dsi83_funcs = {
.attach = sn65dsi83_attach,
.pre_enable = sn65dsi83_pre_enable,
.enable = sn65dsi83_enable,
.disable = sn65dsi83_disable,
.post_disable = sn65dsi83_post_disable,
.mode_valid = sn65dsi83_mode_valid,
.mode_set = sn65dsi83_mode_set,
.mode_fixup = sn65dsi83_mode_fixup,
};
static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model)
{
struct drm_bridge *panel_bridge;
struct device *dev = ctx->dev;
struct device_node *endpoint;
struct drm_panel *panel;
int ret;
endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
ctx->dsi_lanes = of_property_count_u32_elems(endpoint, "data-lanes");
ctx->host_node = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4)
return -EINVAL;
if (!ctx->host_node)
return -ENODEV;
ctx->lvds_dual_link = false;
ctx->lvds_dual_link_even_odd_swap = false;
if (model != MODEL_SN65DSI83) {
struct device_node *port2, *port3;
int dual_link;
port2 = of_graph_get_port_by_id(dev->of_node, 2);
port3 = of_graph_get_port_by_id(dev->of_node, 3);
dual_link = drm_of_lvds_get_dual_link_pixel_order(port2, port3);
of_node_put(port2);
of_node_put(port3);
if (dual_link == DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS) {
ctx->lvds_dual_link = true;
/* Odd pixels to LVDS Channel A, even pixels to B */
ctx->lvds_dual_link_even_odd_swap = false;
} else if (dual_link == DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS) {
ctx->lvds_dual_link = true;
/* Even pixels to LVDS Channel A, odd pixels to B */
ctx->lvds_dual_link_even_odd_swap = true;
}
}
ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, &panel_bridge);
if (ret < 0)
return ret;
if (panel) {
panel_bridge = devm_drm_panel_bridge_add(dev, panel);
if (IS_ERR(panel_bridge))
return PTR_ERR(panel_bridge);
}
ctx->panel_bridge = panel_bridge;
return 0;
}
static int sn65dsi83_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
enum sn65dsi83_model model;
struct sn65dsi83 *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->dev = dev;
if (dev->of_node) {
model = (enum sn65dsi83_model)(uintptr_t)
of_device_get_match_data(dev);
} else {
model = id->driver_data;
}
ctx->enable_gpio = devm_gpiod_get(ctx->dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(ctx->enable_gpio))
return PTR_ERR(ctx->enable_gpio);
ret = sn65dsi83_parse_dt(ctx, model);
if (ret)
return ret;
ctx->regmap = devm_regmap_init_i2c(client, &sn65dsi83_regmap_config);
if (IS_ERR(ctx->regmap))
return PTR_ERR(ctx->regmap);
dev_set_drvdata(dev, ctx);
i2c_set_clientdata(client, ctx);
ctx->bridge.funcs = &sn65dsi83_funcs;
ctx->bridge.of_node = dev->of_node;
drm_bridge_add(&ctx->bridge);
return 0;
}
static int sn65dsi83_remove(struct i2c_client *client)
{
struct sn65dsi83 *ctx = i2c_get_clientdata(client);
mipi_dsi_detach(ctx->dsi);
mipi_dsi_device_unregister(ctx->dsi);
drm_bridge_remove(&ctx->bridge);
of_node_put(ctx->host_node);
return 0;
}
static struct i2c_device_id sn65dsi83_id[] = {
{ "ti,sn65dsi83", MODEL_SN65DSI83 },
{ "ti,sn65dsi84", MODEL_SN65DSI84 },
{},
};
MODULE_DEVICE_TABLE(i2c, sn65dsi83_id);
static const struct of_device_id sn65dsi83_match_table[] = {
{ .compatible = "ti,sn65dsi83", .data = (void *)MODEL_SN65DSI83 },
{ .compatible = "ti,sn65dsi84", .data = (void *)MODEL_SN65DSI84 },
{},
};
MODULE_DEVICE_TABLE(of, sn65dsi83_match_table);
static struct i2c_driver sn65dsi83_driver = {
.probe = sn65dsi83_probe,
.remove = sn65dsi83_remove,
.id_table = sn65dsi83_id,
.driver = {
.name = "sn65dsi83",
.of_match_table = sn65dsi83_match_table,
},
};
module_i2c_driver(sn65dsi83_driver);
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
MODULE_DESCRIPTION("TI SN65DSI83 DSI to LVDS bridge driver");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -28,6 +28,7 @@
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include <linux/dma-buf-map.h>
#include <linux/export.h>
#include <linux/highmem.h>
#include <linux/mem_encrypt.h>
@ -35,6 +36,9 @@
#include <drm/drm_cache.h>
/* A small bounce buffer that fits on the stack. */
#define MEMCPY_BOUNCE_SIZE 128
#if defined(CONFIG_X86)
#include <asm/smp.h>
@ -209,3 +213,147 @@ bool drm_need_swiotlb(int dma_bits)
return max_iomem > ((u64)1 << dma_bits);
}
EXPORT_SYMBOL(drm_need_swiotlb);
static void memcpy_fallback(struct dma_buf_map *dst,
const struct dma_buf_map *src,
unsigned long len)
{
if (!dst->is_iomem && !src->is_iomem) {
memcpy(dst->vaddr, src->vaddr, len);
} else if (!src->is_iomem) {
dma_buf_map_memcpy_to(dst, src->vaddr, len);
} else if (!dst->is_iomem) {
memcpy_fromio(dst->vaddr, src->vaddr_iomem, len);
} else {
/*
* Bounce size is not performance tuned, but using a
* bounce buffer like this is significantly faster than
* resorting to ioreadxx() + iowritexx().
*/
char bounce[MEMCPY_BOUNCE_SIZE];
void __iomem *_src = src->vaddr_iomem;
void __iomem *_dst = dst->vaddr_iomem;
while (len >= MEMCPY_BOUNCE_SIZE) {
memcpy_fromio(bounce, _src, MEMCPY_BOUNCE_SIZE);
memcpy_toio(_dst, bounce, MEMCPY_BOUNCE_SIZE);
_src += MEMCPY_BOUNCE_SIZE;
_dst += MEMCPY_BOUNCE_SIZE;
len -= MEMCPY_BOUNCE_SIZE;
}
if (len) {
memcpy_fromio(bounce, _src, MEMCPY_BOUNCE_SIZE);
memcpy_toio(_dst, bounce, MEMCPY_BOUNCE_SIZE);
}
}
}
#ifdef CONFIG_X86
static DEFINE_STATIC_KEY_FALSE(has_movntdqa);
static void __memcpy_ntdqa(void *dst, const void *src, unsigned long len)
{
kernel_fpu_begin();
while (len >= 4) {
asm("movntdqa (%0), %%xmm0\n"
"movntdqa 16(%0), %%xmm1\n"
"movntdqa 32(%0), %%xmm2\n"
"movntdqa 48(%0), %%xmm3\n"
"movaps %%xmm0, (%1)\n"
"movaps %%xmm1, 16(%1)\n"
"movaps %%xmm2, 32(%1)\n"
"movaps %%xmm3, 48(%1)\n"
:: "r" (src), "r" (dst) : "memory");
src += 64;
dst += 64;
len -= 4;
}
while (len--) {
asm("movntdqa (%0), %%xmm0\n"
"movaps %%xmm0, (%1)\n"
:: "r" (src), "r" (dst) : "memory");
src += 16;
dst += 16;
}
kernel_fpu_end();
}
/*
* __drm_memcpy_from_wc copies @len bytes from @src to @dst using
* non-temporal instructions where available. Note that all arguments
* (@src, @dst) must be aligned to 16 bytes and @len must be a multiple
* of 16.
*/
static void __drm_memcpy_from_wc(void *dst, const void *src, unsigned long len)
{
if (unlikely(((unsigned long)dst | (unsigned long)src | len) & 15))
memcpy(dst, src, len);
else if (likely(len))
__memcpy_ntdqa(dst, src, len >> 4);
}
/**
* drm_memcpy_from_wc - Perform the fastest available memcpy from a source
* that may be WC.
* @dst: The destination pointer
* @src: The source pointer
* @len: The size of the area o transfer in bytes
*
* Tries an arch optimized memcpy for prefetching reading out of a WC region,
* and if no such beast is available, falls back to a normal memcpy.
*/
void drm_memcpy_from_wc(struct dma_buf_map *dst,
const struct dma_buf_map *src,
unsigned long len)
{
if (WARN_ON(in_interrupt())) {
memcpy_fallback(dst, src, len);
return;
}
if (static_branch_likely(&has_movntdqa)) {
__drm_memcpy_from_wc(dst->is_iomem ?
(void __force *)dst->vaddr_iomem :
dst->vaddr,
src->is_iomem ?
(void const __force *)src->vaddr_iomem :
src->vaddr,
len);
return;
}
memcpy_fallback(dst, src, len);
}
EXPORT_SYMBOL(drm_memcpy_from_wc);
/*
* drm_memcpy_init_early - One time initialization of the WC memcpy code
*/
void drm_memcpy_init_early(void)
{
/*
* Some hypervisors (e.g. KVM) don't support VEX-prefix instructions
* emulation. So don't enable movntdqa in hypervisor guest.
*/
if (static_cpu_has(X86_FEATURE_XMM4_1) &&
!boot_cpu_has(X86_FEATURE_HYPERVISOR))
static_branch_enable(&has_movntdqa);
}
#else
void drm_memcpy_from_wc(struct dma_buf_map *dst,
const struct dma_buf_map *src,
unsigned long len)
{
WARN_ON(in_interrupt());
memcpy_fallback(dst, src, len);
}
EXPORT_SYMBOL(drm_memcpy_from_wc);
void drm_memcpy_init_early(void)
{
}
#endif /* CONFIG_X86 */

Просмотреть файл

@ -35,6 +35,7 @@
#include <linux/slab.h>
#include <linux/srcu.h>
#include <drm/drm_cache.h>
#include <drm/drm_client.h>
#include <drm/drm_color_mgmt.h>
#include <drm/drm_drv.h>
@ -1041,6 +1042,7 @@ static int __init drm_core_init(void)
drm_connector_ida_init();
idr_init(&drm_minors_idr);
drm_memcpy_init_early();
ret = drm_sysfs_init();
if (ret < 0) {

Просмотреть файл

@ -770,8 +770,7 @@ long drm_gem_dma_resv_wait(struct drm_file *filep, u32 handle,
return -EINVAL;
}
ret = dma_resv_wait_timeout_rcu(obj->resv, wait_all,
true, timeout);
ret = dma_resv_wait_timeout(obj->resv, wait_all, true, timeout);
if (ret == 0)
ret = -ETIME;
else if (ret > 0)
@ -1375,12 +1374,12 @@ int drm_gem_fence_array_add_implicit(struct xarray *fence_array,
if (!write) {
struct dma_fence *fence =
dma_resv_get_excl_rcu(obj->resv);
dma_resv_get_excl_unlocked(obj->resv);
return drm_gem_fence_array_add(fence_array, fence);
}
ret = dma_resv_get_fences_rcu(obj->resv, NULL,
ret = dma_resv_get_fences(obj->resv, NULL,
&fence_count, &fences);
if (ret || !fence_count)
return ret;

Просмотреть файл

@ -147,7 +147,7 @@ int drm_gem_plane_helper_prepare_fb(struct drm_plane *plane, struct drm_plane_st
return 0;
obj = drm_gem_fb_get_obj(state->fb, 0);
fence = dma_resv_get_excl_rcu(obj->resv);
fence = dma_resv_get_excl_unlocked(obj->resv);
drm_atomic_set_fence_for_plane(state, fence);
return 0;

Просмотреть файл

@ -104,8 +104,7 @@ error:
* @size: size of the object to allocate
*
* This function creates a CMA GEM object and allocates a contiguous chunk of
* memory as backing store. The backing memory has the writecombine attribute
* set.
* memory as backing store.
*
* Returns:
* A struct drm_gem_cma_object * on success or an ERR_PTR()-encoded negative

Просмотреть файл

@ -40,12 +40,12 @@ void drm_gem_ttm_print_info(struct drm_printer *p, unsigned int indent,
const struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem);
drm_printf_indent(p, indent, "placement=");
drm_print_bits(p, bo->mem.placement, plname, ARRAY_SIZE(plname));
drm_print_bits(p, bo->resource->placement, plname, ARRAY_SIZE(plname));
drm_printf(p, "\n");
if (bo->mem.bus.is_iomem)
if (bo->resource->bus.is_iomem)
drm_printf_indent(p, indent, "bus.offset=%lx\n",
(unsigned long)bo->mem.bus.offset);
(unsigned long)bo->resource->bus.offset);
}
EXPORT_SYMBOL(drm_gem_ttm_print_info);

Просмотреть файл

@ -17,6 +17,8 @@
#include <drm/drm_prime.h>
#include <drm/drm_simple_kms_helper.h>
#include <drm/ttm/ttm_range_manager.h>
static const struct drm_gem_object_funcs drm_gem_vram_object_funcs;
/**
@ -248,10 +250,11 @@ EXPORT_SYMBOL(drm_gem_vram_put);
static u64 drm_gem_vram_pg_offset(struct drm_gem_vram_object *gbo)
{
/* Keep TTM behavior for now, remove when drivers are audited */
if (WARN_ON_ONCE(!gbo->bo.mem.mm_node))
if (WARN_ON_ONCE(!gbo->bo.resource ||
gbo->bo.resource->mem_type == TTM_PL_SYSTEM))
return 0;
return gbo->bo.mem.start;
return gbo->bo.resource->start;
}
/**

Просмотреть файл

@ -390,14 +390,12 @@ int etnaviv_gem_cpu_prep(struct drm_gem_object *obj, u32 op,
}
if (op & ETNA_PREP_NOSYNC) {
if (!dma_resv_test_signaled_rcu(obj->resv,
write))
if (!dma_resv_test_signaled(obj->resv, write))
return -EBUSY;
} else {
unsigned long remain = etnaviv_timeout_to_jiffies(timeout);
ret = dma_resv_wait_timeout_rcu(obj->resv,
write, true, remain);
ret = dma_resv_wait_timeout(obj->resv, write, true, remain);
if (ret <= 0)
return ret == 0 ? -ETIMEDOUT : ret;
}
@ -461,7 +459,7 @@ static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
off, etnaviv_obj->vaddr, obj->size);
rcu_read_lock();
fobj = rcu_dereference(robj->fence);
fobj = dma_resv_shared_list(robj);
if (fobj) {
unsigned int i, shared_count = fobj->shared_count;
@ -471,7 +469,7 @@ static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
}
}
fence = rcu_dereference(robj->fence_excl);
fence = dma_resv_excl_fence(robj);
if (fence)
etnaviv_gem_describe_fence(fence, "Exclusive", m);
rcu_read_unlock();

Просмотреть файл

@ -189,13 +189,13 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit)
continue;
if (bo->flags & ETNA_SUBMIT_BO_WRITE) {
ret = dma_resv_get_fences_rcu(robj, &bo->excl,
&bo->nr_shared,
&bo->shared);
ret = dma_resv_get_fences(robj, &bo->excl,
&bo->nr_shared,
&bo->shared);
if (ret)
return ret;
} else {
bo->excl = dma_resv_get_excl_rcu(robj);
bo->excl = dma_resv_get_excl_unlocked(robj);
}
}

Просмотреть файл

@ -344,7 +344,7 @@ static void decon_win_set_colkey(struct decon_context *ctx, unsigned int win)
}
/**
* shadow_protect_win() - disable updating values from shadow registers at vsync
* decon_shadow_protect_win() - disable updating values from shadow registers at vsync
*
* @ctx: display and enhancement controller context
* @win: window to protect registers for

Просмотреть файл

@ -88,7 +88,7 @@ void exynos_drm_ipp_unregister(struct device *dev,
}
/**
* exynos_drm_ipp_ioctl_get_res_ioctl - enumerate all ipp modules
* exynos_drm_ipp_get_res_ioctl - enumerate all ipp modules
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info
@ -136,7 +136,7 @@ static inline struct exynos_drm_ipp *__ipp_get(uint32_t id)
}
/**
* exynos_drm_ipp_ioctl_get_caps - get ipp module capabilities and formats
* exynos_drm_ipp_get_caps_ioctl - get ipp module capabilities and formats
* @dev: DRM device
* @data: ioctl data
* @file_priv: DRM file info

Просмотреть файл

@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
hyperv_drm-y := \
hyperv_drm_drv.o \
hyperv_drm_modeset.o \
hyperv_drm_proto.o
obj-$(CONFIG_DRM_HYPERV) += hyperv_drm.o

Просмотреть файл

@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2021 Microsoft
*/
#ifndef _HYPERV_DRM_H_
#define _HYPERV_DRM_H_
#define VMBUS_MAX_PACKET_SIZE 0x4000
struct hyperv_drm_device {
/* drm */
struct drm_device dev;
struct drm_simple_display_pipe pipe;
struct drm_connector connector;
/* mode */
u32 screen_width_max;
u32 screen_height_max;
u32 preferred_width;
u32 preferred_height;
u32 screen_depth;
/* hw */
struct resource *mem;
void __iomem *vram;
unsigned long fb_base;
unsigned long fb_size;
struct completion wait;
u32 synthvid_version;
u32 mmio_megabytes;
bool dirt_needed;
u8 init_buf[VMBUS_MAX_PACKET_SIZE];
u8 recv_buf[VMBUS_MAX_PACKET_SIZE];
struct hv_device *hdev;
};
#define to_hv(_dev) container_of(_dev, struct hyperv_drm_device, dev)
/* hyperv_drm_modeset */
int hyperv_mode_config_init(struct hyperv_drm_device *hv);
/* hyperv_drm_proto */
int hyperv_update_vram_location(struct hv_device *hdev, phys_addr_t vram_pp);
int hyperv_update_situation(struct hv_device *hdev, u8 active, u32 bpp,
u32 w, u32 h, u32 pitch);
int hyperv_update_dirt(struct hv_device *hdev, struct drm_rect *rect);
int hyperv_connect_vsp(struct hv_device *hdev);
#endif

Просмотреть файл

@ -0,0 +1,311 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2021 Microsoft
*/
#include <linux/efi.h>
#include <linux/hyperv.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "hyperv_drm.h"
#define DRIVER_NAME "hyperv_drm"
#define DRIVER_DESC "DRM driver for Hyper-V synthetic video device"
#define DRIVER_DATE "2020"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
#define PCI_VENDOR_ID_MICROSOFT 0x1414
#define PCI_DEVICE_ID_HYPERV_VIDEO 0x5353
DEFINE_DRM_GEM_FOPS(hv_fops);
static struct drm_driver hyperv_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.fops = &hv_fops,
DRM_GEM_SHMEM_DRIVER_OPS,
};
static int hyperv_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
return 0;
}
static void hyperv_pci_remove(struct pci_dev *pdev)
{
}
static const struct pci_device_id hyperv_pci_tbl[] = {
{
.vendor = PCI_VENDOR_ID_MICROSOFT,
.device = PCI_DEVICE_ID_HYPERV_VIDEO,
},
{ /* end of list */ }
};
/*
* PCI stub to support gen1 VM.
*/
static struct pci_driver hyperv_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = hyperv_pci_tbl,
.probe = hyperv_pci_probe,
.remove = hyperv_pci_remove,
};
static int hyperv_setup_gen1(struct hyperv_drm_device *hv)
{
struct drm_device *dev = &hv->dev;
struct pci_dev *pdev;
int ret;
pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
if (!pdev) {
drm_err(dev, "Unable to find PCI Hyper-V video\n");
return -ENODEV;
}
ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "hypervdrmfb");
if (ret) {
drm_err(dev, "Not able to remove boot fb\n");
return ret;
}
if (pci_request_region(pdev, 0, DRIVER_NAME) != 0)
drm_warn(dev, "Cannot request framebuffer, boot fb still active?\n");
if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0) {
drm_err(dev, "Resource at bar 0 is not IORESOURCE_MEM\n");
ret = -ENODEV;
goto error;
}
hv->fb_base = pci_resource_start(pdev, 0);
hv->fb_size = pci_resource_len(pdev, 0);
if (!hv->fb_base) {
drm_err(dev, "Resource not available\n");
ret = -ENODEV;
goto error;
}
hv->fb_size = min(hv->fb_size,
(unsigned long)(hv->mmio_megabytes * 1024 * 1024));
hv->vram = devm_ioremap(&pdev->dev, hv->fb_base, hv->fb_size);
if (!hv->vram) {
drm_err(dev, "Failed to map vram\n");
ret = -ENOMEM;
}
error:
pci_dev_put(pdev);
return ret;
}
static int hyperv_setup_gen2(struct hyperv_drm_device *hv,
struct hv_device *hdev)
{
struct drm_device *dev = &hv->dev;
int ret;
drm_aperture_remove_conflicting_framebuffers(screen_info.lfb_base,
screen_info.lfb_size,
false,
"hypervdrmfb");
hv->fb_size = (unsigned long)hv->mmio_megabytes * 1024 * 1024;
ret = vmbus_allocate_mmio(&hv->mem, hdev, 0, -1, hv->fb_size, 0x100000,
true);
if (ret) {
drm_err(dev, "Failed to allocate mmio\n");
return -ENOMEM;
}
/*
* Map the VRAM cacheable for performance. This is also required for VM
* connect to display properly for ARM64 Linux VM, as the host also maps
* the VRAM cacheable.
*/
hv->vram = ioremap_cache(hv->mem->start, hv->fb_size);
if (!hv->vram) {
drm_err(dev, "Failed to map vram\n");
ret = -ENOMEM;
goto error;
}
hv->fb_base = hv->mem->start;
return 0;
error:
vmbus_free_mmio(hv->mem->start, hv->fb_size);
return ret;
}
static int hyperv_vmbus_probe(struct hv_device *hdev,
const struct hv_vmbus_device_id *dev_id)
{
struct hyperv_drm_device *hv;
struct drm_device *dev;
int ret;
hv = devm_drm_dev_alloc(&hdev->device, &hyperv_driver,
struct hyperv_drm_device, dev);
if (IS_ERR(hv))
return PTR_ERR(hv);
dev = &hv->dev;
init_completion(&hv->wait);
hv_set_drvdata(hdev, hv);
hv->hdev = hdev;
ret = hyperv_connect_vsp(hdev);
if (ret) {
drm_err(dev, "Failed to connect to vmbus.\n");
goto err_hv_set_drv_data;
}
if (efi_enabled(EFI_BOOT))
ret = hyperv_setup_gen2(hv, hdev);
else
ret = hyperv_setup_gen1(hv);
if (ret)
goto err_vmbus_close;
/*
* Should be done only once during init and resume. Failing to update
* vram location is not fatal. Device will update dirty area till
* preferred resolution only.
*/
ret = hyperv_update_vram_location(hdev, hv->fb_base);
if (ret)
drm_warn(dev, "Failed to update vram location.\n");
hv->dirt_needed = true;
ret = hyperv_mode_config_init(hv);
if (ret)
goto err_vmbus_close;
ret = drm_dev_register(dev, 0);
if (ret) {
drm_err(dev, "Failed to register drm driver.\n");
goto err_vmbus_close;
}
drm_fbdev_generic_setup(dev, 0);
return 0;
err_vmbus_close:
vmbus_close(hdev->channel);
err_hv_set_drv_data:
hv_set_drvdata(hdev, NULL);
return ret;
}
static int hyperv_vmbus_remove(struct hv_device *hdev)
{
struct drm_device *dev = hv_get_drvdata(hdev);
struct hyperv_drm_device *hv = to_hv(dev);
drm_dev_unplug(dev);
drm_atomic_helper_shutdown(dev);
vmbus_close(hdev->channel);
hv_set_drvdata(hdev, NULL);
vmbus_free_mmio(hv->mem->start, hv->fb_size);
return 0;
}
static int hyperv_vmbus_suspend(struct hv_device *hdev)
{
struct drm_device *dev = hv_get_drvdata(hdev);
int ret;
ret = drm_mode_config_helper_suspend(dev);
if (ret)
return ret;
vmbus_close(hdev->channel);
return 0;
}
static int hyperv_vmbus_resume(struct hv_device *hdev)
{
struct drm_device *dev = hv_get_drvdata(hdev);
struct hyperv_drm_device *hv = to_hv(dev);
int ret;
ret = hyperv_connect_vsp(hdev);
if (ret)
return ret;
ret = hyperv_update_vram_location(hdev, hv->fb_base);
if (ret)
return ret;
return drm_mode_config_helper_resume(dev);
}
static const struct hv_vmbus_device_id hyperv_vmbus_tbl[] = {
/* Synthetic Video Device GUID */
{HV_SYNTHVID_GUID},
{}
};
static struct hv_driver hyperv_hv_driver = {
.name = KBUILD_MODNAME,
.id_table = hyperv_vmbus_tbl,
.probe = hyperv_vmbus_probe,
.remove = hyperv_vmbus_remove,
.suspend = hyperv_vmbus_suspend,
.resume = hyperv_vmbus_resume,
.driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
static int __init hyperv_init(void)
{
int ret;
ret = pci_register_driver(&hyperv_pci_driver);
if (ret != 0)
return ret;
return vmbus_driver_register(&hyperv_hv_driver);
}
static void __exit hyperv_exit(void)
{
vmbus_driver_unregister(&hyperv_hv_driver);
pci_unregister_driver(&hyperv_pci_driver);
}
module_init(hyperv_init);
module_exit(hyperv_exit);
MODULE_DEVICE_TABLE(pci, hyperv_pci_tbl);
MODULE_DEVICE_TABLE(vmbus, hyperv_vmbus_tbl);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Deepak Rawat <drawat.floss@gmail.com>");
MODULE_DESCRIPTION("DRM driver for Hyper-V synthetic video device");

Просмотреть файл

@ -0,0 +1,231 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2021 Microsoft
*/
#include <linux/hyperv.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "hyperv_drm.h"
static int hyperv_blit_to_vram_rect(struct drm_framebuffer *fb,
const struct dma_buf_map *map,
struct drm_rect *rect)
{
struct hyperv_drm_device *hv = to_hv(fb->dev);
void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
int idx;
if (!drm_dev_enter(&hv->dev, &idx))
return -ENODEV;
drm_fb_memcpy_dstclip(hv->vram, fb->pitches[0], vmap, fb, rect);
drm_dev_exit(idx);
return 0;
}
static int hyperv_blit_to_vram_fullscreen(struct drm_framebuffer *fb, const struct dma_buf_map *map)
{
struct drm_rect fullscreen = {
.x1 = 0,
.x2 = fb->width,
.y1 = 0,
.y2 = fb->height,
};
return hyperv_blit_to_vram_rect(fb, map, &fullscreen);
}
static int hyperv_connector_get_modes(struct drm_connector *connector)
{
struct hyperv_drm_device *hv = to_hv(connector->dev);
int count;
count = drm_add_modes_noedid(connector,
connector->dev->mode_config.max_width,
connector->dev->mode_config.max_height);
drm_set_preferred_mode(connector, hv->preferred_width,
hv->preferred_height);
return count;
}
static const struct drm_connector_helper_funcs hyperv_connector_helper_funcs = {
.get_modes = hyperv_connector_get_modes,
};
static const struct drm_connector_funcs hyperv_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static inline int hyperv_conn_init(struct hyperv_drm_device *hv)
{
drm_connector_helper_add(&hv->connector, &hyperv_connector_helper_funcs);
return drm_connector_init(&hv->dev, &hv->connector,
&hyperv_connector_funcs,
DRM_MODE_CONNECTOR_VIRTUAL);
}
static int hyperv_check_size(struct hyperv_drm_device *hv, int w, int h,
struct drm_framebuffer *fb)
{
u32 pitch = w * (hv->screen_depth / 8);
if (fb)
pitch = fb->pitches[0];
if (pitch * h > hv->fb_size)
return -EINVAL;
return 0;
}
static void hyperv_pipe_enable(struct drm_simple_display_pipe *pipe,
struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state)
{
struct hyperv_drm_device *hv = to_hv(pipe->crtc.dev);
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
hyperv_update_situation(hv->hdev, 1, hv->screen_depth,
crtc_state->mode.hdisplay,
crtc_state->mode.vdisplay,
plane_state->fb->pitches[0]);
hyperv_blit_to_vram_fullscreen(plane_state->fb, &shadow_plane_state->map[0]);
}
static int hyperv_pipe_check(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state,
struct drm_crtc_state *crtc_state)
{
struct hyperv_drm_device *hv = to_hv(pipe->crtc.dev);
struct drm_framebuffer *fb = plane_state->fb;
if (fb->format->format != DRM_FORMAT_XRGB8888)
return -EINVAL;
if (fb->pitches[0] * fb->height > hv->fb_size)
return -EINVAL;
return 0;
}
static void hyperv_pipe_update(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *old_state)
{
struct hyperv_drm_device *hv = to_hv(pipe->crtc.dev);
struct drm_plane_state *state = pipe->plane.state;
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
struct drm_rect rect;
if (drm_atomic_helper_damage_merged(old_state, state, &rect)) {
hyperv_blit_to_vram_rect(state->fb, &shadow_plane_state->map[0], &rect);
hyperv_update_dirt(hv->hdev, &rect);
}
}
static const struct drm_simple_display_pipe_funcs hyperv_pipe_funcs = {
.enable = hyperv_pipe_enable,
.check = hyperv_pipe_check,
.update = hyperv_pipe_update,
DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
};
static const uint32_t hyperv_formats[] = {
DRM_FORMAT_XRGB8888,
};
static const uint64_t hyperv_modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
};
static inline int hyperv_pipe_init(struct hyperv_drm_device *hv)
{
int ret;
ret = drm_simple_display_pipe_init(&hv->dev,
&hv->pipe,
&hyperv_pipe_funcs,
hyperv_formats,
ARRAY_SIZE(hyperv_formats),
NULL,
&hv->connector);
if (ret)
return ret;
drm_plane_enable_fb_damage_clips(&hv->pipe.plane);
return 0;
}
static enum drm_mode_status
hyperv_mode_valid(struct drm_device *dev,
const struct drm_display_mode *mode)
{
struct hyperv_drm_device *hv = to_hv(dev);
if (hyperv_check_size(hv, mode->hdisplay, mode->vdisplay, NULL))
return MODE_BAD;
return MODE_OK;
}
static const struct drm_mode_config_funcs hyperv_mode_config_funcs = {
.fb_create = drm_gem_fb_create_with_dirty,
.mode_valid = hyperv_mode_valid,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
int hyperv_mode_config_init(struct hyperv_drm_device *hv)
{
struct drm_device *dev = &hv->dev;
int ret;
ret = drmm_mode_config_init(dev);
if (ret) {
drm_err(dev, "Failed to initialized mode setting.\n");
return ret;
}
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
dev->mode_config.max_width = hv->screen_width_max;
dev->mode_config.max_height = hv->screen_height_max;
dev->mode_config.preferred_depth = hv->screen_depth;
dev->mode_config.prefer_shadow = 0;
dev->mode_config.funcs = &hyperv_mode_config_funcs;
ret = hyperv_conn_init(hv);
if (ret) {
drm_err(dev, "Failed to initialized connector.\n");
return ret;
}
ret = hyperv_pipe_init(hv);
if (ret) {
drm_err(dev, "Failed to initialized pipe.\n");
return ret;
}
drm_mode_config_reset(dev);
return 0;
}

Просмотреть файл

@ -0,0 +1,485 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2021 Microsoft
*
* Portions of this code is derived from hyperv_fb.c
*/
#include <linux/hyperv.h>
#include <drm/drm_print.h>
#include <drm/drm_simple_kms_helper.h>
#include "hyperv_drm.h"
#define VMBUS_RING_BUFSIZE (256 * 1024)
#define VMBUS_VSP_TIMEOUT (10 * HZ)
#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16)
#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
#define SYNTHVID_DEPTH_WIN7 16
#define SYNTHVID_DEPTH_WIN8 32
#define SYNTHVID_FB_SIZE_WIN7 (4 * 1024 * 1024)
#define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
#define SYNTHVID_WIDTH_MAX_WIN7 1600
#define SYNTHVID_HEIGHT_MAX_WIN7 1200
enum pipe_msg_type {
PIPE_MSG_INVALID,
PIPE_MSG_DATA,
PIPE_MSG_MAX
};
enum synthvid_msg_type {
SYNTHVID_ERROR = 0,
SYNTHVID_VERSION_REQUEST = 1,
SYNTHVID_VERSION_RESPONSE = 2,
SYNTHVID_VRAM_LOCATION = 3,
SYNTHVID_VRAM_LOCATION_ACK = 4,
SYNTHVID_SITUATION_UPDATE = 5,
SYNTHVID_SITUATION_UPDATE_ACK = 6,
SYNTHVID_POINTER_POSITION = 7,
SYNTHVID_POINTER_SHAPE = 8,
SYNTHVID_FEATURE_CHANGE = 9,
SYNTHVID_DIRT = 10,
SYNTHVID_RESOLUTION_REQUEST = 13,
SYNTHVID_RESOLUTION_RESPONSE = 14,
SYNTHVID_MAX = 15
};
struct pipe_msg_hdr {
u32 type;
u32 size; /* size of message after this field */
} __packed;
struct hvd_screen_info {
u16 width;
u16 height;
} __packed;
struct synthvid_msg_hdr {
u32 type;
u32 size; /* size of this header + payload after this field */
} __packed;
struct synthvid_version_req {
u32 version;
} __packed;
struct synthvid_version_resp {
u32 version;
u8 is_accepted;
u8 max_video_outputs;
} __packed;
struct synthvid_vram_location {
u64 user_ctx;
u8 is_vram_gpa_specified;
u64 vram_gpa;
} __packed;
struct synthvid_vram_location_ack {
u64 user_ctx;
} __packed;
struct video_output_situation {
u8 active;
u32 vram_offset;
u8 depth_bits;
u32 width_pixels;
u32 height_pixels;
u32 pitch_bytes;
} __packed;
struct synthvid_situation_update {
u64 user_ctx;
u8 video_output_count;
struct video_output_situation video_output[1];
} __packed;
struct synthvid_situation_update_ack {
u64 user_ctx;
} __packed;
struct synthvid_pointer_position {
u8 is_visible;
u8 video_output;
s32 image_x;
s32 image_y;
} __packed;
#define SYNTHVID_CURSOR_MAX_X 96
#define SYNTHVID_CURSOR_MAX_Y 96
#define SYNTHVID_CURSOR_ARGB_PIXEL_SIZE 4
#define SYNTHVID_CURSOR_MAX_SIZE (SYNTHVID_CURSOR_MAX_X * \
SYNTHVID_CURSOR_MAX_Y * SYNTHVID_CURSOR_ARGB_PIXEL_SIZE)
#define SYNTHVID_CURSOR_COMPLETE (-1)
struct synthvid_pointer_shape {
u8 part_idx;
u8 is_argb;
u32 width; /* SYNTHVID_CURSOR_MAX_X at most */
u32 height; /* SYNTHVID_CURSOR_MAX_Y at most */
u32 hot_x; /* hotspot relative to upper-left of pointer image */
u32 hot_y;
u8 data[4];
} __packed;
struct synthvid_feature_change {
u8 is_dirt_needed;
u8 is_ptr_pos_needed;
u8 is_ptr_shape_needed;
u8 is_situ_needed;
} __packed;
struct rect {
s32 x1, y1; /* top left corner */
s32 x2, y2; /* bottom right corner, exclusive */
} __packed;
struct synthvid_dirt {
u8 video_output;
u8 dirt_count;
struct rect rect[1];
} __packed;
#define SYNTHVID_EDID_BLOCK_SIZE 128
#define SYNTHVID_MAX_RESOLUTION_COUNT 64
struct synthvid_supported_resolution_req {
u8 maximum_resolution_count;
} __packed;
struct synthvid_supported_resolution_resp {
u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
u8 resolution_count;
u8 default_resolution_index;
u8 is_standard;
struct hvd_screen_info supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
} __packed;
struct synthvid_msg {
struct pipe_msg_hdr pipe_hdr;
struct synthvid_msg_hdr vid_hdr;
union {
struct synthvid_version_req ver_req;
struct synthvid_version_resp ver_resp;
struct synthvid_vram_location vram;
struct synthvid_vram_location_ack vram_ack;
struct synthvid_situation_update situ;
struct synthvid_situation_update_ack situ_ack;
struct synthvid_pointer_position ptr_pos;
struct synthvid_pointer_shape ptr_shape;
struct synthvid_feature_change feature_chg;
struct synthvid_dirt dirt;
struct synthvid_supported_resolution_req resolution_req;
struct synthvid_supported_resolution_resp resolution_resp;
};
} __packed;
static inline bool hyperv_version_ge(u32 ver1, u32 ver2)
{
if (SYNTHVID_VER_GET_MAJOR(ver1) > SYNTHVID_VER_GET_MAJOR(ver2) ||
(SYNTHVID_VER_GET_MAJOR(ver1) == SYNTHVID_VER_GET_MAJOR(ver2) &&
SYNTHVID_VER_GET_MINOR(ver1) >= SYNTHVID_VER_GET_MINOR(ver2)))
return true;
return false;
}
static inline int hyperv_sendpacket(struct hv_device *hdev, struct synthvid_msg *msg)
{
static atomic64_t request_id = ATOMIC64_INIT(0);
struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
int ret;
msg->pipe_hdr.type = PIPE_MSG_DATA;
msg->pipe_hdr.size = msg->vid_hdr.size;
ret = vmbus_sendpacket(hdev->channel, msg,
msg->vid_hdr.size + sizeof(struct pipe_msg_hdr),
atomic64_inc_return(&request_id),
VM_PKT_DATA_INBAND, 0);
if (ret)
drm_err(&hv->dev, "Unable to send packet via vmbus\n");
return ret;
}
static int hyperv_negotiate_version(struct hv_device *hdev, u32 ver)
{
struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
struct synthvid_msg *msg = (struct synthvid_msg *)hv->init_buf;
struct drm_device *dev = &hv->dev;
unsigned long t;
memset(msg, 0, sizeof(struct synthvid_msg));
msg->vid_hdr.type = SYNTHVID_VERSION_REQUEST;
msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_version_req);
msg->ver_req.version = ver;
hyperv_sendpacket(hdev, msg);
t = wait_for_completion_timeout(&hv->wait, VMBUS_VSP_TIMEOUT);
if (!t) {
drm_err(dev, "Time out on waiting version response\n");
return -ETIMEDOUT;
}
if (!msg->ver_resp.is_accepted) {
drm_err(dev, "Version request not accepted\n");
return -ENODEV;
}
hv->synthvid_version = ver;
drm_info(dev, "Synthvid Version major %d, minor %d\n",
SYNTHVID_VER_GET_MAJOR(ver), SYNTHVID_VER_GET_MINOR(ver));
return 0;
}
int hyperv_update_vram_location(struct hv_device *hdev, phys_addr_t vram_pp)
{
struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
struct synthvid_msg *msg = (struct synthvid_msg *)hv->init_buf;
struct drm_device *dev = &hv->dev;
unsigned long t;
memset(msg, 0, sizeof(struct synthvid_msg));
msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;
msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_vram_location);
msg->vram.user_ctx = vram_pp;
msg->vram.vram_gpa = vram_pp;
msg->vram.is_vram_gpa_specified = 1;
hyperv_sendpacket(hdev, msg);
t = wait_for_completion_timeout(&hv->wait, VMBUS_VSP_TIMEOUT);
if (!t) {
drm_err(dev, "Time out on waiting vram location ack\n");
return -ETIMEDOUT;
}
if (msg->vram_ack.user_ctx != vram_pp) {
drm_err(dev, "Unable to set VRAM location\n");
return -ENODEV;
}
return 0;
}
int hyperv_update_situation(struct hv_device *hdev, u8 active, u32 bpp,
u32 w, u32 h, u32 pitch)
{
struct synthvid_msg msg;
memset(&msg, 0, sizeof(struct synthvid_msg));
msg.vid_hdr.type = SYNTHVID_SITUATION_UPDATE;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_situation_update);
msg.situ.user_ctx = 0;
msg.situ.video_output_count = 1;
msg.situ.video_output[0].active = active;
/* vram_offset should always be 0 */
msg.situ.video_output[0].vram_offset = 0;
msg.situ.video_output[0].depth_bits = bpp;
msg.situ.video_output[0].width_pixels = w;
msg.situ.video_output[0].height_pixels = h;
msg.situ.video_output[0].pitch_bytes = pitch;
hyperv_sendpacket(hdev, &msg);
return 0;
}
int hyperv_update_dirt(struct hv_device *hdev, struct drm_rect *rect)
{
struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
struct synthvid_msg msg;
if (!hv->dirt_needed)
return 0;
memset(&msg, 0, sizeof(struct synthvid_msg));
msg.vid_hdr.type = SYNTHVID_DIRT;
msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_dirt);
msg.dirt.video_output = 0;
msg.dirt.dirt_count = 1;
msg.dirt.rect[0].x1 = rect->x1;
msg.dirt.rect[0].y1 = rect->y1;
msg.dirt.rect[0].x2 = rect->x2;
msg.dirt.rect[0].y2 = rect->y2;
hyperv_sendpacket(hdev, &msg);
return 0;
}
static int hyperv_get_supported_resolution(struct hv_device *hdev)
{
struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
struct synthvid_msg *msg = (struct synthvid_msg *)hv->init_buf;
struct drm_device *dev = &hv->dev;
unsigned long t;
u8 index;
int i;
memset(msg, 0, sizeof(struct synthvid_msg));
msg->vid_hdr.type = SYNTHVID_RESOLUTION_REQUEST;
msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
sizeof(struct synthvid_supported_resolution_req);
msg->resolution_req.maximum_resolution_count =
SYNTHVID_MAX_RESOLUTION_COUNT;
hyperv_sendpacket(hdev, msg);
t = wait_for_completion_timeout(&hv->wait, VMBUS_VSP_TIMEOUT);
if (!t) {
drm_err(dev, "Time out on waiting resolution response\n");
return -ETIMEDOUT;
}
if (msg->resolution_resp.resolution_count == 0) {
drm_err(dev, "No supported resolutions\n");
return -ENODEV;
}
index = msg->resolution_resp.default_resolution_index;
if (index >= msg->resolution_resp.resolution_count) {
drm_err(dev, "Invalid resolution index: %d\n", index);
return -ENODEV;
}
for (i = 0; i < msg->resolution_resp.resolution_count; i++) {
hv->screen_width_max = max_t(u32, hv->screen_width_max,
msg->resolution_resp.supported_resolution[i].width);
hv->screen_height_max = max_t(u32, hv->screen_height_max,
msg->resolution_resp.supported_resolution[i].height);
}
hv->preferred_width =
msg->resolution_resp.supported_resolution[index].width;
hv->preferred_height =
msg->resolution_resp.supported_resolution[index].height;
return 0;
}
static void hyperv_receive_sub(struct hv_device *hdev)
{
struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
struct synthvid_msg *msg;
if (!hv)
return;
msg = (struct synthvid_msg *)hv->recv_buf;
/* Complete the wait event */
if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
memcpy(hv->init_buf, msg, VMBUS_MAX_PACKET_SIZE);
complete(&hv->wait);
return;
}
if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE)
hv->dirt_needed = msg->feature_chg.is_dirt_needed;
}
static void hyperv_receive(void *ctx)
{
struct hv_device *hdev = ctx;
struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
struct synthvid_msg *recv_buf;
u32 bytes_recvd;
u64 req_id;
int ret;
if (!hv)
return;
recv_buf = (struct synthvid_msg *)hv->recv_buf;
do {
ret = vmbus_recvpacket(hdev->channel, recv_buf,
VMBUS_MAX_PACKET_SIZE,
&bytes_recvd, &req_id);
if (bytes_recvd > 0 &&
recv_buf->pipe_hdr.type == PIPE_MSG_DATA)
hyperv_receive_sub(hdev);
} while (bytes_recvd > 0 && ret == 0);
}
int hyperv_connect_vsp(struct hv_device *hdev)
{
struct hyperv_drm_device *hv = hv_get_drvdata(hdev);
struct drm_device *dev = &hv->dev;
int ret;
ret = vmbus_open(hdev->channel, VMBUS_RING_BUFSIZE, VMBUS_RING_BUFSIZE,
NULL, 0, hyperv_receive, hdev);
if (ret) {
drm_err(dev, "Unable to open vmbus channel\n");
return ret;
}
/* Negotiate the protocol version with host */
switch (vmbus_proto_version) {
case VERSION_WIN10:
case VERSION_WIN10_V5:
ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN10);
if (!ret)
break;
fallthrough;
case VERSION_WIN8:
case VERSION_WIN8_1:
ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN8);
if (!ret)
break;
fallthrough;
case VERSION_WS2008:
case VERSION_WIN7:
ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN7);
break;
default:
ret = hyperv_negotiate_version(hdev, SYNTHVID_VERSION_WIN10);
break;
}
if (ret) {
drm_err(dev, "Synthetic video device version not accepted %d\n", ret);
goto error;
}
if (hv->synthvid_version == SYNTHVID_VERSION_WIN7)
hv->screen_depth = SYNTHVID_DEPTH_WIN7;
else
hv->screen_depth = SYNTHVID_DEPTH_WIN8;
if (hyperv_version_ge(hv->synthvid_version, SYNTHVID_VERSION_WIN10)) {
ret = hyperv_get_supported_resolution(hdev);
if (ret)
drm_err(dev, "Failed to get supported resolution from host, use default\n");
} else {
hv->screen_width_max = SYNTHVID_WIDTH_MAX_WIN7;
hv->screen_height_max = SYNTHVID_HEIGHT_MAX_WIN7;
}
hv->mmio_megabytes = hdev->channel->offermsg.offer.mmio_megabytes;
return 0;
error:
vmbus_close(hdev->channel);
return ret;
}

Просмотреть файл

@ -11040,7 +11040,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane,
if (ret < 0)
goto unpin_fb;
fence = dma_resv_get_excl_rcu(obj->base.resv);
fence = dma_resv_get_excl_unlocked(obj->base.resv);
if (fence) {
add_rps_boost_after_vblank(new_plane_state->hw.crtc,
fence);

Просмотреть файл

@ -10,7 +10,7 @@
void dma_resv_prune(struct dma_resv *resv)
{
if (dma_resv_trylock(resv)) {
if (dma_resv_test_signaled_rcu(resv, true))
if (dma_resv_test_signaled(resv, true))
dma_resv_add_excl_fence(resv, NULL);
dma_resv_unlock(resv);
}

Просмотреть файл

@ -105,7 +105,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
* Alternatively, we can trade that extra information on read/write
* activity with
* args->busy =
* !dma_resv_test_signaled_rcu(obj->resv, true);
* !dma_resv_test_signaled(obj->resv, true);
* to report the overall busyness. This is what the wait-ioctl does.
*
*/
@ -113,11 +113,10 @@ retry:
seq = raw_read_seqcount(&obj->base.resv->seq);
/* Translate the exclusive fence to the READ *and* WRITE engine */
args->busy =
busy_check_writer(rcu_dereference(obj->base.resv->fence_excl));
args->busy = busy_check_writer(dma_resv_excl_fence(obj->base.resv));
/* Translate shared fences to READ set of engines */
list = rcu_dereference(obj->base.resv->fence);
list = dma_resv_shared_list(obj->base.resv);
if (list) {
unsigned int shared_count = list->shared_count, i;

Просмотреть файл

@ -1481,7 +1481,7 @@ static inline bool use_reloc_gpu(struct i915_vma *vma)
if (DBG_FORCE_RELOC)
return false;
return !dma_resv_test_signaled_rcu(vma->resv, true);
return !dma_resv_test_signaled(vma->resv, true);
}
static unsigned long vma_phys_addr(struct i915_vma *vma, u32 offset)

Просмотреть файл

@ -500,7 +500,7 @@ i915_gem_object_last_write_engine(struct drm_i915_gem_object *obj)
struct dma_fence *fence;
rcu_read_lock();
fence = dma_resv_get_excl_rcu(obj->base.resv);
fence = dma_resv_get_excl_unlocked(obj->base.resv);
rcu_read_unlock();
if (fence && dma_fence_is_i915(fence) && !dma_fence_is_signaled(fence))

Просмотреть файл

@ -85,8 +85,8 @@ static bool i915_gem_userptr_invalidate(struct mmu_interval_notifier *mni,
return true;
/* we will unbind on next submission, still have userptr pins */
r = dma_resv_wait_timeout_rcu(obj->base.resv, true, false,
MAX_SCHEDULE_TIMEOUT);
r = dma_resv_wait_timeout(obj->base.resv, true, false,
MAX_SCHEDULE_TIMEOUT);
if (r <= 0)
drm_err(&i915->drm, "(%ld) failed to wait for idle\n", r);

Просмотреть файл

@ -45,7 +45,7 @@ i915_gem_object_wait_reservation(struct dma_resv *resv,
unsigned int count, i;
int ret;
ret = dma_resv_get_fences_rcu(resv, &excl, &count, &shared);
ret = dma_resv_get_fences(resv, &excl, &count, &shared);
if (ret)
return ret;
@ -73,7 +73,7 @@ i915_gem_object_wait_reservation(struct dma_resv *resv,
*/
prune_fences = count && timeout >= 0;
} else {
excl = dma_resv_get_excl_rcu(resv);
excl = dma_resv_get_excl_unlocked(resv);
}
if (excl && timeout >= 0)
@ -158,8 +158,8 @@ i915_gem_object_wait_priority(struct drm_i915_gem_object *obj,
unsigned int count, i;
int ret;
ret = dma_resv_get_fences_rcu(obj->base.resv,
&excl, &count, &shared);
ret = dma_resv_get_fences(obj->base.resv, &excl, &count,
&shared);
if (ret)
return ret;
@ -170,7 +170,7 @@ i915_gem_object_wait_priority(struct drm_i915_gem_object *obj,
kfree(shared);
} else {
excl = dma_resv_get_excl_rcu(obj->base.resv);
excl = dma_resv_get_excl_unlocked(obj->base.resv);
}
if (excl) {

Просмотреть файл

@ -1594,8 +1594,8 @@ i915_request_await_object(struct i915_request *to,
struct dma_fence **shared;
unsigned int count, i;
ret = dma_resv_get_fences_rcu(obj->base.resv,
&excl, &count, &shared);
ret = dma_resv_get_fences(obj->base.resv, &excl, &count,
&shared);
if (ret)
return ret;
@ -1611,7 +1611,7 @@ i915_request_await_object(struct i915_request *to,
dma_fence_put(shared[i]);
kfree(shared);
} else {
excl = dma_resv_get_excl_rcu(obj->base.resv);
excl = dma_resv_get_excl_unlocked(obj->base.resv);
}
if (excl) {

Просмотреть файл

@ -582,7 +582,7 @@ int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
struct dma_fence **shared;
unsigned int count, i;
ret = dma_resv_get_fences_rcu(resv, &excl, &count, &shared);
ret = dma_resv_get_fences(resv, &excl, &count, &shared);
if (ret)
return ret;
@ -606,7 +606,7 @@ int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
dma_fence_put(shared[i]);
kfree(shared);
} else {
excl = dma_resv_get_excl_rcu(resv);
excl = dma_resv_get_excl_unlocked(resv);
}
if (ret >= 0 && excl && excl->ops != exclude) {

Просмотреть файл

@ -30,9 +30,8 @@ struct mtk_disp_color_data {
unsigned int color_offset;
};
/**
/*
* struct mtk_disp_color - DISP_COLOR driver structure
* @ddp_comp: structure containing type enum and hardware resources
* @crtc: associated crtc to report irq events to
* @data: platform colour driver data
*/

Просмотреть файл

@ -29,10 +29,8 @@ struct mtk_disp_gamma_data {
bool has_dither;
};
/**
/*
* struct mtk_disp_gamma - DISP_GAMMA driver structure
* @ddp_comp - structure containing type enum and hardware resources
* @crtc - associated crtc to report irq events to
*/
struct mtk_disp_gamma {
struct clk *clk;

Просмотреть файл

@ -66,9 +66,8 @@ struct mtk_disp_ovl_data {
bool smi_id_en;
};
/**
/*
* struct mtk_disp_ovl - DISP_OVL driver structure
* @ddp_comp: structure containing type enum and hardware resources
* @crtc: associated crtc to report vblank events to
* @data: platform data
*/

Просмотреть файл

@ -55,10 +55,8 @@ struct mtk_disp_rdma_data {
unsigned int fifo_size;
};
/**
/*
* struct mtk_disp_rdma - DISP_RDMA driver structure
* @ddp_comp: structure containing type enum and hardware resources
* @crtc: associated crtc to report irq events to
* @data: local driver data
*/
struct mtk_disp_rdma {

Просмотреть файл

@ -7,6 +7,8 @@ config DRM_MSM
depends on IOMMU_SUPPORT
depends on OF && COMMON_CLK
depends on QCOM_OCMEM || QCOM_OCMEM=n
depends on QCOM_LLCC || QCOM_LLCC=n
depends on QCOM_COMMAND_DB || QCOM_COMMAND_DB=n
select IOMMU_IO_PGTABLE
select QCOM_MDT_LOADER if ARCH_QCOM
select REGULATOR
@ -15,7 +17,6 @@ config DRM_MSM
select SHMEM
select TMPFS
select QCOM_SCM if ARCH_QCOM
select QCOM_COMMAND_DB if ARCH_QCOM
select WANT_DEV_COREDUMP
select SND_SOC_HDMI_CODEC if SND_SOC
select SYNC_FILE

Просмотреть файл

@ -817,9 +817,9 @@ int msm_gem_sync_object(struct drm_gem_object *obj,
struct dma_fence *fence;
int i, ret;
fobj = dma_resv_get_list(obj->resv);
fobj = dma_resv_shared_list(obj->resv);
if (!fobj || (fobj->shared_count == 0)) {
fence = dma_resv_get_excl(obj->resv);
fence = dma_resv_excl_fence(obj->resv);
/* don't need to wait on our own fences, since ring is fifo */
if (fence && (fence->context != fctx->context)) {
ret = dma_fence_wait(fence, true);
@ -915,8 +915,7 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout)
op & MSM_PREP_NOSYNC ? 0 : timeout_to_jiffies(timeout);
long ret;
ret = dma_resv_wait_timeout_rcu(obj->resv, write,
true, remain);
ret = dma_resv_wait_timeout(obj->resv, write, true, remain);
if (ret == 0)
return remain == 0 ? -EBUSY : -ETIMEDOUT;
else if (ret < 0)
@ -1025,7 +1024,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m,
}
rcu_read_lock();
fobj = rcu_dereference(robj->fence);
fobj = dma_resv_shared_list(robj);
if (fobj) {
unsigned int i, shared_count = fobj->shared_count;
@ -1035,7 +1034,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m,
}
}
fence = rcu_dereference(robj->fence_excl);
fence = dma_resv_excl_fence(robj);
if (fence)
describe_fence(fence, "Exclusive", m);
rcu_read_unlock();

Просмотреть файл

@ -561,7 +561,7 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state)
asyw->image.handle[0] = ctxdma->object.handle;
}
asyw->state.fence = dma_resv_get_excl_rcu(nvbo->bo.base.resv);
asyw->state.fence = dma_resv_get_excl_unlocked(nvbo->bo.base.resv);
asyw->image.offset[0] = nvbo->offset;
if (wndw->func->prepare) {

Просмотреть файл

@ -312,7 +312,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
NOUVEAU_GEM_DOMAIN_GART;
else
if (chan->chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM)
if (chan->chan->push.buffer->bo.resource->mem_type == TTM_PL_VRAM)
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
else
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;

Просмотреть файл

@ -433,7 +433,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig)
if (nvbo->bo.pin_count) {
bool error = evict;
switch (bo->mem.mem_type) {
switch (bo->resource->mem_type) {
case TTM_PL_VRAM:
error |= !(domain & NOUVEAU_GEM_DOMAIN_VRAM);
break;
@ -446,7 +446,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig)
if (error) {
NV_ERROR(drm, "bo %p pinned elsewhere: "
"0x%08x vs 0x%08x\n", bo,
bo->mem.mem_type, domain);
bo->resource->mem_type, domain);
ret = -EBUSY;
}
ttm_bo_pin(&nvbo->bo);
@ -467,7 +467,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig)
ttm_bo_pin(&nvbo->bo);
switch (bo->mem.mem_type) {
switch (bo->resource->mem_type) {
case TTM_PL_VRAM:
drm->gem.vram_available -= bo->base.size;
break;
@ -498,7 +498,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
ttm_bo_unpin(&nvbo->bo);
if (!nvbo->bo.pin_count) {
switch (bo->mem.mem_type) {
switch (bo->resource->mem_type) {
case TTM_PL_VRAM:
drm->gem.vram_available += bo->base.size;
break;
@ -523,7 +523,7 @@ nouveau_bo_map(struct nouveau_bo *nvbo)
if (ret)
return ret;
ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, &nvbo->kmap);
ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.resource->num_pages, &nvbo->kmap);
ttm_bo_unreserve(&nvbo->bo);
return ret;
@ -737,7 +737,7 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
{
struct nouveau_bo *nvbo = nouveau_bo(bo);
switch (bo->mem.mem_type) {
switch (bo->resource->mem_type) {
case TTM_PL_VRAM:
nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART,
NOUVEAU_GEM_DOMAIN_CPU);
@ -754,7 +754,7 @@ static int
nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo,
struct ttm_resource *reg)
{
struct nouveau_mem *old_mem = nouveau_mem(&bo->mem);
struct nouveau_mem *old_mem = nouveau_mem(bo->resource);
struct nouveau_mem *new_mem = nouveau_mem(reg);
struct nvif_vmm *vmm = &drm->client.vmm.vmm;
int ret;
@ -809,7 +809,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict,
mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING);
ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, ctx->interruptible);
if (ret == 0) {
ret = drm->ttm.move(chan, bo, &bo->mem, new_reg);
ret = drm->ttm.move(chan, bo, bo->resource, new_reg);
if (ret == 0) {
ret = nouveau_fence_new(chan, false, &fence);
if (ret == 0) {
@ -918,12 +918,8 @@ static void nouveau_bo_move_ntfy(struct ttm_buffer_object *bo,
}
}
if (new_reg) {
if (new_reg->mm_node)
nvbo->offset = (new_reg->start << PAGE_SHIFT);
else
nvbo->offset = 0;
}
if (new_reg)
nvbo->offset = (new_reg->start << PAGE_SHIFT);
}
@ -955,7 +951,7 @@ nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
{
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct drm_device *dev = drm->dev;
struct dma_fence *fence = dma_resv_get_excl(bo->base.resv);
struct dma_fence *fence = dma_resv_excl_fence(bo->base.resv);
nv10_bo_put_tile_region(dev, *old_tile, fence);
*old_tile = new_tile;
@ -969,7 +965,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict,
{
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct ttm_resource *old_reg = &bo->mem;
struct ttm_resource *old_reg = bo->resource;
struct nouveau_drm_tile *new_tile = NULL;
int ret = 0;
@ -1009,7 +1005,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict,
if (old_reg->mem_type == TTM_PL_TT &&
new_reg->mem_type == TTM_PL_SYSTEM) {
nouveau_ttm_tt_unbind(bo->bdev, bo->ttm);
ttm_resource_free(bo, &bo->mem);
ttm_resource_free(bo, &bo->resource);
ttm_bo_assign_mem(bo, new_reg);
goto out;
}
@ -1045,7 +1041,7 @@ out:
}
out_ntfy:
if (ret) {
nouveau_bo_move_ntfy(bo, &bo->mem);
nouveau_bo_move_ntfy(bo, bo->resource);
}
return ret;
}
@ -1170,7 +1166,7 @@ out:
list_del_init(&nvbo->io_reserve_lru);
drm_vma_node_unmap(&nvbo->bo.base.vma_node,
bdev->dev_mapping);
nouveau_ttm_io_mem_free_locked(drm, &nvbo->bo.mem);
nouveau_ttm_io_mem_free_locked(drm, nvbo->bo.resource);
goto retry;
}
@ -1200,12 +1196,12 @@ vm_fault_t nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
/* as long as the bo isn't in vram, and isn't tiled, we've got
* nothing to do here.
*/
if (bo->mem.mem_type != TTM_PL_VRAM) {
if (bo->resource->mem_type != TTM_PL_VRAM) {
if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA ||
!nvbo->kind)
return 0;
if (bo->mem.mem_type != TTM_PL_SYSTEM)
if (bo->resource->mem_type != TTM_PL_SYSTEM)
return 0;
nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART, 0);
@ -1213,7 +1209,7 @@ vm_fault_t nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
} else {
/* make sure bo is in mappable vram */
if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA ||
bo->mem.start + bo->mem.num_pages < mappable)
bo->resource->start + bo->resource->num_pages < mappable)
return 0;
for (i = 0; i < nvbo->placement.num_placement; ++i) {

Просмотреть файл

@ -212,7 +212,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
args.start = 0;
args.limit = chan->vmm->vmm.limit - 1;
} else
if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) {
if (chan->push.buffer->bo.resource->mem_type == TTM_PL_VRAM) {
if (device->info.family == NV_DEVICE_INFO_V0_TNT) {
/* nv04 vram pushbuf hack, retarget to its location in
* the framebuffer bar rather than direct vram access..

Просмотреть файл

@ -378,7 +378,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_IMAGEBLIT;
info->fbops = &nouveau_fbcon_sw_ops;
info->fix.smem_start = nvbo->bo.mem.bus.offset;
info->fix.smem_start = nvbo->bo.resource->bus.offset;
info->fix.smem_len = nvbo->bo.base.size;
info->screen_base = nvbo_kmap_obj_iovirtual(nvbo);

Просмотреть файл

@ -355,8 +355,8 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e
return ret;
}
fobj = dma_resv_get_list(resv);
fence = dma_resv_get_excl(resv);
fobj = dma_resv_shared_list(resv);
fence = dma_resv_excl_fence(resv);
if (fence && (!exclusive || !fobj || !fobj->shared_count)) {
struct nouveau_channel *prev = NULL;

Просмотреть файл

@ -276,7 +276,7 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem,
if (is_power_of_2(nvbo->valid_domains))
rep->domain = nvbo->valid_domains;
else if (nvbo->bo.mem.mem_type == TTM_PL_TT)
else if (nvbo->bo.resource->mem_type == TTM_PL_TT)
rep->domain = NOUVEAU_GEM_DOMAIN_GART;
else
rep->domain = NOUVEAU_GEM_DOMAIN_VRAM;
@ -347,11 +347,11 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains,
valid_domains &= ~(NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART);
if ((domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
bo->mem.mem_type == TTM_PL_VRAM)
bo->resource->mem_type == TTM_PL_VRAM)
pref_domains |= NOUVEAU_GEM_DOMAIN_VRAM;
else if ((domains & NOUVEAU_GEM_DOMAIN_GART) &&
bo->mem.mem_type == TTM_PL_TT)
bo->resource->mem_type == TTM_PL_TT)
pref_domains |= NOUVEAU_GEM_DOMAIN_GART;
else if (domains & NOUVEAU_GEM_DOMAIN_VRAM)
@ -561,13 +561,13 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli,
if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
if (nvbo->offset == b->presumed.offset &&
((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
((nvbo->bo.resource->mem_type == TTM_PL_VRAM &&
b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
(nvbo->bo.mem.mem_type == TTM_PL_TT &&
(nvbo->bo.resource->mem_type == TTM_PL_TT &&
b->presumed.domain & NOUVEAU_GEM_DOMAIN_GART)))
continue;
if (nvbo->bo.mem.mem_type == TTM_PL_TT)
if (nvbo->bo.resource->mem_type == TTM_PL_TT)
b->presumed.domain = NOUVEAU_GEM_DOMAIN_GART;
else
b->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM;
@ -681,7 +681,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli,
}
if (!nvbo->kmap.virtual) {
ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages,
ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.resource->num_pages,
&nvbo->kmap);
if (ret) {
NV_PRINTK(err, cli, "failed kmap for reloc\n");
@ -870,7 +870,7 @@ revalidate:
if (unlikely(cmd != req->suffix0)) {
if (!nvbo->kmap.virtual) {
ret = ttm_bo_kmap(&nvbo->bo, 0,
nvbo->bo.mem.
nvbo->bo.resource->
num_pages,
&nvbo->kmap);
if (ret) {
@ -964,8 +964,8 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
return -ENOENT;
nvbo = nouveau_gem_object(gem);
lret = dma_resv_wait_timeout_rcu(nvbo->bo.base.resv, write, true,
no_wait ? 0 : 30 * HZ);
lret = dma_resv_wait_timeout(nvbo->bo.base.resv, write, true,
no_wait ? 0 : 30 * HZ);
if (!lret)
ret = -EBUSY;
else if (lret > 0)

Просмотреть файл

@ -178,25 +178,24 @@ void
nouveau_mem_del(struct ttm_resource *reg)
{
struct nouveau_mem *mem = nouveau_mem(reg);
if (!mem)
return;
nouveau_mem_fini(mem);
kfree(reg->mm_node);
reg->mm_node = NULL;
kfree(mem);
}
int
nouveau_mem_new(struct nouveau_cli *cli, u8 kind, u8 comp,
struct ttm_resource *reg)
struct ttm_resource **res)
{
struct nouveau_mem *mem;
if (!(mem = kzalloc(sizeof(*mem), GFP_KERNEL)))
return -ENOMEM;
mem->cli = cli;
mem->kind = kind;
mem->comp = comp;
reg->mm_node = mem;
*res = &mem->base;
return 0;
}

Просмотреть файл

@ -6,13 +6,8 @@ struct ttm_tt;
#include <nvif/mem.h>
#include <nvif/vmm.h>
static inline struct nouveau_mem *
nouveau_mem(struct ttm_resource *reg)
{
return reg->mm_node;
}
struct nouveau_mem {
struct ttm_resource base;
struct nouveau_cli *cli;
u8 kind;
u8 comp;
@ -20,8 +15,14 @@ struct nouveau_mem {
struct nvif_vma vma[2];
};
static inline struct nouveau_mem *
nouveau_mem(struct ttm_resource *reg)
{
return container_of(reg, struct nouveau_mem, base);
}
int nouveau_mem_new(struct nouveau_cli *, u8 kind, u8 comp,
struct ttm_resource *);
struct ttm_resource **);
void nouveau_mem_del(struct ttm_resource *);
int nouveau_mem_vram(struct ttm_resource *, bool contig, u8 page);
int nouveau_mem_host(struct ttm_resource *, struct ttm_tt *);

Просмотреть файл

@ -26,6 +26,8 @@
#include <linux/limits.h>
#include <linux/swiotlb.h>
#include <drm/ttm/ttm_range_manager.h>
#include "nouveau_drv.h"
#include "nouveau_gem.h"
#include "nouveau_mem.h"
@ -43,7 +45,7 @@ static int
nouveau_vram_manager_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
struct ttm_resource *reg)
struct ttm_resource **res)
{
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
@ -52,13 +54,15 @@ nouveau_vram_manager_new(struct ttm_resource_manager *man,
if (drm->client.device.info.ram_size == 0)
return -ENOMEM;
ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, reg);
ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, res);
if (ret)
return ret;
ret = nouveau_mem_vram(reg, nvbo->contig, nvbo->page);
ttm_resource_init(bo, place, *res);
ret = nouveau_mem_vram(*res, nvbo->contig, nvbo->page);
if (ret) {
nouveau_mem_del(reg);
nouveau_mem_del(*res);
return ret;
}
@ -74,17 +78,18 @@ static int
nouveau_gart_manager_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
struct ttm_resource *reg)
struct ttm_resource **res)
{
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
int ret;
ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, reg);
ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, res);
if (ret)
return ret;
reg->start = 0;
ttm_resource_init(bo, place, *res);
(*res)->start = 0;
return 0;
}
@ -97,26 +102,27 @@ static int
nv04_gart_manager_new(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
struct ttm_resource *reg)
struct ttm_resource **res)
{
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct nouveau_mem *mem;
int ret;
ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, reg);
mem = nouveau_mem(reg);
ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, res);
if (ret)
return ret;
mem = nouveau_mem(*res);
ttm_resource_init(bo, place, *res);
ret = nvif_vmm_get(&mem->cli->vmm.vmm, PTES, false, 12, 0,
(long)reg->num_pages << PAGE_SHIFT, &mem->vma[0]);
(long)(*res)->num_pages << PAGE_SHIFT, &mem->vma[0]);
if (ret) {
nouveau_mem_del(reg);
nouveau_mem_del(*res);
return ret;
}
reg->start = mem->vma[0].addr >> PAGE_SHIFT;
(*res)->start = mem->vma[0].addr >> PAGE_SHIFT;
return 0;
}

Просмотреть файл

@ -77,7 +77,7 @@ int
nouveau_vma_new(struct nouveau_bo *nvbo, struct nouveau_vmm *vmm,
struct nouveau_vma **pvma)
{
struct nouveau_mem *mem = nouveau_mem(&nvbo->bo.mem);
struct nouveau_mem *mem = nouveau_mem(nvbo->bo.resource);
struct nouveau_vma *vma;
struct nvif_vma tmp;
int ret;
@ -96,7 +96,7 @@ nouveau_vma_new(struct nouveau_bo *nvbo, struct nouveau_vmm *vmm,
vma->fence = NULL;
list_add_tail(&vma->head, &nvbo->vma_list);
if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM &&
if (nvbo->bo.resource->mem_type != TTM_PL_SYSTEM &&
mem->mem.page == nvbo->page) {
ret = nvif_vmm_get(&vmm->vmm, LAZY, false, mem->mem.page, 0,
mem->mem.size, &tmp);

Просмотреть файл

@ -77,8 +77,8 @@ static int
nv17_fence_context_new(struct nouveau_channel *chan)
{
struct nv10_fence_priv *priv = chan->drm->fence;
struct ttm_resource *reg = priv->bo->bo.resource;
struct nv10_fence_chan *fctx;
struct ttm_resource *reg = &priv->bo->bo.mem;
u32 start = reg->start * PAGE_SIZE;
u32 limit = start + priv->bo->bo.base.size - 1;
int ret = 0;

Просмотреть файл

@ -37,7 +37,7 @@ nv50_fence_context_new(struct nouveau_channel *chan)
{
struct nv10_fence_priv *priv = chan->drm->fence;
struct nv10_fence_chan *fctx;
struct ttm_resource *reg = &priv->bo->bo.mem;
struct ttm_resource *reg = priv->bo->bo.resource;
u32 start = reg->start * PAGE_SIZE;
u32 limit = start + priv->bo->bo.base.size - 1;
int ret;

Просмотреть файл

@ -46,7 +46,7 @@ tu102_mc_intr_update(struct tu102_mc *mc)
nvkm_wr32(device, 0xb81610, 0x6);
}
void
static void
tu102_mc_intr_unarm(struct nvkm_mc *base)
{
struct tu102_mc *mc = tu102_mc(base);
@ -58,7 +58,7 @@ tu102_mc_intr_unarm(struct nvkm_mc *base)
spin_unlock_irqrestore(&mc->lock, flags);
}
void
static void
tu102_mc_intr_rearm(struct nvkm_mc *base)
{
struct tu102_mc *mc = tu102_mc(base);
@ -70,7 +70,7 @@ tu102_mc_intr_rearm(struct nvkm_mc *base)
spin_unlock_irqrestore(&mc->lock, flags);
}
void
static void
tu102_mc_intr_mask(struct nvkm_mc *base, u32 mask, u32 intr)
{
struct tu102_mc *mc = tu102_mc(base);

Просмотреть файл

@ -42,6 +42,7 @@ struct kd35t133 {
struct gpio_desc *reset_gpio;
struct regulator *vdd;
struct regulator *iovcc;
enum drm_panel_orientation orientation;
bool prepared;
};
@ -216,6 +217,7 @@ static int kd35t133_get_modes(struct drm_panel *panel,
connector->display_info.width_mm = mode->width_mm;
connector->display_info.height_mm = mode->height_mm;
drm_mode_probed_add(connector, mode);
drm_connector_set_panel_orientation(connector, ctx->orientation);
return 1;
}
@ -258,6 +260,12 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi)
return ret;
}
ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
if (ret < 0) {
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
return ret;
}
mipi_dsi_set_drvdata(dsi, ctx);
ctx->dev = dev;

Просмотреть файл

@ -29,7 +29,7 @@
* DEALINGS IN THE SOFTWARE.
*/
/**
/*
* Raspberry Pi 7" touchscreen panel driver.
*
* The 7" touchscreen consists of a DPI LCD panel, a Toshiba

Просмотреть файл

@ -38,7 +38,7 @@
#define DSI_CMD2_BK1_SPD2 0xC2 /* Source EQ2 Setting */
#define DSI_CMD2_BK1_MIPISET1 0xD0 /* MIPI Setting 1 */
/**
/*
* Command2 with BK function selection.
*
* BIT[4, 0]: [CN2, BKXSEL]

Просмотреть файл

@ -45,6 +45,7 @@ struct panfrost_features {
u32 thread_max_workgroup_sz;
u32 thread_max_barrier_sz;
u32 coherency_features;
u32 afbc_features;
u32 texture_features[4];
u32 js_features[16];

Просмотреть файл

@ -63,6 +63,7 @@ static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct
PANFROST_FEATURE(THREAD_MAX_BARRIER_SZ,
thread_max_barrier_sz);
PANFROST_FEATURE(COHERENCY_FEATURES, coherency_features);
PANFROST_FEATURE(AFBC_FEATURES, afbc_features);
PANFROST_FEATURE_ARRAY(TEXTURE_FEATURES, texture_features, 3);
PANFROST_FEATURE_ARRAY(JS_FEATURES, js_features, 15);
PANFROST_FEATURE(NR_CORE_GROUPS, nr_core_groups);
@ -311,8 +312,7 @@ panfrost_ioctl_wait_bo(struct drm_device *dev, void *data,
if (!gem_obj)
return -ENOENT;
ret = dma_resv_wait_timeout_rcu(gem_obj->resv, true,
true, timeout);
ret = dma_resv_wait_timeout(gem_obj->resv, true, true, timeout);
if (!ret)
ret = timeout ? -ETIMEDOUT : -EBUSY;
@ -547,6 +547,7 @@ DEFINE_DRM_GEM_FOPS(panfrost_drm_driver_fops);
* Panfrost driver version:
* - 1.0 - initial interface
* - 1.1 - adds HEAP and NOEXEC flags for CREATE_BO
* - 1.2 - adds AFBC_FEATURES query
*/
static const struct drm_driver panfrost_drm_driver = {
.driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ,
@ -559,7 +560,7 @@ static const struct drm_driver panfrost_drm_driver = {
.desc = "panfrost DRM",
.date = "20180908",
.major = 1,
.minor = 1,
.minor = 2,
.gem_create_object = panfrost_gem_create_object,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,

Просмотреть файл

@ -228,6 +228,7 @@ static void panfrost_gpu_init_features(struct panfrost_device *pfdev)
pfdev->features.thread_max_workgroup_sz = gpu_read(pfdev, GPU_THREAD_MAX_WORKGROUP_SIZE);
pfdev->features.thread_max_barrier_sz = gpu_read(pfdev, GPU_THREAD_MAX_BARRIER_SIZE);
pfdev->features.coherency_features = gpu_read(pfdev, GPU_COHERENCY_FEATURES);
pfdev->features.afbc_features = gpu_read(pfdev, GPU_AFBC_FEATURES);
for (i = 0; i < 4; i++)
pfdev->features.texture_features[i] = gpu_read(pfdev, GPU_TEXTURE_FEATURES(i));

Просмотреть файл

@ -203,7 +203,7 @@ static void panfrost_acquire_object_fences(struct drm_gem_object **bos,
int i;
for (i = 0; i < bo_count; i++)
implicit_fences[i] = dma_resv_get_excl_rcu(bos[i]->resv);
implicit_fences[i] = dma_resv_get_excl_unlocked(bos[i]->resv);
}
static void panfrost_attach_object_fences(struct drm_gem_object **bos,

Просмотреть файл

@ -82,6 +82,7 @@
#define GPU_TEXTURE_FEATURES(n) (0x0B0 + ((n) * 4))
#define GPU_JS_FEATURES(n) (0x0C0 + ((n) * 4))
#define GPU_AFBC_FEATURES (0x4C) /* (RO) AFBC support on Bifrost */
#define GPU_SHADER_PRESENT_LO 0x100 /* (RO) Shader core present bitmap, low word */
#define GPU_SHADER_PRESENT_HI 0x104 /* (RO) Shader core present bitmap, high word */

Просмотреть файл

@ -3,6 +3,7 @@ config DRM_PL111
tristate "DRM Support for PL111 CLCD Controller"
depends on DRM
depends on ARM || ARM64 || COMPILE_TEST
depends on VEXPRESS_CONFIG || VEXPRESS_CONFIG=n
depends on COMMON_CLK
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER

Просмотреть файл

@ -61,7 +61,7 @@ qxl_debugfs_buffers_info(struct seq_file *m, void *data)
int rel;
rcu_read_lock();
fobj = rcu_dereference(bo->tbo.base.resv->fence);
fobj = dma_resv_shared_list(bo->tbo.base.resv);
rel = fobj ? fobj->shared_count : 0;
rcu_read_unlock();

Просмотреть файл

@ -292,12 +292,12 @@ qxl_bo_physical_address(struct qxl_device *qdev, struct qxl_bo *bo,
unsigned long offset)
{
struct qxl_memslot *slot =
(bo->tbo.mem.mem_type == TTM_PL_VRAM)
(bo->tbo.resource->mem_type == TTM_PL_VRAM)
? &qdev->main_slot : &qdev->surfaces_slot;
/* TODO - need to hold one of the locks to read bo->tbo.mem.start */
/* TODO - need to hold one of the locks to read bo->tbo.resource->start */
return slot->high_bits | ((bo->tbo.mem.start << PAGE_SHIFT) + offset);
return slot->high_bits | ((bo->tbo.resource->start << PAGE_SHIFT) + offset);
}
/* qxl_display.c */

Просмотреть файл

@ -58,6 +58,8 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
surf.height = args->height;
surf.stride = pitch;
surf.format = format;
surf.data = 0;
r = qxl_gem_object_create_with_handle(qdev, file_priv,
QXL_GEM_DOMAIN_CPU,
args->size, &surf, &qobj,

Просмотреть файл

@ -212,14 +212,14 @@ void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev,
struct io_mapping *map;
struct dma_buf_map bo_map;
if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
if (bo->tbo.resource->mem_type == TTM_PL_VRAM)
map = qdev->vram_mapping;
else if (bo->tbo.mem.mem_type == TTM_PL_PRIV)
else if (bo->tbo.resource->mem_type == TTM_PL_PRIV)
map = qdev->surface_mapping;
else
goto fallback;
offset = bo->tbo.mem.start << PAGE_SHIFT;
offset = bo->tbo.resource->start << PAGE_SHIFT;
return io_mapping_map_atomic_wc(map, offset + page_offset);
fallback:
if (bo->kptr) {
@ -266,8 +266,8 @@ int qxl_bo_vunmap(struct qxl_bo *bo)
void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev,
struct qxl_bo *bo, void *pmap)
{
if ((bo->tbo.mem.mem_type != TTM_PL_VRAM) &&
(bo->tbo.mem.mem_type != TTM_PL_PRIV))
if ((bo->tbo.resource->mem_type != TTM_PL_VRAM) &&
(bo->tbo.resource->mem_type != TTM_PL_PRIV))
goto fallback;
io_mapping_unmap_atomic(pmap);

Просмотреть файл

@ -32,6 +32,7 @@
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/ttm/ttm_range_manager.h>
#include "qxl_drv.h"
#include "qxl_object.h"
@ -131,7 +132,7 @@ static void qxl_bo_move_notify(struct ttm_buffer_object *bo,
qbo = to_qxl_bo(bo);
qdev = to_qxl(qbo->tbo.base.dev);
if (bo->mem.mem_type == TTM_PL_PRIV && qbo->surface_id)
if (bo->resource->mem_type == TTM_PL_PRIV && qbo->surface_id)
qxl_surface_evict(qdev, qbo, new_mem ? true : false);
}
@ -140,7 +141,7 @@ static int qxl_bo_move(struct ttm_buffer_object *bo, bool evict,
struct ttm_resource *new_mem,
struct ttm_place *hop)
{
struct ttm_resource *old_mem = &bo->mem;
struct ttm_resource *old_mem = bo->resource;
int ret;
qxl_bo_move_notify(bo, new_mem);

Просмотреть файл

@ -400,8 +400,8 @@ static int cmp_size_smaller_first(void *priv, const struct list_head *a,
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.mem.num_pages -
(int)lb->robj->tbo.mem.num_pages;
return (int)la->robj->tbo.resource->num_pages -
(int)lb->robj->tbo.resource->num_pages;
}
/**
@ -516,7 +516,7 @@ static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p,
}
r = radeon_vm_bo_update(rdev, vm->ib_bo_va,
&rdev->ring_tmp_bo.bo->tbo.mem);
rdev->ring_tmp_bo.bo->tbo.resource);
if (r)
return r;
@ -530,7 +530,7 @@ static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p,
return -EINVAL;
}
r = radeon_vm_bo_update(rdev, bo_va, &bo->tbo.mem);
r = radeon_vm_bo_update(rdev, bo_va, bo->tbo.resource);
if (r)
return r;

Просмотреть файл

@ -533,7 +533,7 @@ static int radeon_crtc_page_flip_target(struct drm_crtc *crtc,
DRM_ERROR("failed to pin new rbo buffer before flip\n");
goto cleanup;
}
work->fence = dma_fence_get(dma_resv_get_excl(new_rbo->tbo.base.resv));
work->fence = dma_fence_get(dma_resv_excl_fence(new_rbo->tbo.base.resv));
radeon_bo_get_tiling_flags(new_rbo, &tiling_flags, NULL);
radeon_bo_unreserve(new_rbo);

Просмотреть файл

@ -161,7 +161,7 @@ static int radeon_gem_set_domain(struct drm_gem_object *gobj,
}
if (domain == RADEON_GEM_DOMAIN_CPU) {
/* Asking for cpu access wait for object idle */
r = dma_resv_wait_timeout_rcu(robj->tbo.base.resv, true, true, 30 * HZ);
r = dma_resv_wait_timeout(robj->tbo.base.resv, true, true, 30 * HZ);
if (!r)
r = -EBUSY;
@ -523,13 +523,13 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
}
robj = gem_to_radeon_bo(gobj);
r = dma_resv_test_signaled_rcu(robj->tbo.base.resv, true);
r = dma_resv_test_signaled(robj->tbo.base.resv, true);
if (r == 0)
r = -EBUSY;
else
r = 0;
cur_placement = READ_ONCE(robj->tbo.mem.mem_type);
cur_placement = READ_ONCE(robj->tbo.resource->mem_type);
args->domain = radeon_mem_type_to_domain(cur_placement);
drm_gem_object_put(gobj);
return r;
@ -552,14 +552,14 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
}
robj = gem_to_radeon_bo(gobj);
ret = dma_resv_wait_timeout_rcu(robj->tbo.base.resv, true, true, 30 * HZ);
ret = dma_resv_wait_timeout(robj->tbo.base.resv, true, true, 30 * HZ);
if (ret == 0)
r = -EBUSY;
else if (ret < 0)
r = ret;
/* Flush HDP cache via MMIO if necessary */
cur_placement = READ_ONCE(robj->tbo.mem.mem_type);
cur_placement = READ_ONCE(robj->tbo.resource->mem_type);
if (rdev->asic->mmio_hdp_flush &&
radeon_mem_type_to_domain(cur_placement) == RADEON_GEM_DOMAIN_VRAM)
robj->rdev->asic->mmio_hdp_flush(rdev);
@ -643,7 +643,7 @@ static void radeon_gem_va_update_vm(struct radeon_device *rdev,
goto error_free;
list_for_each_entry(entry, &list, head) {
domain = radeon_mem_type_to_domain(entry->bo->mem.mem_type);
domain = radeon_mem_type_to_domain(entry->bo->resource->mem_type);
/* if anything is swapped out don't swap it in here,
just abort and wait for the next CS */
if (domain == RADEON_GEM_DOMAIN_CPU)
@ -656,7 +656,7 @@ static void radeon_gem_va_update_vm(struct radeon_device *rdev,
goto error_unlock;
if (bo_va->it.start)
r = radeon_vm_bo_update(rdev, bo_va, &bo_va->bo->tbo.mem);
r = radeon_vm_bo_update(rdev, bo_va, bo_va->bo->tbo.resource);
error_unlock:
mutex_unlock(&bo_va->vm->mutex);
@ -860,7 +860,7 @@ static int radeon_debugfs_gem_info_show(struct seq_file *m, void *unused)
unsigned domain;
const char *placement;
domain = radeon_mem_type_to_domain(rbo->tbo.mem.mem_type);
domain = radeon_mem_type_to_domain(rbo->tbo.resource->mem_type);
switch (domain) {
case RADEON_GEM_DOMAIN_VRAM:
placement = "VRAM";

Просмотреть файл

@ -66,8 +66,8 @@ static bool radeon_mn_invalidate(struct mmu_interval_notifier *mn,
return true;
}
r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, true, false,
MAX_SCHEDULE_TIMEOUT);
r = dma_resv_wait_timeout(bo->tbo.base.resv, true, false,
MAX_SCHEDULE_TIMEOUT);
if (r <= 0)
DRM_ERROR("(%ld) failed to wait for user bo\n", r);

Просмотреть файл

@ -76,7 +76,7 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)
bo = container_of(tbo, struct radeon_bo, tbo);
radeon_update_memory_usage(bo, bo->tbo.mem.mem_type, -1);
radeon_update_memory_usage(bo, bo->tbo.resource->mem_type, -1);
mutex_lock(&bo->rdev->gem.mutex);
list_del_init(&bo->list);
@ -250,7 +250,7 @@ int radeon_bo_kmap(struct radeon_bo *bo, void **ptr)
}
return 0;
}
r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.mem.num_pages, &bo->kmap);
r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.resource->num_pages, &bo->kmap);
if (r) {
return r;
}
@ -359,7 +359,7 @@ void radeon_bo_unpin(struct radeon_bo *bo)
{
ttm_bo_unpin(&bo->tbo);
if (!bo->tbo.pin_count) {
if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
if (bo->tbo.resource->mem_type == TTM_PL_VRAM)
bo->rdev->vram_pin_size -= radeon_bo_size(bo);
else
bo->rdev->gart_pin_size -= radeon_bo_size(bo);
@ -506,7 +506,7 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
u32 domain = lobj->preferred_domains;
u32 allowed = lobj->allowed_domains;
u32 current_domain =
radeon_mem_type_to_domain(bo->tbo.mem.mem_type);
radeon_mem_type_to_domain(bo->tbo.resource->mem_type);
/* Check if this buffer will be moved and don't move it
* if we have moved too many buffers for this IB already.
@ -605,7 +605,7 @@ int radeon_bo_get_surface_reg(struct radeon_bo *bo)
out:
radeon_set_surface_reg(rdev, i, bo->tiling_flags, bo->pitch,
bo->tbo.mem.start << PAGE_SHIFT,
bo->tbo.resource->start << PAGE_SHIFT,
bo->tbo.base.size);
return 0;
}
@ -711,7 +711,7 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
return 0;
}
if (bo->tbo.mem.mem_type != TTM_PL_VRAM) {
if (bo->tbo.resource->mem_type != TTM_PL_VRAM) {
if (!has_moved)
return 0;
@ -743,7 +743,7 @@ void radeon_bo_move_notify(struct ttm_buffer_object *bo,
if (!new_mem)
return;
radeon_update_memory_usage(rbo, bo->mem.mem_type, -1);
radeon_update_memory_usage(rbo, bo->resource->mem_type, -1);
radeon_update_memory_usage(rbo, new_mem->mem_type, 1);
}
@ -760,11 +760,11 @@ vm_fault_t radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
rbo = container_of(bo, struct radeon_bo, tbo);
radeon_bo_check_tiling(rbo, 0, 0);
rdev = rbo->rdev;
if (bo->mem.mem_type != TTM_PL_VRAM)
if (bo->resource->mem_type != TTM_PL_VRAM)
return 0;
size = bo->mem.num_pages << PAGE_SHIFT;
offset = bo->mem.start << PAGE_SHIFT;
size = bo->resource->num_pages << PAGE_SHIFT;
offset = bo->resource->start << PAGE_SHIFT;
if ((offset + size) <= rdev->mc.visible_vram_size)
return 0;
@ -786,7 +786,7 @@ vm_fault_t radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT);
r = ttm_bo_validate(bo, &rbo->placement, &ctx);
} else if (likely(!r)) {
offset = bo->mem.start << PAGE_SHIFT;
offset = bo->resource->start << PAGE_SHIFT;
/* this should never happen */
if ((offset + size) > rdev->mc.visible_vram_size)
return VM_FAULT_SIGBUS;

Просмотреть файл

@ -95,7 +95,7 @@ static inline u64 radeon_bo_gpu_offset(struct radeon_bo *bo)
rdev = radeon_get_rdev(bo->tbo.bdev);
switch (bo->tbo.mem.mem_type) {
switch (bo->tbo.resource->mem_type) {
case TTM_PL_TT:
start = rdev->mc.gtt_start;
break;
@ -104,7 +104,7 @@ static inline u64 radeon_bo_gpu_offset(struct radeon_bo *bo)
break;
}
return (bo->tbo.mem.start << PAGE_SHIFT) + start;
return (bo->tbo.resource->start << PAGE_SHIFT) + start;
}
static inline unsigned long radeon_bo_size(struct radeon_bo *bo)

Просмотреть файл

@ -154,7 +154,7 @@ static void radeon_unmap_vram_bos(struct radeon_device *rdev)
return;
list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) {
if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
if (bo->tbo.resource->mem_type == TTM_PL_VRAM)
ttm_bo_unmap_virtual(&bo->tbo);
}
}

Просмотреть файл

@ -98,14 +98,14 @@ int radeon_sync_resv(struct radeon_device *rdev,
int r = 0;
/* always sync to the exclusive fence */
f = dma_resv_get_excl(resv);
f = dma_resv_excl_fence(resv);
fence = f ? to_radeon_fence(f) : NULL;
if (fence && fence->rdev == rdev)
radeon_sync_fence(sync, fence);
else if (f)
r = dma_fence_wait(f, true);
flist = dma_resv_get_list(resv);
flist = dma_resv_shared_list(resv);
if (shared || !flist || r)
return r;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше