1 /*
2 * aQuantia Corporation Network Driver
3 * Copyright (C) 2014-2017 aQuantia Corporation. 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
7 * are met:
8 *
9 * (1) Redistributions of source code must retain the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer.
12 *
13 * (2) Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * (3)The name of the author may not be used to endorse or promote
19 * products derived from this software without specific prior
20 * written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
28 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <sys/param.h>
40 #include <sys/kernel.h>
41 #include <sys/socket.h>
42 #include <sys/bitstring.h>
43 #include <net/if.h>
44 #include <net/if_media.h>
45 #include <net/if_var.h>
46 #include <net/if_dl.h>
47 #include <net/ethernet.h>
48 #include <net/iflib.h>
49
50 #include "aq_common.h"
51 #include "aq_device.h"
52 #include "aq_ring.h"
53 #include "aq_dbg.h"
54 #include "aq_hw.h"
55 #include "aq_hw_llh.h"
56
aq_update_hw_stats(aq_dev_t * aq_dev)57 int aq_update_hw_stats(aq_dev_t *aq_dev)
58 {
59 struct aq_hw *hw = &aq_dev->hw;
60 struct aq_hw_fw_mbox mbox;
61
62 aq_hw_mpi_read_stats(hw, &mbox);
63
64 #define AQ_SDELTA(_N_) (aq_dev->curr_stats._N_ += \
65 mbox.stats._N_ - aq_dev->last_stats._N_)
66 if (aq_dev->linkup) {
67 AQ_SDELTA(uprc);
68 AQ_SDELTA(mprc);
69 AQ_SDELTA(bprc);
70 AQ_SDELTA(cprc);
71 AQ_SDELTA(erpt);
72
73 AQ_SDELTA(uptc);
74 AQ_SDELTA(mptc);
75 AQ_SDELTA(bptc);
76 AQ_SDELTA(erpr);
77
78 AQ_SDELTA(ubrc);
79 AQ_SDELTA(ubtc);
80 AQ_SDELTA(mbrc);
81 AQ_SDELTA(mbtc);
82 AQ_SDELTA(bbrc);
83 AQ_SDELTA(bbtc);
84
85 AQ_SDELTA(ptc);
86 AQ_SDELTA(prc);
87
88 AQ_SDELTA(dpc);
89
90 aq_dev->curr_stats.brc = aq_dev->curr_stats.ubrc +
91 aq_dev->curr_stats.mbrc +
92 aq_dev->curr_stats.bbrc;
93 aq_dev->curr_stats.btc = aq_dev->curr_stats.ubtc +
94 aq_dev->curr_stats.mbtc +
95 aq_dev->curr_stats.bbtc;
96
97 }
98 #undef AQ_SDELTA
99
100 memcpy(&aq_dev->last_stats, &mbox.stats, sizeof(mbox.stats));
101
102 return (0);
103 }
104
105
aq_if_update_admin_status(if_ctx_t ctx)106 void aq_if_update_admin_status(if_ctx_t ctx)
107 {
108 aq_dev_t *aq_dev = iflib_get_softc(ctx);
109 struct aq_hw *hw = &aq_dev->hw;
110 u32 link_speed;
111
112 // AQ_DBG_ENTER();
113
114 struct aq_hw_fc_info fc_neg;
115 aq_hw_get_link_state(hw, &link_speed, &fc_neg);
116 // AQ_DBG_PRINT(" link_speed=%d aq_dev->linkup=%d", link_speed, aq_dev->linkup);
117 if (link_speed && !aq_dev->linkup) { /* link was DOWN */
118 device_printf(aq_dev->dev, "atlantic: link UP: speed=%d\n", link_speed);
119
120 aq_dev->linkup = 1;
121
122 #if __FreeBSD__ >= 12
123 /* Disable TSO if link speed < 1G */
124 if (link_speed < 1000 && (iflib_get_softc_ctx(ctx)->isc_capabilities & (IFCAP_TSO4 | IFCAP_TSO6))) {
125 iflib_get_softc_ctx(ctx)->isc_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6);
126 device_printf(aq_dev->dev, "atlantic: TSO disabled for link speed < 1G");
127 }else{
128 iflib_get_softc_ctx(ctx)->isc_capabilities |= (IFCAP_TSO4 | IFCAP_TSO6);
129 }
130 #endif
131 /* turn on/off RX Pause in RPB */
132 rpb_rx_xoff_en_per_tc_set(hw, fc_neg.fc_rx, 0);
133
134
135 iflib_link_state_change(ctx, LINK_STATE_UP, IF_Mbps(link_speed));
136 aq_mediastatus_update(aq_dev, link_speed, &fc_neg);
137
138 /* update ITR settings according new link speed */
139 aq_hw_interrupt_moderation_set(hw);
140 } else if (link_speed == 0U && aq_dev->linkup) { /* link was UP */
141 device_printf(aq_dev->dev, "atlantic: link DOWN\n");
142
143 aq_dev->linkup = 0;
144
145 /* turn off RX Pause in RPB */
146 rpb_rx_xoff_en_per_tc_set(hw, 0, 0);
147
148 iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
149 aq_mediastatus_update(aq_dev, link_speed, &fc_neg);
150 }
151
152 aq_update_hw_stats(aq_dev);
153 // AQ_DBG_EXIT(0);
154 }
155
156 /**************************************************************************/
157 /* interrupt service routine (Top half) */
158 /**************************************************************************/
aq_isr_rx(void * arg)159 int aq_isr_rx(void *arg)
160 {
161 struct aq_ring *ring = arg;
162 struct aq_dev *aq_dev = ring->dev;
163 struct aq_hw *hw = &aq_dev->hw;
164
165 /* clear interrupt status */
166 itr_irq_status_clearlsw_set(hw, BIT(ring->msix));
167 ring->stats.irq++;
168 return (FILTER_SCHEDULE_THREAD);
169 }
170
171 /**************************************************************************/
172 /* interrupt service routine (Top half) */
173 /**************************************************************************/
aq_linkstat_isr(void * arg)174 int aq_linkstat_isr(void *arg)
175 {
176 aq_dev_t *aq_dev = arg;
177 struct aq_hw *hw = &aq_dev->hw;
178
179 /* clear interrupt status */
180 itr_irq_status_clearlsw_set(hw, aq_dev->msix);
181
182 iflib_admin_intr_deferred(aq_dev->ctx);
183
184 return (FILTER_HANDLED);
185 }
186