]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2010-2018 Intel Corporation | |
3 | */ | |
4 | ||
5 | #include <sys/ioctl.h> | |
6 | ||
7 | #include "ifpga_feature_dev.h" | |
8 | ||
9 | /* | |
10 | * Enable Port by clear the port soft reset bit, which is set by default. | |
11 | * The AFU is unable to respond to any MMIO access while in reset. | |
12 | * __fpga_port_enable function should only be used after __fpga_port_disable | |
13 | * function. | |
14 | */ | |
15 | void __fpga_port_enable(struct ifpga_port_hw *port) | |
16 | { | |
17 | struct feature_port_header *port_hdr; | |
18 | struct feature_port_control control; | |
19 | ||
20 | WARN_ON(!port->disable_count); | |
21 | ||
22 | if (--port->disable_count != 0) | |
23 | return; | |
24 | ||
25 | port_hdr = get_port_feature_ioaddr_by_index(port, | |
26 | PORT_FEATURE_ID_HEADER); | |
27 | WARN_ON(!port_hdr); | |
28 | ||
29 | control.csr = readq(&port_hdr->control); | |
30 | control.port_sftrst = 0x0; | |
31 | writeq(control.csr, &port_hdr->control); | |
32 | } | |
33 | ||
34 | int __fpga_port_disable(struct ifpga_port_hw *port) | |
35 | { | |
36 | struct feature_port_header *port_hdr; | |
37 | struct feature_port_control control; | |
38 | ||
39 | if (port->disable_count++ != 0) | |
40 | return 0; | |
41 | ||
42 | port_hdr = get_port_feature_ioaddr_by_index(port, | |
43 | PORT_FEATURE_ID_HEADER); | |
44 | WARN_ON(!port_hdr); | |
45 | ||
46 | /* Set port soft reset */ | |
47 | control.csr = readq(&port_hdr->control); | |
48 | control.port_sftrst = 0x1; | |
49 | writeq(control.csr, &port_hdr->control); | |
50 | ||
51 | /* | |
52 | * HW sets ack bit to 1 when all outstanding requests have been drained | |
53 | * on this port and minimum soft reset pulse width has elapsed. | |
54 | * Driver polls port_soft_reset_ack to determine if reset done by HW. | |
55 | */ | |
56 | control.port_sftrst_ack = 1; | |
57 | ||
58 | if (fpga_wait_register_field(port_sftrst_ack, control, | |
59 | &port_hdr->control, RST_POLL_TIMEOUT, | |
60 | RST_POLL_INVL)) { | |
61 | dev_err(port, "timeout, fail to reset device\n"); | |
62 | return -ETIMEDOUT; | |
63 | } | |
64 | ||
65 | return 0; | |
66 | } | |
67 | ||
68 | int fpga_get_afu_uuid(struct ifpga_port_hw *port, struct uuid *uuid) | |
69 | { | |
70 | struct feature_port_header *port_hdr; | |
71 | u64 guidl, guidh; | |
72 | ||
9f95a23c TL |
73 | if (!uuid) |
74 | return -EINVAL; | |
75 | ||
11fdf7f2 TL |
76 | port_hdr = get_port_feature_ioaddr_by_index(port, PORT_FEATURE_ID_UAFU); |
77 | ||
78 | spinlock_lock(&port->lock); | |
79 | guidl = readq(&port_hdr->afu_header.guid.b[0]); | |
80 | guidh = readq(&port_hdr->afu_header.guid.b[8]); | |
81 | spinlock_unlock(&port->lock); | |
82 | ||
9f95a23c TL |
83 | opae_memcpy(uuid->b, &guidl, sizeof(u64)); |
84 | opae_memcpy(uuid->b + 8, &guidh, sizeof(u64)); | |
11fdf7f2 TL |
85 | |
86 | return 0; | |
87 | } | |
88 | ||
89 | /* Mask / Unmask Port Errors by the Error Mask register. */ | |
90 | void port_err_mask(struct ifpga_port_hw *port, bool mask) | |
91 | { | |
92 | struct feature_port_error *port_err; | |
93 | struct feature_port_err_key err_mask; | |
94 | ||
95 | port_err = get_port_feature_ioaddr_by_index(port, | |
96 | PORT_FEATURE_ID_ERROR); | |
97 | ||
98 | if (mask) | |
99 | err_mask.csr = PORT_ERR_MASK; | |
100 | else | |
101 | err_mask.csr = 0; | |
102 | ||
103 | writeq(err_mask.csr, &port_err->error_mask); | |
104 | } | |
105 | ||
106 | /* Clear All Port Errors. */ | |
107 | int port_err_clear(struct ifpga_port_hw *port, u64 err) | |
108 | { | |
109 | struct feature_port_header *port_hdr; | |
110 | struct feature_port_error *port_err; | |
111 | struct feature_port_err_key mask; | |
112 | struct feature_port_first_err_key first; | |
113 | struct feature_port_status status; | |
114 | int ret = 0; | |
115 | ||
116 | port_err = get_port_feature_ioaddr_by_index(port, | |
117 | PORT_FEATURE_ID_ERROR); | |
118 | port_hdr = get_port_feature_ioaddr_by_index(port, | |
119 | PORT_FEATURE_ID_HEADER); | |
120 | ||
121 | /* | |
122 | * Clear All Port Errors | |
123 | * | |
124 | * - Check for AP6 State | |
125 | * - Halt Port by keeping Port in reset | |
126 | * - Set PORT Error mask to all 1 to mask errors | |
127 | * - Clear all errors | |
128 | * - Set Port mask to all 0 to enable errors | |
129 | * - All errors start capturing new errors | |
130 | * - Enable Port by pulling the port out of reset | |
131 | */ | |
132 | ||
133 | /* If device is still in AP6 state, can not clear any error.*/ | |
134 | status.csr = readq(&port_hdr->status); | |
135 | if (status.power_state == PORT_POWER_STATE_AP6) { | |
136 | dev_err(dev, "Could not clear errors, device in AP6 state.\n"); | |
137 | return -EBUSY; | |
138 | } | |
139 | ||
140 | /* Halt Port by keeping Port in reset */ | |
141 | ret = __fpga_port_disable(port); | |
142 | if (ret) | |
143 | return ret; | |
144 | ||
145 | /* Mask all errors */ | |
146 | port_err_mask(port, true); | |
147 | ||
148 | /* Clear errors if err input matches with current port errors.*/ | |
149 | mask.csr = readq(&port_err->port_error); | |
150 | ||
151 | if (mask.csr == err) { | |
152 | writeq(mask.csr, &port_err->port_error); | |
153 | ||
154 | first.csr = readq(&port_err->port_first_error); | |
155 | writeq(first.csr, &port_err->port_first_error); | |
156 | } else { | |
157 | ret = -EBUSY; | |
158 | } | |
159 | ||
160 | /* Clear mask */ | |
161 | port_err_mask(port, false); | |
162 | ||
163 | /* Enable the Port by clear the reset */ | |
164 | __fpga_port_enable(port); | |
165 | ||
166 | return ret; | |
167 | } | |
168 | ||
169 | int port_clear_error(struct ifpga_port_hw *port) | |
170 | { | |
171 | struct feature_port_error *port_err; | |
172 | struct feature_port_err_key error; | |
173 | ||
174 | port_err = get_port_feature_ioaddr_by_index(port, | |
175 | PORT_FEATURE_ID_ERROR); | |
176 | error.csr = readq(&port_err->port_error); | |
177 | ||
178 | dev_info(port, "read port error: 0x%lx\n", (unsigned long)error.csr); | |
179 | ||
180 | return port_err_clear(port, error.csr); | |
181 | } | |
182 | ||
9f95a23c TL |
183 | static struct feature_driver fme_feature_drvs[] = { |
184 | {FEATURE_DRV(FME_FEATURE_ID_HEADER, FME_FEATURE_HEADER, | |
185 | &fme_hdr_ops),}, | |
186 | {FEATURE_DRV(FME_FEATURE_ID_THERMAL_MGMT, FME_FEATURE_THERMAL_MGMT, | |
187 | &fme_thermal_mgmt_ops),}, | |
188 | {FEATURE_DRV(FME_FEATURE_ID_POWER_MGMT, FME_FEATURE_POWER_MGMT, | |
189 | &fme_power_mgmt_ops),}, | |
190 | {FEATURE_DRV(FME_FEATURE_ID_GLOBAL_ERR, FME_FEATURE_GLOBAL_ERR, | |
191 | &fme_global_err_ops),}, | |
192 | {FEATURE_DRV(FME_FEATURE_ID_PR_MGMT, FME_FEATURE_PR_MGMT, | |
193 | &fme_pr_mgmt_ops),}, | |
194 | {FEATURE_DRV(FME_FEATURE_ID_GLOBAL_DPERF, FME_FEATURE_GLOBAL_DPERF, | |
195 | &fme_global_dperf_ops),}, | |
196 | {FEATURE_DRV(FME_FEATURE_ID_HSSI_ETH, FME_FEATURE_HSSI_ETH, | |
197 | &fme_hssi_eth_ops),}, | |
198 | {FEATURE_DRV(FME_FEATURE_ID_EMIF_MGMT, FME_FEATURE_EMIF_MGMT, | |
199 | &fme_emif_ops),}, | |
200 | {FEATURE_DRV(FME_FEATURE_ID_MAX10_SPI, FME_FEATURE_MAX10_SPI, | |
201 | &fme_spi_master_ops),}, | |
202 | {FEATURE_DRV(FME_FEATURE_ID_NIOS_SPI, FME_FEATURE_NIOS_SPI, | |
203 | &fme_nios_spi_master_ops),}, | |
204 | {FEATURE_DRV(FME_FEATURE_ID_I2C_MASTER, FME_FEATURE_I2C_MASTER, | |
205 | &fme_i2c_master_ops),}, | |
206 | {FEATURE_DRV(FME_FEATURE_ID_ETH_GROUP, FME_FEATURE_ETH_GROUP, | |
207 | &fme_eth_group_ops),}, | |
208 | {0, NULL, NULL}, /* end of arrary */ | |
209 | }; | |
210 | ||
211 | static struct feature_driver port_feature_drvs[] = { | |
212 | {FEATURE_DRV(PORT_FEATURE_ID_HEADER, PORT_FEATURE_HEADER, | |
213 | &ifpga_rawdev_port_hdr_ops)}, | |
214 | {FEATURE_DRV(PORT_FEATURE_ID_ERROR, PORT_FEATURE_ERR, | |
215 | &ifpga_rawdev_port_error_ops)}, | |
216 | {FEATURE_DRV(PORT_FEATURE_ID_UINT, PORT_FEATURE_UINT, | |
217 | &ifpga_rawdev_port_uint_ops)}, | |
218 | {FEATURE_DRV(PORT_FEATURE_ID_STP, PORT_FEATURE_STP, | |
219 | &ifpga_rawdev_port_stp_ops)}, | |
220 | {FEATURE_DRV(PORT_FEATURE_ID_UAFU, PORT_FEATURE_UAFU, | |
221 | &ifpga_rawdev_port_afu_ops)}, | |
222 | {0, NULL, NULL}, /* end of array */ | |
223 | }; | |
224 | ||
225 | const char *get_fme_feature_name(unsigned int id) | |
11fdf7f2 | 226 | { |
9f95a23c | 227 | struct feature_driver *drv = fme_feature_drvs; |
11fdf7f2 | 228 | |
9f95a23c TL |
229 | while (drv->name) { |
230 | if (drv->id == id) | |
231 | return drv->name; | |
11fdf7f2 | 232 | |
9f95a23c | 233 | drv++; |
11fdf7f2 | 234 | } |
9f95a23c TL |
235 | |
236 | return NULL; | |
11fdf7f2 TL |
237 | } |
238 | ||
9f95a23c | 239 | const char *get_port_feature_name(unsigned int id) |
11fdf7f2 | 240 | { |
9f95a23c | 241 | struct feature_driver *drv = port_feature_drvs; |
11fdf7f2 | 242 | |
9f95a23c TL |
243 | while (drv->name) { |
244 | if (drv->id == id) | |
245 | return drv->name; | |
246 | ||
247 | drv++; | |
248 | } | |
11fdf7f2 | 249 | |
9f95a23c TL |
250 | return NULL; |
251 | } | |
252 | ||
253 | static void feature_uinit(struct ifpga_feature_list *list) | |
254 | { | |
255 | struct ifpga_feature *feature; | |
256 | ||
257 | TAILQ_FOREACH(feature, list, next) { | |
258 | if (feature->state != IFPGA_FEATURE_ATTACHED) | |
259 | continue; | |
260 | if (feature->ops && feature->ops->uinit) | |
261 | feature->ops->uinit(feature); | |
262 | } | |
263 | } | |
264 | ||
265 | static int feature_init(struct feature_driver *drv, | |
266 | struct ifpga_feature_list *list) | |
267 | { | |
268 | struct ifpga_feature *feature; | |
269 | int ret; | |
270 | ||
271 | while (drv->ops) { | |
272 | TAILQ_FOREACH(feature, list, next) { | |
273 | if (feature->state != IFPGA_FEATURE_ATTACHED) | |
274 | continue; | |
275 | if (feature->id == drv->id) { | |
276 | feature->ops = drv->ops; | |
277 | feature->name = drv->name; | |
278 | if (feature->ops->init) { | |
279 | ret = feature->ops->init(feature); | |
280 | if (ret) | |
281 | goto error; | |
282 | } | |
11fdf7f2 TL |
283 | } |
284 | } | |
9f95a23c | 285 | drv++; |
11fdf7f2 TL |
286 | } |
287 | ||
288 | return 0; | |
9f95a23c TL |
289 | error: |
290 | feature_uinit(list); | |
291 | return ret; | |
11fdf7f2 TL |
292 | } |
293 | ||
9f95a23c | 294 | int fme_hw_init(struct ifpga_fme_hw *fme) |
11fdf7f2 | 295 | { |
9f95a23c | 296 | int ret; |
11fdf7f2 | 297 | |
9f95a23c TL |
298 | if (fme->state != IFPGA_FME_IMPLEMENTED) |
299 | return -ENODEV; | |
300 | ||
301 | ret = feature_init(fme_feature_drvs, &fme->feature_list); | |
302 | if (ret) | |
303 | return ret; | |
304 | ||
305 | return 0; | |
306 | } | |
307 | ||
308 | void fme_hw_uinit(struct ifpga_fme_hw *fme) | |
309 | { | |
310 | feature_uinit(&fme->feature_list); | |
311 | } | |
312 | ||
313 | void port_hw_uinit(struct ifpga_port_hw *port) | |
314 | { | |
315 | feature_uinit(&port->feature_list); | |
11fdf7f2 TL |
316 | } |
317 | ||
318 | int port_hw_init(struct ifpga_port_hw *port) | |
319 | { | |
9f95a23c | 320 | int ret; |
11fdf7f2 TL |
321 | |
322 | if (port->state == IFPGA_PORT_UNUSED) | |
323 | return 0; | |
324 | ||
9f95a23c TL |
325 | ret = feature_init(port_feature_drvs, &port->feature_list); |
326 | if (ret) | |
327 | goto error; | |
11fdf7f2 TL |
328 | |
329 | return 0; | |
9f95a23c TL |
330 | error: |
331 | port_hw_uinit(port); | |
332 | return ret; | |
11fdf7f2 | 333 | } |