2 * SN Platform GRU Driver
6 * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/kernel.h>
25 #include <linux/spinlock.h>
26 #include <linux/uaccess.h>
27 #include <linux/delay.h>
28 #include <linux/bitops.h>
29 #include <asm/uv/uv_hub.h>
31 #include "grutables.h"
32 #include "gruhandles.h"
35 #define CCH_LOCK_ATTEMPTS 10
37 static int gru_user_copy_handle(void __user
**dp
, void *s
)
39 if (copy_to_user(*dp
, s
, GRU_HANDLE_BYTES
))
41 *dp
+= GRU_HANDLE_BYTES
;
45 static int gru_dump_context_data(void *grubase
,
46 struct gru_context_configuration_handle
*cch
,
47 void __user
*ubuf
, int ctxnum
, int dsrcnt
)
49 void *cb
, *cbe
, *tfh
, *gseg
;
52 gseg
= grubase
+ ctxnum
* GRU_GSEG_STRIDE
;
53 cb
= gseg
+ GRU_CB_BASE
;
54 cbe
= grubase
+ GRU_CBE_BASE
;
55 tfh
= grubase
+ GRU_TFH_BASE
;
57 for_each_cbr_in_allocation_map(i
, &cch
->cbr_allocation_map
, scr
) {
58 if (gru_user_copy_handle(&ubuf
, cb
))
60 if (gru_user_copy_handle(&ubuf
, tfh
+ i
* GRU_HANDLE_STRIDE
))
62 if (gru_user_copy_handle(&ubuf
, cbe
+ i
* GRU_HANDLE_STRIDE
))
64 cb
+= GRU_HANDLE_STRIDE
;
67 memcpy(ubuf
, gseg
+ GRU_DS_BASE
, dsrcnt
* GRU_HANDLE_STRIDE
);
74 static int gru_dump_tfm(struct gru_state
*gru
,
75 void __user
*ubuf
, void __user
*ubufend
)
77 struct gru_tlb_fault_map
*tfm
;
80 bytes
= GRU_NUM_TFM
* GRU_CACHE_LINE_BYTES
;
81 if (bytes
> ubufend
- ubuf
)
84 for (i
= 0; i
< GRU_NUM_TFM
; i
++) {
85 tfm
= get_tfm(gru
->gs_gru_base_vaddr
, i
);
86 if (gru_user_copy_handle(&ubuf
, tfm
))
89 return GRU_NUM_TFM
* GRU_CACHE_LINE_BYTES
;
95 static int gru_dump_tgh(struct gru_state
*gru
,
96 void __user
*ubuf
, void __user
*ubufend
)
98 struct gru_tlb_global_handle
*tgh
;
101 bytes
= GRU_NUM_TGH
* GRU_CACHE_LINE_BYTES
;
102 if (bytes
> ubufend
- ubuf
)
105 for (i
= 0; i
< GRU_NUM_TGH
; i
++) {
106 tgh
= get_tgh(gru
->gs_gru_base_vaddr
, i
);
107 if (gru_user_copy_handle(&ubuf
, tgh
))
110 return GRU_NUM_TGH
* GRU_CACHE_LINE_BYTES
;
116 static int gru_dump_context(struct gru_state
*gru
, int ctxnum
,
117 void __user
*ubuf
, void __user
*ubufend
, char data_opt
,
120 struct gru_dump_context_header hdr
;
121 struct gru_dump_context_header __user
*uhdr
= ubuf
;
122 struct gru_context_configuration_handle
*cch
, *ubufcch
;
123 struct gru_thread_state
*gts
;
124 int try, cch_locked
, cbrcnt
= 0, dsrcnt
= 0, bytes
= 0, ret
= 0;
127 memset(&hdr
, 0, sizeof(hdr
));
128 grubase
= gru
->gs_gru_base_vaddr
;
129 cch
= get_cch(grubase
, ctxnum
);
130 for (try = 0; try < CCH_LOCK_ATTEMPTS
; try++) {
131 cch_locked
= trylock_cch_handle(cch
);
139 if (gru_user_copy_handle(&ubuf
, cch
))
142 ubufcch
->delresp
= 0;
143 bytes
= sizeof(hdr
) + GRU_CACHE_LINE_BYTES
;
145 if (cch_locked
|| !lock_cch
) {
146 gts
= gru
->gs_gts
[ctxnum
];
147 if (gts
&& gts
->ts_vma
) {
148 hdr
.pid
= gts
->ts_tgid_owner
;
149 hdr
.vaddr
= gts
->ts_vma
->vm_start
;
151 if (cch
->state
!= CCHSTATE_INACTIVE
) {
152 cbrcnt
= hweight64(cch
->cbr_allocation_map
) *
154 dsrcnt
= data_opt
? hweight32(cch
->dsr_allocation_map
) *
157 bytes
+= (3 * cbrcnt
+ dsrcnt
) * GRU_CACHE_LINE_BYTES
;
158 if (bytes
> ubufend
- ubuf
)
161 ret
= gru_dump_context_data(grubase
, cch
, ubuf
, ctxnum
,
166 unlock_cch_handle(cch
);
170 hdr
.magic
= GRU_DUMP_MAGIC
;
171 hdr
.gid
= gru
->gs_gid
;
175 hdr
.cch_locked
= cch_locked
;
176 if (!ret
&& copy_to_user((void __user
*)uhdr
, &hdr
, sizeof(hdr
)))
179 return ret
? ret
: bytes
;
182 unlock_cch_handle(cch
);
186 int gru_dump_chiplet_request(unsigned long arg
)
188 struct gru_state
*gru
;
189 struct gru_dump_chiplet_state_req req
;
191 void __user
*ubufend
;
192 int ctxnum
, ret
, cnt
= 0;
194 if (copy_from_user(&req
, (void __user
*)arg
, sizeof(req
)))
197 /* Currently, only dump by gid is implemented */
198 if (req
.gid
>= gru_max_gids
|| req
.gid
< 0)
201 gru
= GID_TO_GRU(req
.gid
);
203 ubufend
= req
.buf
+ req
.buflen
;
205 ret
= gru_dump_tfm(gru
, ubuf
, ubufend
);
210 ret
= gru_dump_tgh(gru
, ubuf
, ubufend
);
215 for (ctxnum
= 0; ctxnum
< GRU_NUM_CCH
; ctxnum
++) {
216 if (req
.ctxnum
== ctxnum
|| req
.ctxnum
< 0) {
217 ret
= gru_dump_context(gru
, ctxnum
, ubuf
, ubufend
,
218 req
.data_opt
, req
.lock_cch
);
226 if (copy_to_user((void __user
*)arg
, &req
, sizeof(req
)))