| .. | .. |
|---|
| 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, |
|---|