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