1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * SN Platform GRU Driver
7 * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved.
10 #include <linux/kernel.h>
12 #include <linux/spinlock.h>
13 #include <linux/uaccess.h>
14 #include <linux/delay.h>
15 #include <linux/bitops.h>
16 #include <asm/uv/uv_hub.h>
18 #include <linux/nospec.h>
21 #include "grutables.h"
22 #include "gruhandles.h"
25 #define CCH_LOCK_ATTEMPTS 10
27 static int gru_user_copy_handle(void __user
**dp
, void *s
)
29 if (copy_to_user(*dp
, s
, GRU_HANDLE_BYTES
))
31 *dp
+= GRU_HANDLE_BYTES
;
35 static int gru_dump_context_data(void *grubase
,
36 struct gru_context_configuration_handle
*cch
,
37 void __user
*ubuf
, int ctxnum
, int dsrcnt
,
40 void *cb
, *cbe
, *tfh
, *gseg
;
43 gseg
= grubase
+ ctxnum
* GRU_GSEG_STRIDE
;
44 cb
= gseg
+ GRU_CB_BASE
;
45 cbe
= grubase
+ GRU_CBE_BASE
;
46 tfh
= grubase
+ GRU_TFH_BASE
;
48 for_each_cbr_in_allocation_map(i
, &cch
->cbr_allocation_map
, scr
) {
51 if (gru_user_copy_handle(&ubuf
, cb
))
53 if (gru_user_copy_handle(&ubuf
, tfh
+ i
* GRU_HANDLE_STRIDE
))
55 if (gru_user_copy_handle(&ubuf
, cbe
+ i
* GRU_HANDLE_STRIDE
))
57 cb
+= GRU_HANDLE_STRIDE
;
60 memcpy(ubuf
, gseg
+ GRU_DS_BASE
, dsrcnt
* GRU_HANDLE_STRIDE
);
67 static int gru_dump_tfm(struct gru_state
*gru
,
68 void __user
*ubuf
, void __user
*ubufend
)
70 struct gru_tlb_fault_map
*tfm
;
73 if (GRU_NUM_TFM
* GRU_CACHE_LINE_BYTES
> ubufend
- ubuf
)
76 for (i
= 0; i
< GRU_NUM_TFM
; i
++) {
77 tfm
= get_tfm(gru
->gs_gru_base_vaddr
, i
);
78 if (gru_user_copy_handle(&ubuf
, tfm
))
81 return GRU_NUM_TFM
* GRU_CACHE_LINE_BYTES
;
87 static int gru_dump_tgh(struct gru_state
*gru
,
88 void __user
*ubuf
, void __user
*ubufend
)
90 struct gru_tlb_global_handle
*tgh
;
93 if (GRU_NUM_TGH
* GRU_CACHE_LINE_BYTES
> ubufend
- ubuf
)
96 for (i
= 0; i
< GRU_NUM_TGH
; i
++) {
97 tgh
= get_tgh(gru
->gs_gru_base_vaddr
, i
);
98 if (gru_user_copy_handle(&ubuf
, tgh
))
101 return GRU_NUM_TGH
* GRU_CACHE_LINE_BYTES
;
107 static int gru_dump_context(struct gru_state
*gru
, int ctxnum
,
108 void __user
*ubuf
, void __user
*ubufend
, char data_opt
,
109 char lock_cch
, char flush_cbrs
)
111 struct gru_dump_context_header hdr
;
112 struct gru_dump_context_header __user
*uhdr
= ubuf
;
113 struct gru_context_configuration_handle
*cch
, *ubufcch
;
114 struct gru_thread_state
*gts
;
115 int try, cch_locked
, cbrcnt
= 0, dsrcnt
= 0, bytes
= 0, ret
= 0;
118 memset(&hdr
, 0, sizeof(hdr
));
119 grubase
= gru
->gs_gru_base_vaddr
;
120 cch
= get_cch(grubase
, ctxnum
);
121 for (try = 0; try < CCH_LOCK_ATTEMPTS
; try++) {
122 cch_locked
= trylock_cch_handle(cch
);
130 if (gru_user_copy_handle(&ubuf
, cch
)) {
132 unlock_cch_handle(cch
);
136 ubufcch
->delresp
= 0;
137 bytes
= sizeof(hdr
) + GRU_CACHE_LINE_BYTES
;
139 if (cch_locked
|| !lock_cch
) {
140 gts
= gru
->gs_gts
[ctxnum
];
141 if (gts
&& gts
->ts_vma
) {
142 hdr
.pid
= gts
->ts_tgid_owner
;
143 hdr
.vaddr
= gts
->ts_vma
->vm_start
;
145 if (cch
->state
!= CCHSTATE_INACTIVE
) {
146 cbrcnt
= hweight64(cch
->cbr_allocation_map
) *
148 dsrcnt
= data_opt
? hweight32(cch
->dsr_allocation_map
) *
151 bytes
+= (3 * cbrcnt
+ dsrcnt
) * GRU_CACHE_LINE_BYTES
;
152 if (bytes
> ubufend
- ubuf
)
155 ret
= gru_dump_context_data(grubase
, cch
, ubuf
, ctxnum
,
159 unlock_cch_handle(cch
);
163 hdr
.magic
= GRU_DUMP_MAGIC
;
164 hdr
.gid
= gru
->gs_gid
;
168 hdr
.cch_locked
= cch_locked
;
169 if (copy_to_user(uhdr
, &hdr
, sizeof(hdr
)))
175 int gru_dump_chiplet_request(unsigned long arg
)
177 struct gru_state
*gru
;
178 struct gru_dump_chiplet_state_req req
;
180 void __user
*ubufend
;
181 int ctxnum
, ret
, cnt
= 0;
183 if (copy_from_user(&req
, (void __user
*)arg
, sizeof(req
)))
186 /* Currently, only dump by gid is implemented */
187 if (req
.gid
>= gru_max_gids
)
189 req
.gid
= array_index_nospec(req
.gid
, gru_max_gids
);
191 gru
= GID_TO_GRU(req
.gid
);
193 ubufend
= req
.buf
+ req
.buflen
;
195 ret
= gru_dump_tfm(gru
, ubuf
, ubufend
);
200 ret
= gru_dump_tgh(gru
, ubuf
, ubufend
);
205 for (ctxnum
= 0; ctxnum
< GRU_NUM_CCH
; ctxnum
++) {
206 if (req
.ctxnum
== ctxnum
|| req
.ctxnum
< 0) {
207 ret
= gru_dump_context(gru
, ctxnum
, ubuf
, ubufend
,
208 req
.data_opt
, req
.lock_cch
,
217 if (copy_to_user((void __user
*)arg
, &req
, sizeof(req
)))