162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* Authors: Cheng Xu <chengyou@linux.alibaba.com> */ 462306a36Sopenharmony_ci/* Kai Shen <kaishen@linux.alibaba.com> */ 562306a36Sopenharmony_ci/* Copyright (c) 2020-2022, Alibaba Group. */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <net/addrconf.h> 962306a36Sopenharmony_ci#include <rdma/erdma-abi.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "erdma.h" 1262306a36Sopenharmony_ci#include "erdma_cm.h" 1362306a36Sopenharmony_ci#include "erdma_verbs.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciMODULE_AUTHOR("Cheng Xu <chengyou@linux.alibaba.com>"); 1662306a36Sopenharmony_ciMODULE_DESCRIPTION("Alibaba elasticRDMA adapter driver"); 1762306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int erdma_netdev_event(struct notifier_block *nb, unsigned long event, 2062306a36Sopenharmony_ci void *arg) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct net_device *netdev = netdev_notifier_info_to_dev(arg); 2362306a36Sopenharmony_ci struct erdma_dev *dev = container_of(nb, struct erdma_dev, netdev_nb); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci if (dev->netdev == NULL || dev->netdev != netdev) 2662306a36Sopenharmony_ci goto done; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci switch (event) { 2962306a36Sopenharmony_ci case NETDEV_UP: 3062306a36Sopenharmony_ci dev->state = IB_PORT_ACTIVE; 3162306a36Sopenharmony_ci erdma_port_event(dev, IB_EVENT_PORT_ACTIVE); 3262306a36Sopenharmony_ci break; 3362306a36Sopenharmony_ci case NETDEV_DOWN: 3462306a36Sopenharmony_ci dev->state = IB_PORT_DOWN; 3562306a36Sopenharmony_ci erdma_port_event(dev, IB_EVENT_PORT_ERR); 3662306a36Sopenharmony_ci break; 3762306a36Sopenharmony_ci case NETDEV_CHANGEMTU: 3862306a36Sopenharmony_ci if (dev->mtu != netdev->mtu) { 3962306a36Sopenharmony_ci erdma_set_mtu(dev, netdev->mtu); 4062306a36Sopenharmony_ci dev->mtu = netdev->mtu; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci break; 4362306a36Sopenharmony_ci case NETDEV_REGISTER: 4462306a36Sopenharmony_ci case NETDEV_UNREGISTER: 4562306a36Sopenharmony_ci case NETDEV_CHANGEADDR: 4662306a36Sopenharmony_ci case NETDEV_GOING_DOWN: 4762306a36Sopenharmony_ci case NETDEV_CHANGE: 4862306a36Sopenharmony_ci default: 4962306a36Sopenharmony_ci break; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cidone: 5362306a36Sopenharmony_ci return NOTIFY_OK; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int erdma_enum_and_get_netdev(struct erdma_dev *dev) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct net_device *netdev; 5962306a36Sopenharmony_ci int ret = -EPROBE_DEFER; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* Already binded to a net_device, so we skip. */ 6262306a36Sopenharmony_ci if (dev->netdev) 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci rtnl_lock(); 6662306a36Sopenharmony_ci for_each_netdev(&init_net, netdev) { 6762306a36Sopenharmony_ci /* 6862306a36Sopenharmony_ci * In erdma, the paired netdev and ibdev should have the same 6962306a36Sopenharmony_ci * MAC address. erdma can get the value from its PCIe bar 7062306a36Sopenharmony_ci * registers. Since erdma can not get the paired netdev 7162306a36Sopenharmony_ci * reference directly, we do a traverse here to get the paired 7262306a36Sopenharmony_ci * netdev. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci if (ether_addr_equal_unaligned(netdev->perm_addr, 7562306a36Sopenharmony_ci dev->attrs.peer_addr)) { 7662306a36Sopenharmony_ci ret = ib_device_set_netdev(&dev->ibdev, netdev, 1); 7762306a36Sopenharmony_ci if (ret) { 7862306a36Sopenharmony_ci rtnl_unlock(); 7962306a36Sopenharmony_ci ibdev_warn(&dev->ibdev, 8062306a36Sopenharmony_ci "failed (%d) to link netdev", ret); 8162306a36Sopenharmony_ci return ret; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci dev->netdev = netdev; 8562306a36Sopenharmony_ci break; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci rtnl_unlock(); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return ret; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int erdma_device_register(struct erdma_dev *dev) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct ib_device *ibdev = &dev->ibdev; 9762306a36Sopenharmony_ci int ret; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci ret = erdma_enum_and_get_netdev(dev); 10062306a36Sopenharmony_ci if (ret) 10162306a36Sopenharmony_ci return ret; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci dev->mtu = dev->netdev->mtu; 10462306a36Sopenharmony_ci addrconf_addr_eui48((u8 *)&ibdev->node_guid, dev->netdev->dev_addr); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci ret = ib_register_device(ibdev, "erdma_%d", &dev->pdev->dev); 10762306a36Sopenharmony_ci if (ret) { 10862306a36Sopenharmony_ci dev_err(&dev->pdev->dev, 10962306a36Sopenharmony_ci "ib_register_device failed: ret = %d\n", ret); 11062306a36Sopenharmony_ci return ret; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci dev->netdev_nb.notifier_call = erdma_netdev_event; 11462306a36Sopenharmony_ci ret = register_netdevice_notifier(&dev->netdev_nb); 11562306a36Sopenharmony_ci if (ret) { 11662306a36Sopenharmony_ci ibdev_err(&dev->ibdev, "failed to register notifier.\n"); 11762306a36Sopenharmony_ci ib_unregister_device(ibdev); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return ret; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic irqreturn_t erdma_comm_irq_handler(int irq, void *data) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct erdma_dev *dev = data; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci erdma_cmdq_completion_handler(&dev->cmdq); 12862306a36Sopenharmony_ci erdma_aeq_event_handler(dev); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return IRQ_HANDLED; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int erdma_request_vectors(struct erdma_dev *dev) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci int expect_irq_num = min(num_possible_cpus() + 1, ERDMA_NUM_MSIX_VEC); 13662306a36Sopenharmony_ci int ret; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(dev->pdev, 1, expect_irq_num, PCI_IRQ_MSIX); 13962306a36Sopenharmony_ci if (ret < 0) { 14062306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "request irq vectors failed(%d)\n", 14162306a36Sopenharmony_ci ret); 14262306a36Sopenharmony_ci return ret; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci dev->attrs.irq_num = ret; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic int erdma_comm_irq_init(struct erdma_dev *dev) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci snprintf(dev->comm_irq.name, ERDMA_IRQNAME_SIZE, "erdma-common@pci:%s", 15262306a36Sopenharmony_ci pci_name(dev->pdev)); 15362306a36Sopenharmony_ci dev->comm_irq.msix_vector = 15462306a36Sopenharmony_ci pci_irq_vector(dev->pdev, ERDMA_MSIX_VECTOR_CMDQ); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci cpumask_set_cpu(cpumask_first(cpumask_of_pcibus(dev->pdev->bus)), 15762306a36Sopenharmony_ci &dev->comm_irq.affinity_hint_mask); 15862306a36Sopenharmony_ci irq_set_affinity_hint(dev->comm_irq.msix_vector, 15962306a36Sopenharmony_ci &dev->comm_irq.affinity_hint_mask); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return request_irq(dev->comm_irq.msix_vector, erdma_comm_irq_handler, 0, 16262306a36Sopenharmony_ci dev->comm_irq.name, dev); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic void erdma_comm_irq_uninit(struct erdma_dev *dev) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci irq_set_affinity_hint(dev->comm_irq.msix_vector, NULL); 16862306a36Sopenharmony_ci free_irq(dev->comm_irq.msix_vector, dev); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int erdma_device_init(struct erdma_dev *dev, struct pci_dev *pdev) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci int ret; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(&pdev->dev, 17662306a36Sopenharmony_ci DMA_BIT_MASK(ERDMA_PCI_WIDTH)); 17762306a36Sopenharmony_ci if (ret) 17862306a36Sopenharmony_ci return ret; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci dma_set_max_seg_size(&pdev->dev, UINT_MAX); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic void erdma_hw_reset(struct erdma_dev *dev) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci u32 ctrl = FIELD_PREP(ERDMA_REG_DEV_CTRL_RESET_MASK, 1); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci erdma_reg_write32(dev, ERDMA_REGS_DEV_CTRL_REG, ctrl); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int erdma_wait_hw_init_done(struct erdma_dev *dev) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci int i; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci erdma_reg_write32(dev, ERDMA_REGS_DEV_CTRL_REG, 19762306a36Sopenharmony_ci FIELD_PREP(ERDMA_REG_DEV_CTRL_INIT_MASK, 1)); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci for (i = 0; i < ERDMA_WAIT_DEV_DONE_CNT; i++) { 20062306a36Sopenharmony_ci if (erdma_reg_read32_filed(dev, ERDMA_REGS_DEV_ST_REG, 20162306a36Sopenharmony_ci ERDMA_REG_DEV_ST_INIT_DONE_MASK)) 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci msleep(ERDMA_REG_ACCESS_WAIT_MS); 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (i == ERDMA_WAIT_DEV_DONE_CNT) { 20862306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "wait init done failed.\n"); 20962306a36Sopenharmony_ci return -ETIMEDOUT; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci return 0; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic const struct pci_device_id erdma_pci_tbl[] = { 21662306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ALIBABA, 0x107f) }, 21762306a36Sopenharmony_ci {} 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int erdma_probe_dev(struct pci_dev *pdev) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct erdma_dev *dev; 22362306a36Sopenharmony_ci int bars, err; 22462306a36Sopenharmony_ci u32 version; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci err = pci_enable_device(pdev); 22762306a36Sopenharmony_ci if (err) { 22862306a36Sopenharmony_ci dev_err(&pdev->dev, "pci_enable_device failed(%d)\n", err); 22962306a36Sopenharmony_ci return err; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci pci_set_master(pdev); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci dev = ib_alloc_device(erdma_dev, ibdev); 23562306a36Sopenharmony_ci if (!dev) { 23662306a36Sopenharmony_ci dev_err(&pdev->dev, "ib_alloc_device failed\n"); 23762306a36Sopenharmony_ci err = -ENOMEM; 23862306a36Sopenharmony_ci goto err_disable_device; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci pci_set_drvdata(pdev, dev); 24262306a36Sopenharmony_ci dev->pdev = pdev; 24362306a36Sopenharmony_ci dev->attrs.numa_node = dev_to_node(&pdev->dev); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci bars = pci_select_bars(pdev, IORESOURCE_MEM); 24662306a36Sopenharmony_ci err = pci_request_selected_regions(pdev, bars, DRV_MODULE_NAME); 24762306a36Sopenharmony_ci if (bars != ERDMA_BAR_MASK || err) { 24862306a36Sopenharmony_ci err = err ? err : -EINVAL; 24962306a36Sopenharmony_ci goto err_ib_device_release; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci dev->func_bar_addr = pci_resource_start(pdev, ERDMA_FUNC_BAR); 25362306a36Sopenharmony_ci dev->func_bar_len = pci_resource_len(pdev, ERDMA_FUNC_BAR); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci dev->func_bar = 25662306a36Sopenharmony_ci devm_ioremap(&pdev->dev, dev->func_bar_addr, dev->func_bar_len); 25762306a36Sopenharmony_ci if (!dev->func_bar) { 25862306a36Sopenharmony_ci dev_err(&pdev->dev, "devm_ioremap failed.\n"); 25962306a36Sopenharmony_ci err = -EFAULT; 26062306a36Sopenharmony_ci goto err_release_bars; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci version = erdma_reg_read32(dev, ERDMA_REGS_VERSION_REG); 26462306a36Sopenharmony_ci if (version == 0) { 26562306a36Sopenharmony_ci /* we knows that it is a non-functional function. */ 26662306a36Sopenharmony_ci err = -ENODEV; 26762306a36Sopenharmony_ci goto err_iounmap_func_bar; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci err = erdma_device_init(dev, pdev); 27162306a36Sopenharmony_ci if (err) 27262306a36Sopenharmony_ci goto err_iounmap_func_bar; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci err = erdma_request_vectors(dev); 27562306a36Sopenharmony_ci if (err) 27662306a36Sopenharmony_ci goto err_iounmap_func_bar; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci err = erdma_comm_irq_init(dev); 27962306a36Sopenharmony_ci if (err) 28062306a36Sopenharmony_ci goto err_free_vectors; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci err = erdma_aeq_init(dev); 28362306a36Sopenharmony_ci if (err) 28462306a36Sopenharmony_ci goto err_uninit_comm_irq; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci err = erdma_cmdq_init(dev); 28762306a36Sopenharmony_ci if (err) 28862306a36Sopenharmony_ci goto err_uninit_aeq; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci err = erdma_wait_hw_init_done(dev); 29162306a36Sopenharmony_ci if (err) 29262306a36Sopenharmony_ci goto err_uninit_cmdq; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci err = erdma_ceqs_init(dev); 29562306a36Sopenharmony_ci if (err) 29662306a36Sopenharmony_ci goto err_reset_hw; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci erdma_finish_cmdq_init(dev); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cierr_reset_hw: 30362306a36Sopenharmony_ci erdma_hw_reset(dev); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cierr_uninit_cmdq: 30662306a36Sopenharmony_ci erdma_cmdq_destroy(dev); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cierr_uninit_aeq: 30962306a36Sopenharmony_ci erdma_aeq_destroy(dev); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cierr_uninit_comm_irq: 31262306a36Sopenharmony_ci erdma_comm_irq_uninit(dev); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cierr_free_vectors: 31562306a36Sopenharmony_ci pci_free_irq_vectors(dev->pdev); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cierr_iounmap_func_bar: 31862306a36Sopenharmony_ci devm_iounmap(&pdev->dev, dev->func_bar); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cierr_release_bars: 32162306a36Sopenharmony_ci pci_release_selected_regions(pdev, bars); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cierr_ib_device_release: 32462306a36Sopenharmony_ci ib_dealloc_device(&dev->ibdev); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cierr_disable_device: 32762306a36Sopenharmony_ci pci_disable_device(pdev); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return err; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic void erdma_remove_dev(struct pci_dev *pdev) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct erdma_dev *dev = pci_get_drvdata(pdev); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci erdma_ceqs_uninit(dev); 33762306a36Sopenharmony_ci erdma_hw_reset(dev); 33862306a36Sopenharmony_ci erdma_cmdq_destroy(dev); 33962306a36Sopenharmony_ci erdma_aeq_destroy(dev); 34062306a36Sopenharmony_ci erdma_comm_irq_uninit(dev); 34162306a36Sopenharmony_ci pci_free_irq_vectors(dev->pdev); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci devm_iounmap(&pdev->dev, dev->func_bar); 34462306a36Sopenharmony_ci pci_release_selected_regions(pdev, ERDMA_BAR_MASK); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci ib_dealloc_device(&dev->ibdev); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci pci_disable_device(pdev); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci#define ERDMA_GET_CAP(name, cap) FIELD_GET(ERDMA_CMD_DEV_CAP_##name##_MASK, cap) 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic int erdma_dev_attrs_init(struct erdma_dev *dev) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci int err; 35662306a36Sopenharmony_ci u64 req_hdr, cap0, cap1; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci erdma_cmdq_build_reqhdr(&req_hdr, CMDQ_SUBMOD_RDMA, 35962306a36Sopenharmony_ci CMDQ_OPCODE_QUERY_DEVICE); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci err = erdma_post_cmd_wait(&dev->cmdq, &req_hdr, sizeof(req_hdr), &cap0, 36262306a36Sopenharmony_ci &cap1); 36362306a36Sopenharmony_ci if (err) 36462306a36Sopenharmony_ci return err; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci dev->attrs.max_cqe = 1 << ERDMA_GET_CAP(MAX_CQE, cap0); 36762306a36Sopenharmony_ci dev->attrs.max_mr_size = 1ULL << ERDMA_GET_CAP(MAX_MR_SIZE, cap0); 36862306a36Sopenharmony_ci dev->attrs.max_mw = 1 << ERDMA_GET_CAP(MAX_MW, cap1); 36962306a36Sopenharmony_ci dev->attrs.max_recv_wr = 1 << ERDMA_GET_CAP(MAX_RECV_WR, cap0); 37062306a36Sopenharmony_ci dev->attrs.local_dma_key = ERDMA_GET_CAP(DMA_LOCAL_KEY, cap1); 37162306a36Sopenharmony_ci dev->attrs.cc = ERDMA_GET_CAP(DEFAULT_CC, cap1); 37262306a36Sopenharmony_ci dev->attrs.max_qp = ERDMA_NQP_PER_QBLOCK * ERDMA_GET_CAP(QBLOCK, cap1); 37362306a36Sopenharmony_ci dev->attrs.max_mr = dev->attrs.max_qp << 1; 37462306a36Sopenharmony_ci dev->attrs.max_cq = dev->attrs.max_qp << 1; 37562306a36Sopenharmony_ci dev->attrs.cap_flags = ERDMA_GET_CAP(FLAGS, cap0); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci dev->attrs.max_send_wr = ERDMA_MAX_SEND_WR; 37862306a36Sopenharmony_ci dev->attrs.max_ord = ERDMA_MAX_ORD; 37962306a36Sopenharmony_ci dev->attrs.max_ird = ERDMA_MAX_IRD; 38062306a36Sopenharmony_ci dev->attrs.max_send_sge = ERDMA_MAX_SEND_SGE; 38162306a36Sopenharmony_ci dev->attrs.max_recv_sge = ERDMA_MAX_RECV_SGE; 38262306a36Sopenharmony_ci dev->attrs.max_sge_rd = ERDMA_MAX_SGE_RD; 38362306a36Sopenharmony_ci dev->attrs.max_pd = ERDMA_MAX_PD; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci dev->res_cb[ERDMA_RES_TYPE_PD].max_cap = ERDMA_MAX_PD; 38662306a36Sopenharmony_ci dev->res_cb[ERDMA_RES_TYPE_STAG_IDX].max_cap = dev->attrs.max_mr; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci erdma_cmdq_build_reqhdr(&req_hdr, CMDQ_SUBMOD_COMMON, 38962306a36Sopenharmony_ci CMDQ_OPCODE_QUERY_FW_INFO); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci err = erdma_post_cmd_wait(&dev->cmdq, &req_hdr, sizeof(req_hdr), &cap0, 39262306a36Sopenharmony_ci &cap1); 39362306a36Sopenharmony_ci if (!err) 39462306a36Sopenharmony_ci dev->attrs.fw_version = 39562306a36Sopenharmony_ci FIELD_GET(ERDMA_CMD_INFO0_FW_VER_MASK, cap0); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return err; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int erdma_device_config(struct erdma_dev *dev) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct erdma_cmdq_config_device_req req = {}; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (!(dev->attrs.cap_flags & ERDMA_DEV_CAP_FLAGS_EXTEND_DB)) 40562306a36Sopenharmony_ci return 0; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci erdma_cmdq_build_reqhdr(&req.hdr, CMDQ_SUBMOD_COMMON, 40862306a36Sopenharmony_ci CMDQ_OPCODE_CONF_DEVICE); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci req.cfg = FIELD_PREP(ERDMA_CMD_CONFIG_DEVICE_PGSHIFT_MASK, PAGE_SHIFT) | 41162306a36Sopenharmony_ci FIELD_PREP(ERDMA_CMD_CONFIG_DEVICE_PS_EN_MASK, 1); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return erdma_post_cmd_wait(&dev->cmdq, &req, sizeof(req), NULL, NULL); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int erdma_res_cb_init(struct erdma_dev *dev) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci int i, j; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci for (i = 0; i < ERDMA_RES_CNT; i++) { 42162306a36Sopenharmony_ci dev->res_cb[i].next_alloc_idx = 1; 42262306a36Sopenharmony_ci spin_lock_init(&dev->res_cb[i].lock); 42362306a36Sopenharmony_ci dev->res_cb[i].bitmap = 42462306a36Sopenharmony_ci bitmap_zalloc(dev->res_cb[i].max_cap, GFP_KERNEL); 42562306a36Sopenharmony_ci if (!dev->res_cb[i].bitmap) 42662306a36Sopenharmony_ci goto err; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return 0; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cierr: 43262306a36Sopenharmony_ci for (j = 0; j < i; j++) 43362306a36Sopenharmony_ci bitmap_free(dev->res_cb[j].bitmap); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return -ENOMEM; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic void erdma_res_cb_free(struct erdma_dev *dev) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci int i; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci for (i = 0; i < ERDMA_RES_CNT; i++) 44362306a36Sopenharmony_ci bitmap_free(dev->res_cb[i].bitmap); 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic const struct ib_device_ops erdma_device_ops = { 44762306a36Sopenharmony_ci .owner = THIS_MODULE, 44862306a36Sopenharmony_ci .driver_id = RDMA_DRIVER_ERDMA, 44962306a36Sopenharmony_ci .uverbs_abi_ver = ERDMA_ABI_VERSION, 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci .alloc_mr = erdma_ib_alloc_mr, 45262306a36Sopenharmony_ci .alloc_pd = erdma_alloc_pd, 45362306a36Sopenharmony_ci .alloc_ucontext = erdma_alloc_ucontext, 45462306a36Sopenharmony_ci .create_cq = erdma_create_cq, 45562306a36Sopenharmony_ci .create_qp = erdma_create_qp, 45662306a36Sopenharmony_ci .dealloc_pd = erdma_dealloc_pd, 45762306a36Sopenharmony_ci .dealloc_ucontext = erdma_dealloc_ucontext, 45862306a36Sopenharmony_ci .dereg_mr = erdma_dereg_mr, 45962306a36Sopenharmony_ci .destroy_cq = erdma_destroy_cq, 46062306a36Sopenharmony_ci .destroy_qp = erdma_destroy_qp, 46162306a36Sopenharmony_ci .get_dma_mr = erdma_get_dma_mr, 46262306a36Sopenharmony_ci .get_port_immutable = erdma_get_port_immutable, 46362306a36Sopenharmony_ci .iw_accept = erdma_accept, 46462306a36Sopenharmony_ci .iw_add_ref = erdma_qp_get_ref, 46562306a36Sopenharmony_ci .iw_connect = erdma_connect, 46662306a36Sopenharmony_ci .iw_create_listen = erdma_create_listen, 46762306a36Sopenharmony_ci .iw_destroy_listen = erdma_destroy_listen, 46862306a36Sopenharmony_ci .iw_get_qp = erdma_get_ibqp, 46962306a36Sopenharmony_ci .iw_reject = erdma_reject, 47062306a36Sopenharmony_ci .iw_rem_ref = erdma_qp_put_ref, 47162306a36Sopenharmony_ci .map_mr_sg = erdma_map_mr_sg, 47262306a36Sopenharmony_ci .mmap = erdma_mmap, 47362306a36Sopenharmony_ci .mmap_free = erdma_mmap_free, 47462306a36Sopenharmony_ci .modify_qp = erdma_modify_qp, 47562306a36Sopenharmony_ci .post_recv = erdma_post_recv, 47662306a36Sopenharmony_ci .post_send = erdma_post_send, 47762306a36Sopenharmony_ci .poll_cq = erdma_poll_cq, 47862306a36Sopenharmony_ci .query_device = erdma_query_device, 47962306a36Sopenharmony_ci .query_gid = erdma_query_gid, 48062306a36Sopenharmony_ci .query_port = erdma_query_port, 48162306a36Sopenharmony_ci .query_qp = erdma_query_qp, 48262306a36Sopenharmony_ci .req_notify_cq = erdma_req_notify_cq, 48362306a36Sopenharmony_ci .reg_user_mr = erdma_reg_user_mr, 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_cq, erdma_cq, ibcq), 48662306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_pd, erdma_pd, ibpd), 48762306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_ucontext, erdma_ucontext, ibucontext), 48862306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_qp, erdma_qp, ibqp), 48962306a36Sopenharmony_ci}; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic int erdma_ib_device_add(struct pci_dev *pdev) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct erdma_dev *dev = pci_get_drvdata(pdev); 49462306a36Sopenharmony_ci struct ib_device *ibdev = &dev->ibdev; 49562306a36Sopenharmony_ci u64 mac; 49662306a36Sopenharmony_ci int ret; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci ret = erdma_dev_attrs_init(dev); 49962306a36Sopenharmony_ci if (ret) 50062306a36Sopenharmony_ci return ret; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci ret = erdma_device_config(dev); 50362306a36Sopenharmony_ci if (ret) 50462306a36Sopenharmony_ci return ret; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci ibdev->node_type = RDMA_NODE_RNIC; 50762306a36Sopenharmony_ci memcpy(ibdev->node_desc, ERDMA_NODE_DESC, sizeof(ERDMA_NODE_DESC)); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * Current model (one-to-one device association): 51162306a36Sopenharmony_ci * One ERDMA device per net_device or, equivalently, 51262306a36Sopenharmony_ci * per physical port. 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_ci ibdev->phys_port_cnt = 1; 51562306a36Sopenharmony_ci ibdev->num_comp_vectors = dev->attrs.irq_num - 1; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci ib_set_device_ops(ibdev, &erdma_device_ops); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci INIT_LIST_HEAD(&dev->cep_list); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci spin_lock_init(&dev->lock); 52262306a36Sopenharmony_ci xa_init_flags(&dev->qp_xa, XA_FLAGS_ALLOC1); 52362306a36Sopenharmony_ci xa_init_flags(&dev->cq_xa, XA_FLAGS_ALLOC1); 52462306a36Sopenharmony_ci dev->next_alloc_cqn = 1; 52562306a36Sopenharmony_ci dev->next_alloc_qpn = 1; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci ret = erdma_res_cb_init(dev); 52862306a36Sopenharmony_ci if (ret) 52962306a36Sopenharmony_ci return ret; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci atomic_set(&dev->num_ctx, 0); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci mac = erdma_reg_read32(dev, ERDMA_REGS_NETDEV_MAC_L_REG); 53462306a36Sopenharmony_ci mac |= (u64)erdma_reg_read32(dev, ERDMA_REGS_NETDEV_MAC_H_REG) << 32; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci u64_to_ether_addr(mac, dev->attrs.peer_addr); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci dev->reflush_wq = alloc_workqueue("erdma-reflush-wq", WQ_UNBOUND, 53962306a36Sopenharmony_ci WQ_UNBOUND_MAX_ACTIVE); 54062306a36Sopenharmony_ci if (!dev->reflush_wq) { 54162306a36Sopenharmony_ci ret = -ENOMEM; 54262306a36Sopenharmony_ci goto err_alloc_workqueue; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci ret = erdma_device_register(dev); 54662306a36Sopenharmony_ci if (ret) 54762306a36Sopenharmony_ci goto err_register; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cierr_register: 55262306a36Sopenharmony_ci destroy_workqueue(dev->reflush_wq); 55362306a36Sopenharmony_cierr_alloc_workqueue: 55462306a36Sopenharmony_ci xa_destroy(&dev->qp_xa); 55562306a36Sopenharmony_ci xa_destroy(&dev->cq_xa); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci erdma_res_cb_free(dev); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return ret; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic void erdma_ib_device_remove(struct pci_dev *pdev) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct erdma_dev *dev = pci_get_drvdata(pdev); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci unregister_netdevice_notifier(&dev->netdev_nb); 56762306a36Sopenharmony_ci ib_unregister_device(&dev->ibdev); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci destroy_workqueue(dev->reflush_wq); 57062306a36Sopenharmony_ci erdma_res_cb_free(dev); 57162306a36Sopenharmony_ci xa_destroy(&dev->qp_xa); 57262306a36Sopenharmony_ci xa_destroy(&dev->cq_xa); 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic int erdma_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci int ret; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ret = erdma_probe_dev(pdev); 58062306a36Sopenharmony_ci if (ret) 58162306a36Sopenharmony_ci return ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci ret = erdma_ib_device_add(pdev); 58462306a36Sopenharmony_ci if (ret) { 58562306a36Sopenharmony_ci erdma_remove_dev(pdev); 58662306a36Sopenharmony_ci return ret; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci return 0; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic void erdma_remove(struct pci_dev *pdev) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci erdma_ib_device_remove(pdev); 59562306a36Sopenharmony_ci erdma_remove_dev(pdev); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic struct pci_driver erdma_pci_driver = { 59962306a36Sopenharmony_ci .name = DRV_MODULE_NAME, 60062306a36Sopenharmony_ci .id_table = erdma_pci_tbl, 60162306a36Sopenharmony_ci .probe = erdma_probe, 60262306a36Sopenharmony_ci .remove = erdma_remove 60362306a36Sopenharmony_ci}; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, erdma_pci_tbl); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic __init int erdma_init_module(void) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci int ret; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci ret = erdma_cm_init(); 61262306a36Sopenharmony_ci if (ret) 61362306a36Sopenharmony_ci return ret; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci ret = pci_register_driver(&erdma_pci_driver); 61662306a36Sopenharmony_ci if (ret) 61762306a36Sopenharmony_ci erdma_cm_exit(); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return ret; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic void __exit erdma_exit_module(void) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci pci_unregister_driver(&erdma_pci_driver); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci erdma_cm_exit(); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cimodule_init(erdma_init_module); 63062306a36Sopenharmony_cimodule_exit(erdma_exit_module); 631