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 28ec0467ccSLogan Gunthorpe static bool use_lut_mws; 29ec0467ccSLogan Gunthorpe module_param(use_lut_mws, bool, 0644); 30ec0467ccSLogan Gunthorpe MODULE_PARM_DESC(use_lut_mws, 31ec0467ccSLogan Gunthorpe "Enable the use of the LUT based memory windows"); 32ec0467ccSLogan Gunthorpe 33ec0467ccSLogan Gunthorpe #ifndef ioread64 34ec0467ccSLogan Gunthorpe #ifdef readq 35ec0467ccSLogan Gunthorpe #define ioread64 readq 36ec0467ccSLogan Gunthorpe #else 37ec0467ccSLogan Gunthorpe #define ioread64 _ioread64 38ec0467ccSLogan Gunthorpe static inline u64 _ioread64(void __iomem *mmio) 39ec0467ccSLogan Gunthorpe { 40ec0467ccSLogan Gunthorpe u64 low, high; 41ec0467ccSLogan Gunthorpe 42ec0467ccSLogan Gunthorpe low = ioread32(mmio); 43ec0467ccSLogan Gunthorpe high = ioread32(mmio + sizeof(u32)); 44ec0467ccSLogan Gunthorpe return low | (high << 32); 45ec0467ccSLogan Gunthorpe } 46ec0467ccSLogan Gunthorpe #endif 47ec0467ccSLogan Gunthorpe #endif 48ec0467ccSLogan Gunthorpe 49ec0467ccSLogan Gunthorpe #ifndef iowrite64 50ec0467ccSLogan Gunthorpe #ifdef writeq 51ec0467ccSLogan Gunthorpe #define iowrite64 writeq 52ec0467ccSLogan Gunthorpe #else 53ec0467ccSLogan Gunthorpe #define iowrite64 _iowrite64 54ec0467ccSLogan Gunthorpe static inline void _iowrite64(u64 val, void __iomem *mmio) 55ec0467ccSLogan Gunthorpe { 56ec0467ccSLogan Gunthorpe iowrite32(val, mmio); 57ec0467ccSLogan Gunthorpe iowrite32(val >> 32, mmio + sizeof(u32)); 58ec0467ccSLogan Gunthorpe } 59ec0467ccSLogan Gunthorpe #endif 60ec0467ccSLogan Gunthorpe #endif 61ec0467ccSLogan Gunthorpe 62ec0467ccSLogan Gunthorpe #define SWITCHTEC_NTB_MAGIC 0x45CC0001 63ec0467ccSLogan Gunthorpe #define MAX_MWS 128 64ec0467ccSLogan Gunthorpe 65ec0467ccSLogan Gunthorpe struct shared_mw { 66ec0467ccSLogan Gunthorpe u32 magic; 670ee28f26SLogan Gunthorpe u32 link_sta; 68ec0467ccSLogan Gunthorpe u32 partition_id; 69ec0467ccSLogan Gunthorpe u64 mw_sizes[MAX_MWS]; 70*b9a4acacSLogan Gunthorpe u32 spad[128]; 71ec0467ccSLogan Gunthorpe }; 72ec0467ccSLogan Gunthorpe 73ec0467ccSLogan Gunthorpe #define MAX_DIRECT_MW ARRAY_SIZE(((struct ntb_ctrl_regs *)(0))->bar_entry) 74ec0467ccSLogan Gunthorpe #define LUT_SIZE SZ_64K 75ec0467ccSLogan Gunthorpe 7633dea5aaSLogan Gunthorpe struct switchtec_ntb { 77e099b45bSLogan Gunthorpe struct ntb_dev ntb; 7833dea5aaSLogan Gunthorpe struct switchtec_dev *stdev; 79ec0467ccSLogan Gunthorpe 80ec0467ccSLogan Gunthorpe int self_partition; 81ec0467ccSLogan Gunthorpe int peer_partition; 82ec0467ccSLogan Gunthorpe 833dd4db47SLogan Gunthorpe int doorbell_irq; 843dd4db47SLogan Gunthorpe int message_irq; 853dd4db47SLogan Gunthorpe 86ec0467ccSLogan Gunthorpe struct ntb_info_regs __iomem *mmio_ntb; 87ec0467ccSLogan Gunthorpe struct ntb_ctrl_regs __iomem *mmio_ctrl; 88ec0467ccSLogan Gunthorpe struct ntb_dbmsg_regs __iomem *mmio_dbmsg; 89ec0467ccSLogan Gunthorpe struct ntb_ctrl_regs __iomem *mmio_self_ctrl; 90ec0467ccSLogan Gunthorpe struct ntb_ctrl_regs __iomem *mmio_peer_ctrl; 91ec0467ccSLogan Gunthorpe struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg; 92ec0467ccSLogan Gunthorpe 93ec0467ccSLogan Gunthorpe struct shared_mw *self_shared; 94ec0467ccSLogan Gunthorpe struct shared_mw __iomem *peer_shared; 95ec0467ccSLogan Gunthorpe dma_addr_t self_shared_dma; 96ec0467ccSLogan Gunthorpe 973dd4db47SLogan Gunthorpe u64 db_mask; 983dd4db47SLogan Gunthorpe u64 db_valid_mask; 993dd4db47SLogan Gunthorpe int db_shift; 1003dd4db47SLogan Gunthorpe int db_peer_shift; 1013dd4db47SLogan Gunthorpe 1026619bf95SLogan Gunthorpe /* synchronize rmw access of db_mask and hw reg */ 1036619bf95SLogan Gunthorpe spinlock_t db_mask_lock; 1046619bf95SLogan Gunthorpe 105ec0467ccSLogan Gunthorpe int nr_direct_mw; 106ec0467ccSLogan Gunthorpe int nr_lut_mw; 107ec0467ccSLogan Gunthorpe int direct_mw_to_bar[MAX_DIRECT_MW]; 108ec0467ccSLogan Gunthorpe 109ec0467ccSLogan Gunthorpe int peer_nr_direct_mw; 110ec0467ccSLogan Gunthorpe int peer_nr_lut_mw; 111ec0467ccSLogan Gunthorpe int peer_direct_mw_to_bar[MAX_DIRECT_MW]; 1120ee28f26SLogan Gunthorpe 1130ee28f26SLogan Gunthorpe bool link_is_up; 1140ee28f26SLogan Gunthorpe enum ntb_speed link_speed; 1150ee28f26SLogan Gunthorpe enum ntb_width link_width; 11633dea5aaSLogan Gunthorpe }; 11733dea5aaSLogan Gunthorpe 1180ee28f26SLogan Gunthorpe static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb) 1190ee28f26SLogan Gunthorpe { 1200ee28f26SLogan Gunthorpe return container_of(ntb, struct switchtec_ntb, ntb); 1210ee28f26SLogan Gunthorpe } 1220ee28f26SLogan Gunthorpe 123ec0467ccSLogan Gunthorpe static int switchtec_ntb_part_op(struct switchtec_ntb *sndev, 124ec0467ccSLogan Gunthorpe struct ntb_ctrl_regs __iomem *ctl, 125ec0467ccSLogan Gunthorpe u32 op, int wait_status) 126ec0467ccSLogan Gunthorpe { 127ec0467ccSLogan Gunthorpe static const char * const op_text[] = { 128ec0467ccSLogan Gunthorpe [NTB_CTRL_PART_OP_LOCK] = "lock", 129ec0467ccSLogan Gunthorpe [NTB_CTRL_PART_OP_CFG] = "configure", 130ec0467ccSLogan Gunthorpe [NTB_CTRL_PART_OP_RESET] = "reset", 131ec0467ccSLogan Gunthorpe }; 132ec0467ccSLogan Gunthorpe 133ec0467ccSLogan Gunthorpe int i; 134ec0467ccSLogan Gunthorpe u32 ps; 135ec0467ccSLogan Gunthorpe int status; 136ec0467ccSLogan Gunthorpe 137ec0467ccSLogan Gunthorpe switch (op) { 138ec0467ccSLogan Gunthorpe case NTB_CTRL_PART_OP_LOCK: 139ec0467ccSLogan Gunthorpe status = NTB_CTRL_PART_STATUS_LOCKING; 140ec0467ccSLogan Gunthorpe break; 141ec0467ccSLogan Gunthorpe case NTB_CTRL_PART_OP_CFG: 142ec0467ccSLogan Gunthorpe status = NTB_CTRL_PART_STATUS_CONFIGURING; 143ec0467ccSLogan Gunthorpe break; 144ec0467ccSLogan Gunthorpe case NTB_CTRL_PART_OP_RESET: 145ec0467ccSLogan Gunthorpe status = NTB_CTRL_PART_STATUS_RESETTING; 146ec0467ccSLogan Gunthorpe break; 147ec0467ccSLogan Gunthorpe default: 148ec0467ccSLogan Gunthorpe return -EINVAL; 149ec0467ccSLogan Gunthorpe } 150ec0467ccSLogan Gunthorpe 151ec0467ccSLogan Gunthorpe iowrite32(op, &ctl->partition_op); 152ec0467ccSLogan Gunthorpe 153ec0467ccSLogan Gunthorpe for (i = 0; i < 1000; i++) { 154ec0467ccSLogan Gunthorpe if (msleep_interruptible(50) != 0) { 155ec0467ccSLogan Gunthorpe iowrite32(NTB_CTRL_PART_OP_RESET, &ctl->partition_op); 156ec0467ccSLogan Gunthorpe return -EINTR; 157ec0467ccSLogan Gunthorpe } 158ec0467ccSLogan Gunthorpe 159ec0467ccSLogan Gunthorpe ps = ioread32(&ctl->partition_status) & 0xFFFF; 160ec0467ccSLogan Gunthorpe 161ec0467ccSLogan Gunthorpe if (ps != status) 162ec0467ccSLogan Gunthorpe break; 163ec0467ccSLogan Gunthorpe } 164ec0467ccSLogan Gunthorpe 165ec0467ccSLogan Gunthorpe if (ps == wait_status) 166ec0467ccSLogan Gunthorpe return 0; 167ec0467ccSLogan Gunthorpe 168ec0467ccSLogan Gunthorpe if (ps == status) { 169ec0467ccSLogan Gunthorpe dev_err(&sndev->stdev->dev, 170ec0467ccSLogan Gunthorpe "Timed out while peforming %s (%d). (%08x)", 171ec0467ccSLogan Gunthorpe op_text[op], op, 172ec0467ccSLogan Gunthorpe ioread32(&ctl->partition_status)); 173ec0467ccSLogan Gunthorpe 174ec0467ccSLogan Gunthorpe return -ETIMEDOUT; 175ec0467ccSLogan Gunthorpe } 176ec0467ccSLogan Gunthorpe 177ec0467ccSLogan Gunthorpe return -EIO; 178ec0467ccSLogan Gunthorpe } 179ec0467ccSLogan Gunthorpe 1800ee28f26SLogan Gunthorpe static int switchtec_ntb_send_msg(struct switchtec_ntb *sndev, int idx, 1810ee28f26SLogan Gunthorpe u32 val) 1820ee28f26SLogan Gunthorpe { 1830ee28f26SLogan Gunthorpe if (idx < 0 || idx >= ARRAY_SIZE(sndev->mmio_self_dbmsg->omsg)) 1840ee28f26SLogan Gunthorpe return -EINVAL; 1850ee28f26SLogan Gunthorpe 1860ee28f26SLogan Gunthorpe iowrite32(val, &sndev->mmio_self_dbmsg->omsg[idx].msg); 1870ee28f26SLogan Gunthorpe 1880ee28f26SLogan Gunthorpe return 0; 1890ee28f26SLogan Gunthorpe } 1900ee28f26SLogan Gunthorpe 191e099b45bSLogan Gunthorpe static int switchtec_ntb_mw_count(struct ntb_dev *ntb, int pidx) 192e099b45bSLogan Gunthorpe { 193e099b45bSLogan Gunthorpe return 0; 194e099b45bSLogan Gunthorpe } 195e099b45bSLogan Gunthorpe 196e099b45bSLogan Gunthorpe static int switchtec_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, 197e099b45bSLogan Gunthorpe int widx, resource_size_t *addr_align, 198e099b45bSLogan Gunthorpe resource_size_t *size_align, 199e099b45bSLogan Gunthorpe resource_size_t *size_max) 200e099b45bSLogan Gunthorpe { 201e099b45bSLogan Gunthorpe return 0; 202e099b45bSLogan Gunthorpe } 203e099b45bSLogan Gunthorpe 204e099b45bSLogan Gunthorpe static int switchtec_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx, 205e099b45bSLogan Gunthorpe dma_addr_t addr, resource_size_t size) 206e099b45bSLogan Gunthorpe { 207e099b45bSLogan Gunthorpe return 0; 208e099b45bSLogan Gunthorpe } 209e099b45bSLogan Gunthorpe 210e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_mw_count(struct ntb_dev *ntb) 211e099b45bSLogan Gunthorpe { 212e099b45bSLogan Gunthorpe return 0; 213e099b45bSLogan Gunthorpe } 214e099b45bSLogan Gunthorpe 215e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx, 216e099b45bSLogan Gunthorpe phys_addr_t *base, 217e099b45bSLogan Gunthorpe resource_size_t *size) 218e099b45bSLogan Gunthorpe { 219e099b45bSLogan Gunthorpe return 0; 220e099b45bSLogan Gunthorpe } 221e099b45bSLogan Gunthorpe 2220ee28f26SLogan Gunthorpe static void switchtec_ntb_part_link_speed(struct switchtec_ntb *sndev, 2230ee28f26SLogan Gunthorpe int partition, 2240ee28f26SLogan Gunthorpe enum ntb_speed *speed, 2250ee28f26SLogan Gunthorpe enum ntb_width *width) 2260ee28f26SLogan Gunthorpe { 2270ee28f26SLogan Gunthorpe struct switchtec_dev *stdev = sndev->stdev; 2280ee28f26SLogan Gunthorpe 2290ee28f26SLogan Gunthorpe u32 pff = ioread32(&stdev->mmio_part_cfg[partition].vep_pff_inst_id); 2300ee28f26SLogan Gunthorpe u32 linksta = ioread32(&stdev->mmio_pff_csr[pff].pci_cap_region[13]); 2310ee28f26SLogan Gunthorpe 2320ee28f26SLogan Gunthorpe if (speed) 2330ee28f26SLogan Gunthorpe *speed = (linksta >> 16) & 0xF; 2340ee28f26SLogan Gunthorpe 2350ee28f26SLogan Gunthorpe if (width) 2360ee28f26SLogan Gunthorpe *width = (linksta >> 20) & 0x3F; 2370ee28f26SLogan Gunthorpe } 2380ee28f26SLogan Gunthorpe 2390ee28f26SLogan Gunthorpe static void switchtec_ntb_set_link_speed(struct switchtec_ntb *sndev) 2400ee28f26SLogan Gunthorpe { 2410ee28f26SLogan Gunthorpe enum ntb_speed self_speed, peer_speed; 2420ee28f26SLogan Gunthorpe enum ntb_width self_width, peer_width; 2430ee28f26SLogan Gunthorpe 2440ee28f26SLogan Gunthorpe if (!sndev->link_is_up) { 2450ee28f26SLogan Gunthorpe sndev->link_speed = NTB_SPEED_NONE; 2460ee28f26SLogan Gunthorpe sndev->link_width = NTB_WIDTH_NONE; 2470ee28f26SLogan Gunthorpe return; 2480ee28f26SLogan Gunthorpe } 2490ee28f26SLogan Gunthorpe 2500ee28f26SLogan Gunthorpe switchtec_ntb_part_link_speed(sndev, sndev->self_partition, 2510ee28f26SLogan Gunthorpe &self_speed, &self_width); 2520ee28f26SLogan Gunthorpe switchtec_ntb_part_link_speed(sndev, sndev->peer_partition, 2530ee28f26SLogan Gunthorpe &peer_speed, &peer_width); 2540ee28f26SLogan Gunthorpe 2550ee28f26SLogan Gunthorpe sndev->link_speed = min(self_speed, peer_speed); 2560ee28f26SLogan Gunthorpe sndev->link_width = min(self_width, peer_width); 2570ee28f26SLogan Gunthorpe } 2580ee28f26SLogan Gunthorpe 2590ee28f26SLogan Gunthorpe enum { 2600ee28f26SLogan Gunthorpe LINK_MESSAGE = 0, 2610ee28f26SLogan Gunthorpe MSG_LINK_UP = 1, 2620ee28f26SLogan Gunthorpe MSG_LINK_DOWN = 2, 2630ee28f26SLogan Gunthorpe MSG_CHECK_LINK = 3, 2640ee28f26SLogan Gunthorpe }; 2650ee28f26SLogan Gunthorpe 2660ee28f26SLogan Gunthorpe static void switchtec_ntb_check_link(struct switchtec_ntb *sndev) 2670ee28f26SLogan Gunthorpe { 2680ee28f26SLogan Gunthorpe int link_sta; 2690ee28f26SLogan Gunthorpe int old = sndev->link_is_up; 2700ee28f26SLogan Gunthorpe 2710ee28f26SLogan Gunthorpe link_sta = sndev->self_shared->link_sta; 2720ee28f26SLogan Gunthorpe if (link_sta) { 2730ee28f26SLogan Gunthorpe u64 peer = ioread64(&sndev->peer_shared->magic); 2740ee28f26SLogan Gunthorpe 2750ee28f26SLogan Gunthorpe if ((peer & 0xFFFFFFFF) == SWITCHTEC_NTB_MAGIC) 2760ee28f26SLogan Gunthorpe link_sta = peer >> 32; 2770ee28f26SLogan Gunthorpe else 2780ee28f26SLogan Gunthorpe link_sta = 0; 2790ee28f26SLogan Gunthorpe } 2800ee28f26SLogan Gunthorpe 2810ee28f26SLogan Gunthorpe sndev->link_is_up = link_sta; 2820ee28f26SLogan Gunthorpe switchtec_ntb_set_link_speed(sndev); 2830ee28f26SLogan Gunthorpe 2840ee28f26SLogan Gunthorpe if (link_sta != old) { 2850ee28f26SLogan Gunthorpe switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_CHECK_LINK); 2860ee28f26SLogan Gunthorpe ntb_link_event(&sndev->ntb); 2870ee28f26SLogan Gunthorpe dev_info(&sndev->stdev->dev, "ntb link %s", 2880ee28f26SLogan Gunthorpe link_sta ? "up" : "down"); 2890ee28f26SLogan Gunthorpe } 2900ee28f26SLogan Gunthorpe } 2910ee28f26SLogan Gunthorpe 2920ee28f26SLogan Gunthorpe static void switchtec_ntb_link_notification(struct switchtec_dev *stdev) 2930ee28f26SLogan Gunthorpe { 2940ee28f26SLogan Gunthorpe struct switchtec_ntb *sndev = stdev->sndev; 2950ee28f26SLogan Gunthorpe 2960ee28f26SLogan Gunthorpe switchtec_ntb_check_link(sndev); 2970ee28f26SLogan Gunthorpe } 2980ee28f26SLogan Gunthorpe 299e099b45bSLogan Gunthorpe static u64 switchtec_ntb_link_is_up(struct ntb_dev *ntb, 300e099b45bSLogan Gunthorpe enum ntb_speed *speed, 301e099b45bSLogan Gunthorpe enum ntb_width *width) 302e099b45bSLogan Gunthorpe { 3030ee28f26SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 3040ee28f26SLogan Gunthorpe 3050ee28f26SLogan Gunthorpe if (speed) 3060ee28f26SLogan Gunthorpe *speed = sndev->link_speed; 3070ee28f26SLogan Gunthorpe if (width) 3080ee28f26SLogan Gunthorpe *width = sndev->link_width; 3090ee28f26SLogan Gunthorpe 3100ee28f26SLogan Gunthorpe return sndev->link_is_up; 311e099b45bSLogan Gunthorpe } 312e099b45bSLogan Gunthorpe 313e099b45bSLogan Gunthorpe static int switchtec_ntb_link_enable(struct ntb_dev *ntb, 314e099b45bSLogan Gunthorpe enum ntb_speed max_speed, 315e099b45bSLogan Gunthorpe enum ntb_width max_width) 316e099b45bSLogan Gunthorpe { 3170ee28f26SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 3180ee28f26SLogan Gunthorpe 3190ee28f26SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "enabling link"); 3200ee28f26SLogan Gunthorpe 3210ee28f26SLogan Gunthorpe sndev->self_shared->link_sta = 1; 3220ee28f26SLogan Gunthorpe switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); 3230ee28f26SLogan Gunthorpe 3240ee28f26SLogan Gunthorpe switchtec_ntb_check_link(sndev); 3250ee28f26SLogan Gunthorpe 326e099b45bSLogan Gunthorpe return 0; 327e099b45bSLogan Gunthorpe } 328e099b45bSLogan Gunthorpe 329e099b45bSLogan Gunthorpe static int switchtec_ntb_link_disable(struct ntb_dev *ntb) 330e099b45bSLogan Gunthorpe { 3310ee28f26SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 3320ee28f26SLogan Gunthorpe 3330ee28f26SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "disabling link"); 3340ee28f26SLogan Gunthorpe 3350ee28f26SLogan Gunthorpe sndev->self_shared->link_sta = 0; 3360ee28f26SLogan Gunthorpe switchtec_ntb_send_msg(sndev, LINK_MESSAGE, MSG_LINK_UP); 3370ee28f26SLogan Gunthorpe 3380ee28f26SLogan Gunthorpe switchtec_ntb_check_link(sndev); 3390ee28f26SLogan Gunthorpe 340e099b45bSLogan Gunthorpe return 0; 341e099b45bSLogan Gunthorpe } 342e099b45bSLogan Gunthorpe 343e099b45bSLogan Gunthorpe static u64 switchtec_ntb_db_valid_mask(struct ntb_dev *ntb) 344e099b45bSLogan Gunthorpe { 3456619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 3466619bf95SLogan Gunthorpe 3476619bf95SLogan Gunthorpe return sndev->db_valid_mask; 348e099b45bSLogan Gunthorpe } 349e099b45bSLogan Gunthorpe 350e099b45bSLogan Gunthorpe static int switchtec_ntb_db_vector_count(struct ntb_dev *ntb) 351e099b45bSLogan Gunthorpe { 3526619bf95SLogan Gunthorpe return 1; 353e099b45bSLogan Gunthorpe } 354e099b45bSLogan Gunthorpe 355e099b45bSLogan Gunthorpe static u64 switchtec_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector) 356e099b45bSLogan Gunthorpe { 3576619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 3586619bf95SLogan Gunthorpe 3596619bf95SLogan Gunthorpe if (db_vector < 0 || db_vector > 1) 360e099b45bSLogan Gunthorpe return 0; 3616619bf95SLogan Gunthorpe 3626619bf95SLogan Gunthorpe return sndev->db_valid_mask; 363e099b45bSLogan Gunthorpe } 364e099b45bSLogan Gunthorpe 365e099b45bSLogan Gunthorpe static u64 switchtec_ntb_db_read(struct ntb_dev *ntb) 366e099b45bSLogan Gunthorpe { 3676619bf95SLogan Gunthorpe u64 ret; 3686619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 3696619bf95SLogan Gunthorpe 3706619bf95SLogan Gunthorpe ret = ioread64(&sndev->mmio_self_dbmsg->idb) >> sndev->db_shift; 3716619bf95SLogan Gunthorpe 3726619bf95SLogan Gunthorpe return ret & sndev->db_valid_mask; 373e099b45bSLogan Gunthorpe } 374e099b45bSLogan Gunthorpe 375e099b45bSLogan Gunthorpe static int switchtec_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) 376e099b45bSLogan Gunthorpe { 3776619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 3786619bf95SLogan Gunthorpe 3796619bf95SLogan Gunthorpe iowrite64(db_bits << sndev->db_shift, &sndev->mmio_self_dbmsg->idb); 3806619bf95SLogan Gunthorpe 381e099b45bSLogan Gunthorpe return 0; 382e099b45bSLogan Gunthorpe } 383e099b45bSLogan Gunthorpe 384e099b45bSLogan Gunthorpe static int switchtec_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) 385e099b45bSLogan Gunthorpe { 3866619bf95SLogan Gunthorpe unsigned long irqflags; 3876619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 3886619bf95SLogan Gunthorpe 3896619bf95SLogan Gunthorpe if (db_bits & ~sndev->db_valid_mask) 3906619bf95SLogan Gunthorpe return -EINVAL; 3916619bf95SLogan Gunthorpe 3926619bf95SLogan Gunthorpe spin_lock_irqsave(&sndev->db_mask_lock, irqflags); 3936619bf95SLogan Gunthorpe 3946619bf95SLogan Gunthorpe sndev->db_mask |= db_bits << sndev->db_shift; 3956619bf95SLogan Gunthorpe iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 3966619bf95SLogan Gunthorpe 3976619bf95SLogan Gunthorpe spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags); 3986619bf95SLogan Gunthorpe 399e099b45bSLogan Gunthorpe return 0; 400e099b45bSLogan Gunthorpe } 401e099b45bSLogan Gunthorpe 402e099b45bSLogan Gunthorpe static int switchtec_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) 403e099b45bSLogan Gunthorpe { 4046619bf95SLogan Gunthorpe unsigned long irqflags; 4056619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 4066619bf95SLogan Gunthorpe 4076619bf95SLogan Gunthorpe if (db_bits & ~sndev->db_valid_mask) 4086619bf95SLogan Gunthorpe return -EINVAL; 4096619bf95SLogan Gunthorpe 4106619bf95SLogan Gunthorpe spin_lock_irqsave(&sndev->db_mask_lock, irqflags); 4116619bf95SLogan Gunthorpe 4126619bf95SLogan Gunthorpe sndev->db_mask &= ~(db_bits << sndev->db_shift); 4136619bf95SLogan Gunthorpe iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 4146619bf95SLogan Gunthorpe 4156619bf95SLogan Gunthorpe spin_unlock_irqrestore(&sndev->db_mask_lock, irqflags); 4166619bf95SLogan Gunthorpe 4176619bf95SLogan Gunthorpe return 0; 4186619bf95SLogan Gunthorpe } 4196619bf95SLogan Gunthorpe 4206619bf95SLogan Gunthorpe static u64 switchtec_ntb_db_read_mask(struct ntb_dev *ntb) 4216619bf95SLogan Gunthorpe { 4226619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 4236619bf95SLogan Gunthorpe 4246619bf95SLogan Gunthorpe return (sndev->db_mask >> sndev->db_shift) & sndev->db_valid_mask; 4256619bf95SLogan Gunthorpe } 4266619bf95SLogan Gunthorpe 4276619bf95SLogan Gunthorpe static int switchtec_ntb_peer_db_addr(struct ntb_dev *ntb, 4286619bf95SLogan Gunthorpe phys_addr_t *db_addr, 4296619bf95SLogan Gunthorpe resource_size_t *db_size) 4306619bf95SLogan Gunthorpe { 4316619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 4326619bf95SLogan Gunthorpe unsigned long offset; 4336619bf95SLogan Gunthorpe 4346619bf95SLogan Gunthorpe offset = (unsigned long)sndev->mmio_self_dbmsg->odb - 4356619bf95SLogan Gunthorpe (unsigned long)sndev->stdev->mmio; 4366619bf95SLogan Gunthorpe 4376619bf95SLogan Gunthorpe offset += sndev->db_shift / 8; 4386619bf95SLogan Gunthorpe 4396619bf95SLogan Gunthorpe if (db_addr) 4406619bf95SLogan Gunthorpe *db_addr = pci_resource_start(ntb->pdev, 0) + offset; 4416619bf95SLogan Gunthorpe if (db_size) 4426619bf95SLogan Gunthorpe *db_size = sizeof(u32); 4436619bf95SLogan Gunthorpe 444e099b45bSLogan Gunthorpe return 0; 445e099b45bSLogan Gunthorpe } 446e099b45bSLogan Gunthorpe 447e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) 448e099b45bSLogan Gunthorpe { 4496619bf95SLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 4506619bf95SLogan Gunthorpe 4516619bf95SLogan Gunthorpe iowrite64(db_bits << sndev->db_peer_shift, 4526619bf95SLogan Gunthorpe &sndev->mmio_self_dbmsg->odb); 4536619bf95SLogan Gunthorpe 454e099b45bSLogan Gunthorpe return 0; 455e099b45bSLogan Gunthorpe } 456e099b45bSLogan Gunthorpe 457e099b45bSLogan Gunthorpe static int switchtec_ntb_spad_count(struct ntb_dev *ntb) 458e099b45bSLogan Gunthorpe { 459*b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 460*b9a4acacSLogan Gunthorpe 461*b9a4acacSLogan Gunthorpe return ARRAY_SIZE(sndev->self_shared->spad); 462e099b45bSLogan Gunthorpe } 463e099b45bSLogan Gunthorpe 464e099b45bSLogan Gunthorpe static u32 switchtec_ntb_spad_read(struct ntb_dev *ntb, int idx) 465e099b45bSLogan Gunthorpe { 466*b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 467*b9a4acacSLogan Gunthorpe 468*b9a4acacSLogan Gunthorpe if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad)) 469e099b45bSLogan Gunthorpe return 0; 470*b9a4acacSLogan Gunthorpe 471*b9a4acacSLogan Gunthorpe if (!sndev->self_shared) 472*b9a4acacSLogan Gunthorpe return 0; 473*b9a4acacSLogan Gunthorpe 474*b9a4acacSLogan Gunthorpe return sndev->self_shared->spad[idx]; 475e099b45bSLogan Gunthorpe } 476e099b45bSLogan Gunthorpe 477e099b45bSLogan Gunthorpe static int switchtec_ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val) 478e099b45bSLogan Gunthorpe { 479*b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 480*b9a4acacSLogan Gunthorpe 481*b9a4acacSLogan Gunthorpe if (idx < 0 || idx >= ARRAY_SIZE(sndev->self_shared->spad)) 482*b9a4acacSLogan Gunthorpe return -EINVAL; 483*b9a4acacSLogan Gunthorpe 484*b9a4acacSLogan Gunthorpe if (!sndev->self_shared) 485*b9a4acacSLogan Gunthorpe return -EIO; 486*b9a4acacSLogan Gunthorpe 487*b9a4acacSLogan Gunthorpe sndev->self_shared->spad[idx] = val; 488*b9a4acacSLogan Gunthorpe 489e099b45bSLogan Gunthorpe return 0; 490e099b45bSLogan Gunthorpe } 491e099b45bSLogan Gunthorpe 492*b9a4acacSLogan Gunthorpe static u32 switchtec_ntb_peer_spad_read(struct ntb_dev *ntb, int pidx, 493*b9a4acacSLogan Gunthorpe int sidx) 494*b9a4acacSLogan Gunthorpe { 495*b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 496*b9a4acacSLogan Gunthorpe 497*b9a4acacSLogan Gunthorpe if (pidx != NTB_DEF_PEER_IDX) 498*b9a4acacSLogan Gunthorpe return -EINVAL; 499*b9a4acacSLogan Gunthorpe 500*b9a4acacSLogan Gunthorpe if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad)) 501*b9a4acacSLogan Gunthorpe return 0; 502*b9a4acacSLogan Gunthorpe 503*b9a4acacSLogan Gunthorpe if (!sndev->peer_shared) 504*b9a4acacSLogan Gunthorpe return 0; 505*b9a4acacSLogan Gunthorpe 506*b9a4acacSLogan Gunthorpe return ioread32(&sndev->peer_shared->spad[sidx]); 507*b9a4acacSLogan Gunthorpe } 508*b9a4acacSLogan Gunthorpe 509e099b45bSLogan Gunthorpe static int switchtec_ntb_peer_spad_write(struct ntb_dev *ntb, int pidx, 510e099b45bSLogan Gunthorpe int sidx, u32 val) 511e099b45bSLogan Gunthorpe { 512*b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 513*b9a4acacSLogan Gunthorpe 514*b9a4acacSLogan Gunthorpe if (pidx != NTB_DEF_PEER_IDX) 515*b9a4acacSLogan Gunthorpe return -EINVAL; 516*b9a4acacSLogan Gunthorpe 517*b9a4acacSLogan Gunthorpe if (sidx < 0 || sidx >= ARRAY_SIZE(sndev->peer_shared->spad)) 518*b9a4acacSLogan Gunthorpe return -EINVAL; 519*b9a4acacSLogan Gunthorpe 520*b9a4acacSLogan Gunthorpe if (!sndev->peer_shared) 521*b9a4acacSLogan Gunthorpe return -EIO; 522*b9a4acacSLogan Gunthorpe 523*b9a4acacSLogan Gunthorpe iowrite32(val, &sndev->peer_shared->spad[sidx]); 524*b9a4acacSLogan Gunthorpe 525*b9a4acacSLogan Gunthorpe return 0; 526*b9a4acacSLogan Gunthorpe } 527*b9a4acacSLogan Gunthorpe 528*b9a4acacSLogan Gunthorpe static int switchtec_ntb_peer_spad_addr(struct ntb_dev *ntb, int pidx, 529*b9a4acacSLogan Gunthorpe int sidx, phys_addr_t *spad_addr) 530*b9a4acacSLogan Gunthorpe { 531*b9a4acacSLogan Gunthorpe struct switchtec_ntb *sndev = ntb_sndev(ntb); 532*b9a4acacSLogan Gunthorpe unsigned long offset; 533*b9a4acacSLogan Gunthorpe 534*b9a4acacSLogan Gunthorpe if (pidx != NTB_DEF_PEER_IDX) 535*b9a4acacSLogan Gunthorpe return -EINVAL; 536*b9a4acacSLogan Gunthorpe 537*b9a4acacSLogan Gunthorpe offset = (unsigned long)&sndev->peer_shared->spad[sidx] - 538*b9a4acacSLogan Gunthorpe (unsigned long)sndev->stdev->mmio; 539*b9a4acacSLogan Gunthorpe 540*b9a4acacSLogan Gunthorpe if (spad_addr) 541*b9a4acacSLogan Gunthorpe *spad_addr = pci_resource_start(ntb->pdev, 0) + offset; 542*b9a4acacSLogan Gunthorpe 543e099b45bSLogan Gunthorpe return 0; 544e099b45bSLogan Gunthorpe } 545e099b45bSLogan Gunthorpe 546e099b45bSLogan Gunthorpe static const struct ntb_dev_ops switchtec_ntb_ops = { 547e099b45bSLogan Gunthorpe .mw_count = switchtec_ntb_mw_count, 548e099b45bSLogan Gunthorpe .mw_get_align = switchtec_ntb_mw_get_align, 549e099b45bSLogan Gunthorpe .mw_set_trans = switchtec_ntb_mw_set_trans, 550e099b45bSLogan Gunthorpe .peer_mw_count = switchtec_ntb_peer_mw_count, 551e099b45bSLogan Gunthorpe .peer_mw_get_addr = switchtec_ntb_peer_mw_get_addr, 552e099b45bSLogan Gunthorpe .link_is_up = switchtec_ntb_link_is_up, 553e099b45bSLogan Gunthorpe .link_enable = switchtec_ntb_link_enable, 554e099b45bSLogan Gunthorpe .link_disable = switchtec_ntb_link_disable, 555e099b45bSLogan Gunthorpe .db_valid_mask = switchtec_ntb_db_valid_mask, 556e099b45bSLogan Gunthorpe .db_vector_count = switchtec_ntb_db_vector_count, 557e099b45bSLogan Gunthorpe .db_vector_mask = switchtec_ntb_db_vector_mask, 558e099b45bSLogan Gunthorpe .db_read = switchtec_ntb_db_read, 559e099b45bSLogan Gunthorpe .db_clear = switchtec_ntb_db_clear, 560e099b45bSLogan Gunthorpe .db_set_mask = switchtec_ntb_db_set_mask, 561e099b45bSLogan Gunthorpe .db_clear_mask = switchtec_ntb_db_clear_mask, 5626619bf95SLogan Gunthorpe .db_read_mask = switchtec_ntb_db_read_mask, 5636619bf95SLogan Gunthorpe .peer_db_addr = switchtec_ntb_peer_db_addr, 564e099b45bSLogan Gunthorpe .peer_db_set = switchtec_ntb_peer_db_set, 565e099b45bSLogan Gunthorpe .spad_count = switchtec_ntb_spad_count, 566e099b45bSLogan Gunthorpe .spad_read = switchtec_ntb_spad_read, 567e099b45bSLogan Gunthorpe .spad_write = switchtec_ntb_spad_write, 568*b9a4acacSLogan Gunthorpe .peer_spad_read = switchtec_ntb_peer_spad_read, 569e099b45bSLogan Gunthorpe .peer_spad_write = switchtec_ntb_peer_spad_write, 570*b9a4acacSLogan Gunthorpe .peer_spad_addr = switchtec_ntb_peer_spad_addr, 571e099b45bSLogan Gunthorpe }; 572e099b45bSLogan Gunthorpe 573ec0467ccSLogan Gunthorpe static void switchtec_ntb_init_sndev(struct switchtec_ntb *sndev) 574ec0467ccSLogan Gunthorpe { 575ec0467ccSLogan Gunthorpe u64 part_map; 576ec0467ccSLogan Gunthorpe 577e099b45bSLogan Gunthorpe sndev->ntb.pdev = sndev->stdev->pdev; 578e099b45bSLogan Gunthorpe sndev->ntb.topo = NTB_TOPO_SWITCH; 579e099b45bSLogan Gunthorpe sndev->ntb.ops = &switchtec_ntb_ops; 580e099b45bSLogan Gunthorpe 581ec0467ccSLogan Gunthorpe sndev->self_partition = sndev->stdev->partition; 582ec0467ccSLogan Gunthorpe 583ec0467ccSLogan Gunthorpe sndev->mmio_ntb = sndev->stdev->mmio_ntb; 584ec0467ccSLogan Gunthorpe part_map = ioread64(&sndev->mmio_ntb->ep_map); 585ec0467ccSLogan Gunthorpe part_map &= ~(1 << sndev->self_partition); 586ec0467ccSLogan Gunthorpe sndev->peer_partition = ffs(part_map) - 1; 587ec0467ccSLogan Gunthorpe 588ec0467ccSLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "Partition ID %d of %d (%llx)", 589ec0467ccSLogan Gunthorpe sndev->self_partition, sndev->stdev->partition_count, 590ec0467ccSLogan Gunthorpe part_map); 591ec0467ccSLogan Gunthorpe 592ec0467ccSLogan Gunthorpe sndev->mmio_ctrl = (void * __iomem)sndev->mmio_ntb + 593ec0467ccSLogan Gunthorpe SWITCHTEC_NTB_REG_CTRL_OFFSET; 594ec0467ccSLogan Gunthorpe sndev->mmio_dbmsg = (void * __iomem)sndev->mmio_ntb + 595ec0467ccSLogan Gunthorpe SWITCHTEC_NTB_REG_DBMSG_OFFSET; 596ec0467ccSLogan Gunthorpe 597ec0467ccSLogan Gunthorpe sndev->mmio_self_ctrl = &sndev->mmio_ctrl[sndev->self_partition]; 598ec0467ccSLogan Gunthorpe sndev->mmio_peer_ctrl = &sndev->mmio_ctrl[sndev->peer_partition]; 599ec0467ccSLogan Gunthorpe sndev->mmio_self_dbmsg = &sndev->mmio_dbmsg[sndev->self_partition]; 600ec0467ccSLogan Gunthorpe } 601ec0467ccSLogan Gunthorpe 602ec0467ccSLogan Gunthorpe static int map_bars(int *map, struct ntb_ctrl_regs __iomem *ctrl) 603ec0467ccSLogan Gunthorpe { 604ec0467ccSLogan Gunthorpe int i; 605ec0467ccSLogan Gunthorpe int cnt = 0; 606ec0467ccSLogan Gunthorpe 607ec0467ccSLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(ctrl->bar_entry); i++) { 608ec0467ccSLogan Gunthorpe u32 r = ioread32(&ctrl->bar_entry[i].ctl); 609ec0467ccSLogan Gunthorpe 610ec0467ccSLogan Gunthorpe if (r & NTB_CTRL_BAR_VALID) 611ec0467ccSLogan Gunthorpe map[cnt++] = i; 612ec0467ccSLogan Gunthorpe } 613ec0467ccSLogan Gunthorpe 614ec0467ccSLogan Gunthorpe return cnt; 615ec0467ccSLogan Gunthorpe } 616ec0467ccSLogan Gunthorpe 617ec0467ccSLogan Gunthorpe static void switchtec_ntb_init_mw(struct switchtec_ntb *sndev) 618ec0467ccSLogan Gunthorpe { 619ec0467ccSLogan Gunthorpe sndev->nr_direct_mw = map_bars(sndev->direct_mw_to_bar, 620ec0467ccSLogan Gunthorpe sndev->mmio_self_ctrl); 621ec0467ccSLogan Gunthorpe 622ec0467ccSLogan Gunthorpe sndev->nr_lut_mw = ioread16(&sndev->mmio_self_ctrl->lut_table_entries); 623ec0467ccSLogan Gunthorpe sndev->nr_lut_mw = rounddown_pow_of_two(sndev->nr_lut_mw); 624ec0467ccSLogan Gunthorpe 625ec0467ccSLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "MWs: %d direct, %d lut", 626ec0467ccSLogan Gunthorpe sndev->nr_direct_mw, sndev->nr_lut_mw); 627ec0467ccSLogan Gunthorpe 628ec0467ccSLogan Gunthorpe sndev->peer_nr_direct_mw = map_bars(sndev->peer_direct_mw_to_bar, 629ec0467ccSLogan Gunthorpe sndev->mmio_peer_ctrl); 630ec0467ccSLogan Gunthorpe 631ec0467ccSLogan Gunthorpe sndev->peer_nr_lut_mw = 632ec0467ccSLogan Gunthorpe ioread16(&sndev->mmio_peer_ctrl->lut_table_entries); 633ec0467ccSLogan Gunthorpe sndev->peer_nr_lut_mw = rounddown_pow_of_two(sndev->peer_nr_lut_mw); 634ec0467ccSLogan Gunthorpe 635ec0467ccSLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "Peer MWs: %d direct, %d lut", 636ec0467ccSLogan Gunthorpe sndev->peer_nr_direct_mw, sndev->peer_nr_lut_mw); 637ec0467ccSLogan Gunthorpe 638ec0467ccSLogan Gunthorpe } 639ec0467ccSLogan Gunthorpe 6403dd4db47SLogan Gunthorpe /* 6413dd4db47SLogan Gunthorpe * There are 64 doorbells in the switch hardware but this is 6423dd4db47SLogan Gunthorpe * shared among all partitions. So we must split them in half 6433dd4db47SLogan Gunthorpe * (32 for each partition). However, the message interrupts are 6443dd4db47SLogan Gunthorpe * also shared with the top 4 doorbells so we just limit this to 6453dd4db47SLogan Gunthorpe * 28 doorbells per partition 6463dd4db47SLogan Gunthorpe */ 6473dd4db47SLogan Gunthorpe static void switchtec_ntb_init_db(struct switchtec_ntb *sndev) 6483dd4db47SLogan Gunthorpe { 6493dd4db47SLogan Gunthorpe sndev->db_valid_mask = 0x0FFFFFFF; 6503dd4db47SLogan Gunthorpe 6513dd4db47SLogan Gunthorpe if (sndev->self_partition < sndev->peer_partition) { 6523dd4db47SLogan Gunthorpe sndev->db_shift = 0; 6533dd4db47SLogan Gunthorpe sndev->db_peer_shift = 32; 6543dd4db47SLogan Gunthorpe } else { 6553dd4db47SLogan Gunthorpe sndev->db_shift = 32; 6563dd4db47SLogan Gunthorpe sndev->db_peer_shift = 0; 6573dd4db47SLogan Gunthorpe } 6583dd4db47SLogan Gunthorpe 6593dd4db47SLogan Gunthorpe sndev->db_mask = 0x0FFFFFFFFFFFFFFFULL; 6603dd4db47SLogan Gunthorpe iowrite64(~sndev->db_mask, &sndev->mmio_self_dbmsg->idb_mask); 6613dd4db47SLogan Gunthorpe iowrite64(sndev->db_valid_mask << sndev->db_peer_shift, 6623dd4db47SLogan Gunthorpe &sndev->mmio_self_dbmsg->odb_mask); 6633dd4db47SLogan Gunthorpe } 6643dd4db47SLogan Gunthorpe 6653dd4db47SLogan Gunthorpe static void switchtec_ntb_init_msgs(struct switchtec_ntb *sndev) 6663dd4db47SLogan Gunthorpe { 6673dd4db47SLogan Gunthorpe int i; 6683dd4db47SLogan Gunthorpe u32 msg_map = 0; 6693dd4db47SLogan Gunthorpe 6703dd4db47SLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) { 6713dd4db47SLogan Gunthorpe int m = i | sndev->peer_partition << 2; 6723dd4db47SLogan Gunthorpe 6733dd4db47SLogan Gunthorpe msg_map |= m << i * 8; 6743dd4db47SLogan Gunthorpe } 6753dd4db47SLogan Gunthorpe 6763dd4db47SLogan Gunthorpe iowrite32(msg_map, &sndev->mmio_self_dbmsg->msg_map); 6773dd4db47SLogan Gunthorpe 6783dd4db47SLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) 6793dd4db47SLogan Gunthorpe iowrite64(NTB_DBMSG_IMSG_STATUS | NTB_DBMSG_IMSG_MASK, 6803dd4db47SLogan Gunthorpe &sndev->mmio_self_dbmsg->imsg[i]); 6813dd4db47SLogan Gunthorpe } 6823dd4db47SLogan Gunthorpe 683ec0467ccSLogan Gunthorpe static int switchtec_ntb_init_req_id_table(struct switchtec_ntb *sndev) 684ec0467ccSLogan Gunthorpe { 685ec0467ccSLogan Gunthorpe int rc = 0; 686ec0467ccSLogan Gunthorpe u16 req_id; 687ec0467ccSLogan Gunthorpe u32 error; 688ec0467ccSLogan Gunthorpe 689ec0467ccSLogan Gunthorpe req_id = ioread16(&sndev->mmio_ntb->requester_id); 690ec0467ccSLogan Gunthorpe 691ec0467ccSLogan Gunthorpe if (ioread32(&sndev->mmio_self_ctrl->req_id_table_size) < 2) { 692ec0467ccSLogan Gunthorpe dev_err(&sndev->stdev->dev, 693ec0467ccSLogan Gunthorpe "Not enough requester IDs available."); 694ec0467ccSLogan Gunthorpe return -EFAULT; 695ec0467ccSLogan Gunthorpe } 696ec0467ccSLogan Gunthorpe 697ec0467ccSLogan Gunthorpe rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl, 698ec0467ccSLogan Gunthorpe NTB_CTRL_PART_OP_LOCK, 699ec0467ccSLogan Gunthorpe NTB_CTRL_PART_STATUS_LOCKED); 700ec0467ccSLogan Gunthorpe if (rc) 701ec0467ccSLogan Gunthorpe return rc; 702ec0467ccSLogan Gunthorpe 703ec0467ccSLogan Gunthorpe iowrite32(NTB_PART_CTRL_ID_PROT_DIS, 704ec0467ccSLogan Gunthorpe &sndev->mmio_self_ctrl->partition_ctrl); 705ec0467ccSLogan Gunthorpe 706ec0467ccSLogan Gunthorpe /* 707ec0467ccSLogan Gunthorpe * Root Complex Requester ID (which is 0:00.0) 708ec0467ccSLogan Gunthorpe */ 709ec0467ccSLogan Gunthorpe iowrite32(0 << 16 | NTB_CTRL_REQ_ID_EN, 710ec0467ccSLogan Gunthorpe &sndev->mmio_self_ctrl->req_id_table[0]); 711ec0467ccSLogan Gunthorpe 712ec0467ccSLogan Gunthorpe /* 713ec0467ccSLogan Gunthorpe * Host Bridge Requester ID (as read from the mmap address) 714ec0467ccSLogan Gunthorpe */ 715ec0467ccSLogan Gunthorpe iowrite32(req_id << 16 | NTB_CTRL_REQ_ID_EN, 716ec0467ccSLogan Gunthorpe &sndev->mmio_self_ctrl->req_id_table[1]); 717ec0467ccSLogan Gunthorpe 718ec0467ccSLogan Gunthorpe rc = switchtec_ntb_part_op(sndev, sndev->mmio_self_ctrl, 719ec0467ccSLogan Gunthorpe NTB_CTRL_PART_OP_CFG, 720ec0467ccSLogan Gunthorpe NTB_CTRL_PART_STATUS_NORMAL); 721ec0467ccSLogan Gunthorpe if (rc == -EIO) { 722ec0467ccSLogan Gunthorpe error = ioread32(&sndev->mmio_self_ctrl->req_id_error); 723ec0467ccSLogan Gunthorpe dev_err(&sndev->stdev->dev, 724ec0467ccSLogan Gunthorpe "Error setting up the requester ID table: %08x", 725ec0467ccSLogan Gunthorpe error); 726ec0467ccSLogan Gunthorpe } 727ec0467ccSLogan Gunthorpe 728ec0467ccSLogan Gunthorpe return rc; 729ec0467ccSLogan Gunthorpe } 730ec0467ccSLogan Gunthorpe 731ec0467ccSLogan Gunthorpe static void switchtec_ntb_init_shared(struct switchtec_ntb *sndev) 732ec0467ccSLogan Gunthorpe { 733ec0467ccSLogan Gunthorpe int i; 734ec0467ccSLogan Gunthorpe 735ec0467ccSLogan Gunthorpe memset(sndev->self_shared, 0, LUT_SIZE); 736ec0467ccSLogan Gunthorpe sndev->self_shared->magic = SWITCHTEC_NTB_MAGIC; 737ec0467ccSLogan Gunthorpe sndev->self_shared->partition_id = sndev->stdev->partition; 738ec0467ccSLogan Gunthorpe 739ec0467ccSLogan Gunthorpe for (i = 0; i < sndev->nr_direct_mw; i++) { 740ec0467ccSLogan Gunthorpe int bar = sndev->direct_mw_to_bar[i]; 741ec0467ccSLogan Gunthorpe resource_size_t sz = pci_resource_len(sndev->stdev->pdev, bar); 742ec0467ccSLogan Gunthorpe 743ec0467ccSLogan Gunthorpe if (i == 0) 744ec0467ccSLogan Gunthorpe sz = min_t(resource_size_t, sz, 745ec0467ccSLogan Gunthorpe LUT_SIZE * sndev->nr_lut_mw); 746ec0467ccSLogan Gunthorpe 747ec0467ccSLogan Gunthorpe sndev->self_shared->mw_sizes[i] = sz; 748ec0467ccSLogan Gunthorpe } 749ec0467ccSLogan Gunthorpe 750ec0467ccSLogan Gunthorpe for (i = 0; i < sndev->nr_lut_mw; i++) { 751ec0467ccSLogan Gunthorpe int idx = sndev->nr_direct_mw + i; 752ec0467ccSLogan Gunthorpe 753ec0467ccSLogan Gunthorpe sndev->self_shared->mw_sizes[idx] = LUT_SIZE; 754ec0467ccSLogan Gunthorpe } 755ec0467ccSLogan Gunthorpe } 756ec0467ccSLogan Gunthorpe 757ec0467ccSLogan Gunthorpe static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) 758ec0467ccSLogan Gunthorpe { 759ec0467ccSLogan Gunthorpe struct ntb_ctrl_regs __iomem *ctl = sndev->mmio_peer_ctrl; 760ec0467ccSLogan Gunthorpe int bar = sndev->direct_mw_to_bar[0]; 761ec0467ccSLogan Gunthorpe u32 ctl_val; 762ec0467ccSLogan Gunthorpe int rc; 763ec0467ccSLogan Gunthorpe 764ec0467ccSLogan Gunthorpe sndev->self_shared = dma_zalloc_coherent(&sndev->stdev->pdev->dev, 765ec0467ccSLogan Gunthorpe LUT_SIZE, 766ec0467ccSLogan Gunthorpe &sndev->self_shared_dma, 767ec0467ccSLogan Gunthorpe GFP_KERNEL); 768ec0467ccSLogan Gunthorpe if (!sndev->self_shared) { 769ec0467ccSLogan Gunthorpe dev_err(&sndev->stdev->dev, 770ec0467ccSLogan Gunthorpe "unable to allocate memory for shared mw"); 771ec0467ccSLogan Gunthorpe return -ENOMEM; 772ec0467ccSLogan Gunthorpe } 773ec0467ccSLogan Gunthorpe 774ec0467ccSLogan Gunthorpe switchtec_ntb_init_shared(sndev); 775ec0467ccSLogan Gunthorpe 776ec0467ccSLogan Gunthorpe rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_LOCK, 777ec0467ccSLogan Gunthorpe NTB_CTRL_PART_STATUS_LOCKED); 778ec0467ccSLogan Gunthorpe if (rc) 779ec0467ccSLogan Gunthorpe goto unalloc_and_exit; 780ec0467ccSLogan Gunthorpe 781ec0467ccSLogan Gunthorpe ctl_val = ioread32(&ctl->bar_entry[bar].ctl); 782ec0467ccSLogan Gunthorpe ctl_val &= 0xFF; 783ec0467ccSLogan Gunthorpe ctl_val |= NTB_CTRL_BAR_LUT_WIN_EN; 784ec0467ccSLogan Gunthorpe ctl_val |= ilog2(LUT_SIZE) << 8; 785ec0467ccSLogan Gunthorpe ctl_val |= (sndev->nr_lut_mw - 1) << 14; 786ec0467ccSLogan Gunthorpe iowrite32(ctl_val, &ctl->bar_entry[bar].ctl); 787ec0467ccSLogan Gunthorpe 788ec0467ccSLogan Gunthorpe iowrite64((NTB_CTRL_LUT_EN | (sndev->self_partition << 1) | 789ec0467ccSLogan Gunthorpe sndev->self_shared_dma), 790ec0467ccSLogan Gunthorpe &ctl->lut_entry[0]); 791ec0467ccSLogan Gunthorpe 792ec0467ccSLogan Gunthorpe rc = switchtec_ntb_part_op(sndev, ctl, NTB_CTRL_PART_OP_CFG, 793ec0467ccSLogan Gunthorpe NTB_CTRL_PART_STATUS_NORMAL); 794ec0467ccSLogan Gunthorpe if (rc) { 795ec0467ccSLogan Gunthorpe u32 bar_error, lut_error; 796ec0467ccSLogan Gunthorpe 797ec0467ccSLogan Gunthorpe bar_error = ioread32(&ctl->bar_error); 798ec0467ccSLogan Gunthorpe lut_error = ioread32(&ctl->lut_error); 799ec0467ccSLogan Gunthorpe dev_err(&sndev->stdev->dev, 800ec0467ccSLogan Gunthorpe "Error setting up shared MW: %08x / %08x", 801ec0467ccSLogan Gunthorpe bar_error, lut_error); 802ec0467ccSLogan Gunthorpe goto unalloc_and_exit; 803ec0467ccSLogan Gunthorpe } 804ec0467ccSLogan Gunthorpe 805ec0467ccSLogan Gunthorpe sndev->peer_shared = pci_iomap(sndev->stdev->pdev, bar, LUT_SIZE); 806ec0467ccSLogan Gunthorpe if (!sndev->peer_shared) { 807ec0467ccSLogan Gunthorpe rc = -ENOMEM; 808ec0467ccSLogan Gunthorpe goto unalloc_and_exit; 809ec0467ccSLogan Gunthorpe } 810ec0467ccSLogan Gunthorpe 811ec0467ccSLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "Shared MW Ready"); 812ec0467ccSLogan Gunthorpe return 0; 813ec0467ccSLogan Gunthorpe 814ec0467ccSLogan Gunthorpe unalloc_and_exit: 815ec0467ccSLogan Gunthorpe dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, 816ec0467ccSLogan Gunthorpe sndev->self_shared, sndev->self_shared_dma); 817ec0467ccSLogan Gunthorpe 818ec0467ccSLogan Gunthorpe return rc; 819ec0467ccSLogan Gunthorpe } 820ec0467ccSLogan Gunthorpe 821ec0467ccSLogan Gunthorpe static void switchtec_ntb_deinit_shared_mw(struct switchtec_ntb *sndev) 822ec0467ccSLogan Gunthorpe { 823ec0467ccSLogan Gunthorpe if (sndev->peer_shared) 824ec0467ccSLogan Gunthorpe pci_iounmap(sndev->stdev->pdev, sndev->peer_shared); 825ec0467ccSLogan Gunthorpe 826ec0467ccSLogan Gunthorpe if (sndev->self_shared) 827ec0467ccSLogan Gunthorpe dma_free_coherent(&sndev->stdev->pdev->dev, LUT_SIZE, 828ec0467ccSLogan Gunthorpe sndev->self_shared, 829ec0467ccSLogan Gunthorpe sndev->self_shared_dma); 830ec0467ccSLogan Gunthorpe } 831ec0467ccSLogan Gunthorpe 8323dd4db47SLogan Gunthorpe static irqreturn_t switchtec_ntb_doorbell_isr(int irq, void *dev) 8333dd4db47SLogan Gunthorpe { 8343dd4db47SLogan Gunthorpe struct switchtec_ntb *sndev = dev; 8353dd4db47SLogan Gunthorpe 8363dd4db47SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "doorbell\n"); 8373dd4db47SLogan Gunthorpe 8386619bf95SLogan Gunthorpe ntb_db_event(&sndev->ntb, 0); 8396619bf95SLogan Gunthorpe 8403dd4db47SLogan Gunthorpe return IRQ_HANDLED; 8413dd4db47SLogan Gunthorpe } 8423dd4db47SLogan Gunthorpe 8433dd4db47SLogan Gunthorpe static irqreturn_t switchtec_ntb_message_isr(int irq, void *dev) 8443dd4db47SLogan Gunthorpe { 8453dd4db47SLogan Gunthorpe int i; 8463dd4db47SLogan Gunthorpe struct switchtec_ntb *sndev = dev; 8473dd4db47SLogan Gunthorpe 8483dd4db47SLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(sndev->mmio_self_dbmsg->imsg); i++) { 8493dd4db47SLogan Gunthorpe u64 msg = ioread64(&sndev->mmio_self_dbmsg->imsg[i]); 8503dd4db47SLogan Gunthorpe 8513dd4db47SLogan Gunthorpe if (msg & NTB_DBMSG_IMSG_STATUS) { 8523dd4db47SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "message: %d %08x\n", i, 8533dd4db47SLogan Gunthorpe (u32)msg); 8543dd4db47SLogan Gunthorpe iowrite8(1, &sndev->mmio_self_dbmsg->imsg[i].status); 8550ee28f26SLogan Gunthorpe 8560ee28f26SLogan Gunthorpe if (i == LINK_MESSAGE) 8570ee28f26SLogan Gunthorpe switchtec_ntb_check_link(sndev); 8583dd4db47SLogan Gunthorpe } 8593dd4db47SLogan Gunthorpe } 8603dd4db47SLogan Gunthorpe 8613dd4db47SLogan Gunthorpe return IRQ_HANDLED; 8623dd4db47SLogan Gunthorpe } 8633dd4db47SLogan Gunthorpe 8643dd4db47SLogan Gunthorpe static int switchtec_ntb_init_db_msg_irq(struct switchtec_ntb *sndev) 8653dd4db47SLogan Gunthorpe { 8663dd4db47SLogan Gunthorpe int i; 8673dd4db47SLogan Gunthorpe int rc; 8683dd4db47SLogan Gunthorpe int doorbell_irq = 0; 8693dd4db47SLogan Gunthorpe int message_irq = 0; 8703dd4db47SLogan Gunthorpe int event_irq; 8713dd4db47SLogan Gunthorpe int idb_vecs = sizeof(sndev->mmio_self_dbmsg->idb_vec_map); 8723dd4db47SLogan Gunthorpe 8733dd4db47SLogan Gunthorpe event_irq = ioread32(&sndev->stdev->mmio_part_cfg->vep_vector_number); 8743dd4db47SLogan Gunthorpe 8753dd4db47SLogan Gunthorpe while (doorbell_irq == event_irq) 8763dd4db47SLogan Gunthorpe doorbell_irq++; 8773dd4db47SLogan Gunthorpe while (message_irq == doorbell_irq || 8783dd4db47SLogan Gunthorpe message_irq == event_irq) 8793dd4db47SLogan Gunthorpe message_irq++; 8803dd4db47SLogan Gunthorpe 8813dd4db47SLogan Gunthorpe dev_dbg(&sndev->stdev->dev, "irqs - event: %d, db: %d, msgs: %d", 8823dd4db47SLogan Gunthorpe event_irq, doorbell_irq, message_irq); 8833dd4db47SLogan Gunthorpe 8843dd4db47SLogan Gunthorpe for (i = 0; i < idb_vecs - 4; i++) 8853dd4db47SLogan Gunthorpe iowrite8(doorbell_irq, 8863dd4db47SLogan Gunthorpe &sndev->mmio_self_dbmsg->idb_vec_map[i]); 8873dd4db47SLogan Gunthorpe 8883dd4db47SLogan Gunthorpe for (; i < idb_vecs; i++) 8893dd4db47SLogan Gunthorpe iowrite8(message_irq, 8903dd4db47SLogan Gunthorpe &sndev->mmio_self_dbmsg->idb_vec_map[i]); 8913dd4db47SLogan Gunthorpe 8923dd4db47SLogan Gunthorpe sndev->doorbell_irq = pci_irq_vector(sndev->stdev->pdev, doorbell_irq); 8933dd4db47SLogan Gunthorpe sndev->message_irq = pci_irq_vector(sndev->stdev->pdev, message_irq); 8943dd4db47SLogan Gunthorpe 8953dd4db47SLogan Gunthorpe rc = request_irq(sndev->doorbell_irq, 8963dd4db47SLogan Gunthorpe switchtec_ntb_doorbell_isr, 0, 8973dd4db47SLogan Gunthorpe "switchtec_ntb_doorbell", sndev); 8983dd4db47SLogan Gunthorpe if (rc) 8993dd4db47SLogan Gunthorpe return rc; 9003dd4db47SLogan Gunthorpe 9013dd4db47SLogan Gunthorpe rc = request_irq(sndev->message_irq, 9023dd4db47SLogan Gunthorpe switchtec_ntb_message_isr, 0, 9033dd4db47SLogan Gunthorpe "switchtec_ntb_message", sndev); 9043dd4db47SLogan Gunthorpe if (rc) { 9053dd4db47SLogan Gunthorpe free_irq(sndev->doorbell_irq, sndev); 9063dd4db47SLogan Gunthorpe return rc; 9073dd4db47SLogan Gunthorpe } 9083dd4db47SLogan Gunthorpe 9093dd4db47SLogan Gunthorpe return 0; 9103dd4db47SLogan Gunthorpe } 9113dd4db47SLogan Gunthorpe 9123dd4db47SLogan Gunthorpe static void switchtec_ntb_deinit_db_msg_irq(struct switchtec_ntb *sndev) 9133dd4db47SLogan Gunthorpe { 9143dd4db47SLogan Gunthorpe free_irq(sndev->doorbell_irq, sndev); 9153dd4db47SLogan Gunthorpe free_irq(sndev->message_irq, sndev); 9163dd4db47SLogan Gunthorpe } 9173dd4db47SLogan Gunthorpe 91833dea5aaSLogan Gunthorpe static int switchtec_ntb_add(struct device *dev, 91933dea5aaSLogan Gunthorpe struct class_interface *class_intf) 92033dea5aaSLogan Gunthorpe { 92133dea5aaSLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 92233dea5aaSLogan Gunthorpe struct switchtec_ntb *sndev; 923ec0467ccSLogan Gunthorpe int rc; 92433dea5aaSLogan Gunthorpe 92533dea5aaSLogan Gunthorpe stdev->sndev = NULL; 92633dea5aaSLogan Gunthorpe 92733dea5aaSLogan Gunthorpe if (stdev->pdev->class != MICROSEMI_NTB_CLASSCODE) 92833dea5aaSLogan Gunthorpe return -ENODEV; 92933dea5aaSLogan Gunthorpe 930ec0467ccSLogan Gunthorpe if (stdev->partition_count != 2) 931ec0467ccSLogan Gunthorpe dev_warn(dev, "ntb driver only supports 2 partitions"); 932ec0467ccSLogan Gunthorpe 93333dea5aaSLogan Gunthorpe sndev = kzalloc_node(sizeof(*sndev), GFP_KERNEL, dev_to_node(dev)); 93433dea5aaSLogan Gunthorpe if (!sndev) 93533dea5aaSLogan Gunthorpe return -ENOMEM; 93633dea5aaSLogan Gunthorpe 93733dea5aaSLogan Gunthorpe sndev->stdev = stdev; 938ec0467ccSLogan Gunthorpe switchtec_ntb_init_sndev(sndev); 939ec0467ccSLogan Gunthorpe switchtec_ntb_init_mw(sndev); 9403dd4db47SLogan Gunthorpe switchtec_ntb_init_db(sndev); 9413dd4db47SLogan Gunthorpe switchtec_ntb_init_msgs(sndev); 942ec0467ccSLogan Gunthorpe 943ec0467ccSLogan Gunthorpe rc = switchtec_ntb_init_req_id_table(sndev); 944ec0467ccSLogan Gunthorpe if (rc) 945ec0467ccSLogan Gunthorpe goto free_and_exit; 946ec0467ccSLogan Gunthorpe 947ec0467ccSLogan Gunthorpe rc = switchtec_ntb_init_shared_mw(sndev); 948ec0467ccSLogan Gunthorpe if (rc) 949ec0467ccSLogan Gunthorpe goto free_and_exit; 950ec0467ccSLogan Gunthorpe 9513dd4db47SLogan Gunthorpe rc = switchtec_ntb_init_db_msg_irq(sndev); 9523dd4db47SLogan Gunthorpe if (rc) 9533dd4db47SLogan Gunthorpe goto deinit_shared_and_exit; 9543dd4db47SLogan Gunthorpe 955e099b45bSLogan Gunthorpe rc = ntb_register_device(&sndev->ntb); 956e099b45bSLogan Gunthorpe if (rc) 957e099b45bSLogan Gunthorpe goto deinit_and_exit; 958e099b45bSLogan Gunthorpe 95933dea5aaSLogan Gunthorpe stdev->sndev = sndev; 9600ee28f26SLogan Gunthorpe stdev->link_notifier = switchtec_ntb_link_notification; 96133dea5aaSLogan Gunthorpe dev_info(dev, "NTB device registered"); 96233dea5aaSLogan Gunthorpe 96333dea5aaSLogan Gunthorpe return 0; 964ec0467ccSLogan Gunthorpe 965e099b45bSLogan Gunthorpe deinit_and_exit: 966e099b45bSLogan Gunthorpe switchtec_ntb_deinit_db_msg_irq(sndev); 9673dd4db47SLogan Gunthorpe deinit_shared_and_exit: 9683dd4db47SLogan Gunthorpe switchtec_ntb_deinit_shared_mw(sndev); 969ec0467ccSLogan Gunthorpe free_and_exit: 970ec0467ccSLogan Gunthorpe kfree(sndev); 971ec0467ccSLogan Gunthorpe dev_err(dev, "failed to register ntb device: %d", rc); 972ec0467ccSLogan Gunthorpe return rc; 97333dea5aaSLogan Gunthorpe } 97433dea5aaSLogan Gunthorpe 97533dea5aaSLogan Gunthorpe void switchtec_ntb_remove(struct device *dev, 97633dea5aaSLogan Gunthorpe struct class_interface *class_intf) 97733dea5aaSLogan Gunthorpe { 97833dea5aaSLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 97933dea5aaSLogan Gunthorpe struct switchtec_ntb *sndev = stdev->sndev; 98033dea5aaSLogan Gunthorpe 98133dea5aaSLogan Gunthorpe if (!sndev) 98233dea5aaSLogan Gunthorpe return; 98333dea5aaSLogan Gunthorpe 9840ee28f26SLogan Gunthorpe stdev->link_notifier = NULL; 98533dea5aaSLogan Gunthorpe stdev->sndev = NULL; 986e099b45bSLogan Gunthorpe ntb_unregister_device(&sndev->ntb); 9873dd4db47SLogan Gunthorpe switchtec_ntb_deinit_db_msg_irq(sndev); 988ec0467ccSLogan Gunthorpe switchtec_ntb_deinit_shared_mw(sndev); 98933dea5aaSLogan Gunthorpe kfree(sndev); 99033dea5aaSLogan Gunthorpe dev_info(dev, "ntb device unregistered"); 99133dea5aaSLogan Gunthorpe } 99233dea5aaSLogan Gunthorpe 99333dea5aaSLogan Gunthorpe static struct class_interface switchtec_interface = { 99433dea5aaSLogan Gunthorpe .add_dev = switchtec_ntb_add, 99533dea5aaSLogan Gunthorpe .remove_dev = switchtec_ntb_remove, 99633dea5aaSLogan Gunthorpe }; 99733dea5aaSLogan Gunthorpe 99833dea5aaSLogan Gunthorpe static int __init switchtec_ntb_init(void) 99933dea5aaSLogan Gunthorpe { 100033dea5aaSLogan Gunthorpe switchtec_interface.class = switchtec_class; 100133dea5aaSLogan Gunthorpe return class_interface_register(&switchtec_interface); 100233dea5aaSLogan Gunthorpe } 100333dea5aaSLogan Gunthorpe module_init(switchtec_ntb_init); 100433dea5aaSLogan Gunthorpe 100533dea5aaSLogan Gunthorpe static void __exit switchtec_ntb_exit(void) 100633dea5aaSLogan Gunthorpe { 100733dea5aaSLogan Gunthorpe class_interface_unregister(&switchtec_interface); 100833dea5aaSLogan Gunthorpe } 100933dea5aaSLogan Gunthorpe module_exit(switchtec_ntb_exit); 1010