Path: blob/master/drivers/infiniband/hw/amso1100/c2_rnic.c
15112 views
/*1* Copyright (c) 2005 Ammasso, Inc. All rights reserved.2* Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.3*4* This software is available to you under a choice of one of two5* licenses. You may choose to be licensed under the terms of the GNU6* General Public License (GPL) Version 2, available from the file7* COPYING in the main directory of this source tree, or the8* OpenIB.org BSD license below:9*10* Redistribution and use in source and binary forms, with or11* without modification, are permitted provided that the following12* conditions are met:13*14* - Redistributions of source code must retain the above15* copyright notice, this list of conditions and the following16* disclaimer.17*18* - Redistributions in binary form must reproduce the above19* copyright notice, this list of conditions and the following20* disclaimer in the documentation and/or other materials21* provided with the distribution.22*23* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30* SOFTWARE.31*32*/333435#include <linux/module.h>36#include <linux/moduleparam.h>37#include <linux/pci.h>38#include <linux/netdevice.h>39#include <linux/etherdevice.h>40#include <linux/delay.h>41#include <linux/ethtool.h>42#include <linux/mii.h>43#include <linux/if_vlan.h>44#include <linux/crc32.h>45#include <linux/in.h>46#include <linux/ip.h>47#include <linux/tcp.h>48#include <linux/init.h>49#include <linux/dma-mapping.h>50#include <linux/mm.h>51#include <linux/inet.h>52#include <linux/vmalloc.h>53#include <linux/slab.h>5455#include <linux/route.h>5657#include <asm/io.h>58#include <asm/irq.h>59#include <asm/byteorder.h>60#include <rdma/ib_smi.h>61#include "c2.h"62#include "c2_vq.h"6364/* Device capabilities */65#define C2_MIN_PAGESIZE 10246667#define C2_MAX_MRS 3276868#define C2_MAX_QPS 1600069#define C2_MAX_WQE_SZ 25670#define C2_MAX_QP_WR ((128*1024)/C2_MAX_WQE_SZ)71#define C2_MAX_SGES 472#define C2_MAX_SGE_RD 173#define C2_MAX_CQS 3276874#define C2_MAX_CQES 409675#define C2_MAX_PDS 163847677/*78* Send the adapter INIT message to the amso110079*/80static int c2_adapter_init(struct c2_dev *c2dev)81{82struct c2wr_init_req wr;83int err;8485memset(&wr, 0, sizeof(wr));86c2_wr_set_id(&wr, CCWR_INIT);87wr.hdr.context = 0;88wr.hint_count = cpu_to_be64(c2dev->hint_count_dma);89wr.q0_host_shared = cpu_to_be64(c2dev->req_vq.shared_dma);90wr.q1_host_shared = cpu_to_be64(c2dev->rep_vq.shared_dma);91wr.q1_host_msg_pool = cpu_to_be64(c2dev->rep_vq.host_dma);92wr.q2_host_shared = cpu_to_be64(c2dev->aeq.shared_dma);93wr.q2_host_msg_pool = cpu_to_be64(c2dev->aeq.host_dma);9495/* Post the init message */96err = vq_send_wr(c2dev, (union c2wr *) & wr);9798return err;99}100101/*102* Send the adapter TERM message to the amso1100103*/104static void c2_adapter_term(struct c2_dev *c2dev)105{106struct c2wr_init_req wr;107108memset(&wr, 0, sizeof(wr));109c2_wr_set_id(&wr, CCWR_TERM);110wr.hdr.context = 0;111112/* Post the init message */113vq_send_wr(c2dev, (union c2wr *) & wr);114c2dev->init = 0;115116return;117}118119/*120* Query the adapter121*/122static int c2_rnic_query(struct c2_dev *c2dev, struct ib_device_attr *props)123{124struct c2_vq_req *vq_req;125struct c2wr_rnic_query_req wr;126struct c2wr_rnic_query_rep *reply;127int err;128129vq_req = vq_req_alloc(c2dev);130if (!vq_req)131return -ENOMEM;132133c2_wr_set_id(&wr, CCWR_RNIC_QUERY);134wr.hdr.context = (unsigned long) vq_req;135wr.rnic_handle = c2dev->adapter_handle;136137vq_req_get(c2dev, vq_req);138139err = vq_send_wr(c2dev, (union c2wr *) &wr);140if (err) {141vq_req_put(c2dev, vq_req);142goto bail1;143}144145err = vq_wait_for_reply(c2dev, vq_req);146if (err)147goto bail1;148149reply =150(struct c2wr_rnic_query_rep *) (unsigned long) (vq_req->reply_msg);151if (!reply)152err = -ENOMEM;153else154err = c2_errno(reply);155if (err)156goto bail2;157158props->fw_ver =159((u64)be32_to_cpu(reply->fw_ver_major) << 32) |160((be32_to_cpu(reply->fw_ver_minor) & 0xFFFF) << 16) |161(be32_to_cpu(reply->fw_ver_patch) & 0xFFFF);162memcpy(&props->sys_image_guid, c2dev->netdev->dev_addr, 6);163props->max_mr_size = 0xFFFFFFFF;164props->page_size_cap = ~(C2_MIN_PAGESIZE-1);165props->vendor_id = be32_to_cpu(reply->vendor_id);166props->vendor_part_id = be32_to_cpu(reply->part_number);167props->hw_ver = be32_to_cpu(reply->hw_version);168props->max_qp = be32_to_cpu(reply->max_qps);169props->max_qp_wr = be32_to_cpu(reply->max_qp_depth);170props->device_cap_flags = c2dev->device_cap_flags;171props->max_sge = C2_MAX_SGES;172props->max_sge_rd = C2_MAX_SGE_RD;173props->max_cq = be32_to_cpu(reply->max_cqs);174props->max_cqe = be32_to_cpu(reply->max_cq_depth);175props->max_mr = be32_to_cpu(reply->max_mrs);176props->max_pd = be32_to_cpu(reply->max_pds);177props->max_qp_rd_atom = be32_to_cpu(reply->max_qp_ird);178props->max_ee_rd_atom = 0;179props->max_res_rd_atom = be32_to_cpu(reply->max_global_ird);180props->max_qp_init_rd_atom = be32_to_cpu(reply->max_qp_ord);181props->max_ee_init_rd_atom = 0;182props->atomic_cap = IB_ATOMIC_NONE;183props->max_ee = 0;184props->max_rdd = 0;185props->max_mw = be32_to_cpu(reply->max_mws);186props->max_raw_ipv6_qp = 0;187props->max_raw_ethy_qp = 0;188props->max_mcast_grp = 0;189props->max_mcast_qp_attach = 0;190props->max_total_mcast_qp_attach = 0;191props->max_ah = 0;192props->max_fmr = 0;193props->max_map_per_fmr = 0;194props->max_srq = 0;195props->max_srq_wr = 0;196props->max_srq_sge = 0;197props->max_pkeys = 0;198props->local_ca_ack_delay = 0;199200bail2:201vq_repbuf_free(c2dev, reply);202203bail1:204vq_req_free(c2dev, vq_req);205return err;206}207208/*209* Add an IP address to the RNIC interface210*/211int c2_add_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask)212{213struct c2_vq_req *vq_req;214struct c2wr_rnic_setconfig_req *wr;215struct c2wr_rnic_setconfig_rep *reply;216struct c2_netaddr netaddr;217int err, len;218219vq_req = vq_req_alloc(c2dev);220if (!vq_req)221return -ENOMEM;222223len = sizeof(struct c2_netaddr);224wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);225if (!wr) {226err = -ENOMEM;227goto bail0;228}229230c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG);231wr->hdr.context = (unsigned long) vq_req;232wr->rnic_handle = c2dev->adapter_handle;233wr->option = cpu_to_be32(C2_CFG_ADD_ADDR);234235netaddr.ip_addr = inaddr;236netaddr.netmask = inmask;237netaddr.mtu = 0;238239memcpy(wr->data, &netaddr, len);240241vq_req_get(c2dev, vq_req);242243err = vq_send_wr(c2dev, (union c2wr *) wr);244if (err) {245vq_req_put(c2dev, vq_req);246goto bail1;247}248249err = vq_wait_for_reply(c2dev, vq_req);250if (err)251goto bail1;252253reply =254(struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg);255if (!reply) {256err = -ENOMEM;257goto bail1;258}259260err = c2_errno(reply);261vq_repbuf_free(c2dev, reply);262263bail1:264kfree(wr);265bail0:266vq_req_free(c2dev, vq_req);267return err;268}269270/*271* Delete an IP address from the RNIC interface272*/273int c2_del_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask)274{275struct c2_vq_req *vq_req;276struct c2wr_rnic_setconfig_req *wr;277struct c2wr_rnic_setconfig_rep *reply;278struct c2_netaddr netaddr;279int err, len;280281vq_req = vq_req_alloc(c2dev);282if (!vq_req)283return -ENOMEM;284285len = sizeof(struct c2_netaddr);286wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);287if (!wr) {288err = -ENOMEM;289goto bail0;290}291292c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG);293wr->hdr.context = (unsigned long) vq_req;294wr->rnic_handle = c2dev->adapter_handle;295wr->option = cpu_to_be32(C2_CFG_DEL_ADDR);296297netaddr.ip_addr = inaddr;298netaddr.netmask = inmask;299netaddr.mtu = 0;300301memcpy(wr->data, &netaddr, len);302303vq_req_get(c2dev, vq_req);304305err = vq_send_wr(c2dev, (union c2wr *) wr);306if (err) {307vq_req_put(c2dev, vq_req);308goto bail1;309}310311err = vq_wait_for_reply(c2dev, vq_req);312if (err)313goto bail1;314315reply =316(struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg);317if (!reply) {318err = -ENOMEM;319goto bail1;320}321322err = c2_errno(reply);323vq_repbuf_free(c2dev, reply);324325bail1:326kfree(wr);327bail0:328vq_req_free(c2dev, vq_req);329return err;330}331332/*333* Open a single RNIC instance to use with all334* low level openib calls335*/336static int c2_rnic_open(struct c2_dev *c2dev)337{338struct c2_vq_req *vq_req;339union c2wr wr;340struct c2wr_rnic_open_rep *reply;341int err;342343vq_req = vq_req_alloc(c2dev);344if (vq_req == NULL) {345return -ENOMEM;346}347348memset(&wr, 0, sizeof(wr));349c2_wr_set_id(&wr, CCWR_RNIC_OPEN);350wr.rnic_open.req.hdr.context = (unsigned long) (vq_req);351wr.rnic_open.req.flags = cpu_to_be16(RNIC_PRIV_MODE);352wr.rnic_open.req.port_num = cpu_to_be16(0);353wr.rnic_open.req.user_context = (unsigned long) c2dev;354355vq_req_get(c2dev, vq_req);356357err = vq_send_wr(c2dev, &wr);358if (err) {359vq_req_put(c2dev, vq_req);360goto bail0;361}362363err = vq_wait_for_reply(c2dev, vq_req);364if (err) {365goto bail0;366}367368reply = (struct c2wr_rnic_open_rep *) (unsigned long) (vq_req->reply_msg);369if (!reply) {370err = -ENOMEM;371goto bail0;372}373374if ((err = c2_errno(reply)) != 0) {375goto bail1;376}377378c2dev->adapter_handle = reply->rnic_handle;379380bail1:381vq_repbuf_free(c2dev, reply);382bail0:383vq_req_free(c2dev, vq_req);384return err;385}386387/*388* Close the RNIC instance389*/390static int c2_rnic_close(struct c2_dev *c2dev)391{392struct c2_vq_req *vq_req;393union c2wr wr;394struct c2wr_rnic_close_rep *reply;395int err;396397vq_req = vq_req_alloc(c2dev);398if (vq_req == NULL) {399return -ENOMEM;400}401402memset(&wr, 0, sizeof(wr));403c2_wr_set_id(&wr, CCWR_RNIC_CLOSE);404wr.rnic_close.req.hdr.context = (unsigned long) vq_req;405wr.rnic_close.req.rnic_handle = c2dev->adapter_handle;406407vq_req_get(c2dev, vq_req);408409err = vq_send_wr(c2dev, &wr);410if (err) {411vq_req_put(c2dev, vq_req);412goto bail0;413}414415err = vq_wait_for_reply(c2dev, vq_req);416if (err) {417goto bail0;418}419420reply = (struct c2wr_rnic_close_rep *) (unsigned long) (vq_req->reply_msg);421if (!reply) {422err = -ENOMEM;423goto bail0;424}425426if ((err = c2_errno(reply)) != 0) {427goto bail1;428}429430c2dev->adapter_handle = 0;431432bail1:433vq_repbuf_free(c2dev, reply);434bail0:435vq_req_free(c2dev, vq_req);436return err;437}438439/*440* Called by c2_probe to initialize the RNIC. This principally441* involves initalizing the various limits and resouce pools that442* comprise the RNIC instance.443*/444int __devinit c2_rnic_init(struct c2_dev *c2dev)445{446int err;447u32 qsize, msgsize;448void *q1_pages;449void *q2_pages;450void __iomem *mmio_regs;451452/* Device capabilities */453c2dev->device_cap_flags =454(IB_DEVICE_RESIZE_MAX_WR |455IB_DEVICE_CURR_QP_STATE_MOD |456IB_DEVICE_SYS_IMAGE_GUID |457IB_DEVICE_LOCAL_DMA_LKEY |458IB_DEVICE_MEM_WINDOW);459460/* Allocate the qptr_array */461c2dev->qptr_array = vzalloc(C2_MAX_CQS * sizeof(void *));462if (!c2dev->qptr_array) {463return -ENOMEM;464}465466/* Initialize the qptr_array */467c2dev->qptr_array[0] = (void *) &c2dev->req_vq;468c2dev->qptr_array[1] = (void *) &c2dev->rep_vq;469c2dev->qptr_array[2] = (void *) &c2dev->aeq;470471/* Initialize data structures */472init_waitqueue_head(&c2dev->req_vq_wo);473spin_lock_init(&c2dev->vqlock);474spin_lock_init(&c2dev->lock);475476/* Allocate MQ shared pointer pool for kernel clients. User477* mode client pools are hung off the user context478*/479err = c2_init_mqsp_pool(c2dev, GFP_KERNEL, &c2dev->kern_mqsp_pool);480if (err) {481goto bail0;482}483484/* Allocate shared pointers for Q0, Q1, and Q2 from485* the shared pointer pool.486*/487488c2dev->hint_count = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,489&c2dev->hint_count_dma,490GFP_KERNEL);491c2dev->req_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,492&c2dev->req_vq.shared_dma,493GFP_KERNEL);494c2dev->rep_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,495&c2dev->rep_vq.shared_dma,496GFP_KERNEL);497c2dev->aeq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,498&c2dev->aeq.shared_dma, GFP_KERNEL);499if (!c2dev->hint_count || !c2dev->req_vq.shared ||500!c2dev->rep_vq.shared || !c2dev->aeq.shared) {501err = -ENOMEM;502goto bail1;503}504505mmio_regs = c2dev->kva;506/* Initialize the Verbs Request Queue */507c2_mq_req_init(&c2dev->req_vq, 0,508be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_QSIZE)),509be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_MSGSIZE)),510mmio_regs +511be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_POOLSTART)),512mmio_regs +513be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_SHARED)),514C2_MQ_ADAPTER_TARGET);515516/* Initialize the Verbs Reply Queue */517qsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q1_QSIZE));518msgsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q1_MSGSIZE));519q1_pages = dma_alloc_coherent(&c2dev->pcidev->dev, qsize * msgsize,520&c2dev->rep_vq.host_dma, GFP_KERNEL);521if (!q1_pages) {522err = -ENOMEM;523goto bail1;524}525dma_unmap_addr_set(&c2dev->rep_vq, mapping, c2dev->rep_vq.host_dma);526pr_debug("%s rep_vq va %p dma %llx\n", __func__, q1_pages,527(unsigned long long) c2dev->rep_vq.host_dma);528c2_mq_rep_init(&c2dev->rep_vq,5291,530qsize,531msgsize,532q1_pages,533mmio_regs +534be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q1_SHARED)),535C2_MQ_HOST_TARGET);536537/* Initialize the Asynchronus Event Queue */538qsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q2_QSIZE));539msgsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q2_MSGSIZE));540q2_pages = dma_alloc_coherent(&c2dev->pcidev->dev, qsize * msgsize,541&c2dev->aeq.host_dma, GFP_KERNEL);542if (!q2_pages) {543err = -ENOMEM;544goto bail2;545}546dma_unmap_addr_set(&c2dev->aeq, mapping, c2dev->aeq.host_dma);547pr_debug("%s aeq va %p dma %llx\n", __func__, q2_pages,548(unsigned long long) c2dev->aeq.host_dma);549c2_mq_rep_init(&c2dev->aeq,5502,551qsize,552msgsize,553q2_pages,554mmio_regs +555be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q2_SHARED)),556C2_MQ_HOST_TARGET);557558/* Initialize the verbs request allocator */559err = vq_init(c2dev);560if (err)561goto bail3;562563/* Enable interrupts on the adapter */564writel(0, c2dev->regs + C2_IDIS);565566/* create the WR init message */567err = c2_adapter_init(c2dev);568if (err)569goto bail4;570c2dev->init++;571572/* open an adapter instance */573err = c2_rnic_open(c2dev);574if (err)575goto bail4;576577/* Initialize cached the adapter limits */578if (c2_rnic_query(c2dev, &c2dev->props))579goto bail5;580581/* Initialize the PD pool */582err = c2_init_pd_table(c2dev);583if (err)584goto bail5;585586/* Initialize the QP pool */587c2_init_qp_table(c2dev);588return 0;589590bail5:591c2_rnic_close(c2dev);592bail4:593vq_term(c2dev);594bail3:595dma_free_coherent(&c2dev->pcidev->dev,596c2dev->aeq.q_size * c2dev->aeq.msg_size,597q2_pages, dma_unmap_addr(&c2dev->aeq, mapping));598bail2:599dma_free_coherent(&c2dev->pcidev->dev,600c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size,601q1_pages, dma_unmap_addr(&c2dev->rep_vq, mapping));602bail1:603c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool);604bail0:605vfree(c2dev->qptr_array);606607return err;608}609610/*611* Called by c2_remove to cleanup the RNIC resources.612*/613void __devexit c2_rnic_term(struct c2_dev *c2dev)614{615616/* Close the open adapter instance */617c2_rnic_close(c2dev);618619/* Send the TERM message to the adapter */620c2_adapter_term(c2dev);621622/* Disable interrupts on the adapter */623writel(1, c2dev->regs + C2_IDIS);624625/* Free the QP pool */626c2_cleanup_qp_table(c2dev);627628/* Free the PD pool */629c2_cleanup_pd_table(c2dev);630631/* Free the verbs request allocator */632vq_term(c2dev);633634/* Free the asynchronus event queue */635dma_free_coherent(&c2dev->pcidev->dev,636c2dev->aeq.q_size * c2dev->aeq.msg_size,637c2dev->aeq.msg_pool.host,638dma_unmap_addr(&c2dev->aeq, mapping));639640/* Free the verbs reply queue */641dma_free_coherent(&c2dev->pcidev->dev,642c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size,643c2dev->rep_vq.msg_pool.host,644dma_unmap_addr(&c2dev->rep_vq, mapping));645646/* Free the MQ shared pointer pool */647c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool);648649/* Free the qptr_array */650vfree(c2dev->qptr_array);651652return;653}654655656