18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Microsemi Switchtec(tm) PCIe Management Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2017, Microsemi Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 88c2ecf20Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/kthread.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/ntb.h> 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include <linux/switchtec.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver"); 178c2ecf20Sopenharmony_ciMODULE_VERSION("0.1"); 188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 198c2ecf20Sopenharmony_ciMODULE_AUTHOR("Microsemi Corporation"); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic ulong max_mw_size = SZ_2M; 228c2ecf20Sopenharmony_cimodule_param(max_mw_size, ulong, 0644); 238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_mw_size, 248c2ecf20Sopenharmony_ci "Max memory window size reported to the upper layer"); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic bool use_lut_mws; 278c2ecf20Sopenharmony_cimodule_param(use_lut_mws, bool, 0644); 288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_lut_mws, 298c2ecf20Sopenharmony_ci "Enable the use of the LUT based memory windows"); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define SWITCHTEC_NTB_MAGIC 0x45CC0001 328c2ecf20Sopenharmony_ci#define MAX_MWS 128 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct shared_mw { 358c2ecf20Sopenharmony_ci u32 magic; 368c2ecf20Sopenharmony_ci u32 link_sta; 378c2ecf20Sopenharmony_ci u32 partition_id; 388c2ecf20Sopenharmony_ci u64 mw_sizes[MAX_MWS]; 398c2ecf20Sopenharmony_ci u32 spad[128]; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define MAX_DIRECT_MW ARRAY_SIZE(((struct ntb_ctrl_regs *)(0))->bar_entry) 438c2ecf20Sopenharmony_ci#define LUT_SIZE SZ_64K 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct switchtec_ntb { 468c2ecf20Sopenharmony_ci struct ntb_dev ntb; 478c2ecf20Sopenharmony_ci struct switchtec_dev *stdev; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci int self_partition; 508c2ecf20Sopenharmony_ci int peer_partition; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci int doorbell_irq; 538c2ecf20Sopenharmony_ci int message_irq; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci struct ntb_info_regs __iomem *mmio_ntb; 568c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *mmio_ctrl; 578c2ecf20Sopenharmony_ci struct ntb_dbmsg_regs __iomem *mmio_dbmsg; 588c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *mmio_self_ctrl; 598c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *mmio_peer_ctrl; 608c2ecf20Sopenharmony_ci struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg; 618c2ecf20Sopenharmony_ci struct ntb_dbmsg_regs __iomem *mmio_peer_dbmsg; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci void __iomem *mmio_xlink_win; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci struct shared_mw *self_shared; 668c2ecf20Sopenharmony_ci struct shared_mw __iomem *peer_shared; 678c2ecf20Sopenharmony_ci dma_addr_t self_shared_dma; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci u64 db_mask; 708c2ecf20Sopenharmony_ci u64 db_valid_mask; 718c2ecf20Sopenharmony_ci int db_shift; 728c2ecf20Sopenharmony_ci int db_peer_shift; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* synchronize rmw access of db_mask and hw reg */ 758c2ecf20Sopenharmony_ci spinlock_t db_mask_lock; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci int nr_direct_mw; 788c2ecf20Sopenharmony_ci int nr_lut_mw; 798c2ecf20Sopenharmony_ci int nr_rsvd_luts; 808c2ecf20Sopenharmony_ci int direct_mw_to_bar[MAX_DIRECT_MW]; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci int peer_nr_direct_mw; 838c2ecf20Sopenharmony_ci int peer_nr_lut_mw; 848c2ecf20Sopenharmony_ci int peer_direct_mw_to_bar[MAX_DIRECT_MW]; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci bool link_is_up; 878c2ecf20Sopenharmony_ci enum ntb_speed link_speed; 888c2ecf20Sopenharmony_ci enum ntb_width link_width; 898c2ecf20Sopenharmony_ci struct work_struct check_link_status_work; 908c2ecf20Sopenharmony_ci bool link_force_down; 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci return container_of(ntb, struct switchtec_ntb, ntb); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int switchtec_ntb_part_op(struct switchtec_ntb *sndev, 998c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl, 1008c2ecf20Sopenharmony_ci u32 op, int wait_status) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci static const char * const op_text[] = { 1038c2ecf20Sopenharmony_ci [NTB_CTRL_PART_OP_LOCK] = "lock", 1048c2ecf20Sopenharmony_ci [NTB_CTRL_PART_OP_CFG] = "configure", 1058c2ecf20Sopenharmony_ci [NTB_CTRL_PART_OP_RESET] = "reset", 1068c2ecf20Sopenharmony_ci }; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci int i; 1098c2ecf20Sopenharmony_ci u32 ps; 1108c2ecf20Sopenharmony_ci int status; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci switch (op) { 1138c2ecf20Sopenharmony_ci case NTB_CTRL_PART_OP_LOCK: 1148c2ecf20Sopenharmony_ci status = NTB_CTRL_PART_STATUS_LOCKING; 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci case NTB_CTRL_PART_OP_CFG: 1178c2ecf20Sopenharmony_ci status = NTB_CTRL_PART_STATUS_CONFIGURING; 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci case NTB_CTRL_PART_OP_RESET: 1208c2ecf20Sopenharmony_ci status = NTB_CTRL_PART_STATUS_RESETTING; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci default: 1238c2ecf20Sopenharmony_ci return -EINVAL; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci iowrite32(op, &ctl->partition_op); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci for (i = 0; i < 1000; i++) { 1298c2ecf20Sopenharmony_ci if (msleep_interruptible(50) != 0) { 1308c2ecf20Sopenharmony_ci iowrite32(NTB_CTRL_PART_OP_RESET, &ctl->partition_op); 1318c2ecf20Sopenharmony_ci return -EINTR; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci ps = ioread32(&ctl->partition_status) & 0xFFFF; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (ps != status) 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (ps == wait_status) 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (ps == status) { 1448c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 1458c2ecf20Sopenharmony_ci "Timed out while performing %s (%d). (%08x)\n", 1468c2ecf20Sopenharmony_ci op_text[op], op, 1478c2ecf20Sopenharmony_ci ioread32(&ctl->partition_status)); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return -EIO; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx, 1568c2ecf20Sopenharmony_ci u32 val) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_peer_dbmsg->omsg)) 1598c2ecf20Sopenharmony_ci return -EINVAL; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci iowrite32(val, &sndev->mmio_peer_dbmsg->omsg[idx].msg); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 1698c2ecf20Sopenharmony_ci int nr_direct_mw = sndev->peer_nr_direct_mw; 1708c2ecf20Sopenharmony_ci int nr_lut_mw = sndev->peer_nr_lut_mw - sndev->nr_rsvd_luts; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 1738c2ecf20Sopenharmony_ci return -EINVAL; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (!use_lut_mws) 1768c2ecf20Sopenharmony_ci nr_lut_mw = 0; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return nr_direct_mw + nr_lut_mw; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int lut_index(struct switchtec_ntb *sndev, int mw_idx) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci return mw_idx - sndev->nr_direct_mw + sndev->nr_rsvd_luts; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int peer_lut_index(struct switchtec_ntb *sndev, int mw_idx) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci return mw_idx - sndev->peer_nr_direct_mw + sndev->nr_rsvd_luts; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, 1928c2ecf20Sopenharmony_ci int widx, resource_size_t *addr_align, 1938c2ecf20Sopenharmony_ci resource_size_t *size_align, 1948c2ecf20Sopenharmony_ci resource_size_t *size_max) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 1978c2ecf20Sopenharmony_ci int lut; 1988c2ecf20Sopenharmony_ci resource_size_t size; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 2018c2ecf20Sopenharmony_ci return -EINVAL; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci lut = widx >= sndev->peer_nr_direct_mw; 2048c2ecf20Sopenharmony_ci size = ioread64(&sndev->peer_shared->mw_sizes[widx]); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (size == 0) 2078c2ecf20Sopenharmony_ci return -EINVAL; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (addr_align) 2108c2ecf20Sopenharmony_ci *addr_align = lut ? size : SZ_4K; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (size_align) 2138c2ecf20Sopenharmony_ci *size_align = lut ? size : SZ_4K; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (size_max) 2168c2ecf20Sopenharmony_ci *size_max = size; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void switchtec_ntb_mw_clr_direct(struct switchtec_ntb *sndev, int idx) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 2248c2ecf20Sopenharmony_ci int bar = sndev->peer_direct_mw_to_bar[idx]; 2258c2ecf20Sopenharmony_ci u32 ctl_val; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ctl_val = ioread32(&ctl->bar_entry[bar].ctl); 2288c2ecf20Sopenharmony_ci ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN; 2298c2ecf20Sopenharmony_ci iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); 2308c2ecf20Sopenharmony_ci iowrite32(0, &ctl->bar_entry[bar].win_size); 2318c2ecf20Sopenharmony_ci iowrite32(0, &ctl->bar_ext_entry[bar].win_size); 2328c2ecf20Sopenharmony_ci iowrite64(sndev->self_partition, &ctl->bar_entry[bar].xlate_addr); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic void switchtec_ntb_mw_clr_lut(struct switchtec_ntb *sndev, int idx) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci iowrite64(0, &ctl->lut_entry[peer_lut_index(sndev, idx)]); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void switchtec_ntb_mw_set_direct(struct switchtec_ntb *sndev, int idx, 2438c2ecf20Sopenharmony_ci dma_addr_t addr, resource_size_t size) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci int xlate_pos = ilog2(size); 2468c2ecf20Sopenharmony_ci int bar = sndev->peer_direct_mw_to_bar[idx]; 2478c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 2488c2ecf20Sopenharmony_ci u32 ctl_val; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci ctl_val = ioread32(&ctl->bar_entry[bar].ctl); 2518c2ecf20Sopenharmony_ci ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); 2548c2ecf20Sopenharmony_ci iowrite32(xlate_pos | (lower_32_bits(size) & 0xFFFFF000), 2558c2ecf20Sopenharmony_ci &ctl->bar_entry[bar].win_size); 2568c2ecf20Sopenharmony_ci iowrite32(upper_32_bits(size), &ctl->bar_ext_entry[bar].win_size); 2578c2ecf20Sopenharmony_ci iowrite64(sndev->self_partition | addr, 2588c2ecf20Sopenharmony_ci &ctl->bar_entry[bar].xlate_addr); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic void switchtec_ntb_mw_set_lut(struct switchtec_ntb *sndev, int idx, 2628c2ecf20Sopenharmony_ci dma_addr_t addr, resource_size_t size) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | addr), 2678c2ecf20Sopenharmony_ci &ctl->lut_entry[peer_lut_index(sndev, idx)]); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, 2718c2ecf20Sopenharmony_ci dma_addr_t addr, resource_size_t size) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 2748c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 2758c2ecf20Sopenharmony_ci int xlate_pos = ilog2(size); 2768c2ecf20Sopenharmony_ci int nr_direct_mw = sndev->peer_nr_direct_mw; 2778c2ecf20Sopenharmony_ci int rc; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 2808c2ecf20Sopenharmony_ci return -EINVAL; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "MW %d: part %d addr %pad size %pap\n", 2838c2ecf20Sopenharmony_ci widx, pidx, &addr, &size); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (widx >= switchtec_ntb_mw_count(ntb, pidx)) 2868c2ecf20Sopenharmony_ci return -EINVAL; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (size != 0 && xlate_pos < 12) 2898c2ecf20Sopenharmony_ci return -EINVAL; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (!IS_ALIGNED(addr, BIT_ULL(xlate_pos))) { 2928c2ecf20Sopenharmony_ci /* 2938c2ecf20Sopenharmony_ci * In certain circumstances we can get a buffer that is 2948c2ecf20Sopenharmony_ci * not aligned to its size. (Most of the time 2958c2ecf20Sopenharmony_ci * dma_alloc_coherent ensures this). This can happen when 2968c2ecf20Sopenharmony_ci * using large buffers allocated by the CMA 2978c2ecf20Sopenharmony_ci * (see CMA_CONFIG_ALIGNMENT) 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 3008c2ecf20Sopenharmony_ci "ERROR: Memory window address is not aligned to it's size!\n"); 3018c2ecf20Sopenharmony_ci return -EINVAL; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, 3058c2ecf20Sopenharmony_ci NTB_CTRL_PART_STATUS_LOCKED); 3068c2ecf20Sopenharmony_ci if (rc) 3078c2ecf20Sopenharmony_ci return rc; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (size == 0) { 3108c2ecf20Sopenharmony_ci if (widx < nr_direct_mw) 3118c2ecf20Sopenharmony_ci switchtec_ntb_mw_clr_direct(sndev, widx); 3128c2ecf20Sopenharmony_ci else 3138c2ecf20Sopenharmony_ci switchtec_ntb_mw_clr_lut(sndev, widx); 3148c2ecf20Sopenharmony_ci } else { 3158c2ecf20Sopenharmony_ci if (widx < nr_direct_mw) 3168c2ecf20Sopenharmony_ci switchtec_ntb_mw_set_direct(sndev, widx, addr, size); 3178c2ecf20Sopenharmony_ci else 3188c2ecf20Sopenharmony_ci switchtec_ntb_mw_set_lut(sndev, widx, addr, size); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 3228c2ecf20Sopenharmony_ci NTB_CTRL_PART_STATUS_NORMAL); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (rc == -EIO) { 3258c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 3268c2ecf20Sopenharmony_ci "Hardware reported an error configuring mw %d: %08x\n", 3278c2ecf20Sopenharmony_ci widx, ioread32(&ctl->bar_error)); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (widx < nr_direct_mw) 3308c2ecf20Sopenharmony_ci switchtec_ntb_mw_clr_direct(sndev, widx); 3318c2ecf20Sopenharmony_ci else 3328c2ecf20Sopenharmony_ci switchtec_ntb_mw_clr_lut(sndev, widx); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 3358c2ecf20Sopenharmony_ci NTB_CTRL_PART_STATUS_NORMAL); 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return rc; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 3448c2ecf20Sopenharmony_ci int nr_lut_mw = sndev->nr_lut_mw - sndev->nr_rsvd_luts; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return sndev->nr_direct_mw + (use_lut_mws ? nr_lut_mw : 0); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int switchtec_ntb_direct_get_addr(struct switchtec_ntb *sndev, 3508c2ecf20Sopenharmony_ci int idx, phys_addr_t *base, 3518c2ecf20Sopenharmony_ci resource_size_t *size) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci int bar = sndev->direct_mw_to_bar[idx]; 3548c2ecf20Sopenharmony_ci size_t offset = 0; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (bar < 0) 3578c2ecf20Sopenharmony_ci return -EINVAL; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (idx == 0) { 3608c2ecf20Sopenharmony_ci /* 3618c2ecf20Sopenharmony_ci * This is the direct BAR shared with the LUTs 3628c2ecf20Sopenharmony_ci * which means the actual window will be offset 3638c2ecf20Sopenharmony_ci * by the size of all the LUT entries. 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci offset = LUT_SIZE * sndev->nr_lut_mw; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (base) 3708c2ecf20Sopenharmony_ci *base = pci_resource_start(sndev->ntb.pdev, bar) + offset; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (size) { 3738c2ecf20Sopenharmony_ci *size = pci_resource_len(sndev->ntb.pdev, bar) - offset; 3748c2ecf20Sopenharmony_ci if (offset && *size > offset) 3758c2ecf20Sopenharmony_ci *size = offset; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (*size > max_mw_size) 3788c2ecf20Sopenharmony_ci *size = max_mw_size; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int switchtec_ntb_lut_get_addr(struct switchtec_ntb *sndev, 3858c2ecf20Sopenharmony_ci int idx, phys_addr_t *base, 3868c2ecf20Sopenharmony_ci resource_size_t *size) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci int bar = sndev->direct_mw_to_bar[0]; 3898c2ecf20Sopenharmony_ci int offset; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci offset = LUT_SIZE * lut_index(sndev, idx); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (base) 3948c2ecf20Sopenharmony_ci *base = pci_resource_start(sndev->ntb.pdev, bar) + offset; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (size) 3978c2ecf20Sopenharmony_ci *size = LUT_SIZE; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx, 4038c2ecf20Sopenharmony_ci phys_addr_t *base, 4048c2ecf20Sopenharmony_ci resource_size_t *size) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (idx < sndev->nr_direct_mw) 4098c2ecf20Sopenharmony_ci return switchtec_ntb_direct_get_addr(sndev, idx, base, size); 4108c2ecf20Sopenharmony_ci else if (idx < switchtec_ntb_peer_mw_count(ntb)) 4118c2ecf20Sopenharmony_ci return switchtec_ntb_lut_get_addr(sndev, idx, base, size); 4128c2ecf20Sopenharmony_ci else 4138c2ecf20Sopenharmony_ci return -EINVAL; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev, 4178c2ecf20Sopenharmony_ci int partition, 4188c2ecf20Sopenharmony_ci enum ntb_speed *speed, 4198c2ecf20Sopenharmony_ci enum ntb_width *width) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci struct switchtec_dev *stdev = sndev->stdev; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci u32 pff = ioread32(&stdev->mmio_part_cfg[partition].vep_pff_inst_id); 4248c2ecf20Sopenharmony_ci u32 linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (speed) 4278c2ecf20Sopenharmony_ci *speed = (linksta >> 16) & 0xF; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (width) 4308c2ecf20Sopenharmony_ci *width = (linksta >> 20) & 0x3F; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci enum ntb_speed self_speed, peer_speed; 4368c2ecf20Sopenharmony_ci enum ntb_width self_width, peer_width; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (!sndev->link_is_up) { 4398c2ecf20Sopenharmony_ci sndev->link_speed = NTB_SPEED_NONE; 4408c2ecf20Sopenharmony_ci sndev->link_width = NTB_WIDTH_NONE; 4418c2ecf20Sopenharmony_ci return; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci switchtec_ntb_part_link_speed(sndev, sndev->self_partition, 4458c2ecf20Sopenharmony_ci &self_speed, &self_width); 4468c2ecf20Sopenharmony_ci switchtec_ntb_part_link_speed(sndev, sndev->peer_partition, 4478c2ecf20Sopenharmony_ci &peer_speed, &peer_width); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci sndev->link_speed = min(self_speed, peer_speed); 4508c2ecf20Sopenharmony_ci sndev->link_width = min(self_width, peer_width); 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int crosslink_is_enabled(struct switchtec_ntb *sndev) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct ntb_info_regs __iomem *inf = sndev->mmio_ntb; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return ioread8(&inf->ntp_info[sndev->peer_partition].xlink_enabled); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic void crosslink_init_dbmsgs(struct switchtec_ntb *sndev) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci int i; 4638c2ecf20Sopenharmony_ci u32 msg_map = 0; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (!crosslink_is_enabled(sndev)) 4668c2ecf20Sopenharmony_ci return; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sndev->mmio_peer_dbmsg->imsg); i++) { 4698c2ecf20Sopenharmony_ci int m = i | sndev->self_partition << 2; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci msg_map |= m << i * 8; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci iowrite32(msg_map, &sndev->mmio_peer_dbmsg->msg_map); 4758c2ecf20Sopenharmony_ci iowrite64(sndev->db_valid_mask << sndev->db_peer_shift, 4768c2ecf20Sopenharmony_ci &sndev->mmio_peer_dbmsg->odb_mask); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cienum switchtec_msg { 4808c2ecf20Sopenharmony_ci LINK_MESSAGE = 0, 4818c2ecf20Sopenharmony_ci MSG_LINK_UP = 1, 4828c2ecf20Sopenharmony_ci MSG_LINK_DOWN = 2, 4838c2ecf20Sopenharmony_ci MSG_CHECK_LINK = 3, 4848c2ecf20Sopenharmony_ci MSG_LINK_FORCE_DOWN = 4, 4858c2ecf20Sopenharmony_ci}; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic void switchtec_ntb_link_status_update(struct switchtec_ntb *sndev) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci int link_sta; 4928c2ecf20Sopenharmony_ci int old = sndev->link_is_up; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci link_sta = sndev->self_shared->link_sta; 4958c2ecf20Sopenharmony_ci if (link_sta) { 4968c2ecf20Sopenharmony_ci u64 peer = ioread64(&sndev->peer_shared->magic); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if ((peer & 0xFFFFFFFF) == SWITCHTEC_NTB_MAGIC) 4998c2ecf20Sopenharmony_ci link_sta = peer >> 32; 5008c2ecf20Sopenharmony_ci else 5018c2ecf20Sopenharmony_ci link_sta = 0; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci sndev->link_is_up = link_sta; 5058c2ecf20Sopenharmony_ci switchtec_ntb_set_link_speed(sndev); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (link_sta != old) { 5088c2ecf20Sopenharmony_ci switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK); 5098c2ecf20Sopenharmony_ci ntb_link_event(&sndev->ntb); 5108c2ecf20Sopenharmony_ci dev_info(&sndev->stdev->dev, "ntb link %s\n", 5118c2ecf20Sopenharmony_ci link_sta ? "up" : "down"); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (link_sta) 5148c2ecf20Sopenharmony_ci crosslink_init_dbmsgs(sndev); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic void check_link_status_work(struct work_struct *work) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci sndev = container_of(work, struct switchtec_ntb, 5238c2ecf20Sopenharmony_ci check_link_status_work); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (sndev->link_force_down) { 5268c2ecf20Sopenharmony_ci sndev->link_force_down = false; 5278c2ecf20Sopenharmony_ci switchtec_ntb_reinit_peer(sndev); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (sndev->link_is_up) { 5308c2ecf20Sopenharmony_ci sndev->link_is_up = 0; 5318c2ecf20Sopenharmony_ci ntb_link_event(&sndev->ntb); 5328c2ecf20Sopenharmony_ci dev_info(&sndev->stdev->dev, "ntb link forced down\n"); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci return; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci switchtec_ntb_link_status_update(sndev); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic void switchtec_ntb_check_link(struct switchtec_ntb *sndev, 5428c2ecf20Sopenharmony_ci enum switchtec_msg msg) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci if (msg == MSG_LINK_FORCE_DOWN) 5458c2ecf20Sopenharmony_ci sndev->link_force_down = true; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci schedule_work(&sndev->check_link_status_work); 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic void switchtec_ntb_link_notification(struct switchtec_dev *stdev) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = stdev->sndev; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb, 5588c2ecf20Sopenharmony_ci enum ntb_speed *speed, 5598c2ecf20Sopenharmony_ci enum ntb_width *width) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (speed) 5648c2ecf20Sopenharmony_ci *speed = sndev->link_speed; 5658c2ecf20Sopenharmony_ci if (width) 5668c2ecf20Sopenharmony_ci *width = sndev->link_width; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return sndev->link_is_up; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int switchtec_ntb_link_enable(struct ntb_dev *ntb, 5728c2ecf20Sopenharmony_ci enum ntb_speed max_speed, 5738c2ecf20Sopenharmony_ci enum ntb_width max_width) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "enabling link\n"); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci sndev->self_shared->link_sta = 1; 5808c2ecf20Sopenharmony_ci switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci switchtec_ntb_link_status_update(sndev); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic int switchtec_ntb_link_disable(struct ntb_dev *ntb) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "disabling link\n"); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci sndev->self_shared->link_sta = 0; 5948c2ecf20Sopenharmony_ci switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci switchtec_ntb_link_status_update(sndev); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci return 0; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic u64 switchtec_ntb_db_valid_mask(struct ntb_dev *ntb) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return sndev->db_valid_mask; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic int switchtec_ntb_db_vector_count(struct ntb_dev *ntb) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci return 1; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic u64 switchtec_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (db_vector < 0 || db_vector > 1) 6188c2ecf20Sopenharmony_ci return 0; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return sndev->db_valid_mask; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic u64 switchtec_ntb_db_read(struct ntb_dev *ntb) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci u64 ret; 6268c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci ret = ioread64(&sndev->mmio_self_dbmsg->idb) >> sndev->db_shift; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return ret & sndev->db_valid_mask; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int switchtec_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci iowrite64(db_bits << sndev->db_shift, &sndev->mmio_self_dbmsg->idb); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci return 0; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic int switchtec_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci unsigned long irqflags; 6458c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (db_bits & ~sndev->db_valid_mask) 6488c2ecf20Sopenharmony_ci return -EINVAL; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci spin_lock_irqsave(&sndev->db_mask_lock, irqflags); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci sndev->db_mask |= db_bits << sndev->db_shift; 6538c2ecf20Sopenharmony_ci iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic int switchtec_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci unsigned long irqflags; 6638c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (db_bits & ~sndev->db_valid_mask) 6668c2ecf20Sopenharmony_ci return -EINVAL; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci spin_lock_irqsave(&sndev->db_mask_lock, irqflags); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci sndev->db_mask &= ~(db_bits << sndev->db_shift); 6718c2ecf20Sopenharmony_ci iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci return 0; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic u64 switchtec_ntb_db_read_mask(struct ntb_dev *ntb) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci return (sndev->db_mask >> sndev->db_shift) & sndev->db_valid_mask; 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_db_addr(struct ntb_dev *ntb, 6868c2ecf20Sopenharmony_ci phys_addr_t *db_addr, 6878c2ecf20Sopenharmony_ci resource_size_t *db_size, 6888c2ecf20Sopenharmony_ci u64 *db_data, 6898c2ecf20Sopenharmony_ci int db_bit) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 6928c2ecf20Sopenharmony_ci unsigned long offset; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (unlikely(db_bit >= BITS_PER_LONG_LONG)) 6958c2ecf20Sopenharmony_ci return -EINVAL; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci offset = (unsigned long)sndev->mmio_peer_dbmsg->odb - 6988c2ecf20Sopenharmony_ci (unsigned long)sndev->stdev->mmio; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci offset += sndev->db_shift / 8; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (db_addr) 7038c2ecf20Sopenharmony_ci *db_addr = pci_resource_start(ntb->pdev, 0) + offset; 7048c2ecf20Sopenharmony_ci if (db_size) 7058c2ecf20Sopenharmony_ci *db_size = sizeof(u32); 7068c2ecf20Sopenharmony_ci if (db_data) 7078c2ecf20Sopenharmony_ci *db_data = BIT_ULL(db_bit) << sndev->db_peer_shift; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci iowrite64(db_bits << sndev->db_peer_shift, 7178c2ecf20Sopenharmony_ci &sndev->mmio_peer_dbmsg->odb); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic int switchtec_ntb_spad_count(struct ntb_dev *ntb) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return ARRAY_SIZE(sndev->self_shared->spad); 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic u32 switchtec_ntb_spad_read(struct ntb_dev *ntb, int idx) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad)) 7348c2ecf20Sopenharmony_ci return 0; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (!sndev->self_shared) 7378c2ecf20Sopenharmony_ci return 0; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return sndev->self_shared->spad[idx]; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic int switchtec_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad)) 7478c2ecf20Sopenharmony_ci return -EINVAL; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (!sndev->self_shared) 7508c2ecf20Sopenharmony_ci return -EIO; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci sndev->self_shared->spad[idx] = val; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci return 0; 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic u32 switchtec_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, 7588c2ecf20Sopenharmony_ci int sidx) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 7638c2ecf20Sopenharmony_ci return -EINVAL; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad)) 7668c2ecf20Sopenharmony_ci return 0; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (!sndev->peer_shared) 7698c2ecf20Sopenharmony_ci return 0; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return ioread32(&sndev->peer_shared->spad[sidx]); 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, 7758c2ecf20Sopenharmony_ci int sidx, u32 val) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 7808c2ecf20Sopenharmony_ci return -EINVAL; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad)) 7838c2ecf20Sopenharmony_ci return -EINVAL; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (!sndev->peer_shared) 7868c2ecf20Sopenharmony_ci return -EIO; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci iowrite32(val, &sndev->peer_shared->spad[sidx]); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic int switchtec_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, 7948c2ecf20Sopenharmony_ci int sidx, phys_addr_t *spad_addr) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 7978c2ecf20Sopenharmony_ci unsigned long offset; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 8008c2ecf20Sopenharmony_ci return -EINVAL; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci offset = (unsigned long)&sndev->peer_shared->spad[sidx] - 8038c2ecf20Sopenharmony_ci (unsigned long)sndev->stdev->mmio; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (spad_addr) 8068c2ecf20Sopenharmony_ci *spad_addr = pci_resource_start(ntb->pdev, 0) + offset; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci return 0; 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic const struct ntb_dev_ops switchtec_ntb_ops = { 8128c2ecf20Sopenharmony_ci .mw_count = switchtec_ntb_mw_count, 8138c2ecf20Sopenharmony_ci .mw_get_align = switchtec_ntb_mw_get_align, 8148c2ecf20Sopenharmony_ci .mw_set_trans = switchtec_ntb_mw_set_trans, 8158c2ecf20Sopenharmony_ci .peer_mw_count = switchtec_ntb_peer_mw_count, 8168c2ecf20Sopenharmony_ci .peer_mw_get_addr = switchtec_ntb_peer_mw_get_addr, 8178c2ecf20Sopenharmony_ci .link_is_up = switchtec_ntb_link_is_up, 8188c2ecf20Sopenharmony_ci .link_enable = switchtec_ntb_link_enable, 8198c2ecf20Sopenharmony_ci .link_disable = switchtec_ntb_link_disable, 8208c2ecf20Sopenharmony_ci .db_valid_mask = switchtec_ntb_db_valid_mask, 8218c2ecf20Sopenharmony_ci .db_vector_count = switchtec_ntb_db_vector_count, 8228c2ecf20Sopenharmony_ci .db_vector_mask = switchtec_ntb_db_vector_mask, 8238c2ecf20Sopenharmony_ci .db_read = switchtec_ntb_db_read, 8248c2ecf20Sopenharmony_ci .db_clear = switchtec_ntb_db_clear, 8258c2ecf20Sopenharmony_ci .db_set_mask = switchtec_ntb_db_set_mask, 8268c2ecf20Sopenharmony_ci .db_clear_mask = switchtec_ntb_db_clear_mask, 8278c2ecf20Sopenharmony_ci .db_read_mask = switchtec_ntb_db_read_mask, 8288c2ecf20Sopenharmony_ci .peer_db_addr = switchtec_ntb_peer_db_addr, 8298c2ecf20Sopenharmony_ci .peer_db_set = switchtec_ntb_peer_db_set, 8308c2ecf20Sopenharmony_ci .spad_count = switchtec_ntb_spad_count, 8318c2ecf20Sopenharmony_ci .spad_read = switchtec_ntb_spad_read, 8328c2ecf20Sopenharmony_ci .spad_write = switchtec_ntb_spad_write, 8338c2ecf20Sopenharmony_ci .peer_spad_read = switchtec_ntb_peer_spad_read, 8348c2ecf20Sopenharmony_ci .peer_spad_write = switchtec_ntb_peer_spad_write, 8358c2ecf20Sopenharmony_ci .peer_spad_addr = switchtec_ntb_peer_spad_addr, 8368c2ecf20Sopenharmony_ci}; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci u64 tpart_vec; 8418c2ecf20Sopenharmony_ci int self; 8428c2ecf20Sopenharmony_ci u64 part_map; 8438c2ecf20Sopenharmony_ci int bit; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci sndev->ntb.pdev = sndev->stdev->pdev; 8468c2ecf20Sopenharmony_ci sndev->ntb.topo = NTB_TOPO_SWITCH; 8478c2ecf20Sopenharmony_ci sndev->ntb.ops = &switchtec_ntb_ops; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci INIT_WORK(&sndev->check_link_status_work, check_link_status_work); 8508c2ecf20Sopenharmony_ci sndev->link_force_down = false; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci sndev->self_partition = sndev->stdev->partition; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci sndev->mmio_ntb = sndev->stdev->mmio_ntb; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci self = sndev->self_partition; 8578c2ecf20Sopenharmony_ci tpart_vec = ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_high); 8588c2ecf20Sopenharmony_ci tpart_vec <<= 32; 8598c2ecf20Sopenharmony_ci tpart_vec |= ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_low); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci part_map = ioread64(&sndev->mmio_ntb->ep_map); 8628c2ecf20Sopenharmony_ci part_map &= ~(1 << sndev->self_partition); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (!ffs(tpart_vec)) { 8658c2ecf20Sopenharmony_ci if (sndev->stdev->partition_count != 2) { 8668c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 8678c2ecf20Sopenharmony_ci "ntb target partition not defined\n"); 8688c2ecf20Sopenharmony_ci return -ENODEV; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci bit = ffs(part_map); 8728c2ecf20Sopenharmony_ci if (!bit) { 8738c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 8748c2ecf20Sopenharmony_ci "peer partition is not NT partition\n"); 8758c2ecf20Sopenharmony_ci return -ENODEV; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci sndev->peer_partition = bit - 1; 8798c2ecf20Sopenharmony_ci } else { 8808c2ecf20Sopenharmony_ci if (ffs(tpart_vec) != fls(tpart_vec)) { 8818c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 8828c2ecf20Sopenharmony_ci "ntb driver only supports 1 pair of 1-1 ntb mapping\n"); 8838c2ecf20Sopenharmony_ci return -ENODEV; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci sndev->peer_partition = ffs(tpart_vec) - 1; 8878c2ecf20Sopenharmony_ci if (!(part_map & (1ULL << sndev->peer_partition))) { 8888c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 8898c2ecf20Sopenharmony_ci "ntb target partition is not NT partition\n"); 8908c2ecf20Sopenharmony_ci return -ENODEV; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d\n", 8958c2ecf20Sopenharmony_ci sndev->self_partition, sndev->stdev->partition_count); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb + 8988c2ecf20Sopenharmony_ci SWITCHTEC_NTB_REG_CTRL_OFFSET; 8998c2ecf20Sopenharmony_ci sndev->mmio_dbmsg = (void * __iomem)sndev->mmio_ntb + 9008c2ecf20Sopenharmony_ci SWITCHTEC_NTB_REG_DBMSG_OFFSET; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition]; 9038c2ecf20Sopenharmony_ci sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition]; 9048c2ecf20Sopenharmony_ci sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition]; 9058c2ecf20Sopenharmony_ci sndev->mmio_peer_dbmsg = sndev->mmio_self_dbmsg; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci return 0; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic int config_rsvd_lut_win(struct switchtec_ntb *sndev, 9118c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl, 9128c2ecf20Sopenharmony_ci int lut_idx, int partition, u64 addr) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci int peer_bar = sndev->peer_direct_mw_to_bar[0]; 9158c2ecf20Sopenharmony_ci u32 ctl_val; 9168c2ecf20Sopenharmony_ci int rc; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, 9198c2ecf20Sopenharmony_ci NTB_CTRL_PART_STATUS_LOCKED); 9208c2ecf20Sopenharmony_ci if (rc) 9218c2ecf20Sopenharmony_ci return rc; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci ctl_val = ioread32(&ctl->bar_entry[peer_bar].ctl); 9248c2ecf20Sopenharmony_ci ctl_val &= 0xFF; 9258c2ecf20Sopenharmony_ci ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN; 9268c2ecf20Sopenharmony_ci ctl_val |= ilog2(LUT_SIZE) << 8; 9278c2ecf20Sopenharmony_ci ctl_val |= (sndev->nr_lut_mw - 1) << 14; 9288c2ecf20Sopenharmony_ci iowrite32(ctl_val, &ctl->bar_entry[peer_bar].ctl); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci iowrite64((NTB_CTRL_LUT_EN | (partition << 1) | addr), 9318c2ecf20Sopenharmony_ci &ctl->lut_entry[lut_idx]); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 9348c2ecf20Sopenharmony_ci NTB_CTRL_PART_STATUS_NORMAL); 9358c2ecf20Sopenharmony_ci if (rc) { 9368c2ecf20Sopenharmony_ci u32 bar_error, lut_error; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci bar_error = ioread32(&ctl->bar_error); 9398c2ecf20Sopenharmony_ci lut_error = ioread32(&ctl->lut_error); 9408c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 9418c2ecf20Sopenharmony_ci "Error setting up reserved lut window: %08x / %08x\n", 9428c2ecf20Sopenharmony_ci bar_error, lut_error); 9438c2ecf20Sopenharmony_ci return rc; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci return 0; 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic int config_req_id_table(struct switchtec_ntb *sndev, 9508c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *mmio_ctrl, 9518c2ecf20Sopenharmony_ci int *req_ids, int count) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci int i, rc = 0; 9548c2ecf20Sopenharmony_ci u32 error; 9558c2ecf20Sopenharmony_ci u32 proxy_id; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (ioread32(&mmio_ctrl->req_id_table_size) < count) { 9588c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 9598c2ecf20Sopenharmony_ci "Not enough requester IDs available.\n"); 9608c2ecf20Sopenharmony_ci return -EFAULT; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, mmio_ctrl, 9648c2ecf20Sopenharmony_ci NTB_CTRL_PART_OP_LOCK, 9658c2ecf20Sopenharmony_ci NTB_CTRL_PART_STATUS_LOCKED); 9668c2ecf20Sopenharmony_ci if (rc) 9678c2ecf20Sopenharmony_ci return rc; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci iowrite32(NTB_PART_CTRL_ID_PROT_DIS, 9708c2ecf20Sopenharmony_ci &mmio_ctrl->partition_ctrl); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 9738c2ecf20Sopenharmony_ci iowrite32(req_ids[i] << 16 | NTB_CTRL_REQ_ID_EN, 9748c2ecf20Sopenharmony_ci &mmio_ctrl->req_id_table[i]); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci proxy_id = ioread32(&mmio_ctrl->req_id_table[i]); 9778c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, 9788c2ecf20Sopenharmony_ci "Requester ID %02X:%02X.%X -> BB:%02X.%X\n", 9798c2ecf20Sopenharmony_ci req_ids[i] >> 8, (req_ids[i] >> 3) & 0x1F, 9808c2ecf20Sopenharmony_ci req_ids[i] & 0x7, (proxy_id >> 4) & 0x1F, 9818c2ecf20Sopenharmony_ci (proxy_id >> 1) & 0x7); 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, mmio_ctrl, 9858c2ecf20Sopenharmony_ci NTB_CTRL_PART_OP_CFG, 9868c2ecf20Sopenharmony_ci NTB_CTRL_PART_STATUS_NORMAL); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci if (rc == -EIO) { 9898c2ecf20Sopenharmony_ci error = ioread32(&mmio_ctrl->req_id_error); 9908c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 9918c2ecf20Sopenharmony_ci "Error setting up the requester ID table: %08x\n", 9928c2ecf20Sopenharmony_ci error); 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci return 0; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic int crosslink_setup_mws(struct switchtec_ntb *sndev, int ntb_lut_idx, 9998c2ecf20Sopenharmony_ci u64 *mw_addrs, int mw_count) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci int rc, i; 10028c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_self_ctrl; 10038c2ecf20Sopenharmony_ci u64 addr; 10048c2ecf20Sopenharmony_ci size_t size, offset; 10058c2ecf20Sopenharmony_ci int bar; 10068c2ecf20Sopenharmony_ci int xlate_pos; 10078c2ecf20Sopenharmony_ci u32 ctl_val; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, 10108c2ecf20Sopenharmony_ci NTB_CTRL_PART_STATUS_LOCKED); 10118c2ecf20Sopenharmony_ci if (rc) 10128c2ecf20Sopenharmony_ci return rc; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci for (i = 0; i < sndev->nr_lut_mw; i++) { 10158c2ecf20Sopenharmony_ci if (i == ntb_lut_idx) 10168c2ecf20Sopenharmony_ci continue; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci addr = mw_addrs[0] + LUT_SIZE * i; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci iowrite64((NTB_CTRL_LUT_EN | (sndev->peer_partition << 1) | 10218c2ecf20Sopenharmony_ci addr), 10228c2ecf20Sopenharmony_ci &ctl->lut_entry[i]); 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci sndev->nr_direct_mw = min_t(int, sndev->nr_direct_mw, mw_count); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci for (i = 0; i < sndev->nr_direct_mw; i++) { 10288c2ecf20Sopenharmony_ci bar = sndev->direct_mw_to_bar[i]; 10298c2ecf20Sopenharmony_ci offset = (i == 0) ? LUT_SIZE * sndev->nr_lut_mw : 0; 10308c2ecf20Sopenharmony_ci addr = mw_addrs[i] + offset; 10318c2ecf20Sopenharmony_ci size = pci_resource_len(sndev->ntb.pdev, bar) - offset; 10328c2ecf20Sopenharmony_ci xlate_pos = ilog2(size); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if (offset && size > offset) 10358c2ecf20Sopenharmony_ci size = offset; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci ctl_val = ioread32(&ctl->bar_entry[bar].ctl); 10388c2ecf20Sopenharmony_ci ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); 10418c2ecf20Sopenharmony_ci iowrite32(xlate_pos | (lower_32_bits(size) & 0xFFFFF000), 10428c2ecf20Sopenharmony_ci &ctl->bar_entry[bar].win_size); 10438c2ecf20Sopenharmony_ci iowrite32(upper_32_bits(size), &ctl->bar_ext_entry[bar].win_size); 10448c2ecf20Sopenharmony_ci iowrite64(sndev->peer_partition | addr, 10458c2ecf20Sopenharmony_ci &ctl->bar_entry[bar].xlate_addr); 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 10498c2ecf20Sopenharmony_ci NTB_CTRL_PART_STATUS_NORMAL); 10508c2ecf20Sopenharmony_ci if (rc) { 10518c2ecf20Sopenharmony_ci u32 bar_error, lut_error; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci bar_error = ioread32(&ctl->bar_error); 10548c2ecf20Sopenharmony_ci lut_error = ioread32(&ctl->lut_error); 10558c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 10568c2ecf20Sopenharmony_ci "Error setting up cross link windows: %08x / %08x\n", 10578c2ecf20Sopenharmony_ci bar_error, lut_error); 10588c2ecf20Sopenharmony_ci return rc; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci return 0; 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic int crosslink_setup_req_ids(struct switchtec_ntb *sndev, 10658c2ecf20Sopenharmony_ci struct ntb_ctrl_regs __iomem *mmio_ctrl) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci int req_ids[16]; 10688c2ecf20Sopenharmony_ci int i; 10698c2ecf20Sopenharmony_ci u32 proxy_id; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(req_ids); i++) { 10728c2ecf20Sopenharmony_ci proxy_id = ioread32(&sndev->mmio_self_ctrl->req_id_table[i]); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (!(proxy_id & NTB_CTRL_REQ_ID_EN)) 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci req_ids[i] = ((proxy_id >> 1) & 0xFF); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci return config_req_id_table(sndev, mmio_ctrl, req_ids, i); 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci/* 10848c2ecf20Sopenharmony_ci * In crosslink configuration there is a virtual partition in the 10858c2ecf20Sopenharmony_ci * middle of the two switches. The BARs in this partition have to be 10868c2ecf20Sopenharmony_ci * enumerated and assigned addresses. 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_cistatic int crosslink_enum_partition(struct switchtec_ntb *sndev, 10898c2ecf20Sopenharmony_ci u64 *bar_addrs) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci struct part_cfg_regs __iomem *part_cfg = 10928c2ecf20Sopenharmony_ci &sndev->stdev->mmio_part_cfg_all[sndev->peer_partition]; 10938c2ecf20Sopenharmony_ci u32 pff = ioread32(&part_cfg->vep_pff_inst_id); 10948c2ecf20Sopenharmony_ci struct pff_csr_regs __iomem *mmio_pff = 10958c2ecf20Sopenharmony_ci &sndev->stdev->mmio_pff_csr[pff]; 10968c2ecf20Sopenharmony_ci const u64 bar_space = 0x1000000000LL; 10978c2ecf20Sopenharmony_ci u64 bar_addr; 10988c2ecf20Sopenharmony_ci int bar_cnt = 0; 10998c2ecf20Sopenharmony_ci int i; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci iowrite16(0x6, &mmio_pff->pcicmd); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mmio_pff->pci_bar64); i++) { 11048c2ecf20Sopenharmony_ci iowrite64(bar_space * i, &mmio_pff->pci_bar64[i]); 11058c2ecf20Sopenharmony_ci bar_addr = ioread64(&mmio_pff->pci_bar64[i]); 11068c2ecf20Sopenharmony_ci bar_addr &= ~0xf; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, 11098c2ecf20Sopenharmony_ci "Crosslink BAR%d addr: %llx\n", 11108c2ecf20Sopenharmony_ci i*2, bar_addr); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (bar_addr != bar_space * i) 11138c2ecf20Sopenharmony_ci continue; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci bar_addrs[bar_cnt++] = bar_addr; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci return bar_cnt; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic int switchtec_ntb_init_crosslink(struct switchtec_ntb *sndev) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci int rc; 11248c2ecf20Sopenharmony_ci int bar = sndev->direct_mw_to_bar[0]; 11258c2ecf20Sopenharmony_ci const int ntb_lut_idx = 1; 11268c2ecf20Sopenharmony_ci u64 bar_addrs[6]; 11278c2ecf20Sopenharmony_ci u64 addr; 11288c2ecf20Sopenharmony_ci int offset; 11298c2ecf20Sopenharmony_ci int bar_cnt; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (!crosslink_is_enabled(sndev)) 11328c2ecf20Sopenharmony_ci return 0; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci dev_info(&sndev->stdev->dev, "Using crosslink configuration\n"); 11358c2ecf20Sopenharmony_ci sndev->ntb.topo = NTB_TOPO_CROSSLINK; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci bar_cnt = crosslink_enum_partition(sndev, bar_addrs); 11388c2ecf20Sopenharmony_ci if (bar_cnt < sndev->nr_direct_mw + 1) { 11398c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 11408c2ecf20Sopenharmony_ci "Error enumerating crosslink partition\n"); 11418c2ecf20Sopenharmony_ci return -EINVAL; 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci addr = (bar_addrs[0] + SWITCHTEC_GAS_NTB_OFFSET + 11458c2ecf20Sopenharmony_ci SWITCHTEC_NTB_REG_DBMSG_OFFSET + 11468c2ecf20Sopenharmony_ci sizeof(struct ntb_dbmsg_regs) * sndev->peer_partition); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci offset = addr & (LUT_SIZE - 1); 11498c2ecf20Sopenharmony_ci addr -= offset; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci rc = config_rsvd_lut_win(sndev, sndev->mmio_self_ctrl, ntb_lut_idx, 11528c2ecf20Sopenharmony_ci sndev->peer_partition, addr); 11538c2ecf20Sopenharmony_ci if (rc) 11548c2ecf20Sopenharmony_ci return rc; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci rc = crosslink_setup_mws(sndev, ntb_lut_idx, &bar_addrs[1], 11578c2ecf20Sopenharmony_ci bar_cnt - 1); 11588c2ecf20Sopenharmony_ci if (rc) 11598c2ecf20Sopenharmony_ci return rc; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci rc = crosslink_setup_req_ids(sndev, sndev->mmio_peer_ctrl); 11628c2ecf20Sopenharmony_ci if (rc) 11638c2ecf20Sopenharmony_ci return rc; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci sndev->mmio_xlink_win = pci_iomap_range(sndev->stdev->pdev, bar, 11668c2ecf20Sopenharmony_ci LUT_SIZE, LUT_SIZE); 11678c2ecf20Sopenharmony_ci if (!sndev->mmio_xlink_win) { 11688c2ecf20Sopenharmony_ci rc = -ENOMEM; 11698c2ecf20Sopenharmony_ci return rc; 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci sndev->mmio_peer_dbmsg = sndev->mmio_xlink_win + offset; 11738c2ecf20Sopenharmony_ci sndev->nr_rsvd_luts++; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci crosslink_init_dbmsgs(sndev); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci return 0; 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_cistatic void switchtec_ntb_deinit_crosslink(struct switchtec_ntb *sndev) 11818c2ecf20Sopenharmony_ci{ 11828c2ecf20Sopenharmony_ci if (sndev->mmio_xlink_win) 11838c2ecf20Sopenharmony_ci pci_iounmap(sndev->stdev->pdev, sndev->mmio_xlink_win); 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci int i; 11898c2ecf20Sopenharmony_ci int cnt = 0; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ctrl->bar_entry); i++) { 11928c2ecf20Sopenharmony_ci u32 r = ioread32(&ctrl->bar_entry[i].ctl); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci if (r & NTB_CTRL_BAR_VALID) 11958c2ecf20Sopenharmony_ci map[cnt++] = i; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci return cnt; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic void switchtec_ntb_init_mw(struct switchtec_ntb *sndev) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci sndev->nr_direct_mw = map_bars(sndev->direct_mw_to_bar, 12048c2ecf20Sopenharmony_ci sndev->mmio_self_ctrl); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries); 12078c2ecf20Sopenharmony_ci sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut\n", 12108c2ecf20Sopenharmony_ci sndev->nr_direct_mw, sndev->nr_lut_mw); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci sndev->peer_nr_direct_mw = map_bars(sndev->peer_direct_mw_to_bar, 12138c2ecf20Sopenharmony_ci sndev->mmio_peer_ctrl); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci sndev->peer_nr_lut_mw = 12168c2ecf20Sopenharmony_ci ioread16(&sndev->mmio_peer_ctrl->lut_table_entries); 12178c2ecf20Sopenharmony_ci sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut\n", 12208c2ecf20Sopenharmony_ci sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci/* 12258c2ecf20Sopenharmony_ci * There are 64 doorbells in the switch hardware but this is 12268c2ecf20Sopenharmony_ci * shared among all partitions. So we must split them in half 12278c2ecf20Sopenharmony_ci * (32 for each partition). However, the message interrupts are 12288c2ecf20Sopenharmony_ci * also shared with the top 4 doorbells so we just limit this to 12298c2ecf20Sopenharmony_ci * 28 doorbells per partition. 12308c2ecf20Sopenharmony_ci * 12318c2ecf20Sopenharmony_ci * In crosslink mode, each side has it's own dbmsg register so 12328c2ecf20Sopenharmony_ci * they can each use all 60 of the available doorbells. 12338c2ecf20Sopenharmony_ci */ 12348c2ecf20Sopenharmony_cistatic void switchtec_ntb_init_db(struct switchtec_ntb *sndev) 12358c2ecf20Sopenharmony_ci{ 12368c2ecf20Sopenharmony_ci sndev->db_mask = 0x0FFFFFFFFFFFFFFFULL; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (sndev->mmio_peer_dbmsg != sndev->mmio_self_dbmsg) { 12398c2ecf20Sopenharmony_ci sndev->db_shift = 0; 12408c2ecf20Sopenharmony_ci sndev->db_peer_shift = 0; 12418c2ecf20Sopenharmony_ci sndev->db_valid_mask = sndev->db_mask; 12428c2ecf20Sopenharmony_ci } else if (sndev->self_partition < sndev->peer_partition) { 12438c2ecf20Sopenharmony_ci sndev->db_shift = 0; 12448c2ecf20Sopenharmony_ci sndev->db_peer_shift = 32; 12458c2ecf20Sopenharmony_ci sndev->db_valid_mask = 0x0FFFFFFF; 12468c2ecf20Sopenharmony_ci } else { 12478c2ecf20Sopenharmony_ci sndev->db_shift = 32; 12488c2ecf20Sopenharmony_ci sndev->db_peer_shift = 0; 12498c2ecf20Sopenharmony_ci sndev->db_valid_mask = 0x0FFFFFFF; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 12538c2ecf20Sopenharmony_ci iowrite64(sndev->db_valid_mask << sndev->db_peer_shift, 12548c2ecf20Sopenharmony_ci &sndev->mmio_peer_dbmsg->odb_mask); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "dbs: shift %d/%d, mask %016llx\n", 12578c2ecf20Sopenharmony_ci sndev->db_shift, sndev->db_peer_shift, sndev->db_valid_mask); 12588c2ecf20Sopenharmony_ci} 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic void switchtec_ntb_init_msgs(struct switchtec_ntb *sndev) 12618c2ecf20Sopenharmony_ci{ 12628c2ecf20Sopenharmony_ci int i; 12638c2ecf20Sopenharmony_ci u32 msg_map = 0; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) { 12668c2ecf20Sopenharmony_ci int m = i | sndev->peer_partition << 2; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci msg_map |= m << i * 8; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci iowrite32(msg_map, &sndev->mmio_self_dbmsg->msg_map); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) 12748c2ecf20Sopenharmony_ci iowrite64(NTB_DBMSG_IMSG_STATUS | NTB_DBMSG_IMSG_MASK, 12758c2ecf20Sopenharmony_ci &sndev->mmio_self_dbmsg->imsg[i]); 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic int 12798c2ecf20Sopenharmony_ciswitchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci int req_ids[2]; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* 12848c2ecf20Sopenharmony_ci * Root Complex Requester ID (which is 0:00.0) 12858c2ecf20Sopenharmony_ci */ 12868c2ecf20Sopenharmony_ci req_ids[0] = 0; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci /* 12898c2ecf20Sopenharmony_ci * Host Bridge Requester ID (as read from the mmap address) 12908c2ecf20Sopenharmony_ci */ 12918c2ecf20Sopenharmony_ci req_ids[1] = ioread16(&sndev->mmio_ntb->requester_id); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci return config_req_id_table(sndev, sndev->mmio_self_ctrl, req_ids, 12948c2ecf20Sopenharmony_ci ARRAY_SIZE(req_ids)); 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic void switchtec_ntb_init_shared(struct switchtec_ntb *sndev) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci int i; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci memset(sndev->self_shared, 0, LUT_SIZE); 13028c2ecf20Sopenharmony_ci sndev->self_shared->magic = SWITCHTEC_NTB_MAGIC; 13038c2ecf20Sopenharmony_ci sndev->self_shared->partition_id = sndev->stdev->partition; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci for (i = 0; i < sndev->nr_direct_mw; i++) { 13068c2ecf20Sopenharmony_ci int bar = sndev->direct_mw_to_bar[i]; 13078c2ecf20Sopenharmony_ci resource_size_t sz = pci_resource_len(sndev->stdev->pdev, bar); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (i == 0) 13108c2ecf20Sopenharmony_ci sz = min_t(resource_size_t, sz, 13118c2ecf20Sopenharmony_ci LUT_SIZE * sndev->nr_lut_mw); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci sndev->self_shared->mw_sizes[i] = sz; 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci for (i = 0; i < sndev->nr_lut_mw; i++) { 13178c2ecf20Sopenharmony_ci int idx = sndev->nr_direct_mw + i; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci sndev->self_shared->mw_sizes[idx] = LUT_SIZE; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cistatic int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci int self_bar = sndev->direct_mw_to_bar[0]; 13268c2ecf20Sopenharmony_ci int rc; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci sndev->nr_rsvd_luts++; 13298c2ecf20Sopenharmony_ci sndev->self_shared = dma_alloc_coherent(&sndev->stdev->pdev->dev, 13308c2ecf20Sopenharmony_ci LUT_SIZE, 13318c2ecf20Sopenharmony_ci &sndev->self_shared_dma, 13328c2ecf20Sopenharmony_ci GFP_KERNEL); 13338c2ecf20Sopenharmony_ci if (!sndev->self_shared) { 13348c2ecf20Sopenharmony_ci dev_err(&sndev->stdev->dev, 13358c2ecf20Sopenharmony_ci "unable to allocate memory for shared mw\n"); 13368c2ecf20Sopenharmony_ci return -ENOMEM; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci switchtec_ntb_init_shared(sndev); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0, 13428c2ecf20Sopenharmony_ci sndev->self_partition, 13438c2ecf20Sopenharmony_ci sndev->self_shared_dma); 13448c2ecf20Sopenharmony_ci if (rc) 13458c2ecf20Sopenharmony_ci goto unalloc_and_exit; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci sndev->peer_shared = pci_iomap(sndev->stdev->pdev, self_bar, LUT_SIZE); 13488c2ecf20Sopenharmony_ci if (!sndev->peer_shared) { 13498c2ecf20Sopenharmony_ci rc = -ENOMEM; 13508c2ecf20Sopenharmony_ci goto unalloc_and_exit; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "Shared MW Ready\n"); 13548c2ecf20Sopenharmony_ci return 0; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ciunalloc_and_exit: 13578c2ecf20Sopenharmony_ci dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, 13588c2ecf20Sopenharmony_ci sndev->self_shared, sndev->self_shared_dma); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci return rc; 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic void switchtec_ntb_deinit_shared_mw(struct switchtec_ntb *sndev) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci if (sndev->peer_shared) 13668c2ecf20Sopenharmony_ci pci_iounmap(sndev->stdev->pdev, sndev->peer_shared); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (sndev->self_shared) 13698c2ecf20Sopenharmony_ci dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, 13708c2ecf20Sopenharmony_ci sndev->self_shared, 13718c2ecf20Sopenharmony_ci sndev->self_shared_dma); 13728c2ecf20Sopenharmony_ci sndev->nr_rsvd_luts--; 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_cistatic irqreturn_t switchtec_ntb_doorbell_isr(int irq, void *dev) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = dev; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "doorbell\n"); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci ntb_db_event(&sndev->ntb, 0); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic irqreturn_t switchtec_ntb_message_isr(int irq, void *dev) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci int i; 13898c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = dev; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) { 13928c2ecf20Sopenharmony_ci u64 msg = ioread64(&sndev->mmio_self_dbmsg->imsg[i]); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (msg & NTB_DBMSG_IMSG_STATUS) { 13958c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", 13968c2ecf20Sopenharmony_ci i, (u32)msg); 13978c2ecf20Sopenharmony_ci iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (i == LINK_MESSAGE) 14008c2ecf20Sopenharmony_ci switchtec_ntb_check_link(sndev, msg); 14018c2ecf20Sopenharmony_ci } 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci return IRQ_HANDLED; 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_cistatic int switchtec_ntb_init_db_msg_irq(struct switchtec_ntb *sndev) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci int i; 14108c2ecf20Sopenharmony_ci int rc; 14118c2ecf20Sopenharmony_ci int doorbell_irq = 0; 14128c2ecf20Sopenharmony_ci int message_irq = 0; 14138c2ecf20Sopenharmony_ci int event_irq; 14148c2ecf20Sopenharmony_ci int idb_vecs = sizeof(sndev->mmio_self_dbmsg->idb_vec_map); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci event_irq = ioread32(&sndev->stdev->mmio_part_cfg->vep_vector_number); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci while (doorbell_irq == event_irq) 14198c2ecf20Sopenharmony_ci doorbell_irq++; 14208c2ecf20Sopenharmony_ci while (message_irq == doorbell_irq || 14218c2ecf20Sopenharmony_ci message_irq == event_irq) 14228c2ecf20Sopenharmony_ci message_irq++; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "irqs - event: %d, db: %d, msgs: %d\n", 14258c2ecf20Sopenharmony_ci event_irq, doorbell_irq, message_irq); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci for (i = 0; i < idb_vecs - 4; i++) 14288c2ecf20Sopenharmony_ci iowrite8(doorbell_irq, 14298c2ecf20Sopenharmony_ci &sndev->mmio_self_dbmsg->idb_vec_map[i]); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci for (; i < idb_vecs; i++) 14328c2ecf20Sopenharmony_ci iowrite8(message_irq, 14338c2ecf20Sopenharmony_ci &sndev->mmio_self_dbmsg->idb_vec_map[i]); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci sndev->doorbell_irq = pci_irq_vector(sndev->stdev->pdev, doorbell_irq); 14368c2ecf20Sopenharmony_ci sndev->message_irq = pci_irq_vector(sndev->stdev->pdev, message_irq); 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci rc = request_irq(sndev->doorbell_irq, 14398c2ecf20Sopenharmony_ci switchtec_ntb_doorbell_isr, 0, 14408c2ecf20Sopenharmony_ci "switchtec_ntb_doorbell", sndev); 14418c2ecf20Sopenharmony_ci if (rc) 14428c2ecf20Sopenharmony_ci return rc; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci rc = request_irq(sndev->message_irq, 14458c2ecf20Sopenharmony_ci switchtec_ntb_message_isr, 0, 14468c2ecf20Sopenharmony_ci "switchtec_ntb_message", sndev); 14478c2ecf20Sopenharmony_ci if (rc) { 14488c2ecf20Sopenharmony_ci free_irq(sndev->doorbell_irq, sndev); 14498c2ecf20Sopenharmony_ci return rc; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci return 0; 14538c2ecf20Sopenharmony_ci} 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_cistatic void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev) 14568c2ecf20Sopenharmony_ci{ 14578c2ecf20Sopenharmony_ci free_irq(sndev->doorbell_irq, sndev); 14588c2ecf20Sopenharmony_ci free_irq(sndev->message_irq, sndev); 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_cistatic int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev) 14628c2ecf20Sopenharmony_ci{ 14638c2ecf20Sopenharmony_ci int rc; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (crosslink_is_enabled(sndev)) 14668c2ecf20Sopenharmony_ci return 0; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci dev_info(&sndev->stdev->dev, "reinitialize shared memory window\n"); 14698c2ecf20Sopenharmony_ci rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0, 14708c2ecf20Sopenharmony_ci sndev->self_partition, 14718c2ecf20Sopenharmony_ci sndev->self_shared_dma); 14728c2ecf20Sopenharmony_ci return rc; 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_cistatic int switchtec_ntb_add(struct device *dev, 14768c2ecf20Sopenharmony_ci struct class_interface *class_intf) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci struct switchtec_dev *stdev = to_stdev(dev); 14798c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev; 14808c2ecf20Sopenharmony_ci int rc; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci stdev->sndev = NULL; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci if (stdev->pdev->class != (PCI_CLASS_BRIDGE_OTHER << 8)) 14858c2ecf20Sopenharmony_ci return -ENODEV; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev)); 14888c2ecf20Sopenharmony_ci if (!sndev) 14898c2ecf20Sopenharmony_ci return -ENOMEM; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci sndev->stdev = stdev; 14928c2ecf20Sopenharmony_ci rc = switchtec_ntb_init_sndev(sndev); 14938c2ecf20Sopenharmony_ci if (rc) 14948c2ecf20Sopenharmony_ci goto free_and_exit; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci switchtec_ntb_init_mw(sndev); 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci rc = switchtec_ntb_init_req_id_table(sndev); 14998c2ecf20Sopenharmony_ci if (rc) 15008c2ecf20Sopenharmony_ci goto free_and_exit; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci rc = switchtec_ntb_init_crosslink(sndev); 15038c2ecf20Sopenharmony_ci if (rc) 15048c2ecf20Sopenharmony_ci goto free_and_exit; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci switchtec_ntb_init_db(sndev); 15078c2ecf20Sopenharmony_ci switchtec_ntb_init_msgs(sndev); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci rc = switchtec_ntb_init_shared_mw(sndev); 15108c2ecf20Sopenharmony_ci if (rc) 15118c2ecf20Sopenharmony_ci goto deinit_crosslink; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci rc = switchtec_ntb_init_db_msg_irq(sndev); 15148c2ecf20Sopenharmony_ci if (rc) 15158c2ecf20Sopenharmony_ci goto deinit_shared_and_exit; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci /* 15188c2ecf20Sopenharmony_ci * If this host crashed, the other host may think the link is 15198c2ecf20Sopenharmony_ci * still up. Tell them to force it down (it will go back up 15208c2ecf20Sopenharmony_ci * once we register the ntb device). 15218c2ecf20Sopenharmony_ci */ 15228c2ecf20Sopenharmony_ci switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_FORCE_DOWN); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci rc = ntb_register_device(&sndev->ntb); 15258c2ecf20Sopenharmony_ci if (rc) 15268c2ecf20Sopenharmony_ci goto deinit_and_exit; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci stdev->sndev = sndev; 15298c2ecf20Sopenharmony_ci stdev->link_notifier = switchtec_ntb_link_notification; 15308c2ecf20Sopenharmony_ci dev_info(dev, "NTB device registered\n"); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci return 0; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_cideinit_and_exit: 15358c2ecf20Sopenharmony_ci switchtec_ntb_deinit_db_msg_irq(sndev); 15368c2ecf20Sopenharmony_cideinit_shared_and_exit: 15378c2ecf20Sopenharmony_ci switchtec_ntb_deinit_shared_mw(sndev); 15388c2ecf20Sopenharmony_cideinit_crosslink: 15398c2ecf20Sopenharmony_ci switchtec_ntb_deinit_crosslink(sndev); 15408c2ecf20Sopenharmony_cifree_and_exit: 15418c2ecf20Sopenharmony_ci kfree(sndev); 15428c2ecf20Sopenharmony_ci dev_err(dev, "failed to register ntb device: %d\n", rc); 15438c2ecf20Sopenharmony_ci return rc; 15448c2ecf20Sopenharmony_ci} 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_cistatic void switchtec_ntb_remove(struct device *dev, 15478c2ecf20Sopenharmony_ci struct class_interface *class_intf) 15488c2ecf20Sopenharmony_ci{ 15498c2ecf20Sopenharmony_ci struct switchtec_dev *stdev = to_stdev(dev); 15508c2ecf20Sopenharmony_ci struct switchtec_ntb *sndev = stdev->sndev; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (!sndev) 15538c2ecf20Sopenharmony_ci return; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci stdev->link_notifier = NULL; 15568c2ecf20Sopenharmony_ci stdev->sndev = NULL; 15578c2ecf20Sopenharmony_ci ntb_unregister_device(&sndev->ntb); 15588c2ecf20Sopenharmony_ci switchtec_ntb_deinit_db_msg_irq(sndev); 15598c2ecf20Sopenharmony_ci switchtec_ntb_deinit_shared_mw(sndev); 15608c2ecf20Sopenharmony_ci switchtec_ntb_deinit_crosslink(sndev); 15618c2ecf20Sopenharmony_ci kfree(sndev); 15628c2ecf20Sopenharmony_ci dev_info(dev, "ntb device unregistered\n"); 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_cistatic struct class_interface switchtec_interface = { 15668c2ecf20Sopenharmony_ci .add_dev = switchtec_ntb_add, 15678c2ecf20Sopenharmony_ci .remove_dev = switchtec_ntb_remove, 15688c2ecf20Sopenharmony_ci}; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_cistatic int __init switchtec_ntb_init(void) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci switchtec_interface.class = switchtec_class; 15738c2ecf20Sopenharmony_ci return class_interface_register(&switchtec_interface); 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_cimodule_init(switchtec_ntb_init); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic void __exit switchtec_ntb_exit(void) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci class_interface_unregister(&switchtec_interface); 15808c2ecf20Sopenharmony_ci} 15818c2ecf20Sopenharmony_cimodule_exit(switchtec_ntb_exit); 1582