162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Microsemi Switchtec(tm) PCIe Management Driver 462306a36Sopenharmony_ci * Copyright (c) 2017, Microsemi Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/interrupt.h> 862306a36Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/kthread.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/ntb.h> 1362306a36Sopenharmony_ci#include <linux/pci.h> 1462306a36Sopenharmony_ci#include <linux/switchtec.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciMODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver"); 1762306a36Sopenharmony_ciMODULE_VERSION("0.1"); 1862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1962306a36Sopenharmony_ciMODULE_AUTHOR("Microsemi Corporation"); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic ulong max_mw_size = SZ_2M; 2262306a36Sopenharmony_cimodule_param(max_mw_size, ulong, 0644); 2362306a36Sopenharmony_ciMODULE_PARM_DESC(max_mw_size, 2462306a36Sopenharmony_ci "Max memory window size reported to the upper layer"); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic bool use_lut_mws; 2762306a36Sopenharmony_cimodule_param(use_lut_mws, bool, 0644); 2862306a36Sopenharmony_ciMODULE_PARM_DESC(use_lut_mws, 2962306a36Sopenharmony_ci "Enable the use of the LUT based memory windows"); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define SWITCHTEC_NTB_MAGIC 0x45CC0001 3262306a36Sopenharmony_ci#define MAX_MWS 128 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct shared_mw { 3562306a36Sopenharmony_ci u32 magic; 3662306a36Sopenharmony_ci u32 link_sta; 3762306a36Sopenharmony_ci u32 partition_id; 3862306a36Sopenharmony_ci u64 mw_sizes[MAX_MWS]; 3962306a36Sopenharmony_ci u32 spad[128]; 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define MAX_DIRECT_MW ARRAY_SIZE(((struct ntb_ctrl_regs *)(0))->bar_entry) 4362306a36Sopenharmony_ci#define LUT_SIZE SZ_64K 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct switchtec_ntb { 4662306a36Sopenharmony_ci struct ntb_dev ntb; 4762306a36Sopenharmony_ci struct switchtec_dev *stdev; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci int self_partition; 5062306a36Sopenharmony_ci int peer_partition; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci int doorbell_irq; 5362306a36Sopenharmony_ci int message_irq; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci struct ntb_info_regs __iomem *mmio_ntb; 5662306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *mmio_ctrl; 5762306a36Sopenharmony_ci struct ntb_dbmsg_regs __iomem *mmio_dbmsg; 5862306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *mmio_self_ctrl; 5962306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *mmio_peer_ctrl; 6062306a36Sopenharmony_ci struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg; 6162306a36Sopenharmony_ci struct ntb_dbmsg_regs __iomem *mmio_peer_dbmsg; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci void __iomem *mmio_xlink_win; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci struct shared_mw *self_shared; 6662306a36Sopenharmony_ci struct shared_mw __iomem *peer_shared; 6762306a36Sopenharmony_ci dma_addr_t self_shared_dma; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci u64 db_mask; 7062306a36Sopenharmony_ci u64 db_valid_mask; 7162306a36Sopenharmony_ci int db_shift; 7262306a36Sopenharmony_ci int db_peer_shift; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* synchronize rmw access of db_mask and hw reg */ 7562306a36Sopenharmony_ci spinlock_t db_mask_lock; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci int nr_direct_mw; 7862306a36Sopenharmony_ci int nr_lut_mw; 7962306a36Sopenharmony_ci int nr_rsvd_luts; 8062306a36Sopenharmony_ci int direct_mw_to_bar[MAX_DIRECT_MW]; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci int peer_nr_direct_mw; 8362306a36Sopenharmony_ci int peer_nr_lut_mw; 8462306a36Sopenharmony_ci int peer_direct_mw_to_bar[MAX_DIRECT_MW]; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci bool link_is_up; 8762306a36Sopenharmony_ci enum ntb_speed link_speed; 8862306a36Sopenharmony_ci enum ntb_width link_width; 8962306a36Sopenharmony_ci struct work_struct check_link_status_work; 9062306a36Sopenharmony_ci bool link_force_down; 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci return container_of(ntb, struct switchtec_ntb, ntb); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int switchtec_ntb_part_op(struct switchtec_ntb *sndev, 9962306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl, 10062306a36Sopenharmony_ci u32 op, int wait_status) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci static const char * const op_text[] = { 10362306a36Sopenharmony_ci [NTB_CTRL_PART_OP_LOCK] = "lock", 10462306a36Sopenharmony_ci [NTB_CTRL_PART_OP_CFG] = "configure", 10562306a36Sopenharmony_ci [NTB_CTRL_PART_OP_RESET] = "reset", 10662306a36Sopenharmony_ci }; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci int i; 10962306a36Sopenharmony_ci u32 ps; 11062306a36Sopenharmony_ci int status; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci switch (op) { 11362306a36Sopenharmony_ci case NTB_CTRL_PART_OP_LOCK: 11462306a36Sopenharmony_ci status = NTB_CTRL_PART_STATUS_LOCKING; 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci case NTB_CTRL_PART_OP_CFG: 11762306a36Sopenharmony_ci status = NTB_CTRL_PART_STATUS_CONFIGURING; 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci case NTB_CTRL_PART_OP_RESET: 12062306a36Sopenharmony_ci status = NTB_CTRL_PART_STATUS_RESETTING; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci default: 12362306a36Sopenharmony_ci return -EINVAL; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci iowrite32(op, &ctl->partition_op); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci for (i = 0; i < 1000; i++) { 12962306a36Sopenharmony_ci if (msleep_interruptible(50) != 0) { 13062306a36Sopenharmony_ci iowrite32(NTB_CTRL_PART_OP_RESET, &ctl->partition_op); 13162306a36Sopenharmony_ci return -EINTR; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ps = ioread32(&ctl->partition_status) & 0xFFFF; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (ps != status) 13762306a36Sopenharmony_ci break; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (ps == wait_status) 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (ps == status) { 14462306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 14562306a36Sopenharmony_ci "Timed out while performing %s (%d). (%08x)\n", 14662306a36Sopenharmony_ci op_text[op], op, 14762306a36Sopenharmony_ci ioread32(&ctl->partition_status)); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return -ETIMEDOUT; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return -EIO; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx, 15662306a36Sopenharmony_ci u32 val) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_peer_dbmsg->omsg)) 15962306a36Sopenharmony_ci return -EINVAL; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci iowrite32(val, &sndev->mmio_peer_dbmsg->omsg[idx].msg); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 16962306a36Sopenharmony_ci int nr_direct_mw = sndev->peer_nr_direct_mw; 17062306a36Sopenharmony_ci int nr_lut_mw = sndev->peer_nr_lut_mw - sndev->nr_rsvd_luts; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 17362306a36Sopenharmony_ci return -EINVAL; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (!use_lut_mws) 17662306a36Sopenharmony_ci nr_lut_mw = 0; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return nr_direct_mw + nr_lut_mw; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic int lut_index(struct switchtec_ntb *sndev, int mw_idx) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci return mw_idx - sndev->nr_direct_mw + sndev->nr_rsvd_luts; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int peer_lut_index(struct switchtec_ntb *sndev, int mw_idx) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci return mw_idx - sndev->peer_nr_direct_mw + sndev->nr_rsvd_luts; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, 19262306a36Sopenharmony_ci int widx, resource_size_t *addr_align, 19362306a36Sopenharmony_ci resource_size_t *size_align, 19462306a36Sopenharmony_ci resource_size_t *size_max) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 19762306a36Sopenharmony_ci int lut; 19862306a36Sopenharmony_ci resource_size_t size; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 20162306a36Sopenharmony_ci return -EINVAL; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci lut = widx >= sndev->peer_nr_direct_mw; 20462306a36Sopenharmony_ci size = ioread64(&sndev->peer_shared->mw_sizes[widx]); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (size == 0) 20762306a36Sopenharmony_ci return -EINVAL; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (addr_align) 21062306a36Sopenharmony_ci *addr_align = lut ? size : SZ_4K; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (size_align) 21362306a36Sopenharmony_ci *size_align = lut ? size : SZ_4K; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (size_max) 21662306a36Sopenharmony_ci *size_max = size; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void switchtec_ntb_mw_clr_direct(struct switchtec_ntb *sndev, int idx) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 22462306a36Sopenharmony_ci int bar = sndev->peer_direct_mw_to_bar[idx]; 22562306a36Sopenharmony_ci u32 ctl_val; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci ctl_val = ioread32(&ctl->bar_entry[bar].ctl); 22862306a36Sopenharmony_ci ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN; 22962306a36Sopenharmony_ci iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); 23062306a36Sopenharmony_ci iowrite32(0, &ctl->bar_entry[bar].win_size); 23162306a36Sopenharmony_ci iowrite32(0, &ctl->bar_ext_entry[bar].win_size); 23262306a36Sopenharmony_ci iowrite64(sndev->self_partition, &ctl->bar_entry[bar].xlate_addr); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic void switchtec_ntb_mw_clr_lut(struct switchtec_ntb *sndev, int idx) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci iowrite64(0, &ctl->lut_entry[peer_lut_index(sndev, idx)]); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic void switchtec_ntb_mw_set_direct(struct switchtec_ntb *sndev, int idx, 24362306a36Sopenharmony_ci dma_addr_t addr, resource_size_t size) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci int xlate_pos = ilog2(size); 24662306a36Sopenharmony_ci int bar = sndev->peer_direct_mw_to_bar[idx]; 24762306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 24862306a36Sopenharmony_ci u32 ctl_val; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci ctl_val = ioread32(&ctl->bar_entry[bar].ctl); 25162306a36Sopenharmony_ci ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); 25462306a36Sopenharmony_ci iowrite32(xlate_pos | (lower_32_bits(size) & 0xFFFFF000), 25562306a36Sopenharmony_ci &ctl->bar_entry[bar].win_size); 25662306a36Sopenharmony_ci iowrite32(upper_32_bits(size), &ctl->bar_ext_entry[bar].win_size); 25762306a36Sopenharmony_ci iowrite64(sndev->self_partition | addr, 25862306a36Sopenharmony_ci &ctl->bar_entry[bar].xlate_addr); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic void switchtec_ntb_mw_set_lut(struct switchtec_ntb *sndev, int idx, 26262306a36Sopenharmony_ci dma_addr_t addr, resource_size_t size) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | addr), 26762306a36Sopenharmony_ci &ctl->lut_entry[peer_lut_index(sndev, idx)]); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, 27162306a36Sopenharmony_ci dma_addr_t addr, resource_size_t size) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 27462306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 27562306a36Sopenharmony_ci int xlate_pos = ilog2(size); 27662306a36Sopenharmony_ci int nr_direct_mw = sndev->peer_nr_direct_mw; 27762306a36Sopenharmony_ci int rc; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 28062306a36Sopenharmony_ci return -EINVAL; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "MW %d: part %d addr %pad size %pap\n", 28362306a36Sopenharmony_ci widx, pidx, &addr, &size); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (widx >= switchtec_ntb_mw_count(ntb, pidx)) 28662306a36Sopenharmony_ci return -EINVAL; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (size != 0 && xlate_pos < 12) 28962306a36Sopenharmony_ci return -EINVAL; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (!IS_ALIGNED(addr, BIT_ULL(xlate_pos))) { 29262306a36Sopenharmony_ci /* 29362306a36Sopenharmony_ci * In certain circumstances we can get a buffer that is 29462306a36Sopenharmony_ci * not aligned to its size. (Most of the time 29562306a36Sopenharmony_ci * dma_alloc_coherent ensures this). This can happen when 29662306a36Sopenharmony_ci * using large buffers allocated by the CMA 29762306a36Sopenharmony_ci * (see CMA_CONFIG_ALIGNMENT) 29862306a36Sopenharmony_ci */ 29962306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 30062306a36Sopenharmony_ci "ERROR: Memory window address is not aligned to its size!\n"); 30162306a36Sopenharmony_ci return -EINVAL; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, 30562306a36Sopenharmony_ci NTB_CTRL_PART_STATUS_LOCKED); 30662306a36Sopenharmony_ci if (rc) 30762306a36Sopenharmony_ci return rc; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (size == 0) { 31062306a36Sopenharmony_ci if (widx < nr_direct_mw) 31162306a36Sopenharmony_ci switchtec_ntb_mw_clr_direct(sndev, widx); 31262306a36Sopenharmony_ci else 31362306a36Sopenharmony_ci switchtec_ntb_mw_clr_lut(sndev, widx); 31462306a36Sopenharmony_ci } else { 31562306a36Sopenharmony_ci if (widx < nr_direct_mw) 31662306a36Sopenharmony_ci switchtec_ntb_mw_set_direct(sndev, widx, addr, size); 31762306a36Sopenharmony_ci else 31862306a36Sopenharmony_ci switchtec_ntb_mw_set_lut(sndev, widx, addr, size); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 32262306a36Sopenharmony_ci NTB_CTRL_PART_STATUS_NORMAL); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (rc == -EIO) { 32562306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 32662306a36Sopenharmony_ci "Hardware reported an error configuring mw %d: %08x\n", 32762306a36Sopenharmony_ci widx, ioread32(&ctl->bar_error)); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (widx < nr_direct_mw) 33062306a36Sopenharmony_ci switchtec_ntb_mw_clr_direct(sndev, widx); 33162306a36Sopenharmony_ci else 33262306a36Sopenharmony_ci switchtec_ntb_mw_clr_lut(sndev, widx); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 33562306a36Sopenharmony_ci NTB_CTRL_PART_STATUS_NORMAL); 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return rc; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 34462306a36Sopenharmony_ci int nr_lut_mw = sndev->nr_lut_mw - sndev->nr_rsvd_luts; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return sndev->nr_direct_mw + (use_lut_mws ? nr_lut_mw : 0); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int switchtec_ntb_direct_get_addr(struct switchtec_ntb *sndev, 35062306a36Sopenharmony_ci int idx, phys_addr_t *base, 35162306a36Sopenharmony_ci resource_size_t *size) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci int bar = sndev->direct_mw_to_bar[idx]; 35462306a36Sopenharmony_ci size_t offset = 0; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (bar < 0) 35762306a36Sopenharmony_ci return -EINVAL; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (idx == 0) { 36062306a36Sopenharmony_ci /* 36162306a36Sopenharmony_ci * This is the direct BAR shared with the LUTs 36262306a36Sopenharmony_ci * which means the actual window will be offset 36362306a36Sopenharmony_ci * by the size of all the LUT entries. 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci offset = LUT_SIZE * sndev->nr_lut_mw; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (base) 37062306a36Sopenharmony_ci *base = pci_resource_start(sndev->ntb.pdev, bar) + offset; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (size) { 37362306a36Sopenharmony_ci *size = pci_resource_len(sndev->ntb.pdev, bar) - offset; 37462306a36Sopenharmony_ci if (offset && *size > offset) 37562306a36Sopenharmony_ci *size = offset; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (*size > max_mw_size) 37862306a36Sopenharmony_ci *size = max_mw_size; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return 0; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int switchtec_ntb_lut_get_addr(struct switchtec_ntb *sndev, 38562306a36Sopenharmony_ci int idx, phys_addr_t *base, 38662306a36Sopenharmony_ci resource_size_t *size) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci int bar = sndev->direct_mw_to_bar[0]; 38962306a36Sopenharmony_ci int offset; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci offset = LUT_SIZE * lut_index(sndev, idx); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (base) 39462306a36Sopenharmony_ci *base = pci_resource_start(sndev->ntb.pdev, bar) + offset; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (size) 39762306a36Sopenharmony_ci *size = LUT_SIZE; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic int switchtec_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx, 40362306a36Sopenharmony_ci phys_addr_t *base, 40462306a36Sopenharmony_ci resource_size_t *size) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (idx < sndev->nr_direct_mw) 40962306a36Sopenharmony_ci return switchtec_ntb_direct_get_addr(sndev, idx, base, size); 41062306a36Sopenharmony_ci else if (idx < switchtec_ntb_peer_mw_count(ntb)) 41162306a36Sopenharmony_ci return switchtec_ntb_lut_get_addr(sndev, idx, base, size); 41262306a36Sopenharmony_ci else 41362306a36Sopenharmony_ci return -EINVAL; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev, 41762306a36Sopenharmony_ci int partition, 41862306a36Sopenharmony_ci enum ntb_speed *speed, 41962306a36Sopenharmony_ci enum ntb_width *width) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct switchtec_dev *stdev = sndev->stdev; 42262306a36Sopenharmony_ci struct part_cfg_regs __iomem *part_cfg = 42362306a36Sopenharmony_ci &stdev->mmio_part_cfg_all[partition]; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci u32 pff = ioread32(&part_cfg->vep_pff_inst_id) & 0xFF; 42662306a36Sopenharmony_ci u32 linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (speed) 42962306a36Sopenharmony_ci *speed = (linksta >> 16) & 0xF; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (width) 43262306a36Sopenharmony_ci *width = (linksta >> 20) & 0x3F; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci enum ntb_speed self_speed, peer_speed; 43862306a36Sopenharmony_ci enum ntb_width self_width, peer_width; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (!sndev->link_is_up) { 44162306a36Sopenharmony_ci sndev->link_speed = NTB_SPEED_NONE; 44262306a36Sopenharmony_ci sndev->link_width = NTB_WIDTH_NONE; 44362306a36Sopenharmony_ci return; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci switchtec_ntb_part_link_speed(sndev, sndev->self_partition, 44762306a36Sopenharmony_ci &self_speed, &self_width); 44862306a36Sopenharmony_ci switchtec_ntb_part_link_speed(sndev, sndev->peer_partition, 44962306a36Sopenharmony_ci &peer_speed, &peer_width); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci sndev->link_speed = min(self_speed, peer_speed); 45262306a36Sopenharmony_ci sndev->link_width = min(self_width, peer_width); 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic int crosslink_is_enabled(struct switchtec_ntb *sndev) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct ntb_info_regs __iomem *inf = sndev->mmio_ntb; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return ioread8(&inf->ntp_info[sndev->peer_partition].xlink_enabled); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic void crosslink_init_dbmsgs(struct switchtec_ntb *sndev) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci int i; 46562306a36Sopenharmony_ci u32 msg_map = 0; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (!crosslink_is_enabled(sndev)) 46862306a36Sopenharmony_ci return; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sndev->mmio_peer_dbmsg->imsg); i++) { 47162306a36Sopenharmony_ci int m = i | sndev->self_partition << 2; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci msg_map |= m << i * 8; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci iowrite32(msg_map, &sndev->mmio_peer_dbmsg->msg_map); 47762306a36Sopenharmony_ci iowrite64(sndev->db_valid_mask << sndev->db_peer_shift, 47862306a36Sopenharmony_ci &sndev->mmio_peer_dbmsg->odb_mask); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cienum switchtec_msg { 48262306a36Sopenharmony_ci LINK_MESSAGE = 0, 48362306a36Sopenharmony_ci MSG_LINK_UP = 1, 48462306a36Sopenharmony_ci MSG_LINK_DOWN = 2, 48562306a36Sopenharmony_ci MSG_CHECK_LINK = 3, 48662306a36Sopenharmony_ci MSG_LINK_FORCE_DOWN = 4, 48762306a36Sopenharmony_ci}; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic void switchtec_ntb_link_status_update(struct switchtec_ntb *sndev) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci int link_sta; 49462306a36Sopenharmony_ci int old = sndev->link_is_up; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci link_sta = sndev->self_shared->link_sta; 49762306a36Sopenharmony_ci if (link_sta) { 49862306a36Sopenharmony_ci u64 peer = ioread64(&sndev->peer_shared->magic); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if ((peer & 0xFFFFFFFF) == SWITCHTEC_NTB_MAGIC) 50162306a36Sopenharmony_ci link_sta = peer >> 32; 50262306a36Sopenharmony_ci else 50362306a36Sopenharmony_ci link_sta = 0; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci sndev->link_is_up = link_sta; 50762306a36Sopenharmony_ci switchtec_ntb_set_link_speed(sndev); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (link_sta != old) { 51062306a36Sopenharmony_ci switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK); 51162306a36Sopenharmony_ci ntb_link_event(&sndev->ntb); 51262306a36Sopenharmony_ci dev_info(&sndev->stdev->dev, "ntb link %s\n", 51362306a36Sopenharmony_ci link_sta ? "up" : "down"); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (link_sta) 51662306a36Sopenharmony_ci crosslink_init_dbmsgs(sndev); 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic void check_link_status_work(struct work_struct *work) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct switchtec_ntb *sndev; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci sndev = container_of(work, struct switchtec_ntb, 52562306a36Sopenharmony_ci check_link_status_work); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (sndev->link_force_down) { 52862306a36Sopenharmony_ci sndev->link_force_down = false; 52962306a36Sopenharmony_ci switchtec_ntb_reinit_peer(sndev); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (sndev->link_is_up) { 53262306a36Sopenharmony_ci sndev->link_is_up = 0; 53362306a36Sopenharmony_ci ntb_link_event(&sndev->ntb); 53462306a36Sopenharmony_ci dev_info(&sndev->stdev->dev, "ntb link forced down\n"); 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci switchtec_ntb_link_status_update(sndev); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic void switchtec_ntb_check_link(struct switchtec_ntb *sndev, 54462306a36Sopenharmony_ci enum switchtec_msg msg) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci if (msg == MSG_LINK_FORCE_DOWN) 54762306a36Sopenharmony_ci sndev->link_force_down = true; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci schedule_work(&sndev->check_link_status_work); 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic void switchtec_ntb_link_notification(struct switchtec_dev *stdev) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct switchtec_ntb *sndev = stdev->sndev; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci switchtec_ntb_check_link(sndev, MSG_CHECK_LINK); 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb, 56062306a36Sopenharmony_ci enum ntb_speed *speed, 56162306a36Sopenharmony_ci enum ntb_width *width) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (speed) 56662306a36Sopenharmony_ci *speed = sndev->link_speed; 56762306a36Sopenharmony_ci if (width) 56862306a36Sopenharmony_ci *width = sndev->link_width; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci return sndev->link_is_up; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int switchtec_ntb_link_enable(struct ntb_dev *ntb, 57462306a36Sopenharmony_ci enum ntb_speed max_speed, 57562306a36Sopenharmony_ci enum ntb_width max_width) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "enabling link\n"); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci sndev->self_shared->link_sta = 1; 58262306a36Sopenharmony_ci switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci switchtec_ntb_link_status_update(sndev); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci return 0; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic int switchtec_ntb_link_disable(struct ntb_dev *ntb) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "disabling link\n"); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci sndev->self_shared->link_sta = 0; 59662306a36Sopenharmony_ci switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_DOWN); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci switchtec_ntb_link_status_update(sndev); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci return 0; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic u64 switchtec_ntb_db_valid_mask(struct ntb_dev *ntb) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return sndev->db_valid_mask; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic int switchtec_ntb_db_vector_count(struct ntb_dev *ntb) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci return 1; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic u64 switchtec_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (db_vector < 0 || db_vector > 1) 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return sndev->db_valid_mask; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic u64 switchtec_ntb_db_read(struct ntb_dev *ntb) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci u64 ret; 62862306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci ret = ioread64(&sndev->mmio_self_dbmsg->idb) >> sndev->db_shift; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci return ret & sndev->db_valid_mask; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic int switchtec_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci iowrite64(db_bits << sndev->db_shift, &sndev->mmio_self_dbmsg->idb); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int switchtec_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci unsigned long irqflags; 64762306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (db_bits & ~sndev->db_valid_mask) 65062306a36Sopenharmony_ci return -EINVAL; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci spin_lock_irqsave(&sndev->db_mask_lock, irqflags); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci sndev->db_mask |= db_bits << sndev->db_shift; 65562306a36Sopenharmony_ci iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci return 0; 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cistatic int switchtec_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci unsigned long irqflags; 66562306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (db_bits & ~sndev->db_valid_mask) 66862306a36Sopenharmony_ci return -EINVAL; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci spin_lock_irqsave(&sndev->db_mask_lock, irqflags); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci sndev->db_mask &= ~(db_bits << sndev->db_shift); 67362306a36Sopenharmony_ci iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic u64 switchtec_ntb_db_read_mask(struct ntb_dev *ntb) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci return (sndev->db_mask >> sndev->db_shift) & sndev->db_valid_mask; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic int switchtec_ntb_peer_db_addr(struct ntb_dev *ntb, 68862306a36Sopenharmony_ci phys_addr_t *db_addr, 68962306a36Sopenharmony_ci resource_size_t *db_size, 69062306a36Sopenharmony_ci u64 *db_data, 69162306a36Sopenharmony_ci int db_bit) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 69462306a36Sopenharmony_ci unsigned long offset; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (unlikely(db_bit >= BITS_PER_LONG_LONG)) 69762306a36Sopenharmony_ci return -EINVAL; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci offset = (unsigned long)sndev->mmio_peer_dbmsg->odb - 70062306a36Sopenharmony_ci (unsigned long)sndev->stdev->mmio; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci offset += sndev->db_shift / 8; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (db_addr) 70562306a36Sopenharmony_ci *db_addr = pci_resource_start(ntb->pdev, 0) + offset; 70662306a36Sopenharmony_ci if (db_size) 70762306a36Sopenharmony_ci *db_size = sizeof(u32); 70862306a36Sopenharmony_ci if (db_data) 70962306a36Sopenharmony_ci *db_data = BIT_ULL(db_bit) << sndev->db_peer_shift; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci return 0; 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic int switchtec_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci iowrite64(db_bits << sndev->db_peer_shift, 71962306a36Sopenharmony_ci &sndev->mmio_peer_dbmsg->odb); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return 0; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int switchtec_ntb_spad_count(struct ntb_dev *ntb) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return ARRAY_SIZE(sndev->self_shared->spad); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic u32 switchtec_ntb_spad_read(struct ntb_dev *ntb, int idx) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad)) 73662306a36Sopenharmony_ci return 0; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (!sndev->self_shared) 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci return sndev->self_shared->spad[idx]; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic int switchtec_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad)) 74962306a36Sopenharmony_ci return -EINVAL; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (!sndev->self_shared) 75262306a36Sopenharmony_ci return -EIO; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci sndev->self_shared->spad[idx] = val; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci return 0; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic u32 switchtec_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, 76062306a36Sopenharmony_ci int sidx) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 76562306a36Sopenharmony_ci return -EINVAL; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad)) 76862306a36Sopenharmony_ci return 0; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (!sndev->peer_shared) 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return ioread32(&sndev->peer_shared->spad[sidx]); 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic int switchtec_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, 77762306a36Sopenharmony_ci int sidx, u32 val) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 78262306a36Sopenharmony_ci return -EINVAL; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad)) 78562306a36Sopenharmony_ci return -EINVAL; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (!sndev->peer_shared) 78862306a36Sopenharmony_ci return -EIO; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci iowrite32(val, &sndev->peer_shared->spad[sidx]); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci return 0; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic int switchtec_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, 79662306a36Sopenharmony_ci int sidx, phys_addr_t *spad_addr) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct switchtec_ntb *sndev = ntb_sndev(ntb); 79962306a36Sopenharmony_ci unsigned long offset; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 80262306a36Sopenharmony_ci return -EINVAL; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci offset = (unsigned long)&sndev->peer_shared->spad[sidx] - 80562306a36Sopenharmony_ci (unsigned long)sndev->stdev->mmio; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci if (spad_addr) 80862306a36Sopenharmony_ci *spad_addr = pci_resource_start(ntb->pdev, 0) + offset; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci return 0; 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic const struct ntb_dev_ops switchtec_ntb_ops = { 81462306a36Sopenharmony_ci .mw_count = switchtec_ntb_mw_count, 81562306a36Sopenharmony_ci .mw_get_align = switchtec_ntb_mw_get_align, 81662306a36Sopenharmony_ci .mw_set_trans = switchtec_ntb_mw_set_trans, 81762306a36Sopenharmony_ci .peer_mw_count = switchtec_ntb_peer_mw_count, 81862306a36Sopenharmony_ci .peer_mw_get_addr = switchtec_ntb_peer_mw_get_addr, 81962306a36Sopenharmony_ci .link_is_up = switchtec_ntb_link_is_up, 82062306a36Sopenharmony_ci .link_enable = switchtec_ntb_link_enable, 82162306a36Sopenharmony_ci .link_disable = switchtec_ntb_link_disable, 82262306a36Sopenharmony_ci .db_valid_mask = switchtec_ntb_db_valid_mask, 82362306a36Sopenharmony_ci .db_vector_count = switchtec_ntb_db_vector_count, 82462306a36Sopenharmony_ci .db_vector_mask = switchtec_ntb_db_vector_mask, 82562306a36Sopenharmony_ci .db_read = switchtec_ntb_db_read, 82662306a36Sopenharmony_ci .db_clear = switchtec_ntb_db_clear, 82762306a36Sopenharmony_ci .db_set_mask = switchtec_ntb_db_set_mask, 82862306a36Sopenharmony_ci .db_clear_mask = switchtec_ntb_db_clear_mask, 82962306a36Sopenharmony_ci .db_read_mask = switchtec_ntb_db_read_mask, 83062306a36Sopenharmony_ci .peer_db_addr = switchtec_ntb_peer_db_addr, 83162306a36Sopenharmony_ci .peer_db_set = switchtec_ntb_peer_db_set, 83262306a36Sopenharmony_ci .spad_count = switchtec_ntb_spad_count, 83362306a36Sopenharmony_ci .spad_read = switchtec_ntb_spad_read, 83462306a36Sopenharmony_ci .spad_write = switchtec_ntb_spad_write, 83562306a36Sopenharmony_ci .peer_spad_read = switchtec_ntb_peer_spad_read, 83662306a36Sopenharmony_ci .peer_spad_write = switchtec_ntb_peer_spad_write, 83762306a36Sopenharmony_ci .peer_spad_addr = switchtec_ntb_peer_spad_addr, 83862306a36Sopenharmony_ci}; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic int switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci u64 tpart_vec; 84362306a36Sopenharmony_ci int self; 84462306a36Sopenharmony_ci u64 part_map; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci sndev->ntb.pdev = sndev->stdev->pdev; 84762306a36Sopenharmony_ci sndev->ntb.topo = NTB_TOPO_SWITCH; 84862306a36Sopenharmony_ci sndev->ntb.ops = &switchtec_ntb_ops; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci INIT_WORK(&sndev->check_link_status_work, check_link_status_work); 85162306a36Sopenharmony_ci sndev->link_force_down = false; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci sndev->self_partition = sndev->stdev->partition; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci sndev->mmio_ntb = sndev->stdev->mmio_ntb; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci self = sndev->self_partition; 85862306a36Sopenharmony_ci tpart_vec = ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_high); 85962306a36Sopenharmony_ci tpart_vec <<= 32; 86062306a36Sopenharmony_ci tpart_vec |= ioread32(&sndev->mmio_ntb->ntp_info[self].target_part_low); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci part_map = ioread64(&sndev->mmio_ntb->ep_map); 86362306a36Sopenharmony_ci tpart_vec &= part_map; 86462306a36Sopenharmony_ci part_map &= ~(1 << sndev->self_partition); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (!tpart_vec) { 86762306a36Sopenharmony_ci if (sndev->stdev->partition_count != 2) { 86862306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 86962306a36Sopenharmony_ci "ntb target partition not defined\n"); 87062306a36Sopenharmony_ci return -ENODEV; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (!part_map) { 87462306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 87562306a36Sopenharmony_ci "peer partition is not NT partition\n"); 87662306a36Sopenharmony_ci return -ENODEV; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci sndev->peer_partition = __ffs64(part_map); 88062306a36Sopenharmony_ci } else { 88162306a36Sopenharmony_ci if (__ffs64(tpart_vec) != (fls64(tpart_vec) - 1)) { 88262306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 88362306a36Sopenharmony_ci "ntb driver only supports 1 pair of 1-1 ntb mapping\n"); 88462306a36Sopenharmony_ci return -ENODEV; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci sndev->peer_partition = __ffs64(tpart_vec); 88862306a36Sopenharmony_ci if (!(part_map & (1ULL << sndev->peer_partition))) { 88962306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 89062306a36Sopenharmony_ci "ntb target partition is not NT partition\n"); 89162306a36Sopenharmony_ci return -ENODEV; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d\n", 89662306a36Sopenharmony_ci sndev->self_partition, sndev->stdev->partition_count); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb + 89962306a36Sopenharmony_ci SWITCHTEC_NTB_REG_CTRL_OFFSET; 90062306a36Sopenharmony_ci sndev->mmio_dbmsg = (void * __iomem)sndev->mmio_ntb + 90162306a36Sopenharmony_ci SWITCHTEC_NTB_REG_DBMSG_OFFSET; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition]; 90462306a36Sopenharmony_ci sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition]; 90562306a36Sopenharmony_ci sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition]; 90662306a36Sopenharmony_ci sndev->mmio_peer_dbmsg = sndev->mmio_self_dbmsg; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci return 0; 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic int config_rsvd_lut_win(struct switchtec_ntb *sndev, 91262306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl, 91362306a36Sopenharmony_ci int lut_idx, int partition, u64 addr) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci int peer_bar = sndev->peer_direct_mw_to_bar[0]; 91662306a36Sopenharmony_ci u32 ctl_val; 91762306a36Sopenharmony_ci int rc; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, 92062306a36Sopenharmony_ci NTB_CTRL_PART_STATUS_LOCKED); 92162306a36Sopenharmony_ci if (rc) 92262306a36Sopenharmony_ci return rc; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ctl_val = ioread32(&ctl->bar_entry[peer_bar].ctl); 92562306a36Sopenharmony_ci ctl_val &= 0xFF; 92662306a36Sopenharmony_ci ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN; 92762306a36Sopenharmony_ci ctl_val |= ilog2(LUT_SIZE) << 8; 92862306a36Sopenharmony_ci ctl_val |= (sndev->nr_lut_mw - 1) << 14; 92962306a36Sopenharmony_ci iowrite32(ctl_val, &ctl->bar_entry[peer_bar].ctl); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci iowrite64((NTB_CTRL_LUT_EN | (partition << 1) | addr), 93262306a36Sopenharmony_ci &ctl->lut_entry[lut_idx]); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 93562306a36Sopenharmony_ci NTB_CTRL_PART_STATUS_NORMAL); 93662306a36Sopenharmony_ci if (rc) { 93762306a36Sopenharmony_ci u32 bar_error, lut_error; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci bar_error = ioread32(&ctl->bar_error); 94062306a36Sopenharmony_ci lut_error = ioread32(&ctl->lut_error); 94162306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 94262306a36Sopenharmony_ci "Error setting up reserved lut window: %08x / %08x\n", 94362306a36Sopenharmony_ci bar_error, lut_error); 94462306a36Sopenharmony_ci return rc; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci return 0; 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic int config_req_id_table(struct switchtec_ntb *sndev, 95162306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *mmio_ctrl, 95262306a36Sopenharmony_ci int *req_ids, int count) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci int i, rc = 0; 95562306a36Sopenharmony_ci u32 error; 95662306a36Sopenharmony_ci u32 proxy_id; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (ioread16(&mmio_ctrl->req_id_table_size) < count) { 95962306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 96062306a36Sopenharmony_ci "Not enough requester IDs available.\n"); 96162306a36Sopenharmony_ci return -EFAULT; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, mmio_ctrl, 96562306a36Sopenharmony_ci NTB_CTRL_PART_OP_LOCK, 96662306a36Sopenharmony_ci NTB_CTRL_PART_STATUS_LOCKED); 96762306a36Sopenharmony_ci if (rc) 96862306a36Sopenharmony_ci return rc; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci for (i = 0; i < count; i++) { 97162306a36Sopenharmony_ci iowrite32(req_ids[i] << 16 | NTB_CTRL_REQ_ID_EN, 97262306a36Sopenharmony_ci &mmio_ctrl->req_id_table[i]); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci proxy_id = ioread32(&mmio_ctrl->req_id_table[i]); 97562306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, 97662306a36Sopenharmony_ci "Requester ID %02X:%02X.%X -> BB:%02X.%X\n", 97762306a36Sopenharmony_ci req_ids[i] >> 8, (req_ids[i] >> 3) & 0x1F, 97862306a36Sopenharmony_ci req_ids[i] & 0x7, (proxy_id >> 4) & 0x1F, 97962306a36Sopenharmony_ci (proxy_id >> 1) & 0x7); 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, mmio_ctrl, 98362306a36Sopenharmony_ci NTB_CTRL_PART_OP_CFG, 98462306a36Sopenharmony_ci NTB_CTRL_PART_STATUS_NORMAL); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (rc == -EIO) { 98762306a36Sopenharmony_ci error = ioread32(&mmio_ctrl->req_id_error); 98862306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 98962306a36Sopenharmony_ci "Error setting up the requester ID table: %08x\n", 99062306a36Sopenharmony_ci error); 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci return 0; 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic int crosslink_setup_mws(struct switchtec_ntb *sndev, int ntb_lut_idx, 99762306a36Sopenharmony_ci u64 *mw_addrs, int mw_count) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci int rc, i; 100062306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_self_ctrl; 100162306a36Sopenharmony_ci u64 addr; 100262306a36Sopenharmony_ci size_t size, offset; 100362306a36Sopenharmony_ci int bar; 100462306a36Sopenharmony_ci int xlate_pos; 100562306a36Sopenharmony_ci u32 ctl_val; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, 100862306a36Sopenharmony_ci NTB_CTRL_PART_STATUS_LOCKED); 100962306a36Sopenharmony_ci if (rc) 101062306a36Sopenharmony_ci return rc; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci for (i = 0; i < sndev->nr_lut_mw; i++) { 101362306a36Sopenharmony_ci if (i == ntb_lut_idx) 101462306a36Sopenharmony_ci continue; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci addr = mw_addrs[0] + LUT_SIZE * i; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci iowrite64((NTB_CTRL_LUT_EN | (sndev->peer_partition << 1) | 101962306a36Sopenharmony_ci addr), 102062306a36Sopenharmony_ci &ctl->lut_entry[i]); 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci sndev->nr_direct_mw = min_t(int, sndev->nr_direct_mw, mw_count); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci for (i = 0; i < sndev->nr_direct_mw; i++) { 102662306a36Sopenharmony_ci bar = sndev->direct_mw_to_bar[i]; 102762306a36Sopenharmony_ci offset = (i == 0) ? LUT_SIZE * sndev->nr_lut_mw : 0; 102862306a36Sopenharmony_ci addr = mw_addrs[i] + offset; 102962306a36Sopenharmony_ci size = pci_resource_len(sndev->ntb.pdev, bar) - offset; 103062306a36Sopenharmony_ci xlate_pos = ilog2(size); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (offset && size > offset) 103362306a36Sopenharmony_ci size = offset; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci ctl_val = ioread32(&ctl->bar_entry[bar].ctl); 103662306a36Sopenharmony_ci ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); 103962306a36Sopenharmony_ci iowrite32(xlate_pos | (lower_32_bits(size) & 0xFFFFF000), 104062306a36Sopenharmony_ci &ctl->bar_entry[bar].win_size); 104162306a36Sopenharmony_ci iowrite32(upper_32_bits(size), &ctl->bar_ext_entry[bar].win_size); 104262306a36Sopenharmony_ci iowrite64(sndev->peer_partition | addr, 104362306a36Sopenharmony_ci &ctl->bar_entry[bar].xlate_addr); 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 104762306a36Sopenharmony_ci NTB_CTRL_PART_STATUS_NORMAL); 104862306a36Sopenharmony_ci if (rc) { 104962306a36Sopenharmony_ci u32 bar_error, lut_error; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci bar_error = ioread32(&ctl->bar_error); 105262306a36Sopenharmony_ci lut_error = ioread32(&ctl->lut_error); 105362306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 105462306a36Sopenharmony_ci "Error setting up cross link windows: %08x / %08x\n", 105562306a36Sopenharmony_ci bar_error, lut_error); 105662306a36Sopenharmony_ci return rc; 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci return 0; 106062306a36Sopenharmony_ci} 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cistatic int crosslink_setup_req_ids(struct switchtec_ntb *sndev, 106362306a36Sopenharmony_ci struct ntb_ctrl_regs __iomem *mmio_ctrl) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci int req_ids[16]; 106662306a36Sopenharmony_ci int i; 106762306a36Sopenharmony_ci u32 proxy_id; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(req_ids); i++) { 107062306a36Sopenharmony_ci proxy_id = ioread32(&sndev->mmio_self_ctrl->req_id_table[i]); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (!(proxy_id & NTB_CTRL_REQ_ID_EN)) 107362306a36Sopenharmony_ci break; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci req_ids[i] = ((proxy_id >> 1) & 0xFF); 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci return config_req_id_table(sndev, mmio_ctrl, req_ids, i); 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci/* 108262306a36Sopenharmony_ci * In crosslink configuration there is a virtual partition in the 108362306a36Sopenharmony_ci * middle of the two switches. The BARs in this partition have to be 108462306a36Sopenharmony_ci * enumerated and assigned addresses. 108562306a36Sopenharmony_ci */ 108662306a36Sopenharmony_cistatic int crosslink_enum_partition(struct switchtec_ntb *sndev, 108762306a36Sopenharmony_ci u64 *bar_addrs) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci struct part_cfg_regs __iomem *part_cfg = 109062306a36Sopenharmony_ci &sndev->stdev->mmio_part_cfg_all[sndev->peer_partition]; 109162306a36Sopenharmony_ci u32 pff = ioread32(&part_cfg->vep_pff_inst_id) & 0xFF; 109262306a36Sopenharmony_ci struct pff_csr_regs __iomem *mmio_pff = 109362306a36Sopenharmony_ci &sndev->stdev->mmio_pff_csr[pff]; 109462306a36Sopenharmony_ci const u64 bar_space = 0x1000000000LL; 109562306a36Sopenharmony_ci u64 bar_addr; 109662306a36Sopenharmony_ci int bar_cnt = 0; 109762306a36Sopenharmony_ci int i; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci iowrite16(0x6, &mmio_pff->pcicmd); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mmio_pff->pci_bar64); i++) { 110262306a36Sopenharmony_ci iowrite64(bar_space * i, &mmio_pff->pci_bar64[i]); 110362306a36Sopenharmony_ci bar_addr = ioread64(&mmio_pff->pci_bar64[i]); 110462306a36Sopenharmony_ci bar_addr &= ~0xf; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, 110762306a36Sopenharmony_ci "Crosslink BAR%d addr: %llx\n", 110862306a36Sopenharmony_ci i*2, bar_addr); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (bar_addr != bar_space * i) 111162306a36Sopenharmony_ci continue; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci bar_addrs[bar_cnt++] = bar_addr; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci return bar_cnt; 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_cistatic int switchtec_ntb_init_crosslink(struct switchtec_ntb *sndev) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci int rc; 112262306a36Sopenharmony_ci int bar = sndev->direct_mw_to_bar[0]; 112362306a36Sopenharmony_ci const int ntb_lut_idx = 1; 112462306a36Sopenharmony_ci u64 bar_addrs[6]; 112562306a36Sopenharmony_ci u64 addr; 112662306a36Sopenharmony_ci int offset; 112762306a36Sopenharmony_ci int bar_cnt; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci if (!crosslink_is_enabled(sndev)) 113062306a36Sopenharmony_ci return 0; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci dev_info(&sndev->stdev->dev, "Using crosslink configuration\n"); 113362306a36Sopenharmony_ci sndev->ntb.topo = NTB_TOPO_CROSSLINK; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci bar_cnt = crosslink_enum_partition(sndev, bar_addrs); 113662306a36Sopenharmony_ci if (bar_cnt < sndev->nr_direct_mw + 1) { 113762306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 113862306a36Sopenharmony_ci "Error enumerating crosslink partition\n"); 113962306a36Sopenharmony_ci return -EINVAL; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci addr = (bar_addrs[0] + SWITCHTEC_GAS_NTB_OFFSET + 114362306a36Sopenharmony_ci SWITCHTEC_NTB_REG_DBMSG_OFFSET + 114462306a36Sopenharmony_ci sizeof(struct ntb_dbmsg_regs) * sndev->peer_partition); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci offset = addr & (LUT_SIZE - 1); 114762306a36Sopenharmony_ci addr -= offset; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci rc = config_rsvd_lut_win(sndev, sndev->mmio_self_ctrl, ntb_lut_idx, 115062306a36Sopenharmony_ci sndev->peer_partition, addr); 115162306a36Sopenharmony_ci if (rc) 115262306a36Sopenharmony_ci return rc; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci rc = crosslink_setup_mws(sndev, ntb_lut_idx, &bar_addrs[1], 115562306a36Sopenharmony_ci bar_cnt - 1); 115662306a36Sopenharmony_ci if (rc) 115762306a36Sopenharmony_ci return rc; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci rc = crosslink_setup_req_ids(sndev, sndev->mmio_peer_ctrl); 116062306a36Sopenharmony_ci if (rc) 116162306a36Sopenharmony_ci return rc; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci sndev->mmio_xlink_win = pci_iomap_range(sndev->stdev->pdev, bar, 116462306a36Sopenharmony_ci LUT_SIZE, LUT_SIZE); 116562306a36Sopenharmony_ci if (!sndev->mmio_xlink_win) { 116662306a36Sopenharmony_ci rc = -ENOMEM; 116762306a36Sopenharmony_ci return rc; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci sndev->mmio_peer_dbmsg = sndev->mmio_xlink_win + offset; 117162306a36Sopenharmony_ci sndev->nr_rsvd_luts++; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci crosslink_init_dbmsgs(sndev); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci return 0; 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic void switchtec_ntb_deinit_crosslink(struct switchtec_ntb *sndev) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci if (sndev->mmio_xlink_win) 118162306a36Sopenharmony_ci pci_iounmap(sndev->stdev->pdev, sndev->mmio_xlink_win); 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci int i; 118762306a36Sopenharmony_ci int cnt = 0; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ctrl->bar_entry); i++) { 119062306a36Sopenharmony_ci u32 r = ioread32(&ctrl->bar_entry[i].ctl); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (r & NTB_CTRL_BAR_VALID) 119362306a36Sopenharmony_ci map[cnt++] = i; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci return cnt; 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic void switchtec_ntb_init_mw(struct switchtec_ntb *sndev) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci sndev->nr_direct_mw = map_bars(sndev->direct_mw_to_bar, 120262306a36Sopenharmony_ci sndev->mmio_self_ctrl); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries); 120562306a36Sopenharmony_ci sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut\n", 120862306a36Sopenharmony_ci sndev->nr_direct_mw, sndev->nr_lut_mw); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci sndev->peer_nr_direct_mw = map_bars(sndev->peer_direct_mw_to_bar, 121162306a36Sopenharmony_ci sndev->mmio_peer_ctrl); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci sndev->peer_nr_lut_mw = 121462306a36Sopenharmony_ci ioread16(&sndev->mmio_peer_ctrl->lut_table_entries); 121562306a36Sopenharmony_ci sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut\n", 121862306a36Sopenharmony_ci sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci} 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci/* 122362306a36Sopenharmony_ci * There are 64 doorbells in the switch hardware but this is 122462306a36Sopenharmony_ci * shared among all partitions. So we must split them in half 122562306a36Sopenharmony_ci * (32 for each partition). However, the message interrupts are 122662306a36Sopenharmony_ci * also shared with the top 4 doorbells so we just limit this to 122762306a36Sopenharmony_ci * 28 doorbells per partition. 122862306a36Sopenharmony_ci * 122962306a36Sopenharmony_ci * In crosslink mode, each side has it's own dbmsg register so 123062306a36Sopenharmony_ci * they can each use all 60 of the available doorbells. 123162306a36Sopenharmony_ci */ 123262306a36Sopenharmony_cistatic void switchtec_ntb_init_db(struct switchtec_ntb *sndev) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci sndev->db_mask = 0x0FFFFFFFFFFFFFFFULL; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci if (sndev->mmio_peer_dbmsg != sndev->mmio_self_dbmsg) { 123762306a36Sopenharmony_ci sndev->db_shift = 0; 123862306a36Sopenharmony_ci sndev->db_peer_shift = 0; 123962306a36Sopenharmony_ci sndev->db_valid_mask = sndev->db_mask; 124062306a36Sopenharmony_ci } else if (sndev->self_partition < sndev->peer_partition) { 124162306a36Sopenharmony_ci sndev->db_shift = 0; 124262306a36Sopenharmony_ci sndev->db_peer_shift = 32; 124362306a36Sopenharmony_ci sndev->db_valid_mask = 0x0FFFFFFF; 124462306a36Sopenharmony_ci } else { 124562306a36Sopenharmony_ci sndev->db_shift = 32; 124662306a36Sopenharmony_ci sndev->db_peer_shift = 0; 124762306a36Sopenharmony_ci sndev->db_valid_mask = 0x0FFFFFFF; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 125162306a36Sopenharmony_ci iowrite64(sndev->db_valid_mask << sndev->db_peer_shift, 125262306a36Sopenharmony_ci &sndev->mmio_peer_dbmsg->odb_mask); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "dbs: shift %d/%d, mask %016llx\n", 125562306a36Sopenharmony_ci sndev->db_shift, sndev->db_peer_shift, sndev->db_valid_mask); 125662306a36Sopenharmony_ci} 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_cistatic void switchtec_ntb_init_msgs(struct switchtec_ntb *sndev) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci int i; 126162306a36Sopenharmony_ci u32 msg_map = 0; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) { 126462306a36Sopenharmony_ci int m = i | sndev->peer_partition << 2; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci msg_map |= m << i * 8; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci iowrite32(msg_map, &sndev->mmio_self_dbmsg->msg_map); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) 127262306a36Sopenharmony_ci iowrite64(NTB_DBMSG_IMSG_STATUS | NTB_DBMSG_IMSG_MASK, 127362306a36Sopenharmony_ci &sndev->mmio_self_dbmsg->imsg[i]); 127462306a36Sopenharmony_ci} 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_cistatic int 127762306a36Sopenharmony_ciswitchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev) 127862306a36Sopenharmony_ci{ 127962306a36Sopenharmony_ci int req_ids[2]; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci /* 128262306a36Sopenharmony_ci * Root Complex Requester ID (which is 0:00.0) 128362306a36Sopenharmony_ci */ 128462306a36Sopenharmony_ci req_ids[0] = 0; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci /* 128762306a36Sopenharmony_ci * Host Bridge Requester ID (as read from the mmap address) 128862306a36Sopenharmony_ci */ 128962306a36Sopenharmony_ci req_ids[1] = ioread16(&sndev->mmio_ntb->requester_id); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci return config_req_id_table(sndev, sndev->mmio_self_ctrl, req_ids, 129262306a36Sopenharmony_ci ARRAY_SIZE(req_ids)); 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_cistatic void switchtec_ntb_init_shared(struct switchtec_ntb *sndev) 129662306a36Sopenharmony_ci{ 129762306a36Sopenharmony_ci int i; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci memset(sndev->self_shared, 0, LUT_SIZE); 130062306a36Sopenharmony_ci sndev->self_shared->magic = SWITCHTEC_NTB_MAGIC; 130162306a36Sopenharmony_ci sndev->self_shared->partition_id = sndev->stdev->partition; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci for (i = 0; i < sndev->nr_direct_mw; i++) { 130462306a36Sopenharmony_ci int bar = sndev->direct_mw_to_bar[i]; 130562306a36Sopenharmony_ci resource_size_t sz = pci_resource_len(sndev->stdev->pdev, bar); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (i == 0) 130862306a36Sopenharmony_ci sz = min_t(resource_size_t, sz, 130962306a36Sopenharmony_ci LUT_SIZE * sndev->nr_lut_mw); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci sndev->self_shared->mw_sizes[i] = sz; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci for (i = 0; i < sndev->nr_lut_mw; i++) { 131562306a36Sopenharmony_ci int idx = sndev->nr_direct_mw + i; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci sndev->self_shared->mw_sizes[idx] = LUT_SIZE; 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci} 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_cistatic int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) 132262306a36Sopenharmony_ci{ 132362306a36Sopenharmony_ci int self_bar = sndev->direct_mw_to_bar[0]; 132462306a36Sopenharmony_ci int rc; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci sndev->nr_rsvd_luts++; 132762306a36Sopenharmony_ci sndev->self_shared = dma_alloc_coherent(&sndev->stdev->pdev->dev, 132862306a36Sopenharmony_ci LUT_SIZE, 132962306a36Sopenharmony_ci &sndev->self_shared_dma, 133062306a36Sopenharmony_ci GFP_KERNEL); 133162306a36Sopenharmony_ci if (!sndev->self_shared) { 133262306a36Sopenharmony_ci dev_err(&sndev->stdev->dev, 133362306a36Sopenharmony_ci "unable to allocate memory for shared mw\n"); 133462306a36Sopenharmony_ci return -ENOMEM; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci switchtec_ntb_init_shared(sndev); 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0, 134062306a36Sopenharmony_ci sndev->self_partition, 134162306a36Sopenharmony_ci sndev->self_shared_dma); 134262306a36Sopenharmony_ci if (rc) 134362306a36Sopenharmony_ci goto unalloc_and_exit; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci sndev->peer_shared = pci_iomap(sndev->stdev->pdev, self_bar, LUT_SIZE); 134662306a36Sopenharmony_ci if (!sndev->peer_shared) { 134762306a36Sopenharmony_ci rc = -ENOMEM; 134862306a36Sopenharmony_ci goto unalloc_and_exit; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "Shared MW Ready\n"); 135262306a36Sopenharmony_ci return 0; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ciunalloc_and_exit: 135562306a36Sopenharmony_ci dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, 135662306a36Sopenharmony_ci sndev->self_shared, sndev->self_shared_dma); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci return rc; 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_cistatic void switchtec_ntb_deinit_shared_mw(struct switchtec_ntb *sndev) 136262306a36Sopenharmony_ci{ 136362306a36Sopenharmony_ci if (sndev->peer_shared) 136462306a36Sopenharmony_ci pci_iounmap(sndev->stdev->pdev, sndev->peer_shared); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if (sndev->self_shared) 136762306a36Sopenharmony_ci dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, 136862306a36Sopenharmony_ci sndev->self_shared, 136962306a36Sopenharmony_ci sndev->self_shared_dma); 137062306a36Sopenharmony_ci sndev->nr_rsvd_luts--; 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_cistatic irqreturn_t switchtec_ntb_doorbell_isr(int irq, void *dev) 137462306a36Sopenharmony_ci{ 137562306a36Sopenharmony_ci struct switchtec_ntb *sndev = dev; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "doorbell\n"); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci ntb_db_event(&sndev->ntb, 0); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci return IRQ_HANDLED; 138262306a36Sopenharmony_ci} 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_cistatic irqreturn_t switchtec_ntb_message_isr(int irq, void *dev) 138562306a36Sopenharmony_ci{ 138662306a36Sopenharmony_ci int i; 138762306a36Sopenharmony_ci struct switchtec_ntb *sndev = dev; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) { 139062306a36Sopenharmony_ci u64 msg = ioread64(&sndev->mmio_self_dbmsg->imsg[i]); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci if (msg & NTB_DBMSG_IMSG_STATUS) { 139362306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", 139462306a36Sopenharmony_ci i, (u32)msg); 139562306a36Sopenharmony_ci iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (i == LINK_MESSAGE) 139862306a36Sopenharmony_ci switchtec_ntb_check_link(sndev, msg); 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci return IRQ_HANDLED; 140362306a36Sopenharmony_ci} 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_cistatic int switchtec_ntb_init_db_msg_irq(struct switchtec_ntb *sndev) 140662306a36Sopenharmony_ci{ 140762306a36Sopenharmony_ci int i; 140862306a36Sopenharmony_ci int rc; 140962306a36Sopenharmony_ci int doorbell_irq = 0; 141062306a36Sopenharmony_ci int message_irq = 0; 141162306a36Sopenharmony_ci int event_irq; 141262306a36Sopenharmony_ci int idb_vecs = sizeof(sndev->mmio_self_dbmsg->idb_vec_map); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci event_irq = ioread32(&sndev->stdev->mmio_part_cfg->vep_vector_number); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci while (doorbell_irq == event_irq) 141762306a36Sopenharmony_ci doorbell_irq++; 141862306a36Sopenharmony_ci while (message_irq == doorbell_irq || 141962306a36Sopenharmony_ci message_irq == event_irq) 142062306a36Sopenharmony_ci message_irq++; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci dev_dbg(&sndev->stdev->dev, "irqs - event: %d, db: %d, msgs: %d\n", 142362306a36Sopenharmony_ci event_irq, doorbell_irq, message_irq); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci for (i = 0; i < idb_vecs - 4; i++) 142662306a36Sopenharmony_ci iowrite8(doorbell_irq, 142762306a36Sopenharmony_ci &sndev->mmio_self_dbmsg->idb_vec_map[i]); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci for (; i < idb_vecs; i++) 143062306a36Sopenharmony_ci iowrite8(message_irq, 143162306a36Sopenharmony_ci &sndev->mmio_self_dbmsg->idb_vec_map[i]); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci sndev->doorbell_irq = pci_irq_vector(sndev->stdev->pdev, doorbell_irq); 143462306a36Sopenharmony_ci sndev->message_irq = pci_irq_vector(sndev->stdev->pdev, message_irq); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci rc = request_irq(sndev->doorbell_irq, 143762306a36Sopenharmony_ci switchtec_ntb_doorbell_isr, 0, 143862306a36Sopenharmony_ci "switchtec_ntb_doorbell", sndev); 143962306a36Sopenharmony_ci if (rc) 144062306a36Sopenharmony_ci return rc; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci rc = request_irq(sndev->message_irq, 144362306a36Sopenharmony_ci switchtec_ntb_message_isr, 0, 144462306a36Sopenharmony_ci "switchtec_ntb_message", sndev); 144562306a36Sopenharmony_ci if (rc) { 144662306a36Sopenharmony_ci free_irq(sndev->doorbell_irq, sndev); 144762306a36Sopenharmony_ci return rc; 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci return 0; 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_cistatic void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev) 145462306a36Sopenharmony_ci{ 145562306a36Sopenharmony_ci free_irq(sndev->doorbell_irq, sndev); 145662306a36Sopenharmony_ci free_irq(sndev->message_irq, sndev); 145762306a36Sopenharmony_ci} 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_cistatic int switchtec_ntb_reinit_peer(struct switchtec_ntb *sndev) 146062306a36Sopenharmony_ci{ 146162306a36Sopenharmony_ci int rc; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci if (crosslink_is_enabled(sndev)) 146462306a36Sopenharmony_ci return 0; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci dev_info(&sndev->stdev->dev, "reinitialize shared memory window\n"); 146762306a36Sopenharmony_ci rc = config_rsvd_lut_win(sndev, sndev->mmio_peer_ctrl, 0, 146862306a36Sopenharmony_ci sndev->self_partition, 146962306a36Sopenharmony_ci sndev->self_shared_dma); 147062306a36Sopenharmony_ci return rc; 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_cistatic int switchtec_ntb_add(struct device *dev) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci struct switchtec_dev *stdev = to_stdev(dev); 147662306a36Sopenharmony_ci struct switchtec_ntb *sndev; 147762306a36Sopenharmony_ci int rc; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci stdev->sndev = NULL; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci if (stdev->pdev->class != (PCI_CLASS_BRIDGE_OTHER << 8)) 148262306a36Sopenharmony_ci return -ENODEV; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev)); 148562306a36Sopenharmony_ci if (!sndev) 148662306a36Sopenharmony_ci return -ENOMEM; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci sndev->stdev = stdev; 148962306a36Sopenharmony_ci rc = switchtec_ntb_init_sndev(sndev); 149062306a36Sopenharmony_ci if (rc) 149162306a36Sopenharmony_ci goto free_and_exit; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci switchtec_ntb_init_mw(sndev); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci rc = switchtec_ntb_init_req_id_table(sndev); 149662306a36Sopenharmony_ci if (rc) 149762306a36Sopenharmony_ci goto free_and_exit; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci rc = switchtec_ntb_init_crosslink(sndev); 150062306a36Sopenharmony_ci if (rc) 150162306a36Sopenharmony_ci goto free_and_exit; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci switchtec_ntb_init_db(sndev); 150462306a36Sopenharmony_ci switchtec_ntb_init_msgs(sndev); 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci rc = switchtec_ntb_init_shared_mw(sndev); 150762306a36Sopenharmony_ci if (rc) 150862306a36Sopenharmony_ci goto deinit_crosslink; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci rc = switchtec_ntb_init_db_msg_irq(sndev); 151162306a36Sopenharmony_ci if (rc) 151262306a36Sopenharmony_ci goto deinit_shared_and_exit; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci /* 151562306a36Sopenharmony_ci * If this host crashed, the other host may think the link is 151662306a36Sopenharmony_ci * still up. Tell them to force it down (it will go back up 151762306a36Sopenharmony_ci * once we register the ntb device). 151862306a36Sopenharmony_ci */ 151962306a36Sopenharmony_ci switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_FORCE_DOWN); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci rc = ntb_register_device(&sndev->ntb); 152262306a36Sopenharmony_ci if (rc) 152362306a36Sopenharmony_ci goto deinit_and_exit; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci stdev->sndev = sndev; 152662306a36Sopenharmony_ci stdev->link_notifier = switchtec_ntb_link_notification; 152762306a36Sopenharmony_ci dev_info(dev, "NTB device registered\n"); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci return 0; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_cideinit_and_exit: 153262306a36Sopenharmony_ci switchtec_ntb_deinit_db_msg_irq(sndev); 153362306a36Sopenharmony_cideinit_shared_and_exit: 153462306a36Sopenharmony_ci switchtec_ntb_deinit_shared_mw(sndev); 153562306a36Sopenharmony_cideinit_crosslink: 153662306a36Sopenharmony_ci switchtec_ntb_deinit_crosslink(sndev); 153762306a36Sopenharmony_cifree_and_exit: 153862306a36Sopenharmony_ci kfree(sndev); 153962306a36Sopenharmony_ci dev_err(dev, "failed to register ntb device: %d\n", rc); 154062306a36Sopenharmony_ci return rc; 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_cistatic void switchtec_ntb_remove(struct device *dev) 154462306a36Sopenharmony_ci{ 154562306a36Sopenharmony_ci struct switchtec_dev *stdev = to_stdev(dev); 154662306a36Sopenharmony_ci struct switchtec_ntb *sndev = stdev->sndev; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci if (!sndev) 154962306a36Sopenharmony_ci return; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci stdev->link_notifier = NULL; 155262306a36Sopenharmony_ci stdev->sndev = NULL; 155362306a36Sopenharmony_ci ntb_unregister_device(&sndev->ntb); 155462306a36Sopenharmony_ci switchtec_ntb_deinit_db_msg_irq(sndev); 155562306a36Sopenharmony_ci switchtec_ntb_deinit_shared_mw(sndev); 155662306a36Sopenharmony_ci switchtec_ntb_deinit_crosslink(sndev); 155762306a36Sopenharmony_ci kfree(sndev); 155862306a36Sopenharmony_ci dev_info(dev, "ntb device unregistered\n"); 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic struct class_interface switchtec_interface = { 156262306a36Sopenharmony_ci .add_dev = switchtec_ntb_add, 156362306a36Sopenharmony_ci .remove_dev = switchtec_ntb_remove, 156462306a36Sopenharmony_ci}; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_cistatic int __init switchtec_ntb_init(void) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci switchtec_interface.class = switchtec_class; 156962306a36Sopenharmony_ci return class_interface_register(&switchtec_interface); 157062306a36Sopenharmony_ci} 157162306a36Sopenharmony_cimodule_init(switchtec_ntb_init); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_cistatic void __exit switchtec_ntb_exit(void) 157462306a36Sopenharmony_ci{ 157562306a36Sopenharmony_ci class_interface_unregister(&switchtec_interface); 157662306a36Sopenharmony_ci} 157762306a36Sopenharmony_cimodule_exit(switchtec_ntb_exit); 1578