]>
Commit | Line | Data |
---|---|---|
33dea5aa LG |
1 | /* |
2 | * Microsemi Switchtec(tm) PCIe Management Driver | |
3 | * Copyright (c) 2017, Microsemi Corporation | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | */ | |
15 | ||
16 | #include <linux/switchtec.h> | |
17 | #include <linux/module.h> | |
ec0467cc LG |
18 | #include <linux/delay.h> |
19 | #include <linux/kthread.h> | |
3dd4db47 | 20 | #include <linux/interrupt.h> |
e099b45b | 21 | #include <linux/ntb.h> |
33dea5aa LG |
22 | |
23 | MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver"); | |
24 | MODULE_VERSION("0.1"); | |
25 | MODULE_LICENSE("GPL"); | |
26 | MODULE_AUTHOR("Microsemi Corporation"); | |
27 | ||
ec0467cc LG |
28 | static bool use_lut_mws; |
29 | module_param(use_lut_mws, bool, 0644); | |
30 | MODULE_PARM_DESC(use_lut_mws, | |
31 | "Enable the use of the LUT based memory windows"); | |
32 | ||
33 | #ifndef ioread64 | |
34 | #ifdef readq | |
35 | #define ioread64 readq | |
36 | #else | |
37 | #define ioread64 _ioread64 | |
38 | static inline u64 _ioread64(void __iomem *mmio) | |
39 | { | |
40 | u64 low, high; | |
41 | ||
42 | low = ioread32(mmio); | |
43 | high = ioread32(mmio + sizeof(u32)); | |
44 | return low | (high << 32); | |
45 | } | |
46 | #endif | |
47 | #endif | |
48 | ||
49 | #ifndef iowrite64 | |
50 | #ifdef writeq | |
51 | #define iowrite64 writeq | |
52 | #else | |
53 | #define iowrite64 _iowrite64 | |
54 | static inline void _iowrite64(u64 val, void __iomem *mmio) | |
55 | { | |
56 | iowrite32(val, mmio); | |
57 | iowrite32(val >> 32, mmio + sizeof(u32)); | |
58 | } | |
59 | #endif | |
60 | #endif | |
61 | ||
62 | #define SWITCHTEC_NTB_MAGIC 0x45CC0001 | |
63 | #define MAX_MWS 128 | |
64 | ||
65 | struct shared_mw { | |
66 | u32 magic; | |
0ee28f26 | 67 | u32 link_sta; |
ec0467cc LG |
68 | u32 partition_id; |
69 | u64 mw_sizes[MAX_MWS]; | |
70 | }; | |
71 | ||
72 | #define MAX_DIRECT_MW ARRAY_SIZE(((struct ntb_ctrl_regs *)(0))->bar_entry) | |
73 | #define LUT_SIZE SZ_64K | |
74 | ||
33dea5aa | 75 | struct switchtec_ntb { |
e099b45b | 76 | struct ntb_dev ntb; |
33dea5aa | 77 | struct switchtec_dev *stdev; |
ec0467cc LG |
78 | |
79 | int self_partition; | |
80 | int peer_partition; | |
81 | ||
3dd4db47 LG |
82 | int doorbell_irq; |
83 | int message_irq; | |
84 | ||
ec0467cc LG |
85 | struct ntb_info_regs __iomem *mmio_ntb; |
86 | struct ntb_ctrl_regs __iomem *mmio_ctrl; | |
87 | struct ntb_dbmsg_regs __iomem *mmio_dbmsg; | |
88 | struct ntb_ctrl_regs __iomem *mmio_self_ctrl; | |
89 | struct ntb_ctrl_regs __iomem *mmio_peer_ctrl; | |
90 | struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg; | |
91 | ||
92 | struct shared_mw *self_shared; | |
93 | struct shared_mw __iomem *peer_shared; | |
94 | dma_addr_t self_shared_dma; | |
95 | ||
3dd4db47 LG |
96 | u64 db_mask; |
97 | u64 db_valid_mask; | |
98 | int db_shift; | |
99 | int db_peer_shift; | |
100 | ||
ec0467cc LG |
101 | int nr_direct_mw; |
102 | int nr_lut_mw; | |
103 | int direct_mw_to_bar[MAX_DIRECT_MW]; | |
104 | ||
105 | int peer_nr_direct_mw; | |
106 | int peer_nr_lut_mw; | |
107 | int peer_direct_mw_to_bar[MAX_DIRECT_MW]; | |
0ee28f26 LG |
108 | |
109 | bool link_is_up; | |
110 | enum ntb_speed link_speed; | |
111 | enum ntb_width link_width; | |
33dea5aa LG |
112 | }; |
113 | ||
0ee28f26 LG |
114 | static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) |
115 | { | |
116 | return container_of(ntb, struct switchtec_ntb, ntb); | |
117 | } | |
118 | ||
ec0467cc LG |
119 | static int switchtec_ntb_part_op(struct switchtec_ntb *sndev, |
120 | struct ntb_ctrl_regs __iomem *ctl, | |
121 | u32 op, int wait_status) | |
122 | { | |
123 | static const char * const op_text[] = { | |
124 | [NTB_CTRL_PART_OP_LOCK] = "lock", | |
125 | [NTB_CTRL_PART_OP_CFG] = "configure", | |
126 | [NTB_CTRL_PART_OP_RESET] = "reset", | |
127 | }; | |
128 | ||
129 | int i; | |
130 | u32 ps; | |
131 | int status; | |
132 | ||
133 | switch (op) { | |
134 | case NTB_CTRL_PART_OP_LOCK: | |
135 | status = NTB_CTRL_PART_STATUS_LOCKING; | |
136 | break; | |
137 | case NTB_CTRL_PART_OP_CFG: | |
138 | status = NTB_CTRL_PART_STATUS_CONFIGURING; | |
139 | break; | |
140 | case NTB_CTRL_PART_OP_RESET: | |
141 | status = NTB_CTRL_PART_STATUS_RESETTING; | |
142 | break; | |
143 | default: | |
144 | return -EINVAL; | |
145 | } | |
146 | ||
147 | iowrite32(op, &ctl->partition_op); | |
148 | ||
149 | for (i = 0; i < 1000; i++) { | |
150 | if (msleep_interruptible(50) != 0) { | |
151 | iowrite32(NTB_CTRL_PART_OP_RESET, &ctl->partition_op); | |
152 | return -EINTR; | |
153 | } | |
154 | ||
155 | ps = ioread32(&ctl->partition_status) & 0xFFFF; | |
156 | ||
157 | if (ps != status) | |
158 | break; | |
159 | } | |
160 | ||
161 | if (ps == wait_status) | |
162 | return 0; | |
163 | ||
164 | if (ps == status) { | |
165 | dev_err(&sndev->stdev->dev, | |
166 | "Timed out while peforming %s (%d). (%08x)", | |
167 | op_text[op], op, | |
168 | ioread32(&ctl->partition_status)); | |
169 | ||
170 | return -ETIMEDOUT; | |
171 | } | |
172 | ||
173 | return -EIO; | |
174 | } | |
175 | ||
0ee28f26 LG |
176 | static int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx, |
177 | u32 val) | |
178 | { | |
179 | if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_self_dbmsg->omsg)) | |
180 | return -EINVAL; | |
181 | ||
182 | iowrite32(val, &sndev->mmio_self_dbmsg->omsg[idx].msg); | |
183 | ||
184 | return 0; | |
185 | } | |
186 | ||
e099b45b LG |
187 | static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) |
188 | { | |
189 | return 0; | |
190 | } | |
191 | ||
192 | static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, | |
193 | int widx, resource_size_t *addr_align, | |
194 | resource_size_t *size_align, | |
195 | resource_size_t *size_max) | |
196 | { | |
197 | return 0; | |
198 | } | |
199 | ||
200 | static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, | |
201 | dma_addr_t addr, resource_size_t size) | |
202 | { | |
203 | return 0; | |
204 | } | |
205 | ||
206 | static int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb) | |
207 | { | |
208 | return 0; | |
209 | } | |
210 | ||
211 | static int switchtec_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx, | |
212 | phys_addr_t *base, | |
213 | resource_size_t *size) | |
214 | { | |
215 | return 0; | |
216 | } | |
217 | ||
0ee28f26 LG |
218 | static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev, |
219 | int partition, | |
220 | enum ntb_speed *speed, | |
221 | enum ntb_width *width) | |
222 | { | |
223 | struct switchtec_dev *stdev = sndev->stdev; | |
224 | ||
225 | u32 pff = ioread32(&stdev->mmio_part_cfg[partition].vep_pff_inst_id); | |
226 | u32 linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]); | |
227 | ||
228 | if (speed) | |
229 | *speed = (linksta >> 16) & 0xF; | |
230 | ||
231 | if (width) | |
232 | *width = (linksta >> 20) & 0x3F; | |
233 | } | |
234 | ||
235 | static void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev) | |
236 | { | |
237 | enum ntb_speed self_speed, peer_speed; | |
238 | enum ntb_width self_width, peer_width; | |
239 | ||
240 | if (!sndev->link_is_up) { | |
241 | sndev->link_speed = NTB_SPEED_NONE; | |
242 | sndev->link_width = NTB_WIDTH_NONE; | |
243 | return; | |
244 | } | |
245 | ||
246 | switchtec_ntb_part_link_speed(sndev, sndev->self_partition, | |
247 | &self_speed, &self_width); | |
248 | switchtec_ntb_part_link_speed(sndev, sndev->peer_partition, | |
249 | &peer_speed, &peer_width); | |
250 | ||
251 | sndev->link_speed = min(self_speed, peer_speed); | |
252 | sndev->link_width = min(self_width, peer_width); | |
253 | } | |
254 | ||
255 | enum { | |
256 | LINK_MESSAGE = 0, | |
257 | MSG_LINK_UP = 1, | |
258 | MSG_LINK_DOWN = 2, | |
259 | MSG_CHECK_LINK = 3, | |
260 | }; | |
261 | ||
262 | static void switchtec_ntb_check_link(struct switchtec_ntb *sndev) | |
263 | { | |
264 | int link_sta; | |
265 | int old = sndev->link_is_up; | |
266 | ||
267 | link_sta = sndev->self_shared->link_sta; | |
268 | if (link_sta) { | |
269 | u64 peer = ioread64(&sndev->peer_shared->magic); | |
270 | ||
271 | if ((peer & 0xFFFFFFFF) == SWITCHTEC_NTB_MAGIC) | |
272 | link_sta = peer >> 32; | |
273 | else | |
274 | link_sta = 0; | |
275 | } | |
276 | ||
277 | sndev->link_is_up = link_sta; | |
278 | switchtec_ntb_set_link_speed(sndev); | |
279 | ||
280 | if (link_sta != old) { | |
281 | switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK); | |
282 | ntb_link_event(&sndev->ntb); | |
283 | dev_info(&sndev->stdev->dev, "ntb link %s", | |
284 | link_sta ? "up" : "down"); | |
285 | } | |
286 | } | |
287 | ||
288 | static void switchtec_ntb_link_notification(struct switchtec_dev *stdev) | |
289 | { | |
290 | struct switchtec_ntb *sndev = stdev->sndev; | |
291 | ||
292 | switchtec_ntb_check_link(sndev); | |
293 | } | |
294 | ||
e099b45b LG |
295 | static u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb, |
296 | enum ntb_speed *speed, | |
297 | enum ntb_width *width) | |
298 | { | |
0ee28f26 LG |
299 | struct switchtec_ntb *sndev = ntb_sndev(ntb); |
300 | ||
301 | if (speed) | |
302 | *speed = sndev->link_speed; | |
303 | if (width) | |
304 | *width = sndev->link_width; | |
305 | ||
306 | return sndev->link_is_up; | |
e099b45b LG |
307 | } |
308 | ||
309 | static int switchtec_ntb_link_enable(struct ntb_dev *ntb, | |
310 | enum ntb_speed max_speed, | |
311 | enum ntb_width max_width) | |
312 | { | |
0ee28f26 LG |
313 | struct switchtec_ntb *sndev = ntb_sndev(ntb); |
314 | ||
315 | dev_dbg(&sndev->stdev->dev, "enabling link"); | |
316 | ||
317 | sndev->self_shared->link_sta = 1; | |
318 | switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); | |
319 | ||
320 | switchtec_ntb_check_link(sndev); | |
321 | ||
e099b45b LG |
322 | return 0; |
323 | } | |
324 | ||
325 | static int switchtec_ntb_link_disable(struct ntb_dev *ntb) | |
326 | { | |
0ee28f26 LG |
327 | struct switchtec_ntb *sndev = ntb_sndev(ntb); |
328 | ||
329 | dev_dbg(&sndev->stdev->dev, "disabling link"); | |
330 | ||
331 | sndev->self_shared->link_sta = 0; | |
332 | switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); | |
333 | ||
334 | switchtec_ntb_check_link(sndev); | |
335 | ||
e099b45b LG |
336 | return 0; |
337 | } | |
338 | ||
339 | static u64 switchtec_ntb_db_valid_mask(struct ntb_dev *ntb) | |
340 | { | |
341 | return 0; | |
342 | } | |
343 | ||
344 | static int switchtec_ntb_db_vector_count(struct ntb_dev *ntb) | |
345 | { | |
346 | return 0; | |
347 | } | |
348 | ||
349 | static u64 switchtec_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector) | |
350 | { | |
351 | return 0; | |
352 | } | |
353 | ||
354 | static u64 switchtec_ntb_db_read(struct ntb_dev *ntb) | |
355 | { | |
356 | return 0; | |
357 | } | |
358 | ||
359 | static int switchtec_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) | |
360 | { | |
361 | return 0; | |
362 | } | |
363 | ||
364 | static int switchtec_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) | |
365 | { | |
366 | return 0; | |
367 | } | |
368 | ||
369 | static int switchtec_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) | |
370 | { | |
371 | return 0; | |
372 | } | |
373 | ||
374 | static int switchtec_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) | |
375 | { | |
376 | return 0; | |
377 | } | |
378 | ||
379 | static int switchtec_ntb_spad_count(struct ntb_dev *ntb) | |
380 | { | |
381 | return 0; | |
382 | } | |
383 | ||
384 | static u32 switchtec_ntb_spad_read(struct ntb_dev *ntb, int idx) | |
385 | { | |
386 | return 0; | |
387 | } | |
388 | ||
389 | static int switchtec_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val) | |
390 | { | |
391 | return 0; | |
392 | } | |
393 | ||
394 | static int switchtec_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, | |
395 | int sidx, u32 val) | |
396 | { | |
397 | return 0; | |
398 | } | |
399 | ||
400 | static const struct ntb_dev_ops switchtec_ntb_ops = { | |
401 | .mw_count = switchtec_ntb_mw_count, | |
402 | .mw_get_align = switchtec_ntb_mw_get_align, | |
403 | .mw_set_trans = switchtec_ntb_mw_set_trans, | |
404 | .peer_mw_count = switchtec_ntb_peer_mw_count, | |
405 | .peer_mw_get_addr = switchtec_ntb_peer_mw_get_addr, | |
406 | .link_is_up = switchtec_ntb_link_is_up, | |
407 | .link_enable = switchtec_ntb_link_enable, | |
408 | .link_disable = switchtec_ntb_link_disable, | |
409 | .db_valid_mask = switchtec_ntb_db_valid_mask, | |
410 | .db_vector_count = switchtec_ntb_db_vector_count, | |
411 | .db_vector_mask = switchtec_ntb_db_vector_mask, | |
412 | .db_read = switchtec_ntb_db_read, | |
413 | .db_clear = switchtec_ntb_db_clear, | |
414 | .db_set_mask = switchtec_ntb_db_set_mask, | |
415 | .db_clear_mask = switchtec_ntb_db_clear_mask, | |
416 | .peer_db_set = switchtec_ntb_peer_db_set, | |
417 | .spad_count = switchtec_ntb_spad_count, | |
418 | .spad_read = switchtec_ntb_spad_read, | |
419 | .spad_write = switchtec_ntb_spad_write, | |
420 | .peer_spad_write = switchtec_ntb_peer_spad_write, | |
421 | }; | |
422 | ||
ec0467cc LG |
423 | static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) |
424 | { | |
425 | u64 part_map; | |
426 | ||
e099b45b LG |
427 | sndev->ntb.pdev = sndev->stdev->pdev; |
428 | sndev->ntb.topo = NTB_TOPO_SWITCH; | |
429 | sndev->ntb.ops = &switchtec_ntb_ops; | |
430 | ||
ec0467cc LG |
431 | sndev->self_partition = sndev->stdev->partition; |
432 | ||
433 | sndev->mmio_ntb = sndev->stdev->mmio_ntb; | |
434 | part_map = ioread64(&sndev->mmio_ntb->ep_map); | |
435 | part_map &= ~(1 << sndev->self_partition); | |
436 | sndev->peer_partition = ffs(part_map) - 1; | |
437 | ||
438 | dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d (%llx)", | |
439 | sndev->self_partition, sndev->stdev->partition_count, | |
440 | part_map); | |
441 | ||
442 | sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb + | |
443 | SWITCHTEC_NTB_REG_CTRL_OFFSET; | |
444 | sndev->mmio_dbmsg = (void * __iomem)sndev->mmio_ntb + | |
445 | SWITCHTEC_NTB_REG_DBMSG_OFFSET; | |
446 | ||
447 | sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition]; | |
448 | sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition]; | |
449 | sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition]; | |
450 | } | |
451 | ||
452 | static int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl) | |
453 | { | |
454 | int i; | |
455 | int cnt = 0; | |
456 | ||
457 | for (i = 0; i < ARRAY_SIZE(ctrl->bar_entry); i++) { | |
458 | u32 r = ioread32(&ctrl->bar_entry[i].ctl); | |
459 | ||
460 | if (r & NTB_CTRL_BAR_VALID) | |
461 | map[cnt++] = i; | |
462 | } | |
463 | ||
464 | return cnt; | |
465 | } | |
466 | ||
467 | static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev) | |
468 | { | |
469 | sndev->nr_direct_mw = map_bars(sndev->direct_mw_to_bar, | |
470 | sndev->mmio_self_ctrl); | |
471 | ||
472 | sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries); | |
473 | sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw); | |
474 | ||
475 | dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut", | |
476 | sndev->nr_direct_mw, sndev->nr_lut_mw); | |
477 | ||
478 | sndev->peer_nr_direct_mw = map_bars(sndev->peer_direct_mw_to_bar, | |
479 | sndev->mmio_peer_ctrl); | |
480 | ||
481 | sndev->peer_nr_lut_mw = | |
482 | ioread16(&sndev->mmio_peer_ctrl->lut_table_entries); | |
483 | sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw); | |
484 | ||
485 | dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut", | |
486 | sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw); | |
487 | ||
488 | } | |
489 | ||
3dd4db47 LG |
490 | /* |
491 | * There are 64 doorbells in the switch hardware but this is | |
492 | * shared among all partitions. So we must split them in half | |
493 | * (32 for each partition). However, the message interrupts are | |
494 | * also shared with the top 4 doorbells so we just limit this to | |
495 | * 28 doorbells per partition | |
496 | */ | |
497 | static void switchtec_ntb_init_db(struct switchtec_ntb *sndev) | |
498 | { | |
499 | sndev->db_valid_mask = 0x0FFFFFFF; | |
500 | ||
501 | if (sndev->self_partition < sndev->peer_partition) { | |
502 | sndev->db_shift = 0; | |
503 | sndev->db_peer_shift = 32; | |
504 | } else { | |
505 | sndev->db_shift = 32; | |
506 | sndev->db_peer_shift = 0; | |
507 | } | |
508 | ||
509 | sndev->db_mask = 0x0FFFFFFFFFFFFFFFULL; | |
510 | iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); | |
511 | iowrite64(sndev->db_valid_mask << sndev->db_peer_shift, | |
512 | &sndev->mmio_self_dbmsg->odb_mask); | |
513 | } | |
514 | ||
515 | static void switchtec_ntb_init_msgs(struct switchtec_ntb *sndev) | |
516 | { | |
517 | int i; | |
518 | u32 msg_map = 0; | |
519 | ||
520 | for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) { | |
521 | int m = i | sndev->peer_partition << 2; | |
522 | ||
523 | msg_map |= m << i * 8; | |
524 | } | |
525 | ||
526 | iowrite32(msg_map, &sndev->mmio_self_dbmsg->msg_map); | |
527 | ||
528 | for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) | |
529 | iowrite64(NTB_DBMSG_IMSG_STATUS | NTB_DBMSG_IMSG_MASK, | |
530 | &sndev->mmio_self_dbmsg->imsg[i]); | |
531 | } | |
532 | ||
ec0467cc LG |
533 | static int switchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev) |
534 | { | |
535 | int rc = 0; | |
536 | u16 req_id; | |
537 | u32 error; | |
538 | ||
539 | req_id = ioread16(&sndev->mmio_ntb->requester_id); | |
540 | ||
541 | if (ioread32(&sndev->mmio_self_ctrl->req_id_table_size) < 2) { | |
542 | dev_err(&sndev->stdev->dev, | |
543 | "Not enough requester IDs available."); | |
544 | return -EFAULT; | |
545 | } | |
546 | ||
547 | rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl, | |
548 | NTB_CTRL_PART_OP_LOCK, | |
549 | NTB_CTRL_PART_STATUS_LOCKED); | |
550 | if (rc) | |
551 | return rc; | |
552 | ||
553 | iowrite32(NTB_PART_CTRL_ID_PROT_DIS, | |
554 | &sndev->mmio_self_ctrl->partition_ctrl); | |
555 | ||
556 | /* | |
557 | * Root Complex Requester ID (which is 0:00.0) | |
558 | */ | |
559 | iowrite32(0 << 16 | NTB_CTRL_REQ_ID_EN, | |
560 | &sndev->mmio_self_ctrl->req_id_table[0]); | |
561 | ||
562 | /* | |
563 | * Host Bridge Requester ID (as read from the mmap address) | |
564 | */ | |
565 | iowrite32(req_id << 16 | NTB_CTRL_REQ_ID_EN, | |
566 | &sndev->mmio_self_ctrl->req_id_table[1]); | |
567 | ||
568 | rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl, | |
569 | NTB_CTRL_PART_OP_CFG, | |
570 | NTB_CTRL_PART_STATUS_NORMAL); | |
571 | if (rc == -EIO) { | |
572 | error = ioread32(&sndev->mmio_self_ctrl->req_id_error); | |
573 | dev_err(&sndev->stdev->dev, | |
574 | "Error setting up the requester ID table: %08x", | |
575 | error); | |
576 | } | |
577 | ||
578 | return rc; | |
579 | } | |
580 | ||
581 | static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev) | |
582 | { | |
583 | int i; | |
584 | ||
585 | memset(sndev->self_shared, 0, LUT_SIZE); | |
586 | sndev->self_shared->magic = SWITCHTEC_NTB_MAGIC; | |
587 | sndev->self_shared->partition_id = sndev->stdev->partition; | |
588 | ||
589 | for (i = 0; i < sndev->nr_direct_mw; i++) { | |
590 | int bar = sndev->direct_mw_to_bar[i]; | |
591 | resource_size_t sz = pci_resource_len(sndev->stdev->pdev, bar); | |
592 | ||
593 | if (i == 0) | |
594 | sz = min_t(resource_size_t, sz, | |
595 | LUT_SIZE * sndev->nr_lut_mw); | |
596 | ||
597 | sndev->self_shared->mw_sizes[i] = sz; | |
598 | } | |
599 | ||
600 | for (i = 0; i < sndev->nr_lut_mw; i++) { | |
601 | int idx = sndev->nr_direct_mw + i; | |
602 | ||
603 | sndev->self_shared->mw_sizes[idx] = LUT_SIZE; | |
604 | } | |
605 | } | |
606 | ||
607 | static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) | |
608 | { | |
609 | struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; | |
610 | int bar = sndev->direct_mw_to_bar[0]; | |
611 | u32 ctl_val; | |
612 | int rc; | |
613 | ||
614 | sndev->self_shared = dma_zalloc_coherent(&sndev->stdev->pdev->dev, | |
615 | LUT_SIZE, | |
616 | &sndev->self_shared_dma, | |
617 | GFP_KERNEL); | |
618 | if (!sndev->self_shared) { | |
619 | dev_err(&sndev->stdev->dev, | |
620 | "unable to allocate memory for shared mw"); | |
621 | return -ENOMEM; | |
622 | } | |
623 | ||
624 | switchtec_ntb_init_shared(sndev); | |
625 | ||
626 | rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, | |
627 | NTB_CTRL_PART_STATUS_LOCKED); | |
628 | if (rc) | |
629 | goto unalloc_and_exit; | |
630 | ||
631 | ctl_val = ioread32(&ctl->bar_entry[bar].ctl); | |
632 | ctl_val &= 0xFF; | |
633 | ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN; | |
634 | ctl_val |= ilog2(LUT_SIZE) << 8; | |
635 | ctl_val |= (sndev->nr_lut_mw - 1) << 14; | |
636 | iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); | |
637 | ||
638 | iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | | |
639 | sndev->self_shared_dma), | |
640 | &ctl->lut_entry[0]); | |
641 | ||
642 | rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, | |
643 | NTB_CTRL_PART_STATUS_NORMAL); | |
644 | if (rc) { | |
645 | u32 bar_error, lut_error; | |
646 | ||
647 | bar_error = ioread32(&ctl->bar_error); | |
648 | lut_error = ioread32(&ctl->lut_error); | |
649 | dev_err(&sndev->stdev->dev, | |
650 | "Error setting up shared MW: %08x / %08x", | |
651 | bar_error, lut_error); | |
652 | goto unalloc_and_exit; | |
653 | } | |
654 | ||
655 | sndev->peer_shared = pci_iomap(sndev->stdev->pdev, bar, LUT_SIZE); | |
656 | if (!sndev->peer_shared) { | |
657 | rc = -ENOMEM; | |
658 | goto unalloc_and_exit; | |
659 | } | |
660 | ||
661 | dev_dbg(&sndev->stdev->dev, "Shared MW Ready"); | |
662 | return 0; | |
663 | ||
664 | unalloc_and_exit: | |
665 | dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, | |
666 | sndev->self_shared, sndev->self_shared_dma); | |
667 | ||
668 | return rc; | |
669 | } | |
670 | ||
671 | static void switchtec_ntb_deinit_shared_mw(struct switchtec_ntb *sndev) | |
672 | { | |
673 | if (sndev->peer_shared) | |
674 | pci_iounmap(sndev->stdev->pdev, sndev->peer_shared); | |
675 | ||
676 | if (sndev->self_shared) | |
677 | dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, | |
678 | sndev->self_shared, | |
679 | sndev->self_shared_dma); | |
680 | } | |
681 | ||
3dd4db47 LG |
682 | static irqreturn_t switchtec_ntb_doorbell_isr(int irq, void *dev) |
683 | { | |
684 | struct switchtec_ntb *sndev = dev; | |
685 | ||
686 | dev_dbg(&sndev->stdev->dev, "doorbell\n"); | |
687 | ||
688 | return IRQ_HANDLED; | |
689 | } | |
690 | ||
691 | static irqreturn_t switchtec_ntb_message_isr(int irq, void *dev) | |
692 | { | |
693 | int i; | |
694 | struct switchtec_ntb *sndev = dev; | |
695 | ||
696 | for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) { | |
697 | u64 msg = ioread64(&sndev->mmio_self_dbmsg->imsg[i]); | |
698 | ||
699 | if (msg & NTB_DBMSG_IMSG_STATUS) { | |
700 | dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", i, | |
701 | (u32)msg); | |
702 | iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status); | |
0ee28f26 LG |
703 | |
704 | if (i == LINK_MESSAGE) | |
705 | switchtec_ntb_check_link(sndev); | |
3dd4db47 LG |
706 | } |
707 | } | |
708 | ||
709 | return IRQ_HANDLED; | |
710 | } | |
711 | ||
712 | static int switchtec_ntb_init_db_msg_irq(struct switchtec_ntb *sndev) | |
713 | { | |
714 | int i; | |
715 | int rc; | |
716 | int doorbell_irq = 0; | |
717 | int message_irq = 0; | |
718 | int event_irq; | |
719 | int idb_vecs = sizeof(sndev->mmio_self_dbmsg->idb_vec_map); | |
720 | ||
721 | event_irq = ioread32(&sndev->stdev->mmio_part_cfg->vep_vector_number); | |
722 | ||
723 | while (doorbell_irq == event_irq) | |
724 | doorbell_irq++; | |
725 | while (message_irq == doorbell_irq || | |
726 | message_irq == event_irq) | |
727 | message_irq++; | |
728 | ||
729 | dev_dbg(&sndev->stdev->dev, "irqs - event: %d, db: %d, msgs: %d", | |
730 | event_irq, doorbell_irq, message_irq); | |
731 | ||
732 | for (i = 0; i < idb_vecs - 4; i++) | |
733 | iowrite8(doorbell_irq, | |
734 | &sndev->mmio_self_dbmsg->idb_vec_map[i]); | |
735 | ||
736 | for (; i < idb_vecs; i++) | |
737 | iowrite8(message_irq, | |
738 | &sndev->mmio_self_dbmsg->idb_vec_map[i]); | |
739 | ||
740 | sndev->doorbell_irq = pci_irq_vector(sndev->stdev->pdev, doorbell_irq); | |
741 | sndev->message_irq = pci_irq_vector(sndev->stdev->pdev, message_irq); | |
742 | ||
743 | rc = request_irq(sndev->doorbell_irq, | |
744 | switchtec_ntb_doorbell_isr, 0, | |
745 | "switchtec_ntb_doorbell", sndev); | |
746 | if (rc) | |
747 | return rc; | |
748 | ||
749 | rc = request_irq(sndev->message_irq, | |
750 | switchtec_ntb_message_isr, 0, | |
751 | "switchtec_ntb_message", sndev); | |
752 | if (rc) { | |
753 | free_irq(sndev->doorbell_irq, sndev); | |
754 | return rc; | |
755 | } | |
756 | ||
757 | return 0; | |
758 | } | |
759 | ||
760 | static void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev) | |
761 | { | |
762 | free_irq(sndev->doorbell_irq, sndev); | |
763 | free_irq(sndev->message_irq, sndev); | |
764 | } | |
765 | ||
33dea5aa LG |
766 | static int switchtec_ntb_add(struct device *dev, |
767 | struct class_interface *class_intf) | |
768 | { | |
769 | struct switchtec_dev *stdev = to_stdev(dev); | |
770 | struct switchtec_ntb *sndev; | |
ec0467cc | 771 | int rc; |
33dea5aa LG |
772 | |
773 | stdev->sndev = NULL; | |
774 | ||
775 | if (stdev->pdev->class != MICROSEMI_NTB_CLASSCODE) | |
776 | return -ENODEV; | |
777 | ||
ec0467cc LG |
778 | if (stdev->partition_count != 2) |
779 | dev_warn(dev, "ntb driver only supports 2 partitions"); | |
780 | ||
33dea5aa LG |
781 | sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev)); |
782 | if (!sndev) | |
783 | return -ENOMEM; | |
784 | ||
785 | sndev->stdev = stdev; | |
ec0467cc LG |
786 | switchtec_ntb_init_sndev(sndev); |
787 | switchtec_ntb_init_mw(sndev); | |
3dd4db47 LG |
788 | switchtec_ntb_init_db(sndev); |
789 | switchtec_ntb_init_msgs(sndev); | |
ec0467cc LG |
790 | |
791 | rc = switchtec_ntb_init_req_id_table(sndev); | |
792 | if (rc) | |
793 | goto free_and_exit; | |
794 | ||
795 | rc = switchtec_ntb_init_shared_mw(sndev); | |
796 | if (rc) | |
797 | goto free_and_exit; | |
798 | ||
3dd4db47 LG |
799 | rc = switchtec_ntb_init_db_msg_irq(sndev); |
800 | if (rc) | |
801 | goto deinit_shared_and_exit; | |
802 | ||
e099b45b LG |
803 | rc = ntb_register_device(&sndev->ntb); |
804 | if (rc) | |
805 | goto deinit_and_exit; | |
806 | ||
33dea5aa | 807 | stdev->sndev = sndev; |
0ee28f26 | 808 | stdev->link_notifier = switchtec_ntb_link_notification; |
33dea5aa LG |
809 | dev_info(dev, "NTB device registered"); |
810 | ||
811 | return 0; | |
ec0467cc | 812 | |
e099b45b LG |
813 | deinit_and_exit: |
814 | switchtec_ntb_deinit_db_msg_irq(sndev); | |
3dd4db47 LG |
815 | deinit_shared_and_exit: |
816 | switchtec_ntb_deinit_shared_mw(sndev); | |
ec0467cc LG |
817 | free_and_exit: |
818 | kfree(sndev); | |
819 | dev_err(dev, "failed to register ntb device: %d", rc); | |
820 | return rc; | |
33dea5aa LG |
821 | } |
822 | ||
823 | void switchtec_ntb_remove(struct device *dev, | |
824 | struct class_interface *class_intf) | |
825 | { | |
826 | struct switchtec_dev *stdev = to_stdev(dev); | |
827 | struct switchtec_ntb *sndev = stdev->sndev; | |
828 | ||
829 | if (!sndev) | |
830 | return; | |
831 | ||
0ee28f26 | 832 | stdev->link_notifier = NULL; |
33dea5aa | 833 | stdev->sndev = NULL; |
e099b45b | 834 | ntb_unregister_device(&sndev->ntb); |
3dd4db47 | 835 | switchtec_ntb_deinit_db_msg_irq(sndev); |
ec0467cc | 836 | switchtec_ntb_deinit_shared_mw(sndev); |
33dea5aa LG |
837 | kfree(sndev); |
838 | dev_info(dev, "ntb device unregistered"); | |
839 | } | |
840 | ||
841 | static struct class_interface switchtec_interface = { | |
842 | .add_dev = switchtec_ntb_add, | |
843 | .remove_dev = switchtec_ntb_remove, | |
844 | }; | |
845 | ||
846 | static int __init switchtec_ntb_init(void) | |
847 | { | |
848 | switchtec_interface.class = switchtec_class; | |
849 | return class_interface_register(&switchtec_interface); | |
850 | } | |
851 | module_init(switchtec_ntb_init); | |
852 | ||
853 | static void __exit switchtec_ntb_exit(void) | |
854 | { | |
855 | class_interface_unregister(&switchtec_interface); | |
856 | } | |
857 | module_exit(switchtec_ntb_exit); |