162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 362306a36Sopenharmony_ci * redistributing this file, you may do so under either license. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * GPL LICENSE SUMMARY 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 862306a36Sopenharmony_ci * Copyright (C) 2016 T-Platforms. All Rights Reserved. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 1162306a36Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 1262306a36Sopenharmony_ci * published by the Free Software Foundation. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 1562306a36Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 1662306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1762306a36Sopenharmony_ci * General Public License for more details. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * BSD LICENSE 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * Copyright (C) 2015 EMC Corporation. All Rights Reserved. 2262306a36Sopenharmony_ci * Copyright (C) 2016 T-Platforms. All Rights Reserved. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 2562306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 2662306a36Sopenharmony_ci * are met: 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * * Redistributions of source code must retain the above copyright 2962306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 3062306a36Sopenharmony_ci * * Redistributions in binary form must reproduce the above copy 3162306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 3262306a36Sopenharmony_ci * the documentation and/or other materials provided with the 3362306a36Sopenharmony_ci * distribution. 3462306a36Sopenharmony_ci * * Neither the name of Intel Corporation nor the names of its 3562306a36Sopenharmony_ci * contributors may be used to endorse or promote products derived 3662306a36Sopenharmony_ci * from this software without specific prior written permission. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3962306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 4062306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 4162306a36Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 4262306a36Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4362306a36Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 4462306a36Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 4562306a36Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 4662306a36Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 4762306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 4862306a36Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * PCIe NTB Linux driver 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * Contact Information: 5362306a36Sopenharmony_ci * Allen Hubbe <Allen.Hubbe@emc.com> 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include <linux/device.h> 5762306a36Sopenharmony_ci#include <linux/kernel.h> 5862306a36Sopenharmony_ci#include <linux/module.h> 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#include <linux/ntb.h> 6162306a36Sopenharmony_ci#include <linux/pci.h> 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define DRIVER_NAME "ntb" 6462306a36Sopenharmony_ci#define DRIVER_DESCRIPTION "PCIe NTB Driver Framework" 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define DRIVER_VERSION "1.0" 6762306a36Sopenharmony_ci#define DRIVER_RELDATE "24 March 2015" 6862306a36Sopenharmony_ci#define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>" 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 7162306a36Sopenharmony_ciMODULE_VERSION(DRIVER_VERSION); 7262306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 7362306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESCRIPTION); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic struct bus_type ntb_bus; 7662306a36Sopenharmony_cistatic void ntb_dev_release(struct device *dev); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciint __ntb_register_client(struct ntb_client *client, struct module *mod, 7962306a36Sopenharmony_ci const char *mod_name) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci if (!client) 8262306a36Sopenharmony_ci return -EINVAL; 8362306a36Sopenharmony_ci if (!ntb_client_ops_is_valid(&client->ops)) 8462306a36Sopenharmony_ci return -EINVAL; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci memset(&client->drv, 0, sizeof(client->drv)); 8762306a36Sopenharmony_ci client->drv.bus = &ntb_bus; 8862306a36Sopenharmony_ci client->drv.name = mod_name; 8962306a36Sopenharmony_ci client->drv.owner = mod; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return driver_register(&client->drv); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ciEXPORT_SYMBOL(__ntb_register_client); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_civoid ntb_unregister_client(struct ntb_client *client) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci driver_unregister(&client->drv); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_unregister_client); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciint ntb_register_device(struct ntb_dev *ntb) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int ret; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (!ntb) 10662306a36Sopenharmony_ci return -EINVAL; 10762306a36Sopenharmony_ci if (!ntb->pdev) 10862306a36Sopenharmony_ci return -EINVAL; 10962306a36Sopenharmony_ci if (!ntb->ops) 11062306a36Sopenharmony_ci return -EINVAL; 11162306a36Sopenharmony_ci if (!ntb_dev_ops_is_valid(ntb->ops)) 11262306a36Sopenharmony_ci return -EINVAL; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci init_completion(&ntb->released); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci ntb->dev.bus = &ntb_bus; 11762306a36Sopenharmony_ci ntb->dev.parent = &ntb->pdev->dev; 11862306a36Sopenharmony_ci ntb->dev.release = ntb_dev_release; 11962306a36Sopenharmony_ci dev_set_name(&ntb->dev, "%s", pci_name(ntb->pdev)); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci ntb->ctx = NULL; 12262306a36Sopenharmony_ci ntb->ctx_ops = NULL; 12362306a36Sopenharmony_ci spin_lock_init(&ntb->ctx_lock); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci ret = device_register(&ntb->dev); 12662306a36Sopenharmony_ci if (ret) 12762306a36Sopenharmony_ci put_device(&ntb->dev); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return ret; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_register_device); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_civoid ntb_unregister_device(struct ntb_dev *ntb) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci device_unregister(&ntb->dev); 13662306a36Sopenharmony_ci wait_for_completion(&ntb->released); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_unregister_device); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ciint ntb_set_ctx(struct ntb_dev *ntb, void *ctx, 14162306a36Sopenharmony_ci const struct ntb_ctx_ops *ctx_ops) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci unsigned long irqflags; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (!ntb_ctx_ops_is_valid(ctx_ops)) 14662306a36Sopenharmony_ci return -EINVAL; 14762306a36Sopenharmony_ci if (ntb->ctx_ops) 14862306a36Sopenharmony_ci return -EINVAL; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci spin_lock_irqsave(&ntb->ctx_lock, irqflags); 15162306a36Sopenharmony_ci { 15262306a36Sopenharmony_ci ntb->ctx = ctx; 15362306a36Sopenharmony_ci ntb->ctx_ops = ctx_ops; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_set_ctx); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_civoid ntb_clear_ctx(struct ntb_dev *ntb) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci unsigned long irqflags; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci spin_lock_irqsave(&ntb->ctx_lock, irqflags); 16662306a36Sopenharmony_ci { 16762306a36Sopenharmony_ci ntb->ctx_ops = NULL; 16862306a36Sopenharmony_ci ntb->ctx = NULL; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_clear_ctx); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_civoid ntb_link_event(struct ntb_dev *ntb) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci unsigned long irqflags; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci spin_lock_irqsave(&ntb->ctx_lock, irqflags); 17962306a36Sopenharmony_ci { 18062306a36Sopenharmony_ci if (ntb->ctx_ops && ntb->ctx_ops->link_event) 18162306a36Sopenharmony_ci ntb->ctx_ops->link_event(ntb->ctx); 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_link_event); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_civoid ntb_db_event(struct ntb_dev *ntb, int vector) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci unsigned long irqflags; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci spin_lock_irqsave(&ntb->ctx_lock, irqflags); 19262306a36Sopenharmony_ci { 19362306a36Sopenharmony_ci if (ntb->ctx_ops && ntb->ctx_ops->db_event) 19462306a36Sopenharmony_ci ntb->ctx_ops->db_event(ntb->ctx, vector); 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_db_event); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_civoid ntb_msg_event(struct ntb_dev *ntb) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci unsigned long irqflags; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci spin_lock_irqsave(&ntb->ctx_lock, irqflags); 20562306a36Sopenharmony_ci { 20662306a36Sopenharmony_ci if (ntb->ctx_ops && ntb->ctx_ops->msg_event) 20762306a36Sopenharmony_ci ntb->ctx_ops->msg_event(ntb->ctx); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_msg_event); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ciint ntb_default_port_number(struct ntb_dev *ntb) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci switch (ntb->topo) { 21662306a36Sopenharmony_ci case NTB_TOPO_PRI: 21762306a36Sopenharmony_ci case NTB_TOPO_B2B_USD: 21862306a36Sopenharmony_ci return NTB_PORT_PRI_USD; 21962306a36Sopenharmony_ci case NTB_TOPO_SEC: 22062306a36Sopenharmony_ci case NTB_TOPO_B2B_DSD: 22162306a36Sopenharmony_ci return NTB_PORT_SEC_DSD; 22262306a36Sopenharmony_ci default: 22362306a36Sopenharmony_ci return 0; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_default_port_number); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ciint ntb_default_peer_port_count(struct ntb_dev *ntb) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci return NTB_DEF_PEER_CNT; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_default_peer_port_count); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciint ntb_default_peer_port_number(struct ntb_dev *ntb, int pidx) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci if (pidx != NTB_DEF_PEER_IDX) 23762306a36Sopenharmony_ci return -EINVAL; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci switch (ntb->topo) { 24062306a36Sopenharmony_ci case NTB_TOPO_PRI: 24162306a36Sopenharmony_ci case NTB_TOPO_B2B_USD: 24262306a36Sopenharmony_ci return NTB_PORT_SEC_DSD; 24362306a36Sopenharmony_ci case NTB_TOPO_SEC: 24462306a36Sopenharmony_ci case NTB_TOPO_B2B_DSD: 24562306a36Sopenharmony_ci return NTB_PORT_PRI_USD; 24662306a36Sopenharmony_ci default: 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_default_peer_port_number); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ciint ntb_default_peer_port_idx(struct ntb_dev *ntb, int port) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci int peer_port = ntb_default_peer_port_number(ntb, NTB_DEF_PEER_IDX); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (peer_port == -EINVAL || port != peer_port) 25762306a36Sopenharmony_ci return -EINVAL; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ciEXPORT_SYMBOL(ntb_default_peer_port_idx); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int ntb_probe(struct device *dev) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct ntb_dev *ntb; 26662306a36Sopenharmony_ci struct ntb_client *client; 26762306a36Sopenharmony_ci int rc; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci get_device(dev); 27062306a36Sopenharmony_ci ntb = dev_ntb(dev); 27162306a36Sopenharmony_ci client = drv_ntb_client(dev->driver); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci rc = client->ops.probe(client, ntb); 27462306a36Sopenharmony_ci if (rc) 27562306a36Sopenharmony_ci put_device(dev); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return rc; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic void ntb_remove(struct device *dev) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct ntb_dev *ntb; 28362306a36Sopenharmony_ci struct ntb_client *client; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (dev->driver) { 28662306a36Sopenharmony_ci ntb = dev_ntb(dev); 28762306a36Sopenharmony_ci client = drv_ntb_client(dev->driver); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci client->ops.remove(client, ntb); 29062306a36Sopenharmony_ci put_device(dev); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic void ntb_dev_release(struct device *dev) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct ntb_dev *ntb = dev_ntb(dev); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci complete(&ntb->released); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic struct bus_type ntb_bus = { 30262306a36Sopenharmony_ci .name = "ntb", 30362306a36Sopenharmony_ci .probe = ntb_probe, 30462306a36Sopenharmony_ci .remove = ntb_remove, 30562306a36Sopenharmony_ci}; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int __init ntb_driver_init(void) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci return bus_register(&ntb_bus); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_cimodule_init(ntb_driver_init); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic void __exit ntb_driver_exit(void) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci bus_unregister(&ntb_bus); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_cimodule_exit(ntb_driver_exit); 318