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