]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/oce/oce_hw.c
Import DTS files from Linux 5.4
[FreeBSD/FreeBSD.git] / sys / dev / oce / oce_hw.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (C) 2013 Emulex
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Emulex Corporation nor the names of its
18  *    contributors may be used to endorse or promote products derived from
19  *    this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Contact Information:
34  * freebsd-drivers@emulex.com
35  *
36  * Emulex
37  * 3333 Susan Street
38  * Costa Mesa, CA 92626
39  */
40
41 /* $FreeBSD$ */
42
43
44 #include "oce_if.h"
45
46 static int oce_POST(POCE_SOFTC sc);
47
48 /**
49  * @brief               Function to post status
50  * @param sc            software handle to the device
51  */
52 static int
53 oce_POST(POCE_SOFTC sc)
54 {
55         mpu_ep_semaphore_t post_status;
56         int tmo = 60000;
57
58         /* read semaphore CSR */
59         post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
60
61         /* if host is ready then wait for fw ready else send POST */
62         if (post_status.bits.stage <= POST_STAGE_AWAITING_HOST_RDY) {
63                 post_status.bits.stage = POST_STAGE_CHIP_RESET;
64                 OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc), post_status.dw0);
65         }
66
67         /* wait for FW ready */
68         for (;;) {
69                 if (--tmo == 0)
70                         break;
71
72                 DELAY(1000);
73
74                 post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
75                 if (post_status.bits.error) {
76                         device_printf(sc->dev,
77                                   "POST failed: %x\n", post_status.dw0);
78                         return ENXIO;
79                 }
80                 if (post_status.bits.stage == POST_STAGE_ARMFW_READY)
81                         return 0;
82         }
83
84         device_printf(sc->dev, "POST timed out: %x\n", post_status.dw0);
85
86         return ENXIO;
87 }
88
89 /**
90  * @brief               Function for hardware initialization
91  * @param sc            software handle to the device
92  */
93 int
94 oce_hw_init(POCE_SOFTC sc)
95 {
96         int rc = 0;
97
98         rc = oce_POST(sc);
99         if (rc)
100                 return rc;
101         
102         /* create the bootstrap mailbox */
103         rc = oce_dma_alloc(sc, sizeof(struct oce_bmbx), &sc->bsmbx, 0);
104         if (rc) {
105                 device_printf(sc->dev, "Mailbox alloc failed\n");
106                 return rc;
107         }
108
109         rc = oce_reset_fun(sc);
110         if (rc)
111                 goto error;
112                 
113
114         rc = oce_mbox_init(sc);
115         if (rc)
116                 goto error;
117
118
119         rc = oce_get_fw_version(sc);
120         if (rc)
121                 goto error;
122
123
124         rc = oce_get_fw_config(sc);
125         if (rc)
126                 goto error;
127
128
129         sc->macaddr.size_of_struct = 6;
130         rc = oce_read_mac_addr(sc, 0, 1, MAC_ADDRESS_TYPE_NETWORK,
131                                         &sc->macaddr);
132         if (rc)
133                 goto error;
134         
135         if ((IS_BE(sc) && (sc->flags & OCE_FLAGS_BE3)) || IS_SH(sc)) {
136                 rc = oce_mbox_check_native_mode(sc);
137                 if (rc)
138                         goto error;
139         } else
140                 sc->be3_native = 0;
141         
142         return rc;
143
144 error:
145         oce_dma_free(sc, &sc->bsmbx);
146         device_printf(sc->dev, "Hardware initialisation failed\n");
147         return rc;
148 }
149
150
151
152 /**
153  * @brief               Releases the obtained pci resources
154  * @param sc            software handle to the device
155  */
156 void
157 oce_hw_pci_free(POCE_SOFTC sc)
158 {
159         int pci_cfg_barnum = 0;
160
161         if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
162                 pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
163         else
164                 pci_cfg_barnum = OCE_DEV_CFG_BAR;
165
166         if (sc->devcfg_res != NULL) {
167                 bus_release_resource(sc->dev,
168                                      SYS_RES_MEMORY,
169                                      PCIR_BAR(pci_cfg_barnum), sc->devcfg_res);
170                 sc->devcfg_res = (struct resource *)NULL;
171                 sc->devcfg_btag = (bus_space_tag_t) 0;
172                 sc->devcfg_bhandle = (bus_space_handle_t)0;
173                 sc->devcfg_vhandle = (void *)NULL;
174         }
175
176         if (sc->csr_res != NULL) {
177                 bus_release_resource(sc->dev,
178                                      SYS_RES_MEMORY,
179                                      PCIR_BAR(OCE_PCI_CSR_BAR), sc->csr_res);
180                 sc->csr_res = (struct resource *)NULL;
181                 sc->csr_btag = (bus_space_tag_t)0;
182                 sc->csr_bhandle = (bus_space_handle_t)0;
183                 sc->csr_vhandle = (void *)NULL;
184         }
185
186         if (sc->db_res != NULL) {
187                 bus_release_resource(sc->dev,
188                                      SYS_RES_MEMORY,
189                                      PCIR_BAR(OCE_PCI_DB_BAR), sc->db_res);
190                 sc->db_res = (struct resource *)NULL;
191                 sc->db_btag = (bus_space_tag_t)0;
192                 sc->db_bhandle = (bus_space_handle_t)0;
193                 sc->db_vhandle = (void *)NULL;
194         }
195 }
196
197
198
199
200 /**
201  * @brief               Function to get the PCI capabilities
202  * @param sc            software handle to the device
203  */
204 static
205 void oce_get_pci_capabilities(POCE_SOFTC sc)
206 {
207         uint32_t val;
208
209 #if __FreeBSD_version >= 1000000
210         #define pci_find_extcap pci_find_cap
211 #endif
212
213         if (pci_find_extcap(sc->dev, PCIY_PCIX, &val) == 0) {
214                 if (val != 0) 
215                         sc->flags |= OCE_FLAGS_PCIX;
216         }
217
218         if (pci_find_extcap(sc->dev, PCIY_EXPRESS, &val) == 0) {
219                 if (val != 0) {
220                         uint16_t link_status =
221                             pci_read_config(sc->dev, val + 0x12, 2);
222
223                         sc->flags |= OCE_FLAGS_PCIE;
224                         sc->pcie_link_speed = link_status & 0xf;
225                         sc->pcie_link_width = (link_status >> 4) & 0x3f;
226                 }
227         }
228
229         if (pci_find_extcap(sc->dev, PCIY_MSI, &val) == 0) {
230                 if (val != 0)
231                         sc->flags |= OCE_FLAGS_MSI_CAPABLE;
232         }
233
234         if (pci_find_extcap(sc->dev, PCIY_MSIX, &val) == 0) {
235                 if (val != 0) {
236                         val = pci_msix_count(sc->dev);
237                         sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
238                 }
239         }
240 }
241
242 /**
243  * @brief       Allocate PCI resources.
244  *
245  * @param sc            software handle to the device
246  * @returns             0 if successful, or error
247  */
248 int
249 oce_hw_pci_alloc(POCE_SOFTC sc)
250 {
251         int rr, pci_cfg_barnum = 0;
252         pci_sli_intf_t intf;
253
254         pci_enable_busmaster(sc->dev);
255
256         oce_get_pci_capabilities(sc);
257
258         sc->fn = pci_get_function(sc->dev);
259
260         /* setup the device config region */
261         if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
262                 pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
263         else
264                 pci_cfg_barnum = OCE_DEV_CFG_BAR;
265                 
266         rr = PCIR_BAR(pci_cfg_barnum);
267
268         if (IS_BE(sc) || IS_SH(sc)) 
269                 sc->devcfg_res = bus_alloc_resource_any(sc->dev,
270                                 SYS_RES_MEMORY, &rr,
271                                 RF_ACTIVE|RF_SHAREABLE);
272         else
273                 sc->devcfg_res = bus_alloc_resource_anywhere(sc->dev,
274                                 SYS_RES_MEMORY, &rr, 32768,
275                                 RF_ACTIVE|RF_SHAREABLE);
276
277         if (!sc->devcfg_res)
278                 goto error;
279
280         sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
281         sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
282         sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
283
284         /* Read the SLI_INTF register and determine whether we
285          * can use this port and its features
286          */
287         intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
288
289         if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
290                 goto error;
291         
292         if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
293                 device_printf(sc->dev, "Adapter doesnt support SLI4\n");
294                 goto error;
295         }
296
297         if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
298                 sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
299
300         if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
301                 sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
302
303         if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
304                 sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
305
306         /* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
307         if (IS_BE(sc) || IS_SH(sc)) {
308                 /* set up CSR region */
309                 rr = PCIR_BAR(OCE_PCI_CSR_BAR);
310                 sc->csr_res = bus_alloc_resource_any(sc->dev,
311                                 SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
312                 if (!sc->csr_res)
313                         goto error;
314                 sc->csr_btag = rman_get_bustag(sc->csr_res);
315                 sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
316                 sc->csr_vhandle = rman_get_virtual(sc->csr_res);
317                 
318                 /* set up DB doorbell region */
319                 rr = PCIR_BAR(OCE_PCI_DB_BAR);
320                 sc->db_res = bus_alloc_resource_any(sc->dev,
321                                 SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
322                 if (!sc->db_res)
323                         goto error;
324                 sc->db_btag = rman_get_bustag(sc->db_res);
325                 sc->db_bhandle = rman_get_bushandle(sc->db_res);
326                 sc->db_vhandle = rman_get_virtual(sc->db_res);
327         }
328
329         return 0;
330
331 error:  
332         oce_hw_pci_free(sc);
333         return ENXIO;
334 }
335
336
337 /**
338  * @brief               Function for device shutdown
339  * @param sc            software handle to the device
340  * @returns             0 on success, error otherwise
341  */
342 void
343 oce_hw_shutdown(POCE_SOFTC sc)
344 {
345
346         oce_stats_free(sc);
347         /* disable hardware interrupts */
348         oce_hw_intr_disable(sc);
349 #if defined(INET6) || defined(INET)
350         /* Free LRO resources */
351         oce_free_lro(sc);
352 #endif
353         /* Release queue*/
354         oce_queue_release_all(sc);
355         /*Delete Network Interface*/
356         oce_delete_nw_interface(sc);
357         /* After fw clean we dont send any cmds to fw.*/
358         oce_fw_clean(sc);
359         /* release intr resources */
360         oce_intr_free(sc);
361         /* release PCI resources */
362         oce_hw_pci_free(sc);
363         /* free mbox specific resources */
364         LOCK_DESTROY(&sc->bmbx_lock);
365         LOCK_DESTROY(&sc->dev_lock);
366
367         oce_dma_free(sc, &sc->bsmbx);
368 }
369
370
371 /**
372  * @brief               Function for creating nw interface.
373  * @param sc            software handle to the device
374  * @returns             0 on success, error otherwise
375  */
376 int
377 oce_create_nw_interface(POCE_SOFTC sc)
378 {
379         int rc;
380         uint32_t capab_flags;
381         uint32_t capab_en_flags;
382
383         /* interface capabilities to give device when creating interface */
384         capab_flags = OCE_CAPAB_FLAGS;
385
386         /* capabilities to enable by default (others set dynamically) */
387         capab_en_flags = OCE_CAPAB_ENABLE;
388
389         if (IS_XE201(sc)) {
390                 /* LANCER A0 workaround */
391                 capab_en_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
392                 capab_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
393         }
394
395         if (IS_SH(sc) || IS_XE201(sc))
396                 capab_flags |= MBX_RX_IFACE_FLAGS_MULTICAST;
397
398         if (sc->enable_hwlro) {
399                 capab_flags |= MBX_RX_IFACE_FLAGS_LRO;
400                 capab_en_flags |= MBX_RX_IFACE_FLAGS_LRO;
401         }
402
403         /* enable capabilities controlled via driver startup parameters */
404         if (is_rss_enabled(sc))
405                 capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
406         else {
407                 capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
408                 capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
409         }
410
411         rc = oce_if_create(sc,
412                            capab_flags,
413                            capab_en_flags,
414                            0, &sc->macaddr.mac_addr[0], &sc->if_id);
415         if (rc)
416                 return rc;
417
418         atomic_inc_32(&sc->nifs);
419
420         sc->if_cap_flags = capab_en_flags;
421
422         /* set default flow control */
423         rc = oce_set_flow_control(sc, sc->flow_control);
424         if (rc)
425                 goto error;
426
427         rc = oce_rxf_set_promiscuous(sc, sc->promisc);
428         if (rc)
429                 goto error;
430
431         return rc;
432
433 error:
434         oce_delete_nw_interface(sc);
435         return rc;
436
437 }
438
439 /**
440  * @brief               Function to delete a nw interface.
441  * @param sc            software handle to the device
442  */
443 void
444 oce_delete_nw_interface(POCE_SOFTC sc)
445 {
446         /* currently only single interface is implmeneted */
447         if (sc->nifs > 0) {
448                 oce_if_del(sc, sc->if_id);
449                 atomic_dec_32(&sc->nifs);
450         }
451 }
452
453 /**
454  * @brief Soft reset.
455  * @param sc            software handle to the device
456  * @returns             0 on success, error otherwise
457  */
458 int
459 oce_pci_soft_reset(POCE_SOFTC sc)
460 {
461         int rc;
462         mpu_ep_control_t ctrl;
463
464         ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
465         ctrl.bits.cpu_reset = 1;
466         OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
467         DELAY(50);
468         rc=oce_POST(sc);
469
470         return rc;
471 }
472
473 /**
474  * @brief               Function for hardware start
475  * @param sc            software handle to the device
476  * @returns             0 on success, error otherwise
477  */
478 int
479 oce_hw_start(POCE_SOFTC sc)
480 {
481         struct link_status link = { 0 };
482         int rc = 0;
483
484         rc = oce_get_link_status(sc, &link);
485         if (rc) 
486                 return 1;
487         
488         if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
489                 sc->link_status = NTWK_LOGICAL_LINK_UP;
490                 if_link_state_change(sc->ifp, LINK_STATE_UP);
491         } else {
492                 sc->link_status = NTWK_LOGICAL_LINK_DOWN;
493                 if_link_state_change(sc->ifp, LINK_STATE_DOWN);
494         }
495
496         sc->link_speed = link.phys_port_speed;
497         sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
498
499         rc = oce_start_mq(sc->mq);
500         
501         /* we need to get MCC aync events. So enable intrs and arm
502            first EQ, Other EQs will be armed after interface is UP 
503         */
504         oce_hw_intr_enable(sc);
505         oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
506
507         /* Send first mcc cmd and after that we get gracious
508            MCC notifications from FW
509         */
510         oce_first_mcc_cmd(sc);
511
512         return rc;
513 }
514
515
516 /**
517  * @brief               Function for hardware enable interupts.
518  * @param sc            software handle to the device
519  */
520 void
521 oce_hw_intr_enable(POCE_SOFTC sc)
522 {
523         uint32_t reg;
524
525         reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
526         reg |= HOSTINTR_MASK;
527         OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
528
529 }
530
531
532 /**
533  * @brief               Function for hardware disable interupts
534  * @param sc            software handle to the device
535  */
536 void
537 oce_hw_intr_disable(POCE_SOFTC sc)
538 {
539         uint32_t reg;
540         
541         reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
542         reg &= ~HOSTINTR_MASK;
543         OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
544 }
545
546
547 static u_int
548 oce_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
549 {
550         struct mbx_set_common_iface_multicast *req = arg;
551
552         if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE)
553                 return (0);
554
555         bcopy(LLADDR(sdl), &req->params.req.mac[req->params.req.num_mac++],
556             ETHER_ADDR_LEN);
557
558         return (1);
559 }
560
561
562 /**
563  * @brief               Function for hardware update multicast filter
564  * @param sc            software handle to the device
565  */
566 int
567 oce_hw_update_multicast(POCE_SOFTC sc)
568 {
569         struct ifnet    *ifp = sc->ifp;
570         struct mbx_set_common_iface_multicast *req = NULL;
571         OCE_DMA_MEM dma;
572         int rc = 0;
573
574         /* Allocate DMA mem*/
575         if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
576                                                         &dma, 0))
577                 return ENOMEM;
578
579         req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
580         bzero(req, sizeof(struct mbx_set_common_iface_multicast));
581
582         if_foreach_llmaddr(ifp, oce_copy_maddr, req);
583         if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
584                 /*More multicast addresses than our hardware table
585                   So Enable multicast promiscus in our hardware to
586                   accept all multicat packets
587                 */
588                 req->params.req.promiscuous = 1;
589         }
590
591         req->params.req.if_id = sc->if_id;
592         rc = oce_update_multicast(sc, &dma);
593         oce_dma_free(sc, &dma);
594         return rc;
595 }
596