Back to home page

OSCL-LXR

 
 

    


0001 /* Broadcom NetXtreme-C/E network driver.
0002  *
0003  * Copyright (c) 2016-2018 Broadcom Limited
0004  *
0005  * This program is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation.
0008  */
0009 
0010 #include <linux/module.h>
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/errno.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/pci.h>
0016 #include <linux/netdevice.h>
0017 #include <linux/rtnetlink.h>
0018 #include <linux/bitops.h>
0019 #include <linux/irq.h>
0020 #include <asm/byteorder.h>
0021 #include <linux/bitmap.h>
0022 
0023 #include "bnxt_hsi.h"
0024 #include "bnxt.h"
0025 #include "bnxt_hwrm.h"
0026 #include "bnxt_ulp.h"
0027 
0028 static int bnxt_register_dev(struct bnxt_en_dev *edev, unsigned int ulp_id,
0029                  struct bnxt_ulp_ops *ulp_ops, void *handle)
0030 {
0031     struct net_device *dev = edev->net;
0032     struct bnxt *bp = netdev_priv(dev);
0033     struct bnxt_ulp *ulp;
0034 
0035     ASSERT_RTNL();
0036     if (ulp_id >= BNXT_MAX_ULP)
0037         return -EINVAL;
0038 
0039     ulp = &edev->ulp_tbl[ulp_id];
0040     if (rcu_access_pointer(ulp->ulp_ops)) {
0041         netdev_err(bp->dev, "ulp id %d already registered\n", ulp_id);
0042         return -EBUSY;
0043     }
0044     if (ulp_id == BNXT_ROCE_ULP) {
0045         unsigned int max_stat_ctxs;
0046 
0047         max_stat_ctxs = bnxt_get_max_func_stat_ctxs(bp);
0048         if (max_stat_ctxs <= BNXT_MIN_ROCE_STAT_CTXS ||
0049             bp->cp_nr_rings == max_stat_ctxs)
0050             return -ENOMEM;
0051     }
0052 
0053     atomic_set(&ulp->ref_count, 0);
0054     ulp->handle = handle;
0055     rcu_assign_pointer(ulp->ulp_ops, ulp_ops);
0056 
0057     if (ulp_id == BNXT_ROCE_ULP) {
0058         if (test_bit(BNXT_STATE_OPEN, &bp->state))
0059             bnxt_hwrm_vnic_cfg(bp, 0);
0060     }
0061 
0062     return 0;
0063 }
0064 
0065 static int bnxt_unregister_dev(struct bnxt_en_dev *edev, unsigned int ulp_id)
0066 {
0067     struct net_device *dev = edev->net;
0068     struct bnxt *bp = netdev_priv(dev);
0069     struct bnxt_ulp *ulp;
0070     int i = 0;
0071 
0072     ASSERT_RTNL();
0073     if (ulp_id >= BNXT_MAX_ULP)
0074         return -EINVAL;
0075 
0076     ulp = &edev->ulp_tbl[ulp_id];
0077     if (!rcu_access_pointer(ulp->ulp_ops)) {
0078         netdev_err(bp->dev, "ulp id %d not registered\n", ulp_id);
0079         return -EINVAL;
0080     }
0081     if (ulp_id == BNXT_ROCE_ULP && ulp->msix_requested)
0082         edev->en_ops->bnxt_free_msix(edev, ulp_id);
0083 
0084     if (ulp->max_async_event_id)
0085         bnxt_hwrm_func_drv_rgtr(bp, NULL, 0, true);
0086 
0087     RCU_INIT_POINTER(ulp->ulp_ops, NULL);
0088     synchronize_rcu();
0089     ulp->max_async_event_id = 0;
0090     ulp->async_events_bmap = NULL;
0091     while (atomic_read(&ulp->ref_count) != 0 && i < 10) {
0092         msleep(100);
0093         i++;
0094     }
0095     return 0;
0096 }
0097 
0098 static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent)
0099 {
0100     struct bnxt_en_dev *edev = bp->edev;
0101     int num_msix, idx, i;
0102 
0103     num_msix = edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested;
0104     idx = edev->ulp_tbl[BNXT_ROCE_ULP].msix_base;
0105     for (i = 0; i < num_msix; i++) {
0106         ent[i].vector = bp->irq_tbl[idx + i].vector;
0107         ent[i].ring_idx = idx + i;
0108         if (bp->flags & BNXT_FLAG_CHIP_P5) {
0109             ent[i].db_offset = DB_PF_OFFSET_P5;
0110             if (BNXT_VF(bp))
0111                 ent[i].db_offset = DB_VF_OFFSET_P5;
0112         } else {
0113             ent[i].db_offset = (idx + i) * 0x80;
0114         }
0115     }
0116 }
0117 
0118 static int bnxt_req_msix_vecs(struct bnxt_en_dev *edev, unsigned int ulp_id,
0119                   struct bnxt_msix_entry *ent, int num_msix)
0120 {
0121     struct net_device *dev = edev->net;
0122     struct bnxt *bp = netdev_priv(dev);
0123     struct bnxt_hw_resc *hw_resc;
0124     int max_idx, max_cp_rings;
0125     int avail_msix, idx;
0126     int total_vecs;
0127     int rc = 0;
0128 
0129     ASSERT_RTNL();
0130     if (ulp_id != BNXT_ROCE_ULP)
0131         return -EINVAL;
0132 
0133     if (!(bp->flags & BNXT_FLAG_USING_MSIX))
0134         return -ENODEV;
0135 
0136     if (edev->ulp_tbl[ulp_id].msix_requested)
0137         return -EAGAIN;
0138 
0139     max_cp_rings = bnxt_get_max_func_cp_rings(bp);
0140     avail_msix = bnxt_get_avail_msix(bp, num_msix);
0141     if (!avail_msix)
0142         return -ENOMEM;
0143     if (avail_msix > num_msix)
0144         avail_msix = num_msix;
0145 
0146     if (BNXT_NEW_RM(bp)) {
0147         idx = bp->cp_nr_rings;
0148     } else {
0149         max_idx = min_t(int, bp->total_irqs, max_cp_rings);
0150         idx = max_idx - avail_msix;
0151     }
0152     edev->ulp_tbl[ulp_id].msix_base = idx;
0153     edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
0154     hw_resc = &bp->hw_resc;
0155     total_vecs = idx + avail_msix;
0156     if (bp->total_irqs < total_vecs ||
0157         (BNXT_NEW_RM(bp) && hw_resc->resv_irqs < total_vecs)) {
0158         if (netif_running(dev)) {
0159             bnxt_close_nic(bp, true, false);
0160             rc = bnxt_open_nic(bp, true, false);
0161         } else {
0162             rc = bnxt_reserve_rings(bp, true);
0163         }
0164     }
0165     if (rc) {
0166         edev->ulp_tbl[ulp_id].msix_requested = 0;
0167         return -EAGAIN;
0168     }
0169 
0170     if (BNXT_NEW_RM(bp)) {
0171         int resv_msix;
0172 
0173         resv_msix = hw_resc->resv_irqs - bp->cp_nr_rings;
0174         avail_msix = min_t(int, resv_msix, avail_msix);
0175         edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
0176     }
0177     bnxt_fill_msix_vecs(bp, ent);
0178     edev->flags |= BNXT_EN_FLAG_MSIX_REQUESTED;
0179     return avail_msix;
0180 }
0181 
0182 static int bnxt_free_msix_vecs(struct bnxt_en_dev *edev, unsigned int ulp_id)
0183 {
0184     struct net_device *dev = edev->net;
0185     struct bnxt *bp = netdev_priv(dev);
0186 
0187     ASSERT_RTNL();
0188     if (ulp_id != BNXT_ROCE_ULP)
0189         return -EINVAL;
0190 
0191     if (!(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
0192         return 0;
0193 
0194     edev->ulp_tbl[ulp_id].msix_requested = 0;
0195     edev->flags &= ~BNXT_EN_FLAG_MSIX_REQUESTED;
0196     if (netif_running(dev) && !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) {
0197         bnxt_close_nic(bp, true, false);
0198         bnxt_open_nic(bp, true, false);
0199     }
0200     return 0;
0201 }
0202 
0203 int bnxt_get_ulp_msix_num(struct bnxt *bp)
0204 {
0205     if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
0206         struct bnxt_en_dev *edev = bp->edev;
0207 
0208         return edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested;
0209     }
0210     return 0;
0211 }
0212 
0213 int bnxt_get_ulp_msix_base(struct bnxt *bp)
0214 {
0215     if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
0216         struct bnxt_en_dev *edev = bp->edev;
0217 
0218         if (edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested)
0219             return edev->ulp_tbl[BNXT_ROCE_ULP].msix_base;
0220     }
0221     return 0;
0222 }
0223 
0224 int bnxt_get_ulp_stat_ctxs(struct bnxt *bp)
0225 {
0226     if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
0227         struct bnxt_en_dev *edev = bp->edev;
0228 
0229         if (edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested)
0230             return BNXT_MIN_ROCE_STAT_CTXS;
0231     }
0232 
0233     return 0;
0234 }
0235 
0236 static int bnxt_send_msg(struct bnxt_en_dev *edev, unsigned int ulp_id,
0237              struct bnxt_fw_msg *fw_msg)
0238 {
0239     struct net_device *dev = edev->net;
0240     struct bnxt *bp = netdev_priv(dev);
0241     struct output *resp;
0242     struct input *req;
0243     u32 resp_len;
0244     int rc;
0245 
0246     if (ulp_id != BNXT_ROCE_ULP && bp->fw_reset_state)
0247         return -EBUSY;
0248 
0249     rc = hwrm_req_init(bp, req, 0 /* don't care */);
0250     if (rc)
0251         return rc;
0252 
0253     rc = hwrm_req_replace(bp, req, fw_msg->msg, fw_msg->msg_len);
0254     if (rc)
0255         return rc;
0256 
0257     hwrm_req_timeout(bp, req, fw_msg->timeout);
0258     resp = hwrm_req_hold(bp, req);
0259     rc = hwrm_req_send(bp, req);
0260     resp_len = le16_to_cpu(resp->resp_len);
0261     if (resp_len) {
0262         if (fw_msg->resp_max_len < resp_len)
0263             resp_len = fw_msg->resp_max_len;
0264 
0265         memcpy(fw_msg->resp, resp, resp_len);
0266     }
0267     hwrm_req_drop(bp, req);
0268     return rc;
0269 }
0270 
0271 static void bnxt_ulp_get(struct bnxt_ulp *ulp)
0272 {
0273     atomic_inc(&ulp->ref_count);
0274 }
0275 
0276 static void bnxt_ulp_put(struct bnxt_ulp *ulp)
0277 {
0278     atomic_dec(&ulp->ref_count);
0279 }
0280 
0281 void bnxt_ulp_stop(struct bnxt *bp)
0282 {
0283     struct bnxt_en_dev *edev = bp->edev;
0284     struct bnxt_ulp_ops *ops;
0285     int i;
0286 
0287     if (!edev)
0288         return;
0289 
0290     edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
0291     for (i = 0; i < BNXT_MAX_ULP; i++) {
0292         struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
0293 
0294         ops = rtnl_dereference(ulp->ulp_ops);
0295         if (!ops || !ops->ulp_stop)
0296             continue;
0297         ops->ulp_stop(ulp->handle);
0298     }
0299 }
0300 
0301 void bnxt_ulp_start(struct bnxt *bp, int err)
0302 {
0303     struct bnxt_en_dev *edev = bp->edev;
0304     struct bnxt_ulp_ops *ops;
0305     int i;
0306 
0307     if (!edev)
0308         return;
0309 
0310     edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
0311 
0312     if (err)
0313         return;
0314 
0315     for (i = 0; i < BNXT_MAX_ULP; i++) {
0316         struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
0317 
0318         ops = rtnl_dereference(ulp->ulp_ops);
0319         if (!ops || !ops->ulp_start)
0320             continue;
0321         ops->ulp_start(ulp->handle);
0322     }
0323 }
0324 
0325 void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs)
0326 {
0327     struct bnxt_en_dev *edev = bp->edev;
0328     struct bnxt_ulp_ops *ops;
0329     int i;
0330 
0331     if (!edev)
0332         return;
0333 
0334     for (i = 0; i < BNXT_MAX_ULP; i++) {
0335         struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
0336 
0337         rcu_read_lock();
0338         ops = rcu_dereference(ulp->ulp_ops);
0339         if (!ops || !ops->ulp_sriov_config) {
0340             rcu_read_unlock();
0341             continue;
0342         }
0343         bnxt_ulp_get(ulp);
0344         rcu_read_unlock();
0345         ops->ulp_sriov_config(ulp->handle, num_vfs);
0346         bnxt_ulp_put(ulp);
0347     }
0348 }
0349 
0350 void bnxt_ulp_shutdown(struct bnxt *bp)
0351 {
0352     struct bnxt_en_dev *edev = bp->edev;
0353     struct bnxt_ulp_ops *ops;
0354     int i;
0355 
0356     if (!edev)
0357         return;
0358 
0359     for (i = 0; i < BNXT_MAX_ULP; i++) {
0360         struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
0361 
0362         ops = rtnl_dereference(ulp->ulp_ops);
0363         if (!ops || !ops->ulp_shutdown)
0364             continue;
0365         ops->ulp_shutdown(ulp->handle);
0366     }
0367 }
0368 
0369 void bnxt_ulp_irq_stop(struct bnxt *bp)
0370 {
0371     struct bnxt_en_dev *edev = bp->edev;
0372     struct bnxt_ulp_ops *ops;
0373 
0374     if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
0375         return;
0376 
0377     if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
0378         struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP];
0379 
0380         if (!ulp->msix_requested)
0381             return;
0382 
0383         ops = rtnl_dereference(ulp->ulp_ops);
0384         if (!ops || !ops->ulp_irq_stop)
0385             return;
0386         ops->ulp_irq_stop(ulp->handle);
0387     }
0388 }
0389 
0390 void bnxt_ulp_irq_restart(struct bnxt *bp, int err)
0391 {
0392     struct bnxt_en_dev *edev = bp->edev;
0393     struct bnxt_ulp_ops *ops;
0394 
0395     if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
0396         return;
0397 
0398     if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
0399         struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP];
0400         struct bnxt_msix_entry *ent = NULL;
0401 
0402         if (!ulp->msix_requested)
0403             return;
0404 
0405         ops = rtnl_dereference(ulp->ulp_ops);
0406         if (!ops || !ops->ulp_irq_restart)
0407             return;
0408 
0409         if (!err) {
0410             ent = kcalloc(ulp->msix_requested, sizeof(*ent),
0411                       GFP_KERNEL);
0412             if (!ent)
0413                 return;
0414             bnxt_fill_msix_vecs(bp, ent);
0415         }
0416         ops->ulp_irq_restart(ulp->handle, ent);
0417         kfree(ent);
0418     }
0419 }
0420 
0421 void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl)
0422 {
0423     u16 event_id = le16_to_cpu(cmpl->event_id);
0424     struct bnxt_en_dev *edev = bp->edev;
0425     struct bnxt_ulp_ops *ops;
0426     int i;
0427 
0428     if (!edev)
0429         return;
0430 
0431     rcu_read_lock();
0432     for (i = 0; i < BNXT_MAX_ULP; i++) {
0433         struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
0434 
0435         ops = rcu_dereference(ulp->ulp_ops);
0436         if (!ops || !ops->ulp_async_notifier)
0437             continue;
0438         if (!ulp->async_events_bmap ||
0439             event_id > ulp->max_async_event_id)
0440             continue;
0441 
0442         /* Read max_async_event_id first before testing the bitmap. */
0443         smp_rmb();
0444         if (test_bit(event_id, ulp->async_events_bmap))
0445             ops->ulp_async_notifier(ulp->handle, cmpl);
0446     }
0447     rcu_read_unlock();
0448 }
0449 
0450 static int bnxt_register_async_events(struct bnxt_en_dev *edev, unsigned int ulp_id,
0451                       unsigned long *events_bmap, u16 max_id)
0452 {
0453     struct net_device *dev = edev->net;
0454     struct bnxt *bp = netdev_priv(dev);
0455     struct bnxt_ulp *ulp;
0456 
0457     if (ulp_id >= BNXT_MAX_ULP)
0458         return -EINVAL;
0459 
0460     ulp = &edev->ulp_tbl[ulp_id];
0461     ulp->async_events_bmap = events_bmap;
0462     /* Make sure bnxt_ulp_async_events() sees this order */
0463     smp_wmb();
0464     ulp->max_async_event_id = max_id;
0465     bnxt_hwrm_func_drv_rgtr(bp, events_bmap, max_id + 1, true);
0466     return 0;
0467 }
0468 
0469 static const struct bnxt_en_ops bnxt_en_ops_tbl = {
0470     .bnxt_register_device   = bnxt_register_dev,
0471     .bnxt_unregister_device = bnxt_unregister_dev,
0472     .bnxt_request_msix  = bnxt_req_msix_vecs,
0473     .bnxt_free_msix     = bnxt_free_msix_vecs,
0474     .bnxt_send_fw_msg   = bnxt_send_msg,
0475     .bnxt_register_fw_async_events  = bnxt_register_async_events,
0476 };
0477 
0478 struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev)
0479 {
0480     struct bnxt *bp = netdev_priv(dev);
0481     struct bnxt_en_dev *edev;
0482 
0483     edev = bp->edev;
0484     if (!edev) {
0485         edev = kzalloc(sizeof(*edev), GFP_KERNEL);
0486         if (!edev)
0487             return ERR_PTR(-ENOMEM);
0488         edev->en_ops = &bnxt_en_ops_tbl;
0489         edev->net = dev;
0490         edev->pdev = bp->pdev;
0491         edev->l2_db_size = bp->db_size;
0492         edev->l2_db_size_nc = bp->db_size;
0493         bp->edev = edev;
0494     }
0495     edev->flags &= ~BNXT_EN_FLAG_ROCE_CAP;
0496     if (bp->flags & BNXT_FLAG_ROCEV1_CAP)
0497         edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP;
0498     if (bp->flags & BNXT_FLAG_ROCEV2_CAP)
0499         edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP;
0500     return bp->edev;
0501 }
0502 EXPORT_SYMBOL(bnxt_ulp_probe);