xref: /dragonfly/sys/dev/netif/oce/oce_hw.c (revision 56b41dfb6441fc04b572dca61af092c2fdf84696)
1 /*-
2  * Copyright (C) 2013 Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the Emulex Corporation nor the names of its
16  *    contributors may be used to endorse or promote products derived from
17  *    this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Contact Information:
32  * freebsd-drivers@emulex.com
33  *
34  * Emulex
35  * 3333 Susan Street
36  * Costa Mesa, CA 92626
37  */
38 
39 /* $FreeBSD: src/sys/dev/oce/oce_hw.c,v 1.8 2013/07/07 00:30:13 svnexp Exp $ */
40 
41 #include "opt_inet6.h"
42 #include "opt_inet.h"
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
oce_POST(POCE_SOFTC sc)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
oce_hw_init(POCE_SOFTC sc)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
oce_hw_pci_free(POCE_SOFTC sc)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 = NULL;
171                     sc->devcfg_btag = (bus_space_tag_t) 0;
172                     sc->devcfg_bhandle = (bus_space_handle_t)0;
173                     sc->devcfg_vhandle = 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 = NULL;
181                     sc->csr_btag = (bus_space_tag_t)0;
182                     sc->csr_bhandle = (bus_space_handle_t)0;
183                     sc->csr_vhandle = 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 = NULL;
191                     sc->db_btag = (bus_space_tag_t)0;
192                     sc->db_bhandle = (bus_space_handle_t)0;
193                     sc->db_vhandle = 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
oce_get_pci_capabilities(POCE_SOFTC sc)205 void oce_get_pci_capabilities(POCE_SOFTC sc)
206 {
207           uint32_t val;
208 
209           if (pci_is_pcix(sc->dev))
210                     sc->flags |= OCE_FLAGS_PCIX;
211 
212           if (pci_find_extcap(sc->dev, PCIY_EXPRESS, &val) == 0) {
213                     if (val != 0) {
214                               uint16_t link_status =
215                                   pci_read_config(sc->dev, val + 0x12, 2);
216 
217                               sc->flags |= OCE_FLAGS_PCIE;
218                               sc->pcie_link_speed = link_status & 0xf;
219                               sc->pcie_link_width = (link_status >> 4) & 0x3f;
220                     }
221           }
222 
223           if (pci_find_extcap(sc->dev, PCIY_MSI, &val) == 0) {
224                     if (val != 0)
225                               sc->flags |= OCE_FLAGS_MSI_CAPABLE;
226           }
227 
228 #if 0 /* XXX swildner: MSI-X */
229           if (pci_find_cap(sc->dev, PCIY_MSIX, &val) == 0) {
230                     if (val != 0) {
231                               val = pci_msix_count(sc->dev);
232                               sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
233                     }
234           }
235 #endif
236 }
237 
238 /**
239  * @brief Allocate PCI resources.
240  *
241  * @param sc                  software handle to the device
242  * @returns                   0 if successful, or error
243  */
244 int
oce_hw_pci_alloc(POCE_SOFTC sc)245 oce_hw_pci_alloc(POCE_SOFTC sc)
246 {
247           int rr, pci_cfg_barnum = 0;
248           pci_sli_intf_t intf;
249 
250           pci_enable_busmaster(sc->dev);
251 
252           oce_get_pci_capabilities(sc);
253 
254           sc->fn = pci_get_function(sc->dev);
255 
256           /* setup the device config region */
257           if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
258                     pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
259           else
260                     pci_cfg_barnum = OCE_DEV_CFG_BAR;
261 
262           rr = PCIR_BAR(pci_cfg_barnum);
263 
264           if (IS_BE(sc) || IS_SH(sc))
265                     sc->devcfg_res = bus_alloc_resource_any(sc->dev,
266                                         SYS_RES_MEMORY, &rr,
267                                         RF_ACTIVE|RF_SHAREABLE);
268           else
269                     sc->devcfg_res = bus_alloc_resource(sc->dev,
270                                         SYS_RES_MEMORY, &rr,
271                                         0ul, ~0ul, 32768,
272                                         RF_ACTIVE|RF_SHAREABLE);
273 
274           if (!sc->devcfg_res)
275                     goto error;
276 
277           sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
278           sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
279           sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
280 
281           /* Read the SLI_INTF register and determine whether we
282            * can use this port and its features
283            */
284           intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
285 
286           if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
287                     goto error;
288 
289           if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
290                     device_printf(sc->dev, "Adapter does not support SLI4\n");
291                     goto error;
292           }
293 
294           if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
295                     sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
296 
297           if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
298                     sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
299 
300           if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
301                     sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
302 
303           /* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
304           if (IS_BE(sc) || IS_SH(sc)) {
305                     /* set up CSR region */
306                     rr = PCIR_BAR(OCE_PCI_CSR_BAR);
307                     sc->csr_res = bus_alloc_resource_any(sc->dev,
308                                         SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
309                     if (!sc->csr_res)
310                               goto error;
311                     sc->csr_btag = rman_get_bustag(sc->csr_res);
312                     sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
313                     sc->csr_vhandle = rman_get_virtual(sc->csr_res);
314 
315                     /* set up DB doorbell region */
316                     rr = PCIR_BAR(OCE_PCI_DB_BAR);
317                     sc->db_res = bus_alloc_resource_any(sc->dev,
318                                         SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
319                     if (!sc->db_res)
320                               goto error;
321                     sc->db_btag = rman_get_bustag(sc->db_res);
322                     sc->db_bhandle = rman_get_bushandle(sc->db_res);
323                     sc->db_vhandle = rman_get_virtual(sc->db_res);
324           }
325 
326           return 0;
327 
328 error:
329           oce_hw_pci_free(sc);
330           return ENXIO;
331 }
332 
333 
334 /**
335  * @brief           Function for device shutdown
336  * @param sc                  software handle to the device
337  * @returns                   0 on success, error otherwise
338  */
339 void
oce_hw_shutdown(POCE_SOFTC sc)340 oce_hw_shutdown(POCE_SOFTC sc)
341 {
342 
343           oce_stats_free(sc);
344           /* disable hardware interrupts */
345           oce_hw_intr_disable(sc);
346 #if defined(INET6) || defined(INET)
347 #if 0 /* XXX swildner: LRO */
348           /* Free LRO resources */
349           oce_free_lro(sc);
350 #endif
351 #endif
352           /* Release queue*/
353           oce_queue_release_all(sc);
354           /*Delete Network Interface*/
355           oce_delete_nw_interface(sc);
356           /* After fw clean we dont send any cmds to fw.*/
357           oce_fw_clean(sc);
358           /* release intr resources */
359           oce_intr_free(sc);
360           /* release PCI resources */
361           oce_hw_pci_free(sc);
362           /* free mbox specific resources */
363           LOCK_DESTROY(&sc->bmbx_lock);
364           LOCK_DESTROY(&sc->dev_lock);
365 
366           oce_dma_free(sc, &sc->bsmbx);
367 }
368 
369 
370 /**
371  * @brief           Function for creating nw interface.
372  * @param sc                  software handle to the device
373  * @returns                   0 on success, error otherwise
374  */
375 int
oce_create_nw_interface(POCE_SOFTC sc)376 oce_create_nw_interface(POCE_SOFTC sc)
377 {
378           int rc;
379           uint32_t capab_flags;
380           uint32_t capab_en_flags;
381 
382           /* interface capabilities to give device when creating interface */
383           capab_flags = OCE_CAPAB_FLAGS;
384 
385           /* capabilities to enable by default (others set dynamically) */
386           capab_en_flags = OCE_CAPAB_ENABLE;
387 
388           if (IS_XE201(sc)) {
389                     /* LANCER A0 workaround */
390                     capab_en_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
391                     capab_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
392           }
393 
394           /* enable capabilities controlled via driver startup parameters */
395           if (is_rss_enabled(sc))
396                     capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
397           else {
398                     capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
399                     capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
400           }
401 
402           rc = oce_if_create(sc,
403                                  capab_flags,
404                                  capab_en_flags,
405                                  0, &sc->macaddr.mac_addr[0], &sc->if_id);
406           if (rc)
407                     return rc;
408 
409           atomic_inc_32(&sc->nifs);
410 
411           sc->if_cap_flags = capab_en_flags;
412 
413           /* set default flow control */
414           rc = oce_set_flow_control(sc, sc->flow_control);
415           if (rc)
416                     goto error;
417 
418           rc = oce_rxf_set_promiscuous(sc, sc->promisc);
419           if (rc)
420                     goto error;
421 
422           return rc;
423 
424 error:
425           oce_delete_nw_interface(sc);
426           return rc;
427 
428 }
429 
430 /**
431  * @brief           Function to delete a nw interface.
432  * @param sc                  software handle to the device
433  */
434 void
oce_delete_nw_interface(POCE_SOFTC sc)435 oce_delete_nw_interface(POCE_SOFTC sc)
436 {
437           /* currently only single interface is implmeneted */
438           if (sc->nifs > 0) {
439                     oce_if_del(sc, sc->if_id);
440                     atomic_dec_32(&sc->nifs);
441           }
442 }
443 
444 /**
445  * @brief Soft reset.
446  * @param sc                  software handle to the device
447  * @returns                   0 on success, error otherwise
448  */
449 int
oce_pci_soft_reset(POCE_SOFTC sc)450 oce_pci_soft_reset(POCE_SOFTC sc)
451 {
452           int rc;
453           mpu_ep_control_t ctrl;
454 
455           ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
456           ctrl.bits.cpu_reset = 1;
457           OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
458           DELAY(50);
459           rc=oce_POST(sc);
460 
461           return rc;
462 }
463 
464 /**
465  * @brief           Function for hardware start
466  * @param sc                  software handle to the device
467  * @returns                   0 on success, error otherwise
468  */
469 int
oce_hw_start(POCE_SOFTC sc)470 oce_hw_start(POCE_SOFTC sc)
471 {
472           struct link_status link = { 0 };
473           int rc = 0;
474 
475           rc = oce_get_link_status(sc, &link);
476           if (rc)
477                     return 1;
478 
479           if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
480                     sc->link_status = NTWK_LOGICAL_LINK_UP;
481                     if_link_state_change(sc->ifp);
482           } else {
483                     sc->link_status = NTWK_LOGICAL_LINK_DOWN;
484                     if_link_state_change(sc->ifp);
485           }
486 
487           if (link.mac_speed > 0 && link.mac_speed < 5)
488                     sc->link_speed = link.mac_speed;
489           else
490                     sc->link_speed = 0;
491 
492           sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
493 
494           rc = oce_start_mq(sc->mq);
495 
496           /* we need to get MCC aync events. So enable intrs and arm
497              first EQ, Other EQs will be armed after interface is UP
498           */
499           oce_hw_intr_enable(sc);
500           oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
501 
502           /* Send first mcc cmd and after that we get gracious
503              MCC notifications from FW
504           */
505           oce_first_mcc_cmd(sc);
506 
507           return rc;
508 }
509 
510 
511 /**
512  * @brief                     Function for hardware enable interupts.
513  * @param sc                  software handle to the device
514  */
515 void
oce_hw_intr_enable(POCE_SOFTC sc)516 oce_hw_intr_enable(POCE_SOFTC sc)
517 {
518           uint32_t reg;
519 
520           reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
521           reg |= HOSTINTR_MASK;
522           OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
523 
524 }
525 
526 
527 /**
528  * @brief                     Function for hardware disable interupts
529  * @param sc                  software handle to the device
530  */
531 void
oce_hw_intr_disable(POCE_SOFTC sc)532 oce_hw_intr_disable(POCE_SOFTC sc)
533 {
534           uint32_t reg;
535 
536           reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
537           reg &= ~HOSTINTR_MASK;
538           OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
539 }
540 
541 
542 
543 /**
544  * @brief           Function for hardware update multicast filter
545  * @param sc                  software handle to the device
546  */
547 int
oce_hw_update_multicast(POCE_SOFTC sc)548 oce_hw_update_multicast(POCE_SOFTC sc)
549 {
550           struct ifnet    *ifp = sc->ifp;
551           struct ifmultiaddr *ifma;
552           struct mbx_set_common_iface_multicast *req = NULL;
553           OCE_DMA_MEM dma;
554           int rc = 0;
555 
556           /* Allocate DMA mem*/
557           if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
558                                                                       &dma, 0))
559                     return ENOMEM;
560 
561           req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
562           bzero(req, sizeof(struct mbx_set_common_iface_multicast));
563 
564           TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
565                     if (ifma->ifma_addr->sa_family != AF_LINK)
566                               continue;
567 
568                     if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
569                               /*More multicast addresses than our hardware table
570                                 So Enable multicast promiscus in our hardware to
571                                 accept all multicat packets
572                               */
573                               req->params.req.promiscuous = 1;
574                               break;
575                     }
576                     bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
577                               &req->params.req.mac[req->params.req.num_mac],
578                               ETH_ADDR_LEN);
579                     req->params.req.num_mac = req->params.req.num_mac + 1;
580           }
581           req->params.req.if_id = sc->if_id;
582           rc = oce_update_multicast(sc, &dma);
583           oce_dma_free(sc, &dma);
584           return rc;
585 }
586