.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Microsemi Switchtec(tm) PCIe Management Driver |
---|
3 | 4 | * 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 | 5 | */ |
---|
15 | 6 | |
---|
16 | | -#include <linux/switchtec.h> |
---|
17 | | -#include <linux/module.h> |
---|
| 7 | +#include <linux/interrupt.h> |
---|
| 8 | +#include <linux/io-64-nonatomic-lo-hi.h> |
---|
18 | 9 | #include <linux/delay.h> |
---|
19 | 10 | #include <linux/kthread.h> |
---|
20 | | -#include <linux/interrupt.h> |
---|
| 11 | +#include <linux/module.h> |
---|
21 | 12 | #include <linux/ntb.h> |
---|
22 | 13 | #include <linux/pci.h> |
---|
| 14 | +#include <linux/switchtec.h> |
---|
23 | 15 | |
---|
24 | 16 | MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver"); |
---|
25 | 17 | MODULE_VERSION("0.1"); |
---|
.. | .. |
---|
35 | 27 | module_param(use_lut_mws, bool, 0644); |
---|
36 | 28 | MODULE_PARM_DESC(use_lut_mws, |
---|
37 | 29 | "Enable the use of the LUT based memory windows"); |
---|
38 | | - |
---|
39 | | -#ifndef ioread64 |
---|
40 | | -#ifdef readq |
---|
41 | | -#define ioread64 readq |
---|
42 | | -#else |
---|
43 | | -#define ioread64 _ioread64 |
---|
44 | | -static inline u64 _ioread64(void __iomem *mmio) |
---|
45 | | -{ |
---|
46 | | - u64 low, high; |
---|
47 | | - |
---|
48 | | - low = ioread32(mmio); |
---|
49 | | - high = ioread32(mmio + sizeof(u32)); |
---|
50 | | - return low | (high << 32); |
---|
51 | | -} |
---|
52 | | -#endif |
---|
53 | | -#endif |
---|
54 | | - |
---|
55 | | -#ifndef iowrite64 |
---|
56 | | -#ifdef writeq |
---|
57 | | -#define iowrite64 writeq |
---|
58 | | -#else |
---|
59 | | -#define iowrite64 _iowrite64 |
---|
60 | | -static inline void _iowrite64(u64 val, void __iomem *mmio) |
---|
61 | | -{ |
---|
62 | | - iowrite32(val, mmio); |
---|
63 | | - iowrite32(val >> 32, mmio + sizeof(u32)); |
---|
64 | | -} |
---|
65 | | -#endif |
---|
66 | | -#endif |
---|
67 | 30 | |
---|
68 | 31 | #define SWITCHTEC_NTB_MAGIC 0x45CC0001 |
---|
69 | 32 | #define MAX_MWS 128 |
---|
.. | .. |
---|
123 | 86 | bool link_is_up; |
---|
124 | 87 | enum ntb_speed link_speed; |
---|
125 | 88 | enum ntb_width link_width; |
---|
126 | | - struct work_struct link_reinit_work; |
---|
| 89 | + struct work_struct check_link_status_work; |
---|
| 90 | + bool link_force_down; |
---|
127 | 91 | }; |
---|
128 | 92 | |
---|
129 | 93 | static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) |
---|
.. | .. |
---|
264 | 228 | ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN; |
---|
265 | 229 | iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); |
---|
266 | 230 | iowrite32(0, &ctl->bar_entry[bar].win_size); |
---|
| 231 | + iowrite32(0, &ctl->bar_ext_entry[bar].win_size); |
---|
267 | 232 | iowrite64(sndev->self_partition, &ctl->bar_entry[bar].xlate_addr); |
---|
268 | 233 | } |
---|
269 | 234 | |
---|
.. | .. |
---|
286 | 251 | ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; |
---|
287 | 252 | |
---|
288 | 253 | iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); |
---|
289 | | - iowrite32(xlate_pos | size, &ctl->bar_entry[bar].win_size); |
---|
| 254 | + iowrite32(xlate_pos | (lower_32_bits(size) & 0xFFFFF000), |
---|
| 255 | + &ctl->bar_entry[bar].win_size); |
---|
| 256 | + iowrite32(upper_32_bits(size), &ctl->bar_ext_entry[bar].win_size); |
---|
290 | 257 | iowrite64(sndev->self_partition | addr, |
---|
291 | 258 | &ctl->bar_entry[bar].xlate_addr); |
---|
292 | 259 | } |
---|
.. | .. |
---|
318 | 285 | if (widx >= switchtec_ntb_mw_count(ntb, pidx)) |
---|
319 | 286 | return -EINVAL; |
---|
320 | 287 | |
---|
321 | | - if (xlate_pos < 12) |
---|
| 288 | + if (size != 0 && xlate_pos < 12) |
---|
322 | 289 | return -EINVAL; |
---|
323 | 290 | |
---|
324 | 291 | if (!IS_ALIGNED(addr, BIT_ULL(xlate_pos))) { |
---|
.. | .. |
---|
339 | 306 | if (rc) |
---|
340 | 307 | return rc; |
---|
341 | 308 | |
---|
342 | | - if (addr == 0 || size == 0) { |
---|
| 309 | + if (size == 0) { |
---|
343 | 310 | if (widx < nr_direct_mw) |
---|
344 | 311 | switchtec_ntb_mw_clr_direct(sndev, widx); |
---|
345 | 312 | else |
---|
.. | .. |
---|
519 | 486 | |
---|
520 | 487 | static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev); |
---|
521 | 488 | |
---|
522 | | -static void link_reinit_work(struct work_struct *work) |
---|
523 | | -{ |
---|
524 | | - struct switchtec_ntb *sndev; |
---|
525 | | - |
---|
526 | | - sndev = container_of(work, struct switchtec_ntb, link_reinit_work); |
---|
527 | | - |
---|
528 | | - switchtec_ntb_reinit_peer(sndev); |
---|
529 | | -} |
---|
530 | | - |
---|
531 | | -static void switchtec_ntb_check_link(struct switchtec_ntb *sndev, |
---|
532 | | - enum switchtec_msg msg) |
---|
| 489 | +static void switchtec_ntb_link_status_update(struct switchtec_ntb *sndev) |
---|
533 | 490 | { |
---|
534 | 491 | int link_sta; |
---|
535 | 492 | int old = sndev->link_is_up; |
---|
536 | | - |
---|
537 | | - if (msg == MSG_LINK_FORCE_DOWN) { |
---|
538 | | - schedule_work(&sndev->link_reinit_work); |
---|
539 | | - |
---|
540 | | - if (sndev->link_is_up) { |
---|
541 | | - sndev->link_is_up = 0; |
---|
542 | | - ntb_link_event(&sndev->ntb); |
---|
543 | | - dev_info(&sndev->stdev->dev, "ntb link forced down\n"); |
---|
544 | | - } |
---|
545 | | - |
---|
546 | | - return; |
---|
547 | | - } |
---|
548 | 493 | |
---|
549 | 494 | link_sta = sndev->self_shared->link_sta; |
---|
550 | 495 | if (link_sta) { |
---|
.. | .. |
---|
568 | 513 | if (link_sta) |
---|
569 | 514 | crosslink_init_dbmsgs(sndev); |
---|
570 | 515 | } |
---|
| 516 | +} |
---|
| 517 | + |
---|
| 518 | +static void check_link_status_work(struct work_struct *work) |
---|
| 519 | +{ |
---|
| 520 | + struct switchtec_ntb *sndev; |
---|
| 521 | + |
---|
| 522 | + sndev = container_of(work, struct switchtec_ntb, |
---|
| 523 | + check_link_status_work); |
---|
| 524 | + |
---|
| 525 | + if (sndev->link_force_down) { |
---|
| 526 | + sndev->link_force_down = false; |
---|
| 527 | + switchtec_ntb_reinit_peer(sndev); |
---|
| 528 | + |
---|
| 529 | + if (sndev->link_is_up) { |
---|
| 530 | + sndev->link_is_up = 0; |
---|
| 531 | + ntb_link_event(&sndev->ntb); |
---|
| 532 | + dev_info(&sndev->stdev->dev, "ntb link forced down\n"); |
---|
| 533 | + } |
---|
| 534 | + |
---|
| 535 | + return; |
---|
| 536 | + } |
---|
| 537 | + |
---|
| 538 | + switchtec_ntb_link_status_update(sndev); |
---|
| 539 | +} |
---|
| 540 | + |
---|
| 541 | +static void switchtec_ntb_check_link(struct switchtec_ntb *sndev, |
---|
| 542 | + enum switchtec_msg msg) |
---|
| 543 | +{ |
---|
| 544 | + if (msg == MSG_LINK_FORCE_DOWN) |
---|
| 545 | + sndev->link_force_down = true; |
---|
| 546 | + |
---|
| 547 | + schedule_work(&sndev->check_link_status_work); |
---|
571 | 548 | } |
---|
572 | 549 | |
---|
573 | 550 | static void switchtec_ntb_link_notification(struct switchtec_dev *stdev) |
---|
.. | .. |
---|
602 | 579 | sndev->self_shared->link_sta = 1; |
---|
603 | 580 | switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); |
---|
604 | 581 | |
---|
605 | | - switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); |
---|
| 582 | + switchtec_ntb_link_status_update(sndev); |
---|
606 | 583 | |
---|
607 | 584 | return 0; |
---|
608 | 585 | } |
---|
.. | .. |
---|
616 | 593 | sndev->self_shared->link_sta = 0; |
---|
617 | 594 | switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN); |
---|
618 | 595 | |
---|
619 | | - switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); |
---|
| 596 | + switchtec_ntb_link_status_update(sndev); |
---|
620 | 597 | |
---|
621 | 598 | return 0; |
---|
622 | 599 | } |
---|
.. | .. |
---|
707 | 684 | |
---|
708 | 685 | static int switchtec_ntb_peer_db_addr(struct ntb_dev *ntb, |
---|
709 | 686 | phys_addr_t *db_addr, |
---|
710 | | - resource_size_t *db_size) |
---|
| 687 | + resource_size_t *db_size, |
---|
| 688 | + u64 *db_data, |
---|
| 689 | + int db_bit) |
---|
711 | 690 | { |
---|
712 | 691 | struct switchtec_ntb *sndev = ntb_sndev(ntb); |
---|
713 | 692 | unsigned long offset; |
---|
| 693 | + |
---|
| 694 | + if (unlikely(db_bit >= BITS_PER_LONG_LONG)) |
---|
| 695 | + return -EINVAL; |
---|
714 | 696 | |
---|
715 | 697 | offset = (unsigned long)sndev->mmio_peer_dbmsg->odb - |
---|
716 | 698 | (unsigned long)sndev->stdev->mmio; |
---|
.. | .. |
---|
721 | 703 | *db_addr = pci_resource_start(ntb->pdev, 0) + offset; |
---|
722 | 704 | if (db_size) |
---|
723 | 705 | *db_size = sizeof(u32); |
---|
| 706 | + if (db_data) |
---|
| 707 | + *db_data = BIT_ULL(db_bit) << sndev->db_peer_shift; |
---|
724 | 708 | |
---|
725 | 709 | return 0; |
---|
726 | 710 | } |
---|
.. | .. |
---|
862 | 846 | sndev->ntb.topo = NTB_TOPO_SWITCH; |
---|
863 | 847 | sndev->ntb.ops = &switchtec_ntb_ops; |
---|
864 | 848 | |
---|
865 | | - INIT_WORK(&sndev->link_reinit_work, link_reinit_work); |
---|
| 849 | + INIT_WORK(&sndev->check_link_status_work, check_link_status_work); |
---|
| 850 | + sndev->link_force_down = false; |
---|
866 | 851 | |
---|
867 | 852 | sndev->self_partition = sndev->stdev->partition; |
---|
868 | 853 | |
---|
.. | .. |
---|
1053 | 1038 | ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; |
---|
1054 | 1039 | |
---|
1055 | 1040 | iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); |
---|
1056 | | - iowrite32(xlate_pos | size, &ctl->bar_entry[bar].win_size); |
---|
| 1041 | + iowrite32(xlate_pos | (lower_32_bits(size) & 0xFFFFF000), |
---|
| 1042 | + &ctl->bar_entry[bar].win_size); |
---|
| 1043 | + iowrite32(upper_32_bits(size), &ctl->bar_ext_entry[bar].win_size); |
---|
1057 | 1044 | iowrite64(sndev->peer_partition | addr, |
---|
1058 | 1045 | &ctl->bar_entry[bar].xlate_addr); |
---|
1059 | 1046 | } |
---|
.. | .. |
---|
1339 | 1326 | int rc; |
---|
1340 | 1327 | |
---|
1341 | 1328 | sndev->nr_rsvd_luts++; |
---|
1342 | | - sndev->self_shared = dma_zalloc_coherent(&sndev->stdev->pdev->dev, |
---|
1343 | | - LUT_SIZE, |
---|
1344 | | - &sndev->self_shared_dma, |
---|
1345 | | - GFP_KERNEL); |
---|
| 1329 | + sndev->self_shared = dma_alloc_coherent(&sndev->stdev->pdev->dev, |
---|
| 1330 | + LUT_SIZE, |
---|
| 1331 | + &sndev->self_shared_dma, |
---|
| 1332 | + GFP_KERNEL); |
---|
1346 | 1333 | if (!sndev->self_shared) { |
---|
1347 | 1334 | dev_err(&sndev->stdev->dev, |
---|
1348 | 1335 | "unable to allocate memory for shared mw\n"); |
---|
.. | .. |
---|
1473 | 1460 | |
---|
1474 | 1461 | static int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev) |
---|
1475 | 1462 | { |
---|
1476 | | - dev_info(&sndev->stdev->dev, "peer reinitialized\n"); |
---|
1477 | | - switchtec_ntb_deinit_shared_mw(sndev); |
---|
1478 | | - switchtec_ntb_init_mw(sndev); |
---|
1479 | | - return switchtec_ntb_init_shared_mw(sndev); |
---|
| 1463 | + int rc; |
---|
| 1464 | + |
---|
| 1465 | + if (crosslink_is_enabled(sndev)) |
---|
| 1466 | + return 0; |
---|
| 1467 | + |
---|
| 1468 | + dev_info(&sndev->stdev->dev, "reinitialize shared memory window\n"); |
---|
| 1469 | + rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0, |
---|
| 1470 | + sndev->self_partition, |
---|
| 1471 | + sndev->self_shared_dma); |
---|
| 1472 | + return rc; |
---|
1480 | 1473 | } |
---|
1481 | 1474 | |
---|
1482 | 1475 | static int switchtec_ntb_add(struct device *dev, |
---|