133dea5aaSLogan Gunthorpe /* 233dea5aaSLogan Gunthorpe * Microsemi Switchtec(tm) PCIe Management Driver 333dea5aaSLogan Gunthorpe * Copyright (c) 2017, Microsemi Corporation 433dea5aaSLogan Gunthorpe * 533dea5aaSLogan Gunthorpe * This program is free software; you can redistribute it and/or modify it 633dea5aaSLogan Gunthorpe * under the terms and conditions of the GNU General Public License, 733dea5aaSLogan Gunthorpe * version 2, as published by the Free Software Foundation. 833dea5aaSLogan Gunthorpe * 933dea5aaSLogan Gunthorpe * This program is distributed in the hope it will be useful, but WITHOUT 1033dea5aaSLogan Gunthorpe * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1133dea5aaSLogan Gunthorpe * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1233dea5aaSLogan Gunthorpe * more details. 1333dea5aaSLogan Gunthorpe * 1433dea5aaSLogan Gunthorpe */ 1533dea5aaSLogan Gunthorpe 1633dea5aaSLogan Gunthorpe #include <linux/switchtec.h> 1733dea5aaSLogan Gunthorpe #include <linux/module.h> 18ec0467ccSLogan Gunthorpe #include <linux/delay.h> 19ec0467ccSLogan Gunthorpe #include <linux/kthread.h> 203dd4db47SLogan Gunthorpe #include <linux/interrupt.h> 21e099b45bSLogan Gunthorpe #include <linux/ntb.h> 2233dea5aaSLogan Gunthorpe 2333dea5aaSLogan Gunthorpe MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver"); 2433dea5aaSLogan Gunthorpe MODULE_VERSION("0.1"); 2533dea5aaSLogan Gunthorpe MODULE_LICENSE("GPL"); 2633dea5aaSLogan Gunthorpe MODULE_AUTHOR("Microsemi Corporation"); 2733dea5aaSLogan Gunthorpe 2887d11e64SLogan Gunthorpe static ulong max_mw_size = SZ_2M; 2987d11e64SLogan Gunthorpe module_param(max_mw_size, ulong, 0644); 3087d11e64SLogan Gunthorpe MODULE_PARM_DESC(max_mw_size, 3187d11e64SLogan Gunthorpe "Max memory window size reported to the upper layer"); 3287d11e64SLogan Gunthorpe 33ec0467ccSLogan Gunthorpe static bool use_lut_mws; 34ec0467ccSLogan Gunthorpe module_param(use_lut_mws, bool, 0644); 35ec0467ccSLogan Gunthorpe MODULE_PARM_DESC(use_lut_mws, 36ec0467ccSLogan Gunthorpe "Enable the use of the LUT based memory windows"); 37ec0467ccSLogan Gunthorpe 38ec0467ccSLogan Gunthorpe #ifndef ioread64 39ec0467ccSLogan Gunthorpe #ifdef readq 40ec0467ccSLogan Gunthorpe #define ioread64 readq 41ec0467ccSLogan Gunthorpe #else 42ec0467ccSLogan Gunthorpe #define ioread64 _ioread64 43ec0467ccSLogan Gunthorpe static inline u64 _ioread64(void __iomem *mmio) 44ec0467ccSLogan Gunthorpe { 45ec0467ccSLogan Gunthorpe u64 low, high; 46ec0467ccSLogan Gunthorpe 47ec0467ccSLogan Gunthorpe low = ioread32(mmio); 48ec0467ccSLogan Gunthorpe high = ioread32(mmio + sizeof(u32)); 49ec0467ccSLogan Gunthorpe return low | (high << 32); 50ec0467ccSLogan Gunthorpe } 51ec0467ccSLogan Gunthorpe #endif 52ec0467ccSLogan Gunthorpe #endif 53ec0467ccSLogan Gunthorpe 54ec0467ccSLogan Gunthorpe #ifndef iowrite64 55ec0467ccSLogan Gunthorpe #ifdef writeq 56ec0467ccSLogan Gunthorpe #define iowrite64 writeq 57ec0467ccSLogan Gunthorpe #else 58ec0467ccSLogan Gunthorpe #define iowrite64 _iowrite64 59ec0467ccSLogan Gunthorpe static inline void _iowrite64(u64 val, void __iomem *mmio) 60ec0467ccSLogan Gunthorpe { 61ec0467ccSLogan Gunthorpe iowrite32(val, mmio); 62ec0467ccSLogan Gunthorpe iowrite32(val >> 32, mmio + sizeof(u32)); 63ec0467ccSLogan Gunthorpe } 64ec0467ccSLogan Gunthorpe #endif 65ec0467ccSLogan Gunthorpe #endif 66ec0467ccSLogan Gunthorpe 67ec0467ccSLogan Gunthorpe #define SWITCHTEC_NTB_MAGIC 0x45CC0001 68ec0467ccSLogan Gunthorpe #define MAX_MWS 128 69ec0467ccSLogan Gunthorpe 70ec0467ccSLogan Gunthorpe struct shared_mw { 71ec0467ccSLogan Gunthorpe u32 magic; 720ee28f26SLogan Gunthorpe u32 link_sta; 73ec0467ccSLogan Gunthorpe u32 partition_id; 74ec0467ccSLogan Gunthorpe u64 mw_sizes[MAX_MWS]; 75b9a4acacSLogan Gunthorpe u32 spad[128]; 76ec0467ccSLogan Gunthorpe }; 77ec0467ccSLogan Gunthorpe 78ec0467ccSLogan Gunthorpe #define MAX_DIRECT_MW ARRAY_SIZE(((struct ntb_ctrl_regs *)(0))->bar_entry) 79ec0467ccSLogan Gunthorpe #define LUT_SIZE SZ_64K 80ec0467ccSLogan Gunthorpe 8133dea5aaSLogan Gunthorpe struct switchtec_ntb { 82e099b45bSLogan Gunthorpe struct ntb_dev ntb; 8333dea5aaSLogan Gunthorpe struct switchtec_dev *stdev; 84ec0467ccSLogan Gunthorpe 85ec0467ccSLogan Gunthorpe int self_partition; 86ec0467ccSLogan Gunthorpe int peer_partition; 87ec0467ccSLogan Gunthorpe 883dd4db47SLogan Gunthorpe int doorbell_irq; 893dd4db47SLogan Gunthorpe int message_irq; 903dd4db47SLogan Gunthorpe 91ec0467ccSLogan Gunthorpe struct ntb_info_regs __iomem *mmio_ntb; 92ec0467ccSLogan Gunthorpe struct ntb_ctrl_regs __iomem *mmio_ctrl; 93ec0467ccSLogan Gunthorpe struct ntb_dbmsg_regs __iomem *mmio_dbmsg; 94ec0467ccSLogan Gunthorpe struct ntb_ctrl_regs __iomem *mmio_self_ctrl; 95ec0467ccSLogan Gunthorpe struct ntb_ctrl_regs __iomem *mmio_peer_ctrl; 96ec0467ccSLogan Gunthorpe struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg; 97ec0467ccSLogan Gunthorpe 98ec0467ccSLogan Gunthorpe struct shared_mw *self_shared; 99ec0467ccSLogan Gunthorpe struct shared_mw __iomem *peer_shared; 100ec0467ccSLogan Gunthorpe dma_addr_t self_shared_dma; 101ec0467ccSLogan Gunthorpe 1023dd4db47SLogan Gunthorpe u64 db_mask; 1033dd4db47SLogan Gunthorpe u64 db_valid_mask; 1043dd4db47SLogan Gunthorpe int db_shift; 1053dd4db47SLogan Gunthorpe int db_peer_shift; 1063dd4db47SLogan Gunthorpe 1076619bf95SLogan Gunthorpe /* synchronize rmw access of db_mask and hw reg */ 1086619bf95SLogan Gunthorpe spinlock_t db_mask_lock; 1096619bf95SLogan Gunthorpe 110ec0467ccSLogan Gunthorpe int nr_direct_mw; 111ec0467ccSLogan Gunthorpe int nr_lut_mw; 112ec0467ccSLogan Gunthorpe int direct_mw_to_bar[MAX_DIRECT_MW]; 113ec0467ccSLogan Gunthorpe 114ec0467ccSLogan Gunthorpe int peer_nr_direct_mw; 115ec0467ccSLogan Gunthorpe int peer_nr_lut_mw; 116ec0467ccSLogan Gunthorpe int peer_direct_mw_to_bar[MAX_DIRECT_MW]; 1170ee28f26SLogan Gunthorpe 1180ee28f26SLogan Gunthorpe bool link_is_up; 1190ee28f26SLogan Gunthorpe enum ntb_speed link_speed; 1200ee28f26SLogan Gunthorpe enum ntb_width link_width; 12133dea5aaSLogan Gunthorpe }; 12233dea5aaSLogan Gunthorpe 1230ee28f26SLogan Gunthorpe static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) 1240ee28f26SLogan Gunthorpe { 1250ee28f26SLogan Gunthorpe return container_of(ntb, struct switchtec_ntb, ntb); 1260ee28f26SLogan Gunthorpe } 1270ee28f26SLogan Gunthorpe 128ec0467ccSLogan Gunthorpe static int switchtec_ntb_part_op(struct switchtec_ntb *sndev, 129ec0467ccSLogan Gunthorpe struct ntb_ctrl_regs __iomem *ctl, 130ec0467ccSLogan Gunthorpe u32 op, int wait_status) 131ec0467ccSLogan Gunthorpe { 132ec0467ccSLogan Gunthorpe static const char * const op_text[] = { 133ec0467ccSLogan Gunthorpe [NTB_CTRL_PART_OP_LOCK] = "lock", 134ec0467ccSLogan Gunthorpe [NTB_CTRL_PART_OP_CFG] = "configure", 135ec0467ccSLogan Gunthorpe [NTB_CTRL_PART_OP_RESET] = "reset", 136ec0467ccSLogan Gunthorpe }; 137ec0467ccSLogan Gunthorpe 138ec0467ccSLogan Gunthorpe int i; 139ec0467ccSLogan Gunthorpe u32 ps; 140ec0467ccSLogan Gunthorpe int status; 141ec0467ccSLogan Gunthorpe 142ec0467ccSLogan Gunthorpe switch (op) { 143ec0467ccSLogan Gunthorpe case NTB_CTRL_PART_OP_LOCK: 144ec0467ccSLogan Gunthorpe status = NTB_CTRL_PART_STATUS_LOCKING; 145ec0467ccSLogan Gunthorpe break; 146ec0467ccSLogan Gunthorpe case NTB_CTRL_PART_OP_CFG: 147ec0467ccSLogan Gunthorpe status = NTB_CTRL_PART_STATUS_CONFIGURING; 148ec0467ccSLogan Gunthorpe break; 149ec0467ccSLogan Gunthorpe case NTB_CTRL_PART_OP_RESET: 150ec0467ccSLogan Gunthorpe status = NTB_CTRL_PART_STATUS_RESETTING; 151ec0467ccSLogan Gunthorpe break; 152ec0467ccSLogan Gunthorpe default: 153ec0467ccSLogan Gunthorpe return -EINVAL; 154ec0467ccSLogan Gunthorpe } 155ec0467ccSLogan Gunthorpe 156ec0467ccSLogan Gunthorpe iowrite32(op, &ctl->partition_op); 157ec0467ccSLogan Gunthorpe 158ec0467ccSLogan Gunthorpe for (i = 0; i < 1000; i++) { 159ec0467ccSLogan Gunthorpe if (msleep_interruptible(50) != 0) { 160ec0467ccSLogan Gunthorpe iowrite32(NTB_CTRL_PART_OP_RESET, &ctl->partition_op); 161ec0467ccSLogan Gunthorpe return -EINTR; 162ec0467ccSLogan Gunthorpe } 163ec0467ccSLogan Gunthorpe 164ec0467ccSLogan Gunthorpe ps = ioread32(&ctl->partition_status) & 0xFFFF; 165ec0467ccSLogan Gunthorpe 166ec0467ccSLogan Gunthorpe if (ps != status) 167ec0467ccSLogan Gunthorpe break; 168ec0467ccSLogan Gunthorpe } 169ec0467ccSLogan Gunthorpe 170ec0467ccSLogan Gunthorpe if (ps == wait_status) 171ec0467ccSLogan Gunthorpe return 0; 172ec0467ccSLogan Gunthorpe 173ec0467ccSLogan Gunthorpe if (ps == status) { 174ec0467ccSLogan Gunthorpe dev_err(&sndev->stdev->dev, 175ec0467ccSLogan Gunthorpe "Timed out while peforming %s (%d). (%08x)", 176ec0467ccSLogan Gunthorpe op_text[op], op, 177ec0467ccSLogan Gunthorpe ioread32(&ctl->partition_status)); 178ec0467ccSLogan Gunthorpe 179ec0467ccSLogan Gunthorpe return -ETIMEDOUT; 180ec0467ccSLogan Gunthorpe } 181ec0467ccSLogan Gunthorpe 182ec0467ccSLogan Gunthorpe return -EIO; 183ec0467ccSLogan Gunthorpe } 184ec0467ccSLogan Gunthorpe 1850ee28f26SLogan Gunthorpe static int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx, 1860ee28f26SLogan Gunthorpe u32 val) 1870ee28f26SLogan Gunthorpe { 1880ee28f26SLogan Gunthorpe if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_self_dbmsg->omsg)) 1890ee28f26SLogan Gunthorpe return -EINVAL; 1900ee28f26SLogan Gunthorpe 1910ee28f26SLogan Gunthorpe iowrite32(val, &sndev->mmio_self_dbmsg->omsg[idx].msg); 1920ee28f26SLogan Gunthorpe 1930ee28f26SLogan Gunthorpe return 0; 1940ee28f26SLogan Gunthorpe } 1950ee28f26SLogan Gunthorpe 196e099b45bSLogan Gunthorpe static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) 197e099b45bSLogan Gunthorpe { 19887d11e64SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 19987d11e64SLogan Gunthorpe int nr_direct_mw = sndev->peer_nr_direct_mw; 20087d11e64SLogan Gunthorpe int nr_lut_mw = sndev->peer_nr_lut_mw - 1; 20187d11e64SLogan Gunthorpe 20287d11e64SLogan Gunthorpe if (pidx != NTB_DEF_PEER_IDX) 20387d11e64SLogan Gunthorpe return -EINVAL; 20487d11e64SLogan Gunthorpe 20587d11e64SLogan Gunthorpe if (!use_lut_mws) 20687d11e64SLogan Gunthorpe nr_lut_mw = 0; 20787d11e64SLogan Gunthorpe 20887d11e64SLogan Gunthorpe return nr_direct_mw + nr_lut_mw; 20987d11e64SLogan Gunthorpe } 21087d11e64SLogan Gunthorpe 21187d11e64SLogan Gunthorpe static int lut_index(struct switchtec_ntb *sndev, int mw_idx) 21287d11e64SLogan Gunthorpe { 21387d11e64SLogan Gunthorpe return mw_idx - sndev->nr_direct_mw + 1; 21487d11e64SLogan Gunthorpe } 21587d11e64SLogan Gunthorpe 21687d11e64SLogan Gunthorpe static int peer_lut_index(struct switchtec_ntb *sndev, int mw_idx) 21787d11e64SLogan Gunthorpe { 21887d11e64SLogan Gunthorpe return mw_idx - sndev->peer_nr_direct_mw + 1; 219e099b45bSLogan Gunthorpe } 220e099b45bSLogan Gunthorpe 221e099b45bSLogan Gunthorpe static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, 222e099b45bSLogan Gunthorpe int widx, resource_size_t *addr_align, 223e099b45bSLogan Gunthorpe resource_size_t *size_align, 224e099b45bSLogan Gunthorpe resource_size_t *size_max) 225e099b45bSLogan Gunthorpe { 22687d11e64SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 22787d11e64SLogan Gunthorpe int lut; 22887d11e64SLogan Gunthorpe resource_size_t size; 22987d11e64SLogan Gunthorpe 23087d11e64SLogan Gunthorpe if (pidx != NTB_DEF_PEER_IDX) 23187d11e64SLogan Gunthorpe return -EINVAL; 23287d11e64SLogan Gunthorpe 23387d11e64SLogan Gunthorpe lut = widx >= sndev->peer_nr_direct_mw; 23487d11e64SLogan Gunthorpe size = ioread64(&sndev->peer_shared->mw_sizes[widx]); 23587d11e64SLogan Gunthorpe 23687d11e64SLogan Gunthorpe if (size == 0) 23787d11e64SLogan Gunthorpe return -EINVAL; 23887d11e64SLogan Gunthorpe 23987d11e64SLogan Gunthorpe if (addr_align) 24087d11e64SLogan Gunthorpe *addr_align = lut ? size : SZ_4K; 24187d11e64SLogan Gunthorpe 24287d11e64SLogan Gunthorpe if (size_align) 24387d11e64SLogan Gunthorpe *size_align = lut ? size : SZ_4K; 24487d11e64SLogan Gunthorpe 24587d11e64SLogan Gunthorpe if (size_max) 24687d11e64SLogan Gunthorpe *size_max = size; 24787d11e64SLogan Gunthorpe 248e099b45bSLogan Gunthorpe return 0; 249e099b45bSLogan Gunthorpe } 250e099b45bSLogan Gunthorpe 25187d11e64SLogan Gunthorpe static void switchtec_ntb_mw_clr_direct(struct switchtec_ntb *sndev, int idx) 25287d11e64SLogan Gunthorpe { 25387d11e64SLogan Gunthorpe struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 25487d11e64SLogan Gunthorpe int bar = sndev->peer_direct_mw_to_bar[idx]; 25587d11e64SLogan Gunthorpe u32 ctl_val; 25687d11e64SLogan Gunthorpe 25787d11e64SLogan Gunthorpe ctl_val = ioread32(&ctl->bar_entry[bar].ctl); 25887d11e64SLogan Gunthorpe ctl_val &= ~NTB_CTRL_BAR_DIR_WIN_EN; 25987d11e64SLogan Gunthorpe iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); 26087d11e64SLogan Gunthorpe iowrite32(0, &ctl->bar_entry[bar].win_size); 26187d11e64SLogan Gunthorpe iowrite64(sndev->self_partition, &ctl->bar_entry[bar].xlate_addr); 26287d11e64SLogan Gunthorpe } 26387d11e64SLogan Gunthorpe 26487d11e64SLogan Gunthorpe static void switchtec_ntb_mw_clr_lut(struct switchtec_ntb *sndev, int idx) 26587d11e64SLogan Gunthorpe { 26687d11e64SLogan Gunthorpe struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 26787d11e64SLogan Gunthorpe 26887d11e64SLogan Gunthorpe iowrite64(0, &ctl->lut_entry[peer_lut_index(sndev, idx)]); 26987d11e64SLogan Gunthorpe } 27087d11e64SLogan Gunthorpe 27187d11e64SLogan Gunthorpe static void switchtec_ntb_mw_set_direct(struct switchtec_ntb *sndev, int idx, 27287d11e64SLogan Gunthorpe dma_addr_t addr, resource_size_t size) 27387d11e64SLogan Gunthorpe { 27487d11e64SLogan Gunthorpe int xlate_pos = ilog2(size); 27587d11e64SLogan Gunthorpe int bar = sndev->peer_direct_mw_to_bar[idx]; 27687d11e64SLogan Gunthorpe struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 27787d11e64SLogan Gunthorpe u32 ctl_val; 27887d11e64SLogan Gunthorpe 27987d11e64SLogan Gunthorpe ctl_val = ioread32(&ctl->bar_entry[bar].ctl); 28087d11e64SLogan Gunthorpe ctl_val |= NTB_CTRL_BAR_DIR_WIN_EN; 28187d11e64SLogan Gunthorpe 28287d11e64SLogan Gunthorpe iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); 28387d11e64SLogan Gunthorpe iowrite32(xlate_pos | size, &ctl->bar_entry[bar].win_size); 28487d11e64SLogan Gunthorpe iowrite64(sndev->self_partition | addr, 28587d11e64SLogan Gunthorpe &ctl->bar_entry[bar].xlate_addr); 28687d11e64SLogan Gunthorpe } 28787d11e64SLogan Gunthorpe 28887d11e64SLogan Gunthorpe static void switchtec_ntb_mw_set_lut(struct switchtec_ntb *sndev, int idx, 28987d11e64SLogan Gunthorpe dma_addr_t addr, resource_size_t size) 29087d11e64SLogan Gunthorpe { 29187d11e64SLogan Gunthorpe struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 29287d11e64SLogan Gunthorpe 29387d11e64SLogan Gunthorpe iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | addr), 29487d11e64SLogan Gunthorpe &ctl->lut_entry[peer_lut_index(sndev, idx)]); 29587d11e64SLogan Gunthorpe } 29687d11e64SLogan Gunthorpe 297e099b45bSLogan Gunthorpe static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, 298e099b45bSLogan Gunthorpe dma_addr_t addr, resource_size_t size) 299e099b45bSLogan Gunthorpe { 30087d11e64SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 30187d11e64SLogan Gunthorpe struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 30287d11e64SLogan Gunthorpe int xlate_pos = ilog2(size); 30387d11e64SLogan Gunthorpe int nr_direct_mw = sndev->peer_nr_direct_mw; 30487d11e64SLogan Gunthorpe int rc; 30587d11e64SLogan Gunthorpe 30687d11e64SLogan Gunthorpe if (pidx != NTB_DEF_PEER_IDX) 30787d11e64SLogan Gunthorpe return -EINVAL; 30887d11e64SLogan Gunthorpe 30987d11e64SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "MW %d: part %d addr %pad size %pap", 31087d11e64SLogan Gunthorpe widx, pidx, &addr, &size); 31187d11e64SLogan Gunthorpe 31287d11e64SLogan Gunthorpe if (widx >= switchtec_ntb_mw_count(ntb, pidx)) 31387d11e64SLogan Gunthorpe return -EINVAL; 31487d11e64SLogan Gunthorpe 31587d11e64SLogan Gunthorpe if (xlate_pos < 12) 31687d11e64SLogan Gunthorpe return -EINVAL; 31787d11e64SLogan Gunthorpe 31887d11e64SLogan Gunthorpe rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, 31987d11e64SLogan Gunthorpe NTB_CTRL_PART_STATUS_LOCKED); 32087d11e64SLogan Gunthorpe if (rc) 32187d11e64SLogan Gunthorpe return rc; 32287d11e64SLogan Gunthorpe 32387d11e64SLogan Gunthorpe if (addr == 0 || size == 0) { 32487d11e64SLogan Gunthorpe if (widx < nr_direct_mw) 32587d11e64SLogan Gunthorpe switchtec_ntb_mw_clr_direct(sndev, widx); 32687d11e64SLogan Gunthorpe else 32787d11e64SLogan Gunthorpe switchtec_ntb_mw_clr_lut(sndev, widx); 32887d11e64SLogan Gunthorpe } else { 32987d11e64SLogan Gunthorpe if (widx < nr_direct_mw) 33087d11e64SLogan Gunthorpe switchtec_ntb_mw_set_direct(sndev, widx, addr, size); 33187d11e64SLogan Gunthorpe else 33287d11e64SLogan Gunthorpe switchtec_ntb_mw_set_lut(sndev, widx, addr, size); 33387d11e64SLogan Gunthorpe } 33487d11e64SLogan Gunthorpe 33587d11e64SLogan Gunthorpe rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 33687d11e64SLogan Gunthorpe NTB_CTRL_PART_STATUS_NORMAL); 33787d11e64SLogan Gunthorpe 33887d11e64SLogan Gunthorpe if (rc == -EIO) { 33987d11e64SLogan Gunthorpe dev_err(&sndev->stdev->dev, 34087d11e64SLogan Gunthorpe "Hardware reported an error configuring mw %d: %08x", 34187d11e64SLogan Gunthorpe widx, ioread32(&ctl->bar_error)); 34287d11e64SLogan Gunthorpe 34387d11e64SLogan Gunthorpe if (widx < nr_direct_mw) 34487d11e64SLogan Gunthorpe switchtec_ntb_mw_clr_direct(sndev, widx); 34587d11e64SLogan Gunthorpe else 34687d11e64SLogan Gunthorpe switchtec_ntb_mw_clr_lut(sndev, widx); 34787d11e64SLogan Gunthorpe 34887d11e64SLogan Gunthorpe switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 34987d11e64SLogan Gunthorpe NTB_CTRL_PART_STATUS_NORMAL); 35087d11e64SLogan Gunthorpe } 35187d11e64SLogan Gunthorpe 35287d11e64SLogan Gunthorpe return rc; 353e099b45bSLogan Gunthorpe } 354e099b45bSLogan Gunthorpe 355e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb) 356e099b45bSLogan Gunthorpe { 35787d11e64SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 35887d11e64SLogan Gunthorpe 35987d11e64SLogan Gunthorpe return sndev->nr_direct_mw + (use_lut_mws ? sndev->nr_lut_mw - 1 : 0); 36087d11e64SLogan Gunthorpe } 36187d11e64SLogan Gunthorpe 36287d11e64SLogan Gunthorpe static int switchtec_ntb_direct_get_addr(struct switchtec_ntb *sndev, 36387d11e64SLogan Gunthorpe int idx, phys_addr_t *base, 36487d11e64SLogan Gunthorpe resource_size_t *size) 36587d11e64SLogan Gunthorpe { 36687d11e64SLogan Gunthorpe int bar = sndev->direct_mw_to_bar[idx]; 36787d11e64SLogan Gunthorpe size_t offset = 0; 36887d11e64SLogan Gunthorpe 36987d11e64SLogan Gunthorpe if (bar < 0) 37087d11e64SLogan Gunthorpe return -EINVAL; 37187d11e64SLogan Gunthorpe 37287d11e64SLogan Gunthorpe if (idx == 0) { 37387d11e64SLogan Gunthorpe /* 37487d11e64SLogan Gunthorpe * This is the direct BAR shared with the LUTs 37587d11e64SLogan Gunthorpe * which means the actual window will be offset 37687d11e64SLogan Gunthorpe * by the size of all the LUT entries. 37787d11e64SLogan Gunthorpe */ 37887d11e64SLogan Gunthorpe 37987d11e64SLogan Gunthorpe offset = LUT_SIZE * sndev->nr_lut_mw; 38087d11e64SLogan Gunthorpe } 38187d11e64SLogan Gunthorpe 38287d11e64SLogan Gunthorpe if (base) 38387d11e64SLogan Gunthorpe *base = pci_resource_start(sndev->ntb.pdev, bar) + offset; 38487d11e64SLogan Gunthorpe 38587d11e64SLogan Gunthorpe if (size) { 38687d11e64SLogan Gunthorpe *size = pci_resource_len(sndev->ntb.pdev, bar) - offset; 38787d11e64SLogan Gunthorpe if (offset && *size > offset) 38887d11e64SLogan Gunthorpe *size = offset; 38987d11e64SLogan Gunthorpe 39087d11e64SLogan Gunthorpe if (*size > max_mw_size) 39187d11e64SLogan Gunthorpe *size = max_mw_size; 39287d11e64SLogan Gunthorpe } 39387d11e64SLogan Gunthorpe 39487d11e64SLogan Gunthorpe return 0; 39587d11e64SLogan Gunthorpe } 39687d11e64SLogan Gunthorpe 39787d11e64SLogan Gunthorpe static int switchtec_ntb_lut_get_addr(struct switchtec_ntb *sndev, 39887d11e64SLogan Gunthorpe int idx, phys_addr_t *base, 39987d11e64SLogan Gunthorpe resource_size_t *size) 40087d11e64SLogan Gunthorpe { 40187d11e64SLogan Gunthorpe int bar = sndev->direct_mw_to_bar[0]; 40287d11e64SLogan Gunthorpe int offset; 40387d11e64SLogan Gunthorpe 40487d11e64SLogan Gunthorpe offset = LUT_SIZE * lut_index(sndev, idx); 40587d11e64SLogan Gunthorpe 40687d11e64SLogan Gunthorpe if (base) 40787d11e64SLogan Gunthorpe *base = pci_resource_start(sndev->ntb.pdev, bar) + offset; 40887d11e64SLogan Gunthorpe 40987d11e64SLogan Gunthorpe if (size) 41087d11e64SLogan Gunthorpe *size = LUT_SIZE; 41187d11e64SLogan Gunthorpe 412e099b45bSLogan Gunthorpe return 0; 413e099b45bSLogan Gunthorpe } 414e099b45bSLogan Gunthorpe 415e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx, 416e099b45bSLogan Gunthorpe phys_addr_t *base, 417e099b45bSLogan Gunthorpe resource_size_t *size) 418e099b45bSLogan Gunthorpe { 41987d11e64SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 42087d11e64SLogan Gunthorpe 42187d11e64SLogan Gunthorpe if (idx < sndev->nr_direct_mw) 42287d11e64SLogan Gunthorpe return switchtec_ntb_direct_get_addr(sndev, idx, base, size); 42387d11e64SLogan Gunthorpe else if (idx < switchtec_ntb_peer_mw_count(ntb)) 42487d11e64SLogan Gunthorpe return switchtec_ntb_lut_get_addr(sndev, idx, base, size); 42587d11e64SLogan Gunthorpe else 42687d11e64SLogan Gunthorpe return -EINVAL; 427e099b45bSLogan Gunthorpe } 428e099b45bSLogan Gunthorpe 4290ee28f26SLogan Gunthorpe static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev, 4300ee28f26SLogan Gunthorpe int partition, 4310ee28f26SLogan Gunthorpe enum ntb_speed *speed, 4320ee28f26SLogan Gunthorpe enum ntb_width *width) 4330ee28f26SLogan Gunthorpe { 4340ee28f26SLogan Gunthorpe struct switchtec_dev *stdev = sndev->stdev; 4350ee28f26SLogan Gunthorpe 4360ee28f26SLogan Gunthorpe u32 pff = ioread32(&stdev->mmio_part_cfg[partition].vep_pff_inst_id); 4370ee28f26SLogan Gunthorpe u32 linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]); 4380ee28f26SLogan Gunthorpe 4390ee28f26SLogan Gunthorpe if (speed) 4400ee28f26SLogan Gunthorpe *speed = (linksta >> 16) & 0xF; 4410ee28f26SLogan Gunthorpe 4420ee28f26SLogan Gunthorpe if (width) 4430ee28f26SLogan Gunthorpe *width = (linksta >> 20) & 0x3F; 4440ee28f26SLogan Gunthorpe } 4450ee28f26SLogan Gunthorpe 4460ee28f26SLogan Gunthorpe static void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev) 4470ee28f26SLogan Gunthorpe { 4480ee28f26SLogan Gunthorpe enum ntb_speed self_speed, peer_speed; 4490ee28f26SLogan Gunthorpe enum ntb_width self_width, peer_width; 4500ee28f26SLogan Gunthorpe 4510ee28f26SLogan Gunthorpe if (!sndev->link_is_up) { 4520ee28f26SLogan Gunthorpe sndev->link_speed = NTB_SPEED_NONE; 4530ee28f26SLogan Gunthorpe sndev->link_width = NTB_WIDTH_NONE; 4540ee28f26SLogan Gunthorpe return; 4550ee28f26SLogan Gunthorpe } 4560ee28f26SLogan Gunthorpe 4570ee28f26SLogan Gunthorpe switchtec_ntb_part_link_speed(sndev, sndev->self_partition, 4580ee28f26SLogan Gunthorpe &self_speed, &self_width); 4590ee28f26SLogan Gunthorpe switchtec_ntb_part_link_speed(sndev, sndev->peer_partition, 4600ee28f26SLogan Gunthorpe &peer_speed, &peer_width); 4610ee28f26SLogan Gunthorpe 4620ee28f26SLogan Gunthorpe sndev->link_speed = min(self_speed, peer_speed); 4630ee28f26SLogan Gunthorpe sndev->link_width = min(self_width, peer_width); 4640ee28f26SLogan Gunthorpe } 4650ee28f26SLogan Gunthorpe 4660ee28f26SLogan Gunthorpe enum { 4670ee28f26SLogan Gunthorpe LINK_MESSAGE = 0, 4680ee28f26SLogan Gunthorpe MSG_LINK_UP = 1, 4690ee28f26SLogan Gunthorpe MSG_LINK_DOWN = 2, 4700ee28f26SLogan Gunthorpe MSG_CHECK_LINK = 3, 4710ee28f26SLogan Gunthorpe }; 4720ee28f26SLogan Gunthorpe 4730ee28f26SLogan Gunthorpe static void switchtec_ntb_check_link(struct switchtec_ntb *sndev) 4740ee28f26SLogan Gunthorpe { 4750ee28f26SLogan Gunthorpe int link_sta; 4760ee28f26SLogan Gunthorpe int old = sndev->link_is_up; 4770ee28f26SLogan Gunthorpe 4780ee28f26SLogan Gunthorpe link_sta = sndev->self_shared->link_sta; 4790ee28f26SLogan Gunthorpe if (link_sta) { 4800ee28f26SLogan Gunthorpe u64 peer = ioread64(&sndev->peer_shared->magic); 4810ee28f26SLogan Gunthorpe 4820ee28f26SLogan Gunthorpe if ((peer & 0xFFFFFFFF) == SWITCHTEC_NTB_MAGIC) 4830ee28f26SLogan Gunthorpe link_sta = peer >> 32; 4840ee28f26SLogan Gunthorpe else 4850ee28f26SLogan Gunthorpe link_sta = 0; 4860ee28f26SLogan Gunthorpe } 4870ee28f26SLogan Gunthorpe 4880ee28f26SLogan Gunthorpe sndev->link_is_up = link_sta; 4890ee28f26SLogan Gunthorpe switchtec_ntb_set_link_speed(sndev); 4900ee28f26SLogan Gunthorpe 4910ee28f26SLogan Gunthorpe if (link_sta != old) { 4920ee28f26SLogan Gunthorpe switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK); 4930ee28f26SLogan Gunthorpe ntb_link_event(&sndev->ntb); 4940ee28f26SLogan Gunthorpe dev_info(&sndev->stdev->dev, "ntb link %s", 4950ee28f26SLogan Gunthorpe link_sta ? "up" : "down"); 4960ee28f26SLogan Gunthorpe } 4970ee28f26SLogan Gunthorpe } 4980ee28f26SLogan Gunthorpe 4990ee28f26SLogan Gunthorpe static void switchtec_ntb_link_notification(struct switchtec_dev *stdev) 5000ee28f26SLogan Gunthorpe { 5010ee28f26SLogan Gunthorpe struct switchtec_ntb *sndev = stdev->sndev; 5020ee28f26SLogan Gunthorpe 5030ee28f26SLogan Gunthorpe switchtec_ntb_check_link(sndev); 5040ee28f26SLogan Gunthorpe } 5050ee28f26SLogan Gunthorpe 506e099b45bSLogan Gunthorpe static u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb, 507e099b45bSLogan Gunthorpe enum ntb_speed *speed, 508e099b45bSLogan Gunthorpe enum ntb_width *width) 509e099b45bSLogan Gunthorpe { 5100ee28f26SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 5110ee28f26SLogan Gunthorpe 5120ee28f26SLogan Gunthorpe if (speed) 5130ee28f26SLogan Gunthorpe *speed = sndev->link_speed; 5140ee28f26SLogan Gunthorpe if (width) 5150ee28f26SLogan Gunthorpe *width = sndev->link_width; 5160ee28f26SLogan Gunthorpe 5170ee28f26SLogan Gunthorpe return sndev->link_is_up; 518e099b45bSLogan Gunthorpe } 519e099b45bSLogan Gunthorpe 520e099b45bSLogan Gunthorpe static int switchtec_ntb_link_enable(struct ntb_dev *ntb, 521e099b45bSLogan Gunthorpe enum ntb_speed max_speed, 522e099b45bSLogan Gunthorpe enum ntb_width max_width) 523e099b45bSLogan Gunthorpe { 5240ee28f26SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 5250ee28f26SLogan Gunthorpe 5260ee28f26SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "enabling link"); 5270ee28f26SLogan Gunthorpe 5280ee28f26SLogan Gunthorpe sndev->self_shared->link_sta = 1; 5290ee28f26SLogan Gunthorpe switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); 5300ee28f26SLogan Gunthorpe 5310ee28f26SLogan Gunthorpe switchtec_ntb_check_link(sndev); 5320ee28f26SLogan Gunthorpe 533e099b45bSLogan Gunthorpe return 0; 534e099b45bSLogan Gunthorpe } 535e099b45bSLogan Gunthorpe 536e099b45bSLogan Gunthorpe static int switchtec_ntb_link_disable(struct ntb_dev *ntb) 537e099b45bSLogan Gunthorpe { 5380ee28f26SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 5390ee28f26SLogan Gunthorpe 5400ee28f26SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "disabling link"); 5410ee28f26SLogan Gunthorpe 5420ee28f26SLogan Gunthorpe sndev->self_shared->link_sta = 0; 5430ee28f26SLogan Gunthorpe switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); 5440ee28f26SLogan Gunthorpe 5450ee28f26SLogan Gunthorpe switchtec_ntb_check_link(sndev); 5460ee28f26SLogan Gunthorpe 547e099b45bSLogan Gunthorpe return 0; 548e099b45bSLogan Gunthorpe } 549e099b45bSLogan Gunthorpe 550e099b45bSLogan Gunthorpe static u64 switchtec_ntb_db_valid_mask(struct ntb_dev *ntb) 551e099b45bSLogan Gunthorpe { 5526619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 5536619bf95SLogan Gunthorpe 5546619bf95SLogan Gunthorpe return sndev->db_valid_mask; 555e099b45bSLogan Gunthorpe } 556e099b45bSLogan Gunthorpe 557e099b45bSLogan Gunthorpe static int switchtec_ntb_db_vector_count(struct ntb_dev *ntb) 558e099b45bSLogan Gunthorpe { 5596619bf95SLogan Gunthorpe return 1; 560e099b45bSLogan Gunthorpe } 561e099b45bSLogan Gunthorpe 562e099b45bSLogan Gunthorpe static u64 switchtec_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector) 563e099b45bSLogan Gunthorpe { 5646619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 5656619bf95SLogan Gunthorpe 5666619bf95SLogan Gunthorpe if (db_vector < 0 || db_vector > 1) 567e099b45bSLogan Gunthorpe return 0; 5686619bf95SLogan Gunthorpe 5696619bf95SLogan Gunthorpe return sndev->db_valid_mask; 570e099b45bSLogan Gunthorpe } 571e099b45bSLogan Gunthorpe 572e099b45bSLogan Gunthorpe static u64 switchtec_ntb_db_read(struct ntb_dev *ntb) 573e099b45bSLogan Gunthorpe { 5746619bf95SLogan Gunthorpe u64 ret; 5756619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 5766619bf95SLogan Gunthorpe 5776619bf95SLogan Gunthorpe ret = ioread64(&sndev->mmio_self_dbmsg->idb) >> sndev->db_shift; 5786619bf95SLogan Gunthorpe 5796619bf95SLogan Gunthorpe return ret & sndev->db_valid_mask; 580e099b45bSLogan Gunthorpe } 581e099b45bSLogan Gunthorpe 582e099b45bSLogan Gunthorpe static int switchtec_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) 583e099b45bSLogan Gunthorpe { 5846619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 5856619bf95SLogan Gunthorpe 5866619bf95SLogan Gunthorpe iowrite64(db_bits << sndev->db_shift, &sndev->mmio_self_dbmsg->idb); 5876619bf95SLogan Gunthorpe 588e099b45bSLogan Gunthorpe return 0; 589e099b45bSLogan Gunthorpe } 590e099b45bSLogan Gunthorpe 591e099b45bSLogan Gunthorpe static int switchtec_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) 592e099b45bSLogan Gunthorpe { 5936619bf95SLogan Gunthorpe unsigned long irqflags; 5946619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 5956619bf95SLogan Gunthorpe 5966619bf95SLogan Gunthorpe if (db_bits & ~sndev->db_valid_mask) 5976619bf95SLogan Gunthorpe return -EINVAL; 5986619bf95SLogan Gunthorpe 5996619bf95SLogan Gunthorpe spin_lock_irqsave(&sndev->db_mask_lock, irqflags); 6006619bf95SLogan Gunthorpe 6016619bf95SLogan Gunthorpe sndev->db_mask |= db_bits << sndev->db_shift; 6026619bf95SLogan Gunthorpe iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 6036619bf95SLogan Gunthorpe 6046619bf95SLogan Gunthorpe spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags); 6056619bf95SLogan Gunthorpe 606e099b45bSLogan Gunthorpe return 0; 607e099b45bSLogan Gunthorpe } 608e099b45bSLogan Gunthorpe 609e099b45bSLogan Gunthorpe static int switchtec_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) 610e099b45bSLogan Gunthorpe { 6116619bf95SLogan Gunthorpe unsigned long irqflags; 6126619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 6136619bf95SLogan Gunthorpe 6146619bf95SLogan Gunthorpe if (db_bits & ~sndev->db_valid_mask) 6156619bf95SLogan Gunthorpe return -EINVAL; 6166619bf95SLogan Gunthorpe 6176619bf95SLogan Gunthorpe spin_lock_irqsave(&sndev->db_mask_lock, irqflags); 6186619bf95SLogan Gunthorpe 6196619bf95SLogan Gunthorpe sndev->db_mask &= ~(db_bits << sndev->db_shift); 6206619bf95SLogan Gunthorpe iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 6216619bf95SLogan Gunthorpe 6226619bf95SLogan Gunthorpe spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags); 6236619bf95SLogan Gunthorpe 6246619bf95SLogan Gunthorpe return 0; 6256619bf95SLogan Gunthorpe } 6266619bf95SLogan Gunthorpe 6276619bf95SLogan Gunthorpe static u64 switchtec_ntb_db_read_mask(struct ntb_dev *ntb) 6286619bf95SLogan Gunthorpe { 6296619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 6306619bf95SLogan Gunthorpe 6316619bf95SLogan Gunthorpe return (sndev->db_mask >> sndev->db_shift) & sndev->db_valid_mask; 6326619bf95SLogan Gunthorpe } 6336619bf95SLogan Gunthorpe 6346619bf95SLogan Gunthorpe static int switchtec_ntb_peer_db_addr(struct ntb_dev *ntb, 6356619bf95SLogan Gunthorpe phys_addr_t *db_addr, 6366619bf95SLogan Gunthorpe resource_size_t *db_size) 6376619bf95SLogan Gunthorpe { 6386619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 6396619bf95SLogan Gunthorpe unsigned long offset; 6406619bf95SLogan Gunthorpe 6416619bf95SLogan Gunthorpe offset = (unsigned long)sndev->mmio_self_dbmsg->odb - 6426619bf95SLogan Gunthorpe (unsigned long)sndev->stdev->mmio; 6436619bf95SLogan Gunthorpe 6446619bf95SLogan Gunthorpe offset += sndev->db_shift / 8; 6456619bf95SLogan Gunthorpe 6466619bf95SLogan Gunthorpe if (db_addr) 6476619bf95SLogan Gunthorpe *db_addr = pci_resource_start(ntb->pdev, 0) + offset; 6486619bf95SLogan Gunthorpe if (db_size) 6496619bf95SLogan Gunthorpe *db_size = sizeof(u32); 6506619bf95SLogan Gunthorpe 651e099b45bSLogan Gunthorpe return 0; 652e099b45bSLogan Gunthorpe } 653e099b45bSLogan Gunthorpe 654e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) 655e099b45bSLogan Gunthorpe { 6566619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 6576619bf95SLogan Gunthorpe 6586619bf95SLogan Gunthorpe iowrite64(db_bits << sndev->db_peer_shift, 6596619bf95SLogan Gunthorpe &sndev->mmio_self_dbmsg->odb); 6606619bf95SLogan Gunthorpe 661e099b45bSLogan Gunthorpe return 0; 662e099b45bSLogan Gunthorpe } 663e099b45bSLogan Gunthorpe 664e099b45bSLogan Gunthorpe static int switchtec_ntb_spad_count(struct ntb_dev *ntb) 665e099b45bSLogan Gunthorpe { 666b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 667b9a4acacSLogan Gunthorpe 668b9a4acacSLogan Gunthorpe return ARRAY_SIZE(sndev->self_shared->spad); 669e099b45bSLogan Gunthorpe } 670e099b45bSLogan Gunthorpe 671e099b45bSLogan Gunthorpe static u32 switchtec_ntb_spad_read(struct ntb_dev *ntb, int idx) 672e099b45bSLogan Gunthorpe { 673b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 674b9a4acacSLogan Gunthorpe 675b9a4acacSLogan Gunthorpe if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad)) 676e099b45bSLogan Gunthorpe return 0; 677b9a4acacSLogan Gunthorpe 678b9a4acacSLogan Gunthorpe if (!sndev->self_shared) 679b9a4acacSLogan Gunthorpe return 0; 680b9a4acacSLogan Gunthorpe 681b9a4acacSLogan Gunthorpe return sndev->self_shared->spad[idx]; 682e099b45bSLogan Gunthorpe } 683e099b45bSLogan Gunthorpe 684e099b45bSLogan Gunthorpe static int switchtec_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val) 685e099b45bSLogan Gunthorpe { 686b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 687b9a4acacSLogan Gunthorpe 688b9a4acacSLogan Gunthorpe if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad)) 689b9a4acacSLogan Gunthorpe return -EINVAL; 690b9a4acacSLogan Gunthorpe 691b9a4acacSLogan Gunthorpe if (!sndev->self_shared) 692b9a4acacSLogan Gunthorpe return -EIO; 693b9a4acacSLogan Gunthorpe 694b9a4acacSLogan Gunthorpe sndev->self_shared->spad[idx] = val; 695b9a4acacSLogan Gunthorpe 696e099b45bSLogan Gunthorpe return 0; 697e099b45bSLogan Gunthorpe } 698e099b45bSLogan Gunthorpe 699b9a4acacSLogan Gunthorpe static u32 switchtec_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, 700b9a4acacSLogan Gunthorpe int sidx) 701b9a4acacSLogan Gunthorpe { 702b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 703b9a4acacSLogan Gunthorpe 704b9a4acacSLogan Gunthorpe if (pidx != NTB_DEF_PEER_IDX) 705b9a4acacSLogan Gunthorpe return -EINVAL; 706b9a4acacSLogan Gunthorpe 707b9a4acacSLogan Gunthorpe if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad)) 708b9a4acacSLogan Gunthorpe return 0; 709b9a4acacSLogan Gunthorpe 710b9a4acacSLogan Gunthorpe if (!sndev->peer_shared) 711b9a4acacSLogan Gunthorpe return 0; 712b9a4acacSLogan Gunthorpe 713b9a4acacSLogan Gunthorpe return ioread32(&sndev->peer_shared->spad[sidx]); 714b9a4acacSLogan Gunthorpe } 715b9a4acacSLogan Gunthorpe 716e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, 717e099b45bSLogan Gunthorpe int sidx, u32 val) 718e099b45bSLogan Gunthorpe { 719b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 720b9a4acacSLogan Gunthorpe 721b9a4acacSLogan Gunthorpe if (pidx != NTB_DEF_PEER_IDX) 722b9a4acacSLogan Gunthorpe return -EINVAL; 723b9a4acacSLogan Gunthorpe 724b9a4acacSLogan Gunthorpe if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad)) 725b9a4acacSLogan Gunthorpe return -EINVAL; 726b9a4acacSLogan Gunthorpe 727b9a4acacSLogan Gunthorpe if (!sndev->peer_shared) 728b9a4acacSLogan Gunthorpe return -EIO; 729b9a4acacSLogan Gunthorpe 730b9a4acacSLogan Gunthorpe iowrite32(val, &sndev->peer_shared->spad[sidx]); 731b9a4acacSLogan Gunthorpe 732b9a4acacSLogan Gunthorpe return 0; 733b9a4acacSLogan Gunthorpe } 734b9a4acacSLogan Gunthorpe 735b9a4acacSLogan Gunthorpe static int switchtec_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, 736b9a4acacSLogan Gunthorpe int sidx, phys_addr_t *spad_addr) 737b9a4acacSLogan Gunthorpe { 738b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 739b9a4acacSLogan Gunthorpe unsigned long offset; 740b9a4acacSLogan Gunthorpe 741b9a4acacSLogan Gunthorpe if (pidx != NTB_DEF_PEER_IDX) 742b9a4acacSLogan Gunthorpe return -EINVAL; 743b9a4acacSLogan Gunthorpe 744b9a4acacSLogan Gunthorpe offset = (unsigned long)&sndev->peer_shared->spad[sidx] - 745b9a4acacSLogan Gunthorpe (unsigned long)sndev->stdev->mmio; 746b9a4acacSLogan Gunthorpe 747b9a4acacSLogan Gunthorpe if (spad_addr) 748b9a4acacSLogan Gunthorpe *spad_addr = pci_resource_start(ntb->pdev, 0) + offset; 749b9a4acacSLogan Gunthorpe 750e099b45bSLogan Gunthorpe return 0; 751e099b45bSLogan Gunthorpe } 752e099b45bSLogan Gunthorpe 753e099b45bSLogan Gunthorpe static const struct ntb_dev_ops switchtec_ntb_ops = { 754e099b45bSLogan Gunthorpe .mw_count = switchtec_ntb_mw_count, 755e099b45bSLogan Gunthorpe .mw_get_align = switchtec_ntb_mw_get_align, 756e099b45bSLogan Gunthorpe .mw_set_trans = switchtec_ntb_mw_set_trans, 757e099b45bSLogan Gunthorpe .peer_mw_count = switchtec_ntb_peer_mw_count, 758e099b45bSLogan Gunthorpe .peer_mw_get_addr = switchtec_ntb_peer_mw_get_addr, 759e099b45bSLogan Gunthorpe .link_is_up = switchtec_ntb_link_is_up, 760e099b45bSLogan Gunthorpe .link_enable = switchtec_ntb_link_enable, 761e099b45bSLogan Gunthorpe .link_disable = switchtec_ntb_link_disable, 762e099b45bSLogan Gunthorpe .db_valid_mask = switchtec_ntb_db_valid_mask, 763e099b45bSLogan Gunthorpe .db_vector_count = switchtec_ntb_db_vector_count, 764e099b45bSLogan Gunthorpe .db_vector_mask = switchtec_ntb_db_vector_mask, 765e099b45bSLogan Gunthorpe .db_read = switchtec_ntb_db_read, 766e099b45bSLogan Gunthorpe .db_clear = switchtec_ntb_db_clear, 767e099b45bSLogan Gunthorpe .db_set_mask = switchtec_ntb_db_set_mask, 768e099b45bSLogan Gunthorpe .db_clear_mask = switchtec_ntb_db_clear_mask, 7696619bf95SLogan Gunthorpe .db_read_mask = switchtec_ntb_db_read_mask, 7706619bf95SLogan Gunthorpe .peer_db_addr = switchtec_ntb_peer_db_addr, 771e099b45bSLogan Gunthorpe .peer_db_set = switchtec_ntb_peer_db_set, 772e099b45bSLogan Gunthorpe .spad_count = switchtec_ntb_spad_count, 773e099b45bSLogan Gunthorpe .spad_read = switchtec_ntb_spad_read, 774e099b45bSLogan Gunthorpe .spad_write = switchtec_ntb_spad_write, 775b9a4acacSLogan Gunthorpe .peer_spad_read = switchtec_ntb_peer_spad_read, 776e099b45bSLogan Gunthorpe .peer_spad_write = switchtec_ntb_peer_spad_write, 777b9a4acacSLogan Gunthorpe .peer_spad_addr = switchtec_ntb_peer_spad_addr, 778e099b45bSLogan Gunthorpe }; 779e099b45bSLogan Gunthorpe 780ec0467ccSLogan Gunthorpe static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) 781ec0467ccSLogan Gunthorpe { 782ec0467ccSLogan Gunthorpe u64 part_map; 783ec0467ccSLogan Gunthorpe 784e099b45bSLogan Gunthorpe sndev->ntb.pdev = sndev->stdev->pdev; 785e099b45bSLogan Gunthorpe sndev->ntb.topo = NTB_TOPO_SWITCH; 786e099b45bSLogan Gunthorpe sndev->ntb.ops = &switchtec_ntb_ops; 787e099b45bSLogan Gunthorpe 788ec0467ccSLogan Gunthorpe sndev->self_partition = sndev->stdev->partition; 789ec0467ccSLogan Gunthorpe 790ec0467ccSLogan Gunthorpe sndev->mmio_ntb = sndev->stdev->mmio_ntb; 791ec0467ccSLogan Gunthorpe part_map = ioread64(&sndev->mmio_ntb->ep_map); 792ec0467ccSLogan Gunthorpe part_map &= ~(1 << sndev->self_partition); 793ec0467ccSLogan Gunthorpe sndev->peer_partition = ffs(part_map) - 1; 794ec0467ccSLogan Gunthorpe 795ec0467ccSLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d (%llx)", 796ec0467ccSLogan Gunthorpe sndev->self_partition, sndev->stdev->partition_count, 797ec0467ccSLogan Gunthorpe part_map); 798ec0467ccSLogan Gunthorpe 799ec0467ccSLogan Gunthorpe sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb + 800ec0467ccSLogan Gunthorpe SWITCHTEC_NTB_REG_CTRL_OFFSET; 801ec0467ccSLogan Gunthorpe sndev->mmio_dbmsg = (void * __iomem)sndev->mmio_ntb + 802ec0467ccSLogan Gunthorpe SWITCHTEC_NTB_REG_DBMSG_OFFSET; 803ec0467ccSLogan Gunthorpe 804ec0467ccSLogan Gunthorpe sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition]; 805ec0467ccSLogan Gunthorpe sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition]; 806ec0467ccSLogan Gunthorpe sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition]; 807ec0467ccSLogan Gunthorpe } 808ec0467ccSLogan Gunthorpe 809ec0467ccSLogan Gunthorpe static int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl) 810ec0467ccSLogan Gunthorpe { 811ec0467ccSLogan Gunthorpe int i; 812ec0467ccSLogan Gunthorpe int cnt = 0; 813ec0467ccSLogan Gunthorpe 814ec0467ccSLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(ctrl->bar_entry); i++) { 815ec0467ccSLogan Gunthorpe u32 r = ioread32(&ctrl->bar_entry[i].ctl); 816ec0467ccSLogan Gunthorpe 817ec0467ccSLogan Gunthorpe if (r & NTB_CTRL_BAR_VALID) 818ec0467ccSLogan Gunthorpe map[cnt++] = i; 819ec0467ccSLogan Gunthorpe } 820ec0467ccSLogan Gunthorpe 821ec0467ccSLogan Gunthorpe return cnt; 822ec0467ccSLogan Gunthorpe } 823ec0467ccSLogan Gunthorpe 824ec0467ccSLogan Gunthorpe static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev) 825ec0467ccSLogan Gunthorpe { 826ec0467ccSLogan Gunthorpe sndev->nr_direct_mw = map_bars(sndev->direct_mw_to_bar, 827ec0467ccSLogan Gunthorpe sndev->mmio_self_ctrl); 828ec0467ccSLogan Gunthorpe 829ec0467ccSLogan Gunthorpe sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries); 830ec0467ccSLogan Gunthorpe sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw); 831ec0467ccSLogan Gunthorpe 832ec0467ccSLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut", 833ec0467ccSLogan Gunthorpe sndev->nr_direct_mw, sndev->nr_lut_mw); 834ec0467ccSLogan Gunthorpe 835ec0467ccSLogan Gunthorpe sndev->peer_nr_direct_mw = map_bars(sndev->peer_direct_mw_to_bar, 836ec0467ccSLogan Gunthorpe sndev->mmio_peer_ctrl); 837ec0467ccSLogan Gunthorpe 838ec0467ccSLogan Gunthorpe sndev->peer_nr_lut_mw = 839ec0467ccSLogan Gunthorpe ioread16(&sndev->mmio_peer_ctrl->lut_table_entries); 840ec0467ccSLogan Gunthorpe sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw); 841ec0467ccSLogan Gunthorpe 842ec0467ccSLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut", 843ec0467ccSLogan Gunthorpe sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw); 844ec0467ccSLogan Gunthorpe 845ec0467ccSLogan Gunthorpe } 846ec0467ccSLogan Gunthorpe 8473dd4db47SLogan Gunthorpe /* 8483dd4db47SLogan Gunthorpe * There are 64 doorbells in the switch hardware but this is 8493dd4db47SLogan Gunthorpe * shared among all partitions. So we must split them in half 8503dd4db47SLogan Gunthorpe * (32 for each partition). However, the message interrupts are 8513dd4db47SLogan Gunthorpe * also shared with the top 4 doorbells so we just limit this to 8523dd4db47SLogan Gunthorpe * 28 doorbells per partition 8533dd4db47SLogan Gunthorpe */ 8543dd4db47SLogan Gunthorpe static void switchtec_ntb_init_db(struct switchtec_ntb *sndev) 8553dd4db47SLogan Gunthorpe { 8563dd4db47SLogan Gunthorpe sndev->db_valid_mask = 0x0FFFFFFF; 8573dd4db47SLogan Gunthorpe 8583dd4db47SLogan Gunthorpe if (sndev->self_partition < sndev->peer_partition) { 8593dd4db47SLogan Gunthorpe sndev->db_shift = 0; 8603dd4db47SLogan Gunthorpe sndev->db_peer_shift = 32; 8613dd4db47SLogan Gunthorpe } else { 8623dd4db47SLogan Gunthorpe sndev->db_shift = 32; 8633dd4db47SLogan Gunthorpe sndev->db_peer_shift = 0; 8643dd4db47SLogan Gunthorpe } 8653dd4db47SLogan Gunthorpe 8663dd4db47SLogan Gunthorpe sndev->db_mask = 0x0FFFFFFFFFFFFFFFULL; 8673dd4db47SLogan Gunthorpe iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 8683dd4db47SLogan Gunthorpe iowrite64(sndev->db_valid_mask << sndev->db_peer_shift, 8693dd4db47SLogan Gunthorpe &sndev->mmio_self_dbmsg->odb_mask); 8703dd4db47SLogan Gunthorpe } 8713dd4db47SLogan Gunthorpe 8723dd4db47SLogan Gunthorpe static void switchtec_ntb_init_msgs(struct switchtec_ntb *sndev) 8733dd4db47SLogan Gunthorpe { 8743dd4db47SLogan Gunthorpe int i; 8753dd4db47SLogan Gunthorpe u32 msg_map = 0; 8763dd4db47SLogan Gunthorpe 8773dd4db47SLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) { 8783dd4db47SLogan Gunthorpe int m = i | sndev->peer_partition << 2; 8793dd4db47SLogan Gunthorpe 8803dd4db47SLogan Gunthorpe msg_map |= m << i * 8; 8813dd4db47SLogan Gunthorpe } 8823dd4db47SLogan Gunthorpe 8833dd4db47SLogan Gunthorpe iowrite32(msg_map, &sndev->mmio_self_dbmsg->msg_map); 8843dd4db47SLogan Gunthorpe 8853dd4db47SLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) 8863dd4db47SLogan Gunthorpe iowrite64(NTB_DBMSG_IMSG_STATUS | NTB_DBMSG_IMSG_MASK, 8873dd4db47SLogan Gunthorpe &sndev->mmio_self_dbmsg->imsg[i]); 8883dd4db47SLogan Gunthorpe } 8893dd4db47SLogan Gunthorpe 890ec0467ccSLogan Gunthorpe static int switchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev) 891ec0467ccSLogan Gunthorpe { 892ec0467ccSLogan Gunthorpe int rc = 0; 893ec0467ccSLogan Gunthorpe u16 req_id; 894ec0467ccSLogan Gunthorpe u32 error; 895ec0467ccSLogan Gunthorpe 896ec0467ccSLogan Gunthorpe req_id = ioread16(&sndev->mmio_ntb->requester_id); 897ec0467ccSLogan Gunthorpe 898ec0467ccSLogan Gunthorpe if (ioread32(&sndev->mmio_self_ctrl->req_id_table_size) < 2) { 899ec0467ccSLogan Gunthorpe dev_err(&sndev->stdev->dev, 900ec0467ccSLogan Gunthorpe "Not enough requester IDs available."); 901ec0467ccSLogan Gunthorpe return -EFAULT; 902ec0467ccSLogan Gunthorpe } 903ec0467ccSLogan Gunthorpe 904ec0467ccSLogan Gunthorpe rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl, 905ec0467ccSLogan Gunthorpe NTB_CTRL_PART_OP_LOCK, 906ec0467ccSLogan Gunthorpe NTB_CTRL_PART_STATUS_LOCKED); 907ec0467ccSLogan Gunthorpe if (rc) 908ec0467ccSLogan Gunthorpe return rc; 909ec0467ccSLogan Gunthorpe 910ec0467ccSLogan Gunthorpe iowrite32(NTB_PART_CTRL_ID_PROT_DIS, 911ec0467ccSLogan Gunthorpe &sndev->mmio_self_ctrl->partition_ctrl); 912ec0467ccSLogan Gunthorpe 913ec0467ccSLogan Gunthorpe /* 914ec0467ccSLogan Gunthorpe * Root Complex Requester ID (which is 0:00.0) 915ec0467ccSLogan Gunthorpe */ 916ec0467ccSLogan Gunthorpe iowrite32(0 << 16 | NTB_CTRL_REQ_ID_EN, 917ec0467ccSLogan Gunthorpe &sndev->mmio_self_ctrl->req_id_table[0]); 918ec0467ccSLogan Gunthorpe 919ec0467ccSLogan Gunthorpe /* 920ec0467ccSLogan Gunthorpe * Host Bridge Requester ID (as read from the mmap address) 921ec0467ccSLogan Gunthorpe */ 922ec0467ccSLogan Gunthorpe iowrite32(req_id << 16 | NTB_CTRL_REQ_ID_EN, 923ec0467ccSLogan Gunthorpe &sndev->mmio_self_ctrl->req_id_table[1]); 924ec0467ccSLogan Gunthorpe 925ec0467ccSLogan Gunthorpe rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl, 926ec0467ccSLogan Gunthorpe NTB_CTRL_PART_OP_CFG, 927ec0467ccSLogan Gunthorpe NTB_CTRL_PART_STATUS_NORMAL); 928ec0467ccSLogan Gunthorpe if (rc == -EIO) { 929ec0467ccSLogan Gunthorpe error = ioread32(&sndev->mmio_self_ctrl->req_id_error); 930ec0467ccSLogan Gunthorpe dev_err(&sndev->stdev->dev, 931ec0467ccSLogan Gunthorpe "Error setting up the requester ID table: %08x", 932ec0467ccSLogan Gunthorpe error); 933ec0467ccSLogan Gunthorpe } 934ec0467ccSLogan Gunthorpe 935ec0467ccSLogan Gunthorpe return rc; 936ec0467ccSLogan Gunthorpe } 937ec0467ccSLogan Gunthorpe 938ec0467ccSLogan Gunthorpe static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev) 939ec0467ccSLogan Gunthorpe { 940ec0467ccSLogan Gunthorpe int i; 941ec0467ccSLogan Gunthorpe 942ec0467ccSLogan Gunthorpe memset(sndev->self_shared, 0, LUT_SIZE); 943ec0467ccSLogan Gunthorpe sndev->self_shared->magic = SWITCHTEC_NTB_MAGIC; 944ec0467ccSLogan Gunthorpe sndev->self_shared->partition_id = sndev->stdev->partition; 945ec0467ccSLogan Gunthorpe 946ec0467ccSLogan Gunthorpe for (i = 0; i < sndev->nr_direct_mw; i++) { 947ec0467ccSLogan Gunthorpe int bar = sndev->direct_mw_to_bar[i]; 948ec0467ccSLogan Gunthorpe resource_size_t sz = pci_resource_len(sndev->stdev->pdev, bar); 949ec0467ccSLogan Gunthorpe 950ec0467ccSLogan Gunthorpe if (i == 0) 951ec0467ccSLogan Gunthorpe sz = min_t(resource_size_t, sz, 952ec0467ccSLogan Gunthorpe LUT_SIZE * sndev->nr_lut_mw); 953ec0467ccSLogan Gunthorpe 954ec0467ccSLogan Gunthorpe sndev->self_shared->mw_sizes[i] = sz; 955ec0467ccSLogan Gunthorpe } 956ec0467ccSLogan Gunthorpe 957ec0467ccSLogan Gunthorpe for (i = 0; i < sndev->nr_lut_mw; i++) { 958ec0467ccSLogan Gunthorpe int idx = sndev->nr_direct_mw + i; 959ec0467ccSLogan Gunthorpe 960ec0467ccSLogan Gunthorpe sndev->self_shared->mw_sizes[idx] = LUT_SIZE; 961ec0467ccSLogan Gunthorpe } 962ec0467ccSLogan Gunthorpe } 963ec0467ccSLogan Gunthorpe 964ec0467ccSLogan Gunthorpe static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) 965ec0467ccSLogan Gunthorpe { 966ec0467ccSLogan Gunthorpe struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 967*140eb522SDoug Meyer int self_bar = sndev->direct_mw_to_bar[0]; 968*140eb522SDoug Meyer int peer_bar = sndev->peer_direct_mw_to_bar[0]; 969ec0467ccSLogan Gunthorpe u32 ctl_val; 970ec0467ccSLogan Gunthorpe int rc; 971ec0467ccSLogan Gunthorpe 972ec0467ccSLogan Gunthorpe sndev->self_shared = dma_zalloc_coherent(&sndev->stdev->pdev->dev, 973ec0467ccSLogan Gunthorpe LUT_SIZE, 974ec0467ccSLogan Gunthorpe &sndev->self_shared_dma, 975ec0467ccSLogan Gunthorpe GFP_KERNEL); 976ec0467ccSLogan Gunthorpe if (!sndev->self_shared) { 977ec0467ccSLogan Gunthorpe dev_err(&sndev->stdev->dev, 978ec0467ccSLogan Gunthorpe "unable to allocate memory for shared mw"); 979ec0467ccSLogan Gunthorpe return -ENOMEM; 980ec0467ccSLogan Gunthorpe } 981ec0467ccSLogan Gunthorpe 982ec0467ccSLogan Gunthorpe switchtec_ntb_init_shared(sndev); 983ec0467ccSLogan Gunthorpe 984ec0467ccSLogan Gunthorpe rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, 985ec0467ccSLogan Gunthorpe NTB_CTRL_PART_STATUS_LOCKED); 986ec0467ccSLogan Gunthorpe if (rc) 987ec0467ccSLogan Gunthorpe goto unalloc_and_exit; 988ec0467ccSLogan Gunthorpe 989*140eb522SDoug Meyer ctl_val = ioread32(&ctl->bar_entry[peer_bar].ctl); 990ec0467ccSLogan Gunthorpe ctl_val &= 0xFF; 991ec0467ccSLogan Gunthorpe ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN; 992ec0467ccSLogan Gunthorpe ctl_val |= ilog2(LUT_SIZE) << 8; 993ec0467ccSLogan Gunthorpe ctl_val |= (sndev->nr_lut_mw - 1) << 14; 994*140eb522SDoug Meyer iowrite32(ctl_val, &ctl->bar_entry[peer_bar].ctl); 995ec0467ccSLogan Gunthorpe 996ec0467ccSLogan Gunthorpe iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | 997ec0467ccSLogan Gunthorpe sndev->self_shared_dma), 998ec0467ccSLogan Gunthorpe &ctl->lut_entry[0]); 999ec0467ccSLogan Gunthorpe 1000ec0467ccSLogan Gunthorpe rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 1001ec0467ccSLogan Gunthorpe NTB_CTRL_PART_STATUS_NORMAL); 1002ec0467ccSLogan Gunthorpe if (rc) { 1003ec0467ccSLogan Gunthorpe u32 bar_error, lut_error; 1004ec0467ccSLogan Gunthorpe 1005ec0467ccSLogan Gunthorpe bar_error = ioread32(&ctl->bar_error); 1006ec0467ccSLogan Gunthorpe lut_error = ioread32(&ctl->lut_error); 1007ec0467ccSLogan Gunthorpe dev_err(&sndev->stdev->dev, 1008ec0467ccSLogan Gunthorpe "Error setting up shared MW: %08x / %08x", 1009ec0467ccSLogan Gunthorpe bar_error, lut_error); 1010ec0467ccSLogan Gunthorpe goto unalloc_and_exit; 1011ec0467ccSLogan Gunthorpe } 1012ec0467ccSLogan Gunthorpe 1013*140eb522SDoug Meyer sndev->peer_shared = pci_iomap(sndev->stdev->pdev, self_bar, LUT_SIZE); 1014ec0467ccSLogan Gunthorpe if (!sndev->peer_shared) { 1015ec0467ccSLogan Gunthorpe rc = -ENOMEM; 1016ec0467ccSLogan Gunthorpe goto unalloc_and_exit; 1017ec0467ccSLogan Gunthorpe } 1018ec0467ccSLogan Gunthorpe 1019ec0467ccSLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "Shared MW Ready"); 1020ec0467ccSLogan Gunthorpe return 0; 1021ec0467ccSLogan Gunthorpe 1022ec0467ccSLogan Gunthorpe unalloc_and_exit: 1023ec0467ccSLogan Gunthorpe dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, 1024ec0467ccSLogan Gunthorpe sndev->self_shared, sndev->self_shared_dma); 1025ec0467ccSLogan Gunthorpe 1026ec0467ccSLogan Gunthorpe return rc; 1027ec0467ccSLogan Gunthorpe } 1028ec0467ccSLogan Gunthorpe 1029ec0467ccSLogan Gunthorpe static void switchtec_ntb_deinit_shared_mw(struct switchtec_ntb *sndev) 1030ec0467ccSLogan Gunthorpe { 1031ec0467ccSLogan Gunthorpe if (sndev->peer_shared) 1032ec0467ccSLogan Gunthorpe pci_iounmap(sndev->stdev->pdev, sndev->peer_shared); 1033ec0467ccSLogan Gunthorpe 1034ec0467ccSLogan Gunthorpe if (sndev->self_shared) 1035ec0467ccSLogan Gunthorpe dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, 1036ec0467ccSLogan Gunthorpe sndev->self_shared, 1037ec0467ccSLogan Gunthorpe sndev->self_shared_dma); 1038ec0467ccSLogan Gunthorpe } 1039ec0467ccSLogan Gunthorpe 10403dd4db47SLogan Gunthorpe static irqreturn_t switchtec_ntb_doorbell_isr(int irq, void *dev) 10413dd4db47SLogan Gunthorpe { 10423dd4db47SLogan Gunthorpe struct switchtec_ntb *sndev = dev; 10433dd4db47SLogan Gunthorpe 10443dd4db47SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "doorbell\n"); 10453dd4db47SLogan Gunthorpe 10466619bf95SLogan Gunthorpe ntb_db_event(&sndev->ntb, 0); 10476619bf95SLogan Gunthorpe 10483dd4db47SLogan Gunthorpe return IRQ_HANDLED; 10493dd4db47SLogan Gunthorpe } 10503dd4db47SLogan Gunthorpe 10513dd4db47SLogan Gunthorpe static irqreturn_t switchtec_ntb_message_isr(int irq, void *dev) 10523dd4db47SLogan Gunthorpe { 10533dd4db47SLogan Gunthorpe int i; 10543dd4db47SLogan Gunthorpe struct switchtec_ntb *sndev = dev; 10553dd4db47SLogan Gunthorpe 10563dd4db47SLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) { 10573dd4db47SLogan Gunthorpe u64 msg = ioread64(&sndev->mmio_self_dbmsg->imsg[i]); 10583dd4db47SLogan Gunthorpe 10593dd4db47SLogan Gunthorpe if (msg & NTB_DBMSG_IMSG_STATUS) { 10603dd4db47SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", i, 10613dd4db47SLogan Gunthorpe (u32)msg); 10623dd4db47SLogan Gunthorpe iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status); 10630ee28f26SLogan Gunthorpe 10640ee28f26SLogan Gunthorpe if (i == LINK_MESSAGE) 10650ee28f26SLogan Gunthorpe switchtec_ntb_check_link(sndev); 10663dd4db47SLogan Gunthorpe } 10673dd4db47SLogan Gunthorpe } 10683dd4db47SLogan Gunthorpe 10693dd4db47SLogan Gunthorpe return IRQ_HANDLED; 10703dd4db47SLogan Gunthorpe } 10713dd4db47SLogan Gunthorpe 10723dd4db47SLogan Gunthorpe static int switchtec_ntb_init_db_msg_irq(struct switchtec_ntb *sndev) 10733dd4db47SLogan Gunthorpe { 10743dd4db47SLogan Gunthorpe int i; 10753dd4db47SLogan Gunthorpe int rc; 10763dd4db47SLogan Gunthorpe int doorbell_irq = 0; 10773dd4db47SLogan Gunthorpe int message_irq = 0; 10783dd4db47SLogan Gunthorpe int event_irq; 10793dd4db47SLogan Gunthorpe int idb_vecs = sizeof(sndev->mmio_self_dbmsg->idb_vec_map); 10803dd4db47SLogan Gunthorpe 10813dd4db47SLogan Gunthorpe event_irq = ioread32(&sndev->stdev->mmio_part_cfg->vep_vector_number); 10823dd4db47SLogan Gunthorpe 10833dd4db47SLogan Gunthorpe while (doorbell_irq == event_irq) 10843dd4db47SLogan Gunthorpe doorbell_irq++; 10853dd4db47SLogan Gunthorpe while (message_irq == doorbell_irq || 10863dd4db47SLogan Gunthorpe message_irq == event_irq) 10873dd4db47SLogan Gunthorpe message_irq++; 10883dd4db47SLogan Gunthorpe 10893dd4db47SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "irqs - event: %d, db: %d, msgs: %d", 10903dd4db47SLogan Gunthorpe event_irq, doorbell_irq, message_irq); 10913dd4db47SLogan Gunthorpe 10923dd4db47SLogan Gunthorpe for (i = 0; i < idb_vecs - 4; i++) 10933dd4db47SLogan Gunthorpe iowrite8(doorbell_irq, 10943dd4db47SLogan Gunthorpe &sndev->mmio_self_dbmsg->idb_vec_map[i]); 10953dd4db47SLogan Gunthorpe 10963dd4db47SLogan Gunthorpe for (; i < idb_vecs; i++) 10973dd4db47SLogan Gunthorpe iowrite8(message_irq, 10983dd4db47SLogan Gunthorpe &sndev->mmio_self_dbmsg->idb_vec_map[i]); 10993dd4db47SLogan Gunthorpe 11003dd4db47SLogan Gunthorpe sndev->doorbell_irq = pci_irq_vector(sndev->stdev->pdev, doorbell_irq); 11013dd4db47SLogan Gunthorpe sndev->message_irq = pci_irq_vector(sndev->stdev->pdev, message_irq); 11023dd4db47SLogan Gunthorpe 11033dd4db47SLogan Gunthorpe rc = request_irq(sndev->doorbell_irq, 11043dd4db47SLogan Gunthorpe switchtec_ntb_doorbell_isr, 0, 11053dd4db47SLogan Gunthorpe "switchtec_ntb_doorbell", sndev); 11063dd4db47SLogan Gunthorpe if (rc) 11073dd4db47SLogan Gunthorpe return rc; 11083dd4db47SLogan Gunthorpe 11093dd4db47SLogan Gunthorpe rc = request_irq(sndev->message_irq, 11103dd4db47SLogan Gunthorpe switchtec_ntb_message_isr, 0, 11113dd4db47SLogan Gunthorpe "switchtec_ntb_message", sndev); 11123dd4db47SLogan Gunthorpe if (rc) { 11133dd4db47SLogan Gunthorpe free_irq(sndev->doorbell_irq, sndev); 11143dd4db47SLogan Gunthorpe return rc; 11153dd4db47SLogan Gunthorpe } 11163dd4db47SLogan Gunthorpe 11173dd4db47SLogan Gunthorpe return 0; 11183dd4db47SLogan Gunthorpe } 11193dd4db47SLogan Gunthorpe 11203dd4db47SLogan Gunthorpe static void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev) 11213dd4db47SLogan Gunthorpe { 11223dd4db47SLogan Gunthorpe free_irq(sndev->doorbell_irq, sndev); 11233dd4db47SLogan Gunthorpe free_irq(sndev->message_irq, sndev); 11243dd4db47SLogan Gunthorpe } 11253dd4db47SLogan Gunthorpe 112633dea5aaSLogan Gunthorpe static int switchtec_ntb_add(struct device *dev, 112733dea5aaSLogan Gunthorpe struct class_interface *class_intf) 112833dea5aaSLogan Gunthorpe { 112933dea5aaSLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 113033dea5aaSLogan Gunthorpe struct switchtec_ntb *sndev; 1131ec0467ccSLogan Gunthorpe int rc; 113233dea5aaSLogan Gunthorpe 113333dea5aaSLogan Gunthorpe stdev->sndev = NULL; 113433dea5aaSLogan Gunthorpe 113533dea5aaSLogan Gunthorpe if (stdev->pdev->class != MICROSEMI_NTB_CLASSCODE) 113633dea5aaSLogan Gunthorpe return -ENODEV; 113733dea5aaSLogan Gunthorpe 1138ec0467ccSLogan Gunthorpe if (stdev->partition_count != 2) 1139ec0467ccSLogan Gunthorpe dev_warn(dev, "ntb driver only supports 2 partitions"); 1140ec0467ccSLogan Gunthorpe 114133dea5aaSLogan Gunthorpe sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev)); 114233dea5aaSLogan Gunthorpe if (!sndev) 114333dea5aaSLogan Gunthorpe return -ENOMEM; 114433dea5aaSLogan Gunthorpe 114533dea5aaSLogan Gunthorpe sndev->stdev = stdev; 1146ec0467ccSLogan Gunthorpe switchtec_ntb_init_sndev(sndev); 1147ec0467ccSLogan Gunthorpe switchtec_ntb_init_mw(sndev); 11483dd4db47SLogan Gunthorpe switchtec_ntb_init_db(sndev); 11493dd4db47SLogan Gunthorpe switchtec_ntb_init_msgs(sndev); 1150ec0467ccSLogan Gunthorpe 1151ec0467ccSLogan Gunthorpe rc = switchtec_ntb_init_req_id_table(sndev); 1152ec0467ccSLogan Gunthorpe if (rc) 1153ec0467ccSLogan Gunthorpe goto free_and_exit; 1154ec0467ccSLogan Gunthorpe 1155ec0467ccSLogan Gunthorpe rc = switchtec_ntb_init_shared_mw(sndev); 1156ec0467ccSLogan Gunthorpe if (rc) 1157ec0467ccSLogan Gunthorpe goto free_and_exit; 1158ec0467ccSLogan Gunthorpe 11593dd4db47SLogan Gunthorpe rc = switchtec_ntb_init_db_msg_irq(sndev); 11603dd4db47SLogan Gunthorpe if (rc) 11613dd4db47SLogan Gunthorpe goto deinit_shared_and_exit; 11623dd4db47SLogan Gunthorpe 1163e099b45bSLogan Gunthorpe rc = ntb_register_device(&sndev->ntb); 1164e099b45bSLogan Gunthorpe if (rc) 1165e099b45bSLogan Gunthorpe goto deinit_and_exit; 1166e099b45bSLogan Gunthorpe 116733dea5aaSLogan Gunthorpe stdev->sndev = sndev; 11680ee28f26SLogan Gunthorpe stdev->link_notifier = switchtec_ntb_link_notification; 116933dea5aaSLogan Gunthorpe dev_info(dev, "NTB device registered"); 117033dea5aaSLogan Gunthorpe 117133dea5aaSLogan Gunthorpe return 0; 1172ec0467ccSLogan Gunthorpe 1173e099b45bSLogan Gunthorpe deinit_and_exit: 1174e099b45bSLogan Gunthorpe switchtec_ntb_deinit_db_msg_irq(sndev); 11753dd4db47SLogan Gunthorpe deinit_shared_and_exit: 11763dd4db47SLogan Gunthorpe switchtec_ntb_deinit_shared_mw(sndev); 1177ec0467ccSLogan Gunthorpe free_and_exit: 1178ec0467ccSLogan Gunthorpe kfree(sndev); 1179ec0467ccSLogan Gunthorpe dev_err(dev, "failed to register ntb device: %d", rc); 1180ec0467ccSLogan Gunthorpe return rc; 118133dea5aaSLogan Gunthorpe } 118233dea5aaSLogan Gunthorpe 118333dea5aaSLogan Gunthorpe void switchtec_ntb_remove(struct device *dev, 118433dea5aaSLogan Gunthorpe struct class_interface *class_intf) 118533dea5aaSLogan Gunthorpe { 118633dea5aaSLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 118733dea5aaSLogan Gunthorpe struct switchtec_ntb *sndev = stdev->sndev; 118833dea5aaSLogan Gunthorpe 118933dea5aaSLogan Gunthorpe if (!sndev) 119033dea5aaSLogan Gunthorpe return; 119133dea5aaSLogan Gunthorpe 11920ee28f26SLogan Gunthorpe stdev->link_notifier = NULL; 119333dea5aaSLogan Gunthorpe stdev->sndev = NULL; 1194e099b45bSLogan Gunthorpe ntb_unregister_device(&sndev->ntb); 11953dd4db47SLogan Gunthorpe switchtec_ntb_deinit_db_msg_irq(sndev); 1196ec0467ccSLogan Gunthorpe switchtec_ntb_deinit_shared_mw(sndev); 119733dea5aaSLogan Gunthorpe kfree(sndev); 119833dea5aaSLogan Gunthorpe dev_info(dev, "ntb device unregistered"); 119933dea5aaSLogan Gunthorpe } 120033dea5aaSLogan Gunthorpe 120133dea5aaSLogan Gunthorpe static struct class_interface switchtec_interface = { 120233dea5aaSLogan Gunthorpe .add_dev = switchtec_ntb_add, 120333dea5aaSLogan Gunthorpe .remove_dev = switchtec_ntb_remove, 120433dea5aaSLogan Gunthorpe }; 120533dea5aaSLogan Gunthorpe 120633dea5aaSLogan Gunthorpe static int __init switchtec_ntb_init(void) 120733dea5aaSLogan Gunthorpe { 120833dea5aaSLogan Gunthorpe switchtec_interface.class = switchtec_class; 120933dea5aaSLogan Gunthorpe return class_interface_register(&switchtec_interface); 121033dea5aaSLogan Gunthorpe } 121133dea5aaSLogan Gunthorpe module_init(switchtec_ntb_init); 121233dea5aaSLogan Gunthorpe 121333dea5aaSLogan Gunthorpe static void __exit switchtec_ntb_exit(void) 121433dea5aaSLogan Gunthorpe { 121533dea5aaSLogan Gunthorpe class_interface_unregister(&switchtec_interface); 121633dea5aaSLogan Gunthorpe } 121733dea5aaSLogan Gunthorpe module_exit(switchtec_ntb_exit); 1218