This source file includes following definitions.
- diag_ftp_handler
- diag_ftp_2c4
- diag_ftp_cmd
- diag_ftp_startup
- diag_ftp_shutdown
1
2
3
4
5
6
7
8
9
10 #define KMSG_COMPONENT "hmcdrv"
11 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12
13 #include <linux/kernel.h>
14 #include <linux/mm.h>
15 #include <linux/irq.h>
16 #include <linux/wait.h>
17 #include <linux/string.h>
18 #include <asm/ctl_reg.h>
19 #include <asm/diag.h>
20
21 #include "hmcdrv_ftp.h"
22 #include "diag_ftp.h"
23
24
25 #define DIAG_FTP_RET_OK 0
26 #define DIAG_FTP_RET_EBUSY 4
27 #define DIAG_FTP_RET_EIO 8
28
29 #define DIAG_FTP_RET_EPERM 2
30
31
32 #define DIAG_FTP_STAT_OK 0U
33 #define DIAG_FTP_STAT_PGCC 4U
34 #define DIAG_FTP_STAT_PGIOE 8U
35 #define DIAG_FTP_STAT_TIMEOUT 12U
36 #define DIAG_FTP_STAT_EBASE 16U
37 #define DIAG_FTP_STAT_LDFAIL (DIAG_FTP_STAT_EBASE + 1U)
38 #define DIAG_FTP_STAT_LDNPERM (DIAG_FTP_STAT_EBASE + 2U)
39 #define DIAG_FTP_STAT_LDRUNS (DIAG_FTP_STAT_EBASE + 3U)
40 #define DIAG_FTP_STAT_LDNRUNS (DIAG_FTP_STAT_EBASE + 4U)
41
42
43
44
45
46
47
48
49
50
51
52
53
54 struct diag_ftp_ldfpl {
55 u64 bufaddr;
56 u64 buflen;
57 u64 offset;
58 u64 intparm;
59 u64 transferred;
60 u64 fsize;
61 u64 failaddr;
62 u64 spare;
63 u8 fident[HMCDRV_FTP_FIDENT_MAX];
64 } __packed;
65
66 static DECLARE_COMPLETION(diag_ftp_rx_complete);
67 static int diag_ftp_subcode;
68
69
70
71
72
73
74
75 static void diag_ftp_handler(struct ext_code extirq,
76 unsigned int param32,
77 unsigned long param64)
78 {
79 if ((extirq.subcode >> 8) != 8)
80 return;
81
82 inc_irq_stat(IRQEXT_FTP);
83 diag_ftp_subcode = extirq.subcode & 0xffU;
84 complete(&diag_ftp_rx_complete);
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102 static int diag_ftp_2c4(struct diag_ftp_ldfpl *fpl,
103 enum hmcdrv_ftp_cmdid cmd)
104 {
105 int rc;
106
107 diag_stat_inc(DIAG_STAT_X2C4);
108 asm volatile(
109 " diag %[addr],%[cmd],0x2c4\n"
110 "0: j 2f\n"
111 "1: la %[rc],%[err]\n"
112 "2:\n"
113 EX_TABLE(0b, 1b)
114 : [rc] "=d" (rc), "+m" (*fpl)
115 : [cmd] "0" (cmd), [addr] "d" (virt_to_phys(fpl)),
116 [err] "i" (DIAG_FTP_RET_EPERM)
117 : "cc");
118
119 switch (rc) {
120 case DIAG_FTP_RET_OK:
121 return 0;
122 case DIAG_FTP_RET_EBUSY:
123 return -EBUSY;
124 case DIAG_FTP_RET_EPERM:
125 return -EPERM;
126 case DIAG_FTP_RET_EIO:
127 default:
128 return -EIO;
129 }
130 }
131
132
133
134
135
136
137
138
139
140
141
142 ssize_t diag_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)
143 {
144 struct diag_ftp_ldfpl *ldfpl;
145 ssize_t len;
146 #ifdef DEBUG
147 unsigned long start_jiffies;
148
149 pr_debug("starting DIAG X'2C4' on '%s', requesting %zd bytes\n",
150 ftp->fname, ftp->len);
151 start_jiffies = jiffies;
152 #endif
153 init_completion(&diag_ftp_rx_complete);
154
155 ldfpl = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
156 if (!ldfpl) {
157 len = -ENOMEM;
158 goto out;
159 }
160
161 len = strlcpy(ldfpl->fident, ftp->fname, sizeof(ldfpl->fident));
162 if (len >= HMCDRV_FTP_FIDENT_MAX) {
163 len = -EINVAL;
164 goto out_free;
165 }
166
167 ldfpl->transferred = 0;
168 ldfpl->fsize = 0;
169 ldfpl->offset = ftp->ofs;
170 ldfpl->buflen = ftp->len;
171 ldfpl->bufaddr = virt_to_phys(ftp->buf);
172
173 len = diag_ftp_2c4(ldfpl, ftp->id);
174 if (len)
175 goto out_free;
176
177
178
179
180
181 wait_for_completion(&diag_ftp_rx_complete);
182
183 #ifdef DEBUG
184 pr_debug("completed DIAG X'2C4' after %lu ms\n",
185 (jiffies - start_jiffies) * 1000 / HZ);
186 pr_debug("status of DIAG X'2C4' is %u, with %lld/%lld bytes\n",
187 diag_ftp_subcode, ldfpl->transferred, ldfpl->fsize);
188 #endif
189
190 switch (diag_ftp_subcode) {
191 case DIAG_FTP_STAT_OK:
192 len = ldfpl->transferred;
193 if (fsize)
194 *fsize = ldfpl->fsize;
195 break;
196 case DIAG_FTP_STAT_LDNPERM:
197 len = -EPERM;
198 break;
199 case DIAG_FTP_STAT_LDRUNS:
200 len = -EBUSY;
201 break;
202 case DIAG_FTP_STAT_LDFAIL:
203 len = -ENOENT;
204 break;
205 default:
206 len = -EIO;
207 break;
208 }
209
210 out_free:
211 free_page((unsigned long) ldfpl);
212 out:
213 return len;
214 }
215
216
217
218
219
220
221 int diag_ftp_startup(void)
222 {
223 int rc;
224
225 rc = register_external_irq(EXT_IRQ_CP_SERVICE, diag_ftp_handler);
226 if (rc)
227 return rc;
228
229 irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
230 return 0;
231 }
232
233
234
235
236 void diag_ftp_shutdown(void)
237 {
238 irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL);
239 unregister_external_irq(EXT_IRQ_CP_SERVICE, diag_ftp_handler);
240 }