Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
24e8375b
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
24e8375b
编写于
11月 01, 2017
作者:
B
Ben Skeggs
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
drm/nouveau: separate constant-va tracking from nvkm vma structure
Signed-off-by:
N
Ben Skeggs
<
bskeggs@redhat.com
>
上级
9ce523cc
变更
21
隐藏空白更改
内联
并排
Showing
21 changed file
with
245 addition
and
151 deletion
+245
-151
drivers/gpu/drm/nouveau/Kbuild
drivers/gpu/drm/nouveau/Kbuild
+1
-0
drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
+0
-2
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
+5
-5
drivers/gpu/drm/nouveau/nouveau_abi16.h
drivers/gpu/drm/nouveau/nouveau_abi16.h
+1
-1
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_bo.c
+4
-47
drivers/gpu/drm/nouveau/nouveau_bo.h
drivers/gpu/drm/nouveau/nouveau_bo.h
+0
-7
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_chan.c
+11
-8
drivers/gpu/drm/nouveau/nouveau_chan.h
drivers/gpu/drm/nouveau/nouveau_chan.h
+2
-1
drivers/gpu/drm/nouveau/nouveau_display.h
drivers/gpu/drm/nouveau/nouveau_display.h
+1
-4
drivers/gpu/drm/nouveau/nouveau_dma.c
drivers/gpu/drm/nouveau/nouveau_dma.c
+8
-7
drivers/gpu/drm/nouveau/nouveau_dma.h
drivers/gpu/drm/nouveau/nouveau_dma.h
+1
-1
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.c
+5
-6
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_drv.h
+3
-1
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
+4
-3
drivers/gpu/drm/nouveau/nouveau_fence.h
drivers/gpu/drm/nouveau/nouveau_fence.h
+1
-1
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_gem.c
+23
-45
drivers/gpu/drm/nouveau/nouveau_vmm.c
drivers/gpu/drm/nouveau/nouveau_vmm.c
+128
-0
drivers/gpu/drm/nouveau/nouveau_vmm.h
drivers/gpu/drm/nouveau/nouveau_vmm.h
+32
-0
drivers/gpu/drm/nouveau/nv50_fbcon.c
drivers/gpu/drm/nouveau/nv50_fbcon.c
+5
-4
drivers/gpu/drm/nouveau/nv84_fence.c
drivers/gpu/drm/nouveau/nv84_fence.c
+5
-4
drivers/gpu/drm/nouveau/nvc0_fbcon.c
drivers/gpu/drm/nouveau/nvc0_fbcon.c
+5
-4
未找到文件。
drivers/gpu/drm/nouveau/Kbuild
浏览文件 @
24e8375b
...
...
@@ -34,6 +34,7 @@ nouveau-y += nouveau_mem.o
nouveau-y += nouveau_prime.o
nouveau-y += nouveau_sgdma.o
nouveau-y += nouveau_ttm.o
nouveau-y += nouveau_vmm.o
# DRM - modesetting
nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
...
...
drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
浏览文件 @
24e8375b
...
...
@@ -16,8 +16,6 @@ struct nvkm_vm_pgd {
};
struct
nvkm_vma
{
struct
list_head
head
;
int
refcount
;
struct
nvkm_vm
*
vm
;
struct
nvkm_mm_node
*
node
;
union
{
...
...
drivers/gpu/drm/nouveau/nouveau_abi16.c
浏览文件 @
24e8375b
...
...
@@ -34,6 +34,7 @@
#include "nouveau_gem.h"
#include "nouveau_chan.h"
#include "nouveau_abi16.h"
#include "nouveau_vmm.h"
static
struct
nouveau_abi16
*
nouveau_abi16
(
struct
drm_file
*
file_priv
)
...
...
@@ -134,7 +135,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
}
if
(
chan
->
ntfy
)
{
nouveau_
bo_vma_del
(
chan
->
ntfy
,
&
chan
->
ntfy_vma
);
nouveau_
vma_del
(
&
chan
->
ntfy_vma
);
nouveau_bo_unpin
(
chan
->
ntfy
);
drm_gem_object_unreference_unlocked
(
&
chan
->
ntfy
->
gem
);
}
...
...
@@ -329,8 +330,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
goto
done
;
if
(
device
->
info
.
family
>=
NV_DEVICE_INFO_V0_TESLA
)
{
ret
=
nouveau_bo_vma_add
(
chan
->
ntfy
,
cli
->
vm
,
&
chan
->
ntfy_vma
);
ret
=
nouveau_vma_new
(
chan
->
ntfy
,
&
cli
->
vmm
,
&
chan
->
ntfy_vma
);
if
(
ret
)
goto
done
;
}
...
...
@@ -548,8 +548,8 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
if
(
device
->
info
.
family
>=
NV_DEVICE_INFO_V0_TESLA
)
{
args
.
target
=
NV_DMA_V0_TARGET_VM
;
args
.
access
=
NV_DMA_V0_ACCESS_VM
;
args
.
start
+=
chan
->
ntfy_vma
.
offset
;
args
.
limit
+=
chan
->
ntfy_vma
.
offset
;
args
.
start
+=
chan
->
ntfy_vma
->
addr
;
args
.
limit
+=
chan
->
ntfy_vma
->
addr
;
}
else
if
(
drm
->
agp
.
bridge
)
{
args
.
target
=
NV_DMA_V0_TARGET_AGP
;
...
...
drivers/gpu/drm/nouveau/nouveau_abi16.h
浏览文件 @
24e8375b
...
...
@@ -23,7 +23,7 @@ struct nouveau_abi16_chan {
struct
nouveau_channel
*
chan
;
struct
list_head
notifiers
;
struct
nouveau_bo
*
ntfy
;
struct
n
vkm_vma
ntfy_vma
;
struct
n
ouveau_vma
*
ntfy_vma
;
struct
nvkm_mm
heap
;
};
...
...
drivers/gpu/drm/nouveau/nouveau_bo.c
浏览文件 @
24e8375b
...
...
@@ -38,6 +38,7 @@
#include "nouveau_ttm.h"
#include "nouveau_gem.h"
#include "nouveau_mem.h"
#include "nouveau_vmm.h"
/*
* NV10-NV40 tiling helpers
...
...
@@ -1223,7 +1224,7 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
{
struct
nouveau_mem
*
mem
=
new_reg
?
nouveau_mem
(
new_reg
)
:
NULL
;
struct
nouveau_bo
*
nvbo
=
nouveau_bo
(
bo
);
struct
n
vkm
_vma
*
vma
;
struct
n
ouveau
_vma
*
vma
;
/* ttm can now (stupidly) pass the driver bos it didn't create... */
if
(
bo
->
destroy
!=
nouveau_bo_del_ttm
)
...
...
@@ -1232,12 +1233,12 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
if
(
mem
&&
new_reg
->
mem_type
!=
TTM_PL_SYSTEM
&&
mem
->
mem
.
page
==
nvbo
->
page
)
{
list_for_each_entry
(
vma
,
&
nvbo
->
vma_list
,
head
)
{
n
vkm_vm_map
(
vma
,
mem
->
_
mem
);
n
ouveau_vma_map
(
vma
,
mem
);
}
}
else
{
list_for_each_entry
(
vma
,
&
nvbo
->
vma_list
,
head
)
{
WARN_ON
(
ttm_bo_wait
(
bo
,
false
,
false
));
n
vkm_vm
_unmap
(
vma
);
n
ouveau_vma
_unmap
(
vma
);
}
}
}
...
...
@@ -1599,47 +1600,3 @@ struct ttm_bo_driver nouveau_bo_driver = {
.
io_mem_free
=
&
nouveau_ttm_io_mem_free
,
.
io_mem_pfn
=
ttm_bo_default_io_mem_pfn
,
};
struct
nvkm_vma
*
nouveau_bo_vma_find
(
struct
nouveau_bo
*
nvbo
,
struct
nvkm_vm
*
vm
)
{
struct
nvkm_vma
*
vma
;
list_for_each_entry
(
vma
,
&
nvbo
->
vma_list
,
head
)
{
if
(
vma
->
vm
==
vm
)
return
vma
;
}
return
NULL
;
}
int
nouveau_bo_vma_add
(
struct
nouveau_bo
*
nvbo
,
struct
nvkm_vm
*
vm
,
struct
nvkm_vma
*
vma
)
{
const
u32
size
=
nvbo
->
bo
.
mem
.
num_pages
<<
PAGE_SHIFT
;
struct
nouveau_mem
*
mem
=
nouveau_mem
(
&
nvbo
->
bo
.
mem
);
int
ret
;
ret
=
nvkm_vm_get
(
vm
,
size
,
nvbo
->
page
,
NV_MEM_ACCESS_RW
,
vma
);
if
(
ret
)
return
ret
;
if
(
nvbo
->
bo
.
mem
.
mem_type
!=
TTM_PL_SYSTEM
&&
mem
->
mem
.
page
==
nvbo
->
page
)
nvkm_vm_map
(
vma
,
mem
->
_mem
);
list_add_tail
(
&
vma
->
head
,
&
nvbo
->
vma_list
);
vma
->
refcount
=
1
;
return
0
;
}
void
nouveau_bo_vma_del
(
struct
nouveau_bo
*
nvbo
,
struct
nvkm_vma
*
vma
)
{
if
(
vma
->
node
)
{
if
(
nvbo
->
bo
.
mem
.
mem_type
!=
TTM_PL_SYSTEM
)
nvkm_vm_unmap
(
vma
);
nvkm_vm_put
(
vma
);
list_del
(
&
vma
->
head
);
}
}
drivers/gpu/drm/nouveau/nouveau_bo.h
浏览文件 @
24e8375b
...
...
@@ -93,13 +93,6 @@ int nouveau_bo_validate(struct nouveau_bo *, bool interruptible,
void
nouveau_bo_sync_for_device
(
struct
nouveau_bo
*
nvbo
);
void
nouveau_bo_sync_for_cpu
(
struct
nouveau_bo
*
nvbo
);
struct
nvkm_vma
*
nouveau_bo_vma_find
(
struct
nouveau_bo
*
,
struct
nvkm_vm
*
);
int
nouveau_bo_vma_add
(
struct
nouveau_bo
*
,
struct
nvkm_vm
*
,
struct
nvkm_vma
*
);
void
nouveau_bo_vma_del
(
struct
nouveau_bo
*
,
struct
nvkm_vma
*
);
/* TODO: submit equivalent to TTM generic API upstream? */
static
inline
void
__iomem
*
nvbo_kmap_obj_iovirtual
(
struct
nouveau_bo
*
nvbo
)
...
...
drivers/gpu/drm/nouveau/nouveau_chan.c
浏览文件 @
24e8375b
...
...
@@ -40,6 +40,7 @@
#include "nouveau_chan.h"
#include "nouveau_fence.h"
#include "nouveau_abi16.h"
#include "nouveau_vmm.h"
MODULE_PARM_DESC
(
vram_pushbuf
,
"Create DMA push buffers in VRAM"
);
int
nouveau_vram_pushbuf
;
...
...
@@ -91,7 +92,7 @@ nouveau_channel_del(struct nouveau_channel **pchan)
nvif_notify_fini
(
&
chan
->
kill
);
nvif_object_fini
(
&
chan
->
user
);
nvif_object_fini
(
&
chan
->
push
.
ctxdma
);
nouveau_
bo_vma_del
(
chan
->
push
.
buffer
,
&
chan
->
push
.
vma
);
nouveau_
vma_del
(
&
chan
->
push
.
vma
);
nouveau_bo_unmap
(
chan
->
push
.
buffer
);
if
(
chan
->
push
.
buffer
&&
chan
->
push
.
buffer
->
pin_refcnt
)
nouveau_bo_unpin
(
chan
->
push
.
buffer
);
...
...
@@ -142,11 +143,11 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
* pushbuf lives in, this is because the GEM code requires that
* we be able to call out to other (indirect) push buffers
*/
chan
->
push
.
vma
.
offset
=
chan
->
push
.
buffer
->
bo
.
offset
;
chan
->
push
.
addr
=
chan
->
push
.
buffer
->
bo
.
offset
;
if
(
device
->
info
.
family
>=
NV_DEVICE_INFO_V0_TESLA
)
{
ret
=
nouveau_
bo_vma_add
(
chan
->
push
.
buffer
,
cli
->
v
m
,
&
chan
->
push
.
vma
);
ret
=
nouveau_
vma_new
(
chan
->
push
.
buffer
,
&
cli
->
vm
m
,
&
chan
->
push
.
vma
);
if
(
ret
)
{
nouveau_channel_del
(
pchan
);
return
ret
;
...
...
@@ -156,6 +157,8 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
args
.
access
=
NV_DMA_V0_ACCESS_VM
;
args
.
start
=
0
;
args
.
limit
=
cli
->
vm
->
mmu
->
limit
-
1
;
chan
->
push
.
addr
=
chan
->
push
.
vma
->
addr
;
}
else
if
(
chan
->
push
.
buffer
->
bo
.
mem
.
mem_type
==
TTM_PL_VRAM
)
{
if
(
device
->
info
.
family
==
NV_DEVICE_INFO_V0_TNT
)
{
...
...
@@ -233,20 +236,20 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
args
.
kepler
.
version
=
0
;
args
.
kepler
.
engines
=
engine
;
args
.
kepler
.
ilength
=
0x02000
;
args
.
kepler
.
ioffset
=
0x10000
+
chan
->
push
.
vma
.
offset
;
args
.
kepler
.
ioffset
=
0x10000
+
chan
->
push
.
addr
;
args
.
kepler
.
vm
=
0
;
size
=
sizeof
(
args
.
kepler
);
}
else
if
(
oclass
[
0
]
>=
FERMI_CHANNEL_GPFIFO
)
{
args
.
fermi
.
version
=
0
;
args
.
fermi
.
ilength
=
0x02000
;
args
.
fermi
.
ioffset
=
0x10000
+
chan
->
push
.
vma
.
offset
;
args
.
fermi
.
ioffset
=
0x10000
+
chan
->
push
.
addr
;
args
.
fermi
.
vm
=
0
;
size
=
sizeof
(
args
.
fermi
);
}
else
{
args
.
nv50
.
version
=
0
;
args
.
nv50
.
ilength
=
0x02000
;
args
.
nv50
.
ioffset
=
0x10000
+
chan
->
push
.
vma
.
offset
;
args
.
nv50
.
ioffset
=
0x10000
+
chan
->
push
.
addr
;
args
.
nv50
.
pushbuf
=
nvif_handle
(
&
chan
->
push
.
ctxdma
);
args
.
nv50
.
vm
=
0
;
size
=
sizeof
(
args
.
nv50
);
...
...
@@ -293,7 +296,7 @@ nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device,
/* create channel object */
args
.
version
=
0
;
args
.
pushbuf
=
nvif_handle
(
&
chan
->
push
.
ctxdma
);
args
.
offset
=
chan
->
push
.
vma
.
offset
;
args
.
offset
=
chan
->
push
.
addr
;
do
{
ret
=
nvif_object_init
(
&
device
->
object
,
0
,
*
oclass
++
,
...
...
drivers/gpu/drm/nouveau/nouveau_chan.h
浏览文件 @
24e8375b
...
...
@@ -16,8 +16,9 @@ struct nouveau_channel {
struct
{
struct
nouveau_bo
*
buffer
;
struct
n
vkm_vma
vma
;
struct
n
ouveau_vma
*
vma
;
struct
nvif_object
ctxdma
;
u64
addr
;
}
push
;
/* TODO: this will be reworked in the near future */
...
...
drivers/gpu/drm/nouveau/nouveau_display.h
浏览文件 @
24e8375b
#ifndef __NOUVEAU_DISPLAY_H__
#define __NOUVEAU_DISPLAY_H__
#include <subdev/mmu.h>
#include "nouveau_drv.h"
struct
nouveau_framebuffer
{
struct
drm_framebuffer
base
;
struct
nouveau_bo
*
nvbo
;
struct
n
vkm_vma
vma
;
struct
n
ouveau_vma
*
vma
;
u32
r_handle
;
u32
r_format
;
u32
r_pitch
;
...
...
drivers/gpu/drm/nouveau/nouveau_dma.c
浏览文件 @
24e8375b
...
...
@@ -26,6 +26,7 @@
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_vmm.h"
void
OUT_RINGp
(
struct
nouveau_channel
*
chan
,
const
void
*
data
,
unsigned
nr_dwords
)
...
...
@@ -71,11 +72,11 @@ READ_GET(struct nouveau_channel *chan, uint64_t *prev_get, int *timeout)
return
-
EBUSY
;
}
if
(
val
<
chan
->
push
.
vma
.
offset
||
val
>
chan
->
push
.
vma
.
offset
+
(
chan
->
dma
.
max
<<
2
))
if
(
val
<
chan
->
push
.
addr
||
val
>
chan
->
push
.
addr
+
(
chan
->
dma
.
max
<<
2
))
return
-
EINVAL
;
return
(
val
-
chan
->
push
.
vma
.
offset
)
>>
2
;
return
(
val
-
chan
->
push
.
addr
)
>>
2
;
}
void
...
...
@@ -84,13 +85,13 @@ nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo,
{
struct
nouveau_cli
*
cli
=
(
void
*
)
chan
->
user
.
client
;
struct
nouveau_bo
*
pb
=
chan
->
push
.
buffer
;
struct
n
vkm
_vma
*
vma
;
struct
n
ouveau
_vma
*
vma
;
int
ip
=
(
chan
->
dma
.
ib_put
*
2
)
+
chan
->
dma
.
ib_base
;
u64
offset
;
vma
=
nouveau_
bo_vma_find
(
bo
,
cli
->
v
m
);
vma
=
nouveau_
vma_find
(
bo
,
&
cli
->
vm
m
);
BUG_ON
(
!
vma
);
offset
=
vma
->
offset
+
delta
;
offset
=
vma
->
addr
+
delta
;
BUG_ON
(
chan
->
dma
.
ib_free
<
1
);
...
...
@@ -224,7 +225,7 @@ nouveau_dma_wait(struct nouveau_channel *chan, int slots, int size)
* instruct the GPU to jump back to the start right
* after processing the currently pending commands.
*/
OUT_RING
(
chan
,
chan
->
push
.
vma
.
offset
|
0x20000000
);
OUT_RING
(
chan
,
chan
->
push
.
addr
|
0x20000000
);
/* wait for GET to depart from the skips area.
* prevents writing GET==PUT and causing a race
...
...
drivers/gpu/drm/nouveau/nouveau_dma.h
浏览文件 @
24e8375b
...
...
@@ -140,7 +140,7 @@ BEGIN_IMC0(struct nouveau_channel *chan, int subc, int mthd, u16 data)
#define WRITE_PUT(val) do { \
mb(); \
nouveau_bo_rd32(chan->push.buffer, 0); \
nvif_wr32(&chan->user, chan->user_put, ((val) << 2) + chan->push.
vma.offset);
\
nvif_wr32(&chan->user, chan->user_put, ((val) << 2) + chan->push.
addr);
\
} while (0)
static
inline
void
...
...
drivers/gpu/drm/nouveau/nouveau_drm.c
浏览文件 @
24e8375b
...
...
@@ -114,8 +114,8 @@ nouveau_name(struct drm_device *dev)
static
void
nouveau_cli_fini
(
struct
nouveau_cli
*
cli
)
{
nvkm_vm_ref
(
NULL
,
&
nvxx_client
(
&
cli
->
base
)
->
vm
,
NULL
);
usif_client_fini
(
cli
);
nouveau_vmm_fini
(
&
cli
->
vmm
);
nvif_device_fini
(
&
cli
->
device
);
mutex_lock
(
&
cli
->
drm
->
master
.
lock
);
nvif_client_fini
(
&
cli
->
base
);
...
...
@@ -472,12 +472,11 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
goto
fail_device
;
}
ret
=
nvkm_vm_new
(
nvxx_device
(
&
drm
->
client
.
device
),
0
,
(
1ULL
<<
40
),
0x1000
,
NULL
,
&
drm
->
client
.
vm
);
ret
=
nouveau_vmm_init
(
&
drm
->
client
,
0
,
&
drm
->
client
.
vmm
);
if
(
ret
)
goto
fail_device
;
drm
->
client
.
vm
=
drm
->
client
.
vmm
.
vm
;
nvxx_client
(
&
drm
->
client
.
base
)
->
vm
=
drm
->
client
.
vm
;
}
...
...
@@ -863,11 +862,11 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
cli
->
base
.
super
=
false
;
if
(
drm
->
client
.
device
.
info
.
family
>=
NV_DEVICE_INFO_V0_TESLA
)
{
ret
=
nvkm_vm_new
(
nvxx_device
(
&
drm
->
client
.
device
),
0
,
(
1ULL
<<
40
),
0x1000
,
NULL
,
&
cli
->
vm
);
ret
=
nouveau_vmm_init
(
cli
,
0
,
&
cli
->
vmm
);
if
(
ret
)
goto
done
;
cli
->
vm
=
cli
->
vmm
.
vm
;
nvxx_client
(
&
cli
->
base
)
->
vm
=
cli
->
vm
;
}
...
...
drivers/gpu/drm/nouveau/nouveau_drv.h
浏览文件 @
24e8375b
...
...
@@ -61,6 +61,7 @@ struct platform_device;
#include "nouveau_fence.h"
#include "nouveau_bios.h"
#include "nouveau_vmm.h"
struct
nouveau_drm_tile
{
struct
nouveau_fence
*
fence
;
...
...
@@ -90,8 +91,9 @@ struct nouveau_cli {
struct
mutex
mutex
;
struct
nvif_device
device
;
struct
nouveau_vmm
vmm
;
struct
nvkm_vm
*
vm
;
/*XXX*/
struct
nvkm_vm
*
vm
;
struct
list_head
head
;
void
*
abi16
;
struct
list_head
objects
;
...
...
drivers/gpu/drm/nouveau/nouveau_fbcon.c
浏览文件 @
24e8375b
...
...
@@ -48,6 +48,7 @@
#include "nouveau_bo.h"
#include "nouveau_fbcon.h"
#include "nouveau_chan.h"
#include "nouveau_vmm.h"
#include "nouveau_crtc.h"
...
...
@@ -348,7 +349,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
chan
=
nouveau_nofbaccel
?
NULL
:
drm
->
channel
;
if
(
chan
&&
device
->
info
.
family
>=
NV_DEVICE_INFO_V0_TESLA
)
{
ret
=
nouveau_
bo_vma_add
(
nvbo
,
drm
->
client
.
v
m
,
&
fb
->
vma
);
ret
=
nouveau_
vma_new
(
nvbo
,
&
drm
->
client
.
vm
m
,
&
fb
->
vma
);
if
(
ret
)
{
NV_ERROR
(
drm
,
"failed to map fb into chan: %d
\n
"
,
ret
);
chan
=
NULL
;
...
...
@@ -402,7 +403,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
out_unlock:
if
(
chan
)
nouveau_
bo_vma_del
(
fb
->
nvbo
,
&
fb
->
vma
);
nouveau_
vma_del
(
&
fb
->
vma
);
nouveau_bo_unmap
(
fb
->
nvbo
);
out_unpin:
nouveau_bo_unpin
(
fb
->
nvbo
);
...
...
@@ -429,7 +430,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
drm_fb_helper_fini
(
&
fbcon
->
helper
);
if
(
nouveau_fb
->
nvbo
)
{
nouveau_
bo_vma_del
(
nouveau_fb
->
nvbo
,
&
nouveau_fb
->
vma
);
nouveau_
vma_del
(
&
nouveau_fb
->
vma
);
nouveau_bo_unmap
(
nouveau_fb
->
nvbo
);
nouveau_bo_unpin
(
nouveau_fb
->
nvbo
);
drm_framebuffer_unreference
(
&
nouveau_fb
->
base
);
...
...
drivers/gpu/drm/nouveau/nouveau_fence.h
浏览文件 @
24e8375b
...
...
@@ -88,7 +88,7 @@ int nouveau_flip_complete(struct nvif_notify *);
struct
nv84_fence_chan
{
struct
nouveau_fence_chan
base
;
struct
n
vkm_vma
vma
;
struct
n
ouveau_vma
*
vma
;
};
struct
nv84_fence_priv
{
...
...
drivers/gpu/drm/nouveau/nouveau_gem.c
浏览文件 @
24e8375b
...
...
@@ -31,6 +31,7 @@
#include "nouveau_ttm.h"
#include "nouveau_gem.h"
#include "nouveau_vmm.h"
void
nouveau_gem_object_del
(
struct
drm_gem_object
*
gem
)
...
...
@@ -64,8 +65,8 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
struct
nouveau_cli
*
cli
=
nouveau_cli
(
file_priv
);
struct
nouveau_bo
*
nvbo
=
nouveau_gem_object
(
gem
);
struct
nouveau_drm
*
drm
=
nouveau_bdev
(
nvbo
->
bo
.
bdev
);
struct
nvkm_vma
*
vma
;
struct
device
*
dev
=
drm
->
dev
->
dev
;
struct
nouveau_vma
*
vma
;
int
ret
;
if
(
!
cli
->
vm
)
...
...
@@ -75,30 +76,13 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
if
(
ret
)
return
ret
;
vma
=
nouveau_bo_vma_find
(
nvbo
,
cli
->
vm
);
if
(
!
vma
)
{
vma
=
kzalloc
(
sizeof
(
*
vma
),
GFP_KERNEL
);
if
(
!
vma
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
ret
=
pm_runtime_get_sync
(
dev
);
if
(
ret
<
0
&&
ret
!=
-
EACCES
)
{
kfree
(
vma
);
goto
out
;
}
ret
=
nouveau_bo_vma_add
(
nvbo
,
cli
->
vm
,
vma
);
if
(
ret
)
kfree
(
vma
);
pm_runtime_mark_last_busy
(
dev
);
pm_runtime_put_autosuspend
(
dev
);
}
else
{
vma
->
refcount
++
;
}
ret
=
pm_runtime_get_sync
(
dev
);
if
(
ret
<
0
&&
ret
!=
-
EACCES
)
goto
out
;
ret
=
nouveau_vma_new
(
nvbo
,
&
cli
->
vmm
,
&
vma
);
pm_runtime_mark_last_busy
(
dev
);
pm_runtime_put_autosuspend
(
dev
);
out:
ttm_bo_unreserve
(
&
nvbo
->
bo
);
return
ret
;
...
...
@@ -107,14 +91,12 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
static
void
nouveau_gem_object_delete
(
void
*
data
)
{
struct
nvkm_vma
*
vma
=
data
;
nvkm_vm_unmap
(
vma
);
nvkm_vm_put
(
vma
);
kfree
(
vma
);
struct
nouveau_vma
*
vma
=
data
;
nouveau_vma_del
(
&
vma
);
}
static
void
nouveau_gem_object_unmap
(
struct
nouveau_bo
*
nvbo
,
struct
n
vkm
_vma
*
vma
)
nouveau_gem_object_unmap
(
struct
nouveau_bo
*
nvbo
,
struct
n
ouveau
_vma
*
vma
)
{
const
bool
mapped
=
nvbo
->
bo
.
mem
.
mem_type
!=
TTM_PL_SYSTEM
;
struct
reservation_object
*
resv
=
nvbo
->
bo
.
resv
;
...
...
@@ -123,7 +105,7 @@ nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nvkm_vma *vma)
fobj
=
reservation_object_get_list
(
resv
);
list_del
(
&
vma
->
head
);
list_del
_init
(
&
vma
->
head
);
if
(
fobj
&&
fobj
->
shared_count
>
1
)
ttm_bo_wait
(
&
nvbo
->
bo
,
false
,
false
);
...
...
@@ -133,14 +115,10 @@ nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nvkm_vma *vma)
else
fence
=
reservation_object_get_excl
(
nvbo
->
bo
.
resv
);
if
(
fence
&&
mapped
)
{
if
(
fence
&&
mapped
)
nouveau_fence_work
(
fence
,
nouveau_gem_object_delete
,
vma
);
}
else
{
if
(
mapped
)
nvkm_vm_unmap
(
vma
);
nvkm_vm_put
(
vma
);
kfree
(
vma
);
}
else
nouveau_vma_del
(
&
vma
);
}
void
...
...
@@ -150,7 +128,7 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
struct
nouveau_bo
*
nvbo
=
nouveau_gem_object
(
gem
);
struct
nouveau_drm
*
drm
=
nouveau_bdev
(
nvbo
->
bo
.
bdev
);
struct
device
*
dev
=
drm
->
dev
->
dev
;
struct
n
vkm
_vma
*
vma
;
struct
n
ouveau
_vma
*
vma
;
int
ret
;
if
(
!
cli
->
vm
)
...
...
@@ -160,9 +138,9 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
if
(
ret
)
return
;
vma
=
nouveau_
bo_vma_find
(
nvbo
,
cli
->
v
m
);
vma
=
nouveau_
vma_find
(
nvbo
,
&
cli
->
vm
m
);
if
(
vma
)
{
if
(
--
vma
->
ref
count
==
0
)
{
if
(
--
vma
->
ref
s
==
0
)
{
ret
=
pm_runtime_get_sync
(
dev
);
if
(
!
WARN_ON
(
ret
<
0
&&
ret
!=
-
EACCES
))
{
nouveau_gem_object_unmap
(
nvbo
,
vma
);
...
...
@@ -227,7 +205,7 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem,
{
struct
nouveau_cli
*
cli
=
nouveau_cli
(
file_priv
);
struct
nouveau_bo
*
nvbo
=
nouveau_gem_object
(
gem
);
struct
n
vkm
_vma
*
vma
;
struct
n
ouveau
_vma
*
vma
;
if
(
is_power_of_2
(
nvbo
->
valid_domains
))
rep
->
domain
=
nvbo
->
valid_domains
;
...
...
@@ -237,11 +215,11 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem,
rep
->
domain
=
NOUVEAU_GEM_DOMAIN_VRAM
;
rep
->
offset
=
nvbo
->
bo
.
offset
;
if
(
cli
->
vm
)
{
vma
=
nouveau_
bo_vma_find
(
nvbo
,
cli
->
v
m
);
vma
=
nouveau_
vma_find
(
nvbo
,
&
cli
->
vm
m
);
if
(
!
vma
)
return
-
EINVAL
;
rep
->
offset
=
vma
->
offset
;
rep
->
offset
=
vma
->
addr
;
}
rep
->
size
=
nvbo
->
bo
.
mem
.
num_pages
<<
PAGE_SHIFT
;
...
...
@@ -798,7 +776,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
bo
[
push
[
i
].
bo_index
].
user_priv
;
uint32_t
cmd
;
cmd
=
chan
->
push
.
vma
.
offset
+
((
chan
->
dma
.
cur
+
2
)
<<
2
);
cmd
=
chan
->
push
.
addr
+
((
chan
->
dma
.
cur
+
2
)
<<
2
);
cmd
|=
0x20000000
;
if
(
unlikely
(
cmd
!=
req
->
suffix0
))
{
if
(
!
nvbo
->
kmap
.
virtual
)
{
...
...
@@ -850,7 +828,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
req
->
suffix1
=
0x00000000
;
}
else
{
req
->
suffix0
=
0x20000000
|
(
chan
->
push
.
vma
.
offset
+
((
chan
->
dma
.
cur
+
2
)
<<
2
));
(
chan
->
push
.
addr
+
((
chan
->
dma
.
cur
+
2
)
<<
2
));
req
->
suffix1
=
0x00000000
;
}
...
...
drivers/gpu/drm/nouveau/nouveau_vmm.c
0 → 100644
浏览文件 @
24e8375b
/*
* Copyright 2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nouveau_vmm.h"
#include "nouveau_drv.h"
#include "nouveau_bo.h"
#include "nouveau_mem.h"
void
nouveau_vma_unmap
(
struct
nouveau_vma
*
vma
)
{
if
(
vma
->
mem
)
{
nvkm_vm_unmap
(
&
vma
->
_vma
);
vma
->
mem
=
NULL
;
}
}
int
nouveau_vma_map
(
struct
nouveau_vma
*
vma
,
struct
nouveau_mem
*
mem
)
{
int
ret
=
nouveau_mem_map
(
mem
,
vma
->
vmm
->
vm
,
&
vma
->
_vma
);
if
(
ret
)
return
ret
;
vma
->
mem
=
mem
;
return
0
;
}
struct
nouveau_vma
*
nouveau_vma_find
(
struct
nouveau_bo
*
nvbo
,
struct
nouveau_vmm
*
vmm
)
{
struct
nouveau_vma
*
vma
;
list_for_each_entry
(
vma
,
&
nvbo
->
vma_list
,
head
)
{
if
(
vma
->
vmm
==
vmm
)
return
vma
;
}
return
NULL
;
}
void
nouveau_vma_del
(
struct
nouveau_vma
**
pvma
)
{
struct
nouveau_vma
*
vma
=
*
pvma
;
if
(
vma
&&
--
vma
->
refs
<=
0
)
{
if
(
likely
(
vma
->
addr
!=
~
0ULL
))
{
nouveau_vma_unmap
(
vma
);
nvkm_vm_put
(
&
vma
->
_vma
);
}
list_del
(
&
vma
->
head
);
*
pvma
=
NULL
;
kfree
(
*
pvma
);
}
}
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_vma
*
vma
;
int
ret
;
if
((
vma
=
*
pvma
=
nouveau_vma_find
(
nvbo
,
vmm
)))
{
vma
->
refs
++
;
return
0
;
}
if
(
!
(
vma
=
*
pvma
=
kmalloc
(
sizeof
(
*
vma
),
GFP_KERNEL
)))
return
-
ENOMEM
;
vma
->
vmm
=
vmm
;
vma
->
refs
=
1
;
vma
->
addr
=
~
0ULL
;
vma
->
mem
=
NULL
;
list_add_tail
(
&
vma
->
head
,
&
nvbo
->
vma_list
);
if
(
nvbo
->
bo
.
mem
.
mem_type
!=
TTM_PL_SYSTEM
&&
mem
->
mem
.
page
==
nvbo
->
page
)
{
ret
=
nvkm_vm_get
(
vmm
->
vm
,
mem
->
_mem
->
size
<<
12
,
mem
->
mem
.
page
,
NV_MEM_ACCESS_RW
,
&
vma
->
_vma
);
if
(
ret
)
goto
done
;
vma
->
addr
=
vma
->
_vma
.
offset
;
ret
=
nouveau_vma_map
(
vma
,
mem
);
}
else
{
ret
=
nvkm_vm_get
(
vmm
->
vm
,
mem
->
_mem
->
size
<<
12
,
mem
->
mem
.
page
,
NV_MEM_ACCESS_RW
,
&
vma
->
_vma
);
vma
->
addr
=
vma
->
_vma
.
offset
;
}
done:
if
(
ret
)
nouveau_vma_del
(
pvma
);
return
ret
;
}
void
nouveau_vmm_fini
(
struct
nouveau_vmm
*
vmm
)
{
nvkm_vm_ref
(
NULL
,
&
vmm
->
vm
,
NULL
);
}
int
nouveau_vmm_init
(
struct
nouveau_cli
*
cli
,
s32
oclass
,
struct
nouveau_vmm
*
vmm
)
{
vmm
->
cli
=
cli
;
return
nvkm_vm_new
(
nvxx_device
(
&
cli
->
device
),
0
,
(
1ULL
<<
40
),
0x1000
,
NULL
,
&
vmm
->
vm
);
}
drivers/gpu/drm/nouveau/nouveau_vmm.h
0 → 100644
浏览文件 @
24e8375b
#ifndef __NOUVEAU_VMA_H__
#define __NOUVEAU_VMA_H__
#include <subdev/mmu.h>
struct
nouveau_bo
;
struct
nouveau_mem
;
struct
nouveau_vma
{
struct
nouveau_vmm
*
vmm
;
int
refs
;
struct
list_head
head
;
u64
addr
;
struct
nouveau_mem
*
mem
;
struct
nvkm_vma
_vma
;
};
struct
nouveau_vma
*
nouveau_vma_find
(
struct
nouveau_bo
*
,
struct
nouveau_vmm
*
);
int
nouveau_vma_new
(
struct
nouveau_bo
*
,
struct
nouveau_vmm
*
,
struct
nouveau_vma
**
);
void
nouveau_vma_del
(
struct
nouveau_vma
**
);
int
nouveau_vma_map
(
struct
nouveau_vma
*
,
struct
nouveau_mem
*
);
void
nouveau_vma_unmap
(
struct
nouveau_vma
*
);
struct
nouveau_vmm
{
struct
nouveau_cli
*
cli
;
struct
nvkm_vm
*
vm
;
};
int
nouveau_vmm_init
(
struct
nouveau_cli
*
,
s32
oclass
,
struct
nouveau_vmm
*
);
void
nouveau_vmm_fini
(
struct
nouveau_vmm
*
);
#endif
drivers/gpu/drm/nouveau/nv50_fbcon.c
浏览文件 @
24e8375b
...
...
@@ -25,6 +25,7 @@
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"
#include "nouveau_vmm.h"
int
nv50_fbcon_fillrect
(
struct
fb_info
*
info
,
const
struct
fb_fillrect
*
rect
)
...
...
@@ -239,8 +240,8 @@ nv50_fbcon_accel_init(struct fb_info *info)
OUT_RING
(
chan
,
info
->
fix
.
line_length
);
OUT_RING
(
chan
,
info
->
var
.
xres_virtual
);
OUT_RING
(
chan
,
info
->
var
.
yres_virtual
);
OUT_RING
(
chan
,
upper_32_bits
(
fb
->
vma
.
offset
));
OUT_RING
(
chan
,
lower_32_bits
(
fb
->
vma
.
offset
));
OUT_RING
(
chan
,
upper_32_bits
(
fb
->
vma
->
addr
));
OUT_RING
(
chan
,
lower_32_bits
(
fb
->
vma
->
addr
));
BEGIN_NV04
(
chan
,
NvSub2D
,
0x0230
,
2
);
OUT_RING
(
chan
,
format
);
OUT_RING
(
chan
,
1
);
...
...
@@ -248,8 +249,8 @@ nv50_fbcon_accel_init(struct fb_info *info)
OUT_RING
(
chan
,
info
->
fix
.
line_length
);
OUT_RING
(
chan
,
info
->
var
.
xres_virtual
);
OUT_RING
(
chan
,
info
->
var
.
yres_virtual
);
OUT_RING
(
chan
,
upper_32_bits
(
fb
->
vma
.
offset
));
OUT_RING
(
chan
,
lower_32_bits
(
fb
->
vma
.
offset
));
OUT_RING
(
chan
,
upper_32_bits
(
fb
->
vma
->
addr
));
OUT_RING
(
chan
,
lower_32_bits
(
fb
->
vma
->
addr
));
FIRE_RING
(
chan
);
return
0
;
...
...
drivers/gpu/drm/nouveau/nv84_fence.c
浏览文件 @
24e8375b
...
...
@@ -25,6 +25,7 @@
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_fence.h"
#include "nouveau_vmm.h"
#include "nv50_display.h"
...
...
@@ -68,7 +69,7 @@ nv84_fence_emit(struct nouveau_fence *fence)
{
struct
nouveau_channel
*
chan
=
fence
->
channel
;
struct
nv84_fence_chan
*
fctx
=
chan
->
fence
;
u64
addr
=
fctx
->
vma
.
offset
+
chan
->
chid
*
16
;
u64
addr
=
fctx
->
vma
->
addr
+
chan
->
chid
*
16
;
return
fctx
->
base
.
emit32
(
chan
,
addr
,
fence
->
base
.
seqno
);
}
...
...
@@ -78,7 +79,7 @@ nv84_fence_sync(struct nouveau_fence *fence,
struct
nouveau_channel
*
prev
,
struct
nouveau_channel
*
chan
)
{
struct
nv84_fence_chan
*
fctx
=
chan
->
fence
;
u64
addr
=
fctx
->
vma
.
offset
+
prev
->
chid
*
16
;
u64
addr
=
fctx
->
vma
->
addr
+
prev
->
chid
*
16
;
return
fctx
->
base
.
sync32
(
chan
,
addr
,
fence
->
base
.
seqno
);
}
...
...
@@ -98,7 +99,7 @@ nv84_fence_context_del(struct nouveau_channel *chan)
nouveau_bo_wr32
(
priv
->
bo
,
chan
->
chid
*
16
/
4
,
fctx
->
base
.
sequence
);
mutex_lock
(
&
priv
->
mutex
);
nouveau_
bo_vma_del
(
priv
->
bo
,
&
fctx
->
vma
);
nouveau_
vma_del
(
&
fctx
->
vma
);
mutex_unlock
(
&
priv
->
mutex
);
nouveau_fence_context_del
(
&
fctx
->
base
);
chan
->
fence
=
NULL
;
...
...
@@ -126,7 +127,7 @@ nv84_fence_context_new(struct nouveau_channel *chan)
fctx
->
base
.
sequence
=
nv84_fence_read
(
chan
);
mutex_lock
(
&
priv
->
mutex
);
ret
=
nouveau_
bo_vma_add
(
priv
->
bo
,
cli
->
v
m
,
&
fctx
->
vma
);
ret
=
nouveau_
vma_new
(
priv
->
bo
,
&
cli
->
vm
m
,
&
fctx
->
vma
);
mutex_unlock
(
&
priv
->
mutex
);
if
(
ret
)
...
...
drivers/gpu/drm/nouveau/nvc0_fbcon.c
浏览文件 @
24e8375b
...
...
@@ -25,6 +25,7 @@
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"
#include "nouveau_vmm.h"
int
nvc0_fbcon_fillrect
(
struct
fb_info
*
info
,
const
struct
fb_fillrect
*
rect
)
...
...
@@ -239,8 +240,8 @@ nvc0_fbcon_accel_init(struct fb_info *info)
OUT_RING
(
chan
,
info
->
fix
.
line_length
);
OUT_RING
(
chan
,
info
->
var
.
xres_virtual
);
OUT_RING
(
chan
,
info
->
var
.
yres_virtual
);
OUT_RING
(
chan
,
upper_32_bits
(
fb
->
vma
.
offset
));
OUT_RING
(
chan
,
lower_32_bits
(
fb
->
vma
.
offset
));
OUT_RING
(
chan
,
upper_32_bits
(
fb
->
vma
->
addr
));
OUT_RING
(
chan
,
lower_32_bits
(
fb
->
vma
->
addr
));
BEGIN_NVC0
(
chan
,
NvSub2D
,
0x0230
,
10
);
OUT_RING
(
chan
,
format
);
OUT_RING
(
chan
,
1
);
...
...
@@ -250,8 +251,8 @@ nvc0_fbcon_accel_init(struct fb_info *info)
OUT_RING
(
chan
,
info
->
fix
.
line_length
);
OUT_RING
(
chan
,
info
->
var
.
xres_virtual
);
OUT_RING
(
chan
,
info
->
var
.
yres_virtual
);
OUT_RING
(
chan
,
upper_32_bits
(
fb
->
vma
.
offset
));
OUT_RING
(
chan
,
lower_32_bits
(
fb
->
vma
.
offset
));
OUT_RING
(
chan
,
upper_32_bits
(
fb
->
vma
->
addr
));
OUT_RING
(
chan
,
lower_32_bits
(
fb
->
vma
->
addr
));
FIRE_RING
(
chan
);
return
0
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录