1*4882a593Smuzhiyun /* Broadcom NetXtreme-C/E network driver.
2*4882a593Smuzhiyun *
3*4882a593Smuzhiyun * Copyright (c) 2016-2018 Broadcom Limited
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
6*4882a593Smuzhiyun * it under the terms of the GNU General Public License as published by
7*4882a593Smuzhiyun * the Free Software Foundation.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun #include <linux/pci.h>
16*4882a593Smuzhiyun #include <linux/netdevice.h>
17*4882a593Smuzhiyun #include <linux/rtnetlink.h>
18*4882a593Smuzhiyun #include <linux/bitops.h>
19*4882a593Smuzhiyun #include <linux/irq.h>
20*4882a593Smuzhiyun #include <asm/byteorder.h>
21*4882a593Smuzhiyun #include <linux/bitmap.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "bnxt_hsi.h"
24*4882a593Smuzhiyun #include "bnxt.h"
25*4882a593Smuzhiyun #include "bnxt_ulp.h"
26*4882a593Smuzhiyun
bnxt_register_dev(struct bnxt_en_dev * edev,int ulp_id,struct bnxt_ulp_ops * ulp_ops,void * handle)27*4882a593Smuzhiyun static int bnxt_register_dev(struct bnxt_en_dev *edev, int ulp_id,
28*4882a593Smuzhiyun struct bnxt_ulp_ops *ulp_ops, void *handle)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun struct net_device *dev = edev->net;
31*4882a593Smuzhiyun struct bnxt *bp = netdev_priv(dev);
32*4882a593Smuzhiyun struct bnxt_ulp *ulp;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun ASSERT_RTNL();
35*4882a593Smuzhiyun if (ulp_id >= BNXT_MAX_ULP)
36*4882a593Smuzhiyun return -EINVAL;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun ulp = &edev->ulp_tbl[ulp_id];
39*4882a593Smuzhiyun if (rcu_access_pointer(ulp->ulp_ops)) {
40*4882a593Smuzhiyun netdev_err(bp->dev, "ulp id %d already registered\n", ulp_id);
41*4882a593Smuzhiyun return -EBUSY;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun if (ulp_id == BNXT_ROCE_ULP) {
44*4882a593Smuzhiyun unsigned int max_stat_ctxs;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun max_stat_ctxs = bnxt_get_max_func_stat_ctxs(bp);
47*4882a593Smuzhiyun if (max_stat_ctxs <= BNXT_MIN_ROCE_STAT_CTXS ||
48*4882a593Smuzhiyun bp->cp_nr_rings == max_stat_ctxs)
49*4882a593Smuzhiyun return -ENOMEM;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun atomic_set(&ulp->ref_count, 0);
53*4882a593Smuzhiyun ulp->handle = handle;
54*4882a593Smuzhiyun rcu_assign_pointer(ulp->ulp_ops, ulp_ops);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun if (ulp_id == BNXT_ROCE_ULP) {
57*4882a593Smuzhiyun if (test_bit(BNXT_STATE_OPEN, &bp->state))
58*4882a593Smuzhiyun bnxt_hwrm_vnic_cfg(bp, 0);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun return 0;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
bnxt_unregister_dev(struct bnxt_en_dev * edev,int ulp_id)64*4882a593Smuzhiyun static int bnxt_unregister_dev(struct bnxt_en_dev *edev, int ulp_id)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun struct net_device *dev = edev->net;
67*4882a593Smuzhiyun struct bnxt *bp = netdev_priv(dev);
68*4882a593Smuzhiyun struct bnxt_ulp *ulp;
69*4882a593Smuzhiyun int i = 0;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun ASSERT_RTNL();
72*4882a593Smuzhiyun if (ulp_id >= BNXT_MAX_ULP)
73*4882a593Smuzhiyun return -EINVAL;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun ulp = &edev->ulp_tbl[ulp_id];
76*4882a593Smuzhiyun if (!rcu_access_pointer(ulp->ulp_ops)) {
77*4882a593Smuzhiyun netdev_err(bp->dev, "ulp id %d not registered\n", ulp_id);
78*4882a593Smuzhiyun return -EINVAL;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun if (ulp_id == BNXT_ROCE_ULP && ulp->msix_requested)
81*4882a593Smuzhiyun edev->en_ops->bnxt_free_msix(edev, ulp_id);
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (ulp->max_async_event_id)
84*4882a593Smuzhiyun bnxt_hwrm_func_drv_rgtr(bp, NULL, 0, true);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun RCU_INIT_POINTER(ulp->ulp_ops, NULL);
87*4882a593Smuzhiyun synchronize_rcu();
88*4882a593Smuzhiyun ulp->max_async_event_id = 0;
89*4882a593Smuzhiyun ulp->async_events_bmap = NULL;
90*4882a593Smuzhiyun while (atomic_read(&ulp->ref_count) != 0 && i < 10) {
91*4882a593Smuzhiyun msleep(100);
92*4882a593Smuzhiyun i++;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun return 0;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
bnxt_fill_msix_vecs(struct bnxt * bp,struct bnxt_msix_entry * ent)97*4882a593Smuzhiyun static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
100*4882a593Smuzhiyun int num_msix, idx, i;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun num_msix = edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested;
103*4882a593Smuzhiyun idx = edev->ulp_tbl[BNXT_ROCE_ULP].msix_base;
104*4882a593Smuzhiyun for (i = 0; i < num_msix; i++) {
105*4882a593Smuzhiyun ent[i].vector = bp->irq_tbl[idx + i].vector;
106*4882a593Smuzhiyun ent[i].ring_idx = idx + i;
107*4882a593Smuzhiyun if (bp->flags & BNXT_FLAG_CHIP_P5) {
108*4882a593Smuzhiyun ent[i].db_offset = DB_PF_OFFSET_P5;
109*4882a593Smuzhiyun if (BNXT_VF(bp))
110*4882a593Smuzhiyun ent[i].db_offset = DB_VF_OFFSET_P5;
111*4882a593Smuzhiyun } else {
112*4882a593Smuzhiyun ent[i].db_offset = (idx + i) * 0x80;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
bnxt_req_msix_vecs(struct bnxt_en_dev * edev,int ulp_id,struct bnxt_msix_entry * ent,int num_msix)117*4882a593Smuzhiyun static int bnxt_req_msix_vecs(struct bnxt_en_dev *edev, int ulp_id,
118*4882a593Smuzhiyun struct bnxt_msix_entry *ent, int num_msix)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun struct net_device *dev = edev->net;
121*4882a593Smuzhiyun struct bnxt *bp = netdev_priv(dev);
122*4882a593Smuzhiyun struct bnxt_hw_resc *hw_resc;
123*4882a593Smuzhiyun int max_idx, max_cp_rings;
124*4882a593Smuzhiyun int avail_msix, idx;
125*4882a593Smuzhiyun int total_vecs;
126*4882a593Smuzhiyun int rc = 0;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun ASSERT_RTNL();
129*4882a593Smuzhiyun if (ulp_id != BNXT_ROCE_ULP)
130*4882a593Smuzhiyun return -EINVAL;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (!(bp->flags & BNXT_FLAG_USING_MSIX))
133*4882a593Smuzhiyun return -ENODEV;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun if (edev->ulp_tbl[ulp_id].msix_requested)
136*4882a593Smuzhiyun return -EAGAIN;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun max_cp_rings = bnxt_get_max_func_cp_rings(bp);
139*4882a593Smuzhiyun avail_msix = bnxt_get_avail_msix(bp, num_msix);
140*4882a593Smuzhiyun if (!avail_msix)
141*4882a593Smuzhiyun return -ENOMEM;
142*4882a593Smuzhiyun if (avail_msix > num_msix)
143*4882a593Smuzhiyun avail_msix = num_msix;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun if (BNXT_NEW_RM(bp)) {
146*4882a593Smuzhiyun idx = bp->cp_nr_rings;
147*4882a593Smuzhiyun } else {
148*4882a593Smuzhiyun max_idx = min_t(int, bp->total_irqs, max_cp_rings);
149*4882a593Smuzhiyun idx = max_idx - avail_msix;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun edev->ulp_tbl[ulp_id].msix_base = idx;
152*4882a593Smuzhiyun edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
153*4882a593Smuzhiyun hw_resc = &bp->hw_resc;
154*4882a593Smuzhiyun total_vecs = idx + avail_msix;
155*4882a593Smuzhiyun if (bp->total_irqs < total_vecs ||
156*4882a593Smuzhiyun (BNXT_NEW_RM(bp) && hw_resc->resv_irqs < total_vecs)) {
157*4882a593Smuzhiyun if (netif_running(dev)) {
158*4882a593Smuzhiyun bnxt_close_nic(bp, true, false);
159*4882a593Smuzhiyun rc = bnxt_open_nic(bp, true, false);
160*4882a593Smuzhiyun } else {
161*4882a593Smuzhiyun rc = bnxt_reserve_rings(bp, true);
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun if (rc) {
165*4882a593Smuzhiyun edev->ulp_tbl[ulp_id].msix_requested = 0;
166*4882a593Smuzhiyun return -EAGAIN;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun if (BNXT_NEW_RM(bp)) {
170*4882a593Smuzhiyun int resv_msix;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun resv_msix = hw_resc->resv_irqs - bp->cp_nr_rings;
173*4882a593Smuzhiyun avail_msix = min_t(int, resv_msix, avail_msix);
174*4882a593Smuzhiyun edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun bnxt_fill_msix_vecs(bp, ent);
177*4882a593Smuzhiyun edev->flags |= BNXT_EN_FLAG_MSIX_REQUESTED;
178*4882a593Smuzhiyun return avail_msix;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
bnxt_free_msix_vecs(struct bnxt_en_dev * edev,int ulp_id)181*4882a593Smuzhiyun static int bnxt_free_msix_vecs(struct bnxt_en_dev *edev, int ulp_id)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun struct net_device *dev = edev->net;
184*4882a593Smuzhiyun struct bnxt *bp = netdev_priv(dev);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun ASSERT_RTNL();
187*4882a593Smuzhiyun if (ulp_id != BNXT_ROCE_ULP)
188*4882a593Smuzhiyun return -EINVAL;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun if (!(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
191*4882a593Smuzhiyun return 0;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun edev->ulp_tbl[ulp_id].msix_requested = 0;
194*4882a593Smuzhiyun edev->flags &= ~BNXT_EN_FLAG_MSIX_REQUESTED;
195*4882a593Smuzhiyun if (netif_running(dev) && !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) {
196*4882a593Smuzhiyun bnxt_close_nic(bp, true, false);
197*4882a593Smuzhiyun bnxt_open_nic(bp, true, false);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun return 0;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
bnxt_get_ulp_msix_num(struct bnxt * bp)202*4882a593Smuzhiyun int bnxt_get_ulp_msix_num(struct bnxt *bp)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
205*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun return edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun return 0;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
bnxt_get_ulp_msix_base(struct bnxt * bp)212*4882a593Smuzhiyun int bnxt_get_ulp_msix_base(struct bnxt *bp)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
215*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun if (edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested)
218*4882a593Smuzhiyun return edev->ulp_tbl[BNXT_ROCE_ULP].msix_base;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun return 0;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
bnxt_get_ulp_stat_ctxs(struct bnxt * bp)223*4882a593Smuzhiyun int bnxt_get_ulp_stat_ctxs(struct bnxt *bp)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
226*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested)
229*4882a593Smuzhiyun return BNXT_MIN_ROCE_STAT_CTXS;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun return 0;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
bnxt_send_msg(struct bnxt_en_dev * edev,int ulp_id,struct bnxt_fw_msg * fw_msg)235*4882a593Smuzhiyun static int bnxt_send_msg(struct bnxt_en_dev *edev, int ulp_id,
236*4882a593Smuzhiyun struct bnxt_fw_msg *fw_msg)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun struct net_device *dev = edev->net;
239*4882a593Smuzhiyun struct bnxt *bp = netdev_priv(dev);
240*4882a593Smuzhiyun struct input *req;
241*4882a593Smuzhiyun int rc;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun if (ulp_id != BNXT_ROCE_ULP && bp->fw_reset_state)
244*4882a593Smuzhiyun return -EBUSY;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun mutex_lock(&bp->hwrm_cmd_lock);
247*4882a593Smuzhiyun req = fw_msg->msg;
248*4882a593Smuzhiyun req->resp_addr = cpu_to_le64(bp->hwrm_cmd_resp_dma_addr);
249*4882a593Smuzhiyun rc = _hwrm_send_message(bp, fw_msg->msg, fw_msg->msg_len,
250*4882a593Smuzhiyun fw_msg->timeout);
251*4882a593Smuzhiyun if (!rc) {
252*4882a593Smuzhiyun struct output *resp = bp->hwrm_cmd_resp_addr;
253*4882a593Smuzhiyun u32 len = le16_to_cpu(resp->resp_len);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun if (fw_msg->resp_max_len < len)
256*4882a593Smuzhiyun len = fw_msg->resp_max_len;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun memcpy(fw_msg->resp, resp, len);
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun mutex_unlock(&bp->hwrm_cmd_lock);
261*4882a593Smuzhiyun return rc;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
bnxt_ulp_get(struct bnxt_ulp * ulp)264*4882a593Smuzhiyun static void bnxt_ulp_get(struct bnxt_ulp *ulp)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun atomic_inc(&ulp->ref_count);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
bnxt_ulp_put(struct bnxt_ulp * ulp)269*4882a593Smuzhiyun static void bnxt_ulp_put(struct bnxt_ulp *ulp)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun atomic_dec(&ulp->ref_count);
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
bnxt_ulp_stop(struct bnxt * bp)274*4882a593Smuzhiyun void bnxt_ulp_stop(struct bnxt *bp)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
277*4882a593Smuzhiyun struct bnxt_ulp_ops *ops;
278*4882a593Smuzhiyun int i;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun if (!edev)
281*4882a593Smuzhiyun return;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
284*4882a593Smuzhiyun for (i = 0; i < BNXT_MAX_ULP; i++) {
285*4882a593Smuzhiyun struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun ops = rtnl_dereference(ulp->ulp_ops);
288*4882a593Smuzhiyun if (!ops || !ops->ulp_stop)
289*4882a593Smuzhiyun continue;
290*4882a593Smuzhiyun ops->ulp_stop(ulp->handle);
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
bnxt_ulp_start(struct bnxt * bp,int err)294*4882a593Smuzhiyun void bnxt_ulp_start(struct bnxt *bp, int err)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
297*4882a593Smuzhiyun struct bnxt_ulp_ops *ops;
298*4882a593Smuzhiyun int i;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun if (!edev)
301*4882a593Smuzhiyun return;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if (err)
306*4882a593Smuzhiyun return;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun for (i = 0; i < BNXT_MAX_ULP; i++) {
309*4882a593Smuzhiyun struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun ops = rtnl_dereference(ulp->ulp_ops);
312*4882a593Smuzhiyun if (!ops || !ops->ulp_start)
313*4882a593Smuzhiyun continue;
314*4882a593Smuzhiyun ops->ulp_start(ulp->handle);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
bnxt_ulp_sriov_cfg(struct bnxt * bp,int num_vfs)318*4882a593Smuzhiyun void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
321*4882a593Smuzhiyun struct bnxt_ulp_ops *ops;
322*4882a593Smuzhiyun int i;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun if (!edev)
325*4882a593Smuzhiyun return;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun for (i = 0; i < BNXT_MAX_ULP; i++) {
328*4882a593Smuzhiyun struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun rcu_read_lock();
331*4882a593Smuzhiyun ops = rcu_dereference(ulp->ulp_ops);
332*4882a593Smuzhiyun if (!ops || !ops->ulp_sriov_config) {
333*4882a593Smuzhiyun rcu_read_unlock();
334*4882a593Smuzhiyun continue;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun bnxt_ulp_get(ulp);
337*4882a593Smuzhiyun rcu_read_unlock();
338*4882a593Smuzhiyun ops->ulp_sriov_config(ulp->handle, num_vfs);
339*4882a593Smuzhiyun bnxt_ulp_put(ulp);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
bnxt_ulp_shutdown(struct bnxt * bp)343*4882a593Smuzhiyun void bnxt_ulp_shutdown(struct bnxt *bp)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
346*4882a593Smuzhiyun struct bnxt_ulp_ops *ops;
347*4882a593Smuzhiyun int i;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun if (!edev)
350*4882a593Smuzhiyun return;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun for (i = 0; i < BNXT_MAX_ULP; i++) {
353*4882a593Smuzhiyun struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun ops = rtnl_dereference(ulp->ulp_ops);
356*4882a593Smuzhiyun if (!ops || !ops->ulp_shutdown)
357*4882a593Smuzhiyun continue;
358*4882a593Smuzhiyun ops->ulp_shutdown(ulp->handle);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
bnxt_ulp_irq_stop(struct bnxt * bp)362*4882a593Smuzhiyun void bnxt_ulp_irq_stop(struct bnxt *bp)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
365*4882a593Smuzhiyun struct bnxt_ulp_ops *ops;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
368*4882a593Smuzhiyun return;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
371*4882a593Smuzhiyun struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP];
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if (!ulp->msix_requested)
374*4882a593Smuzhiyun return;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun ops = rtnl_dereference(ulp->ulp_ops);
377*4882a593Smuzhiyun if (!ops || !ops->ulp_irq_stop)
378*4882a593Smuzhiyun return;
379*4882a593Smuzhiyun ops->ulp_irq_stop(ulp->handle);
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
bnxt_ulp_irq_restart(struct bnxt * bp,int err)383*4882a593Smuzhiyun void bnxt_ulp_irq_restart(struct bnxt *bp, int err)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
386*4882a593Smuzhiyun struct bnxt_ulp_ops *ops;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
389*4882a593Smuzhiyun return;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
392*4882a593Smuzhiyun struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP];
393*4882a593Smuzhiyun struct bnxt_msix_entry *ent = NULL;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun if (!ulp->msix_requested)
396*4882a593Smuzhiyun return;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun ops = rtnl_dereference(ulp->ulp_ops);
399*4882a593Smuzhiyun if (!ops || !ops->ulp_irq_restart)
400*4882a593Smuzhiyun return;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun if (!err) {
403*4882a593Smuzhiyun ent = kcalloc(ulp->msix_requested, sizeof(*ent),
404*4882a593Smuzhiyun GFP_KERNEL);
405*4882a593Smuzhiyun if (!ent)
406*4882a593Smuzhiyun return;
407*4882a593Smuzhiyun bnxt_fill_msix_vecs(bp, ent);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun ops->ulp_irq_restart(ulp->handle, ent);
410*4882a593Smuzhiyun kfree(ent);
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
bnxt_ulp_async_events(struct bnxt * bp,struct hwrm_async_event_cmpl * cmpl)414*4882a593Smuzhiyun void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun u16 event_id = le16_to_cpu(cmpl->event_id);
417*4882a593Smuzhiyun struct bnxt_en_dev *edev = bp->edev;
418*4882a593Smuzhiyun struct bnxt_ulp_ops *ops;
419*4882a593Smuzhiyun int i;
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun if (!edev)
422*4882a593Smuzhiyun return;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun rcu_read_lock();
425*4882a593Smuzhiyun for (i = 0; i < BNXT_MAX_ULP; i++) {
426*4882a593Smuzhiyun struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun ops = rcu_dereference(ulp->ulp_ops);
429*4882a593Smuzhiyun if (!ops || !ops->ulp_async_notifier)
430*4882a593Smuzhiyun continue;
431*4882a593Smuzhiyun if (!ulp->async_events_bmap ||
432*4882a593Smuzhiyun event_id > ulp->max_async_event_id)
433*4882a593Smuzhiyun continue;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun /* Read max_async_event_id first before testing the bitmap. */
436*4882a593Smuzhiyun smp_rmb();
437*4882a593Smuzhiyun if (test_bit(event_id, ulp->async_events_bmap))
438*4882a593Smuzhiyun ops->ulp_async_notifier(ulp->handle, cmpl);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun rcu_read_unlock();
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
bnxt_register_async_events(struct bnxt_en_dev * edev,int ulp_id,unsigned long * events_bmap,u16 max_id)443*4882a593Smuzhiyun static int bnxt_register_async_events(struct bnxt_en_dev *edev, int ulp_id,
444*4882a593Smuzhiyun unsigned long *events_bmap, u16 max_id)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun struct net_device *dev = edev->net;
447*4882a593Smuzhiyun struct bnxt *bp = netdev_priv(dev);
448*4882a593Smuzhiyun struct bnxt_ulp *ulp;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun if (ulp_id >= BNXT_MAX_ULP)
451*4882a593Smuzhiyun return -EINVAL;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun ulp = &edev->ulp_tbl[ulp_id];
454*4882a593Smuzhiyun ulp->async_events_bmap = events_bmap;
455*4882a593Smuzhiyun /* Make sure bnxt_ulp_async_events() sees this order */
456*4882a593Smuzhiyun smp_wmb();
457*4882a593Smuzhiyun ulp->max_async_event_id = max_id;
458*4882a593Smuzhiyun bnxt_hwrm_func_drv_rgtr(bp, events_bmap, max_id + 1, true);
459*4882a593Smuzhiyun return 0;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun static const struct bnxt_en_ops bnxt_en_ops_tbl = {
463*4882a593Smuzhiyun .bnxt_register_device = bnxt_register_dev,
464*4882a593Smuzhiyun .bnxt_unregister_device = bnxt_unregister_dev,
465*4882a593Smuzhiyun .bnxt_request_msix = bnxt_req_msix_vecs,
466*4882a593Smuzhiyun .bnxt_free_msix = bnxt_free_msix_vecs,
467*4882a593Smuzhiyun .bnxt_send_fw_msg = bnxt_send_msg,
468*4882a593Smuzhiyun .bnxt_register_fw_async_events = bnxt_register_async_events,
469*4882a593Smuzhiyun };
470*4882a593Smuzhiyun
bnxt_ulp_probe(struct net_device * dev)471*4882a593Smuzhiyun struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun struct bnxt *bp = netdev_priv(dev);
474*4882a593Smuzhiyun struct bnxt_en_dev *edev;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun edev = bp->edev;
477*4882a593Smuzhiyun if (!edev) {
478*4882a593Smuzhiyun edev = kzalloc(sizeof(*edev), GFP_KERNEL);
479*4882a593Smuzhiyun if (!edev)
480*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
481*4882a593Smuzhiyun edev->en_ops = &bnxt_en_ops_tbl;
482*4882a593Smuzhiyun edev->net = dev;
483*4882a593Smuzhiyun edev->pdev = bp->pdev;
484*4882a593Smuzhiyun edev->l2_db_size = bp->db_size;
485*4882a593Smuzhiyun edev->l2_db_size_nc = bp->db_size;
486*4882a593Smuzhiyun bp->edev = edev;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun edev->flags &= ~BNXT_EN_FLAG_ROCE_CAP;
489*4882a593Smuzhiyun if (bp->flags & BNXT_FLAG_ROCEV1_CAP)
490*4882a593Smuzhiyun edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP;
491*4882a593Smuzhiyun if (bp->flags & BNXT_FLAG_ROCEV2_CAP)
492*4882a593Smuzhiyun edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP;
493*4882a593Smuzhiyun return bp->edev;
494*4882a593Smuzhiyun }
495