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