Commit | Line | Data |
---|---|---|
b6fec18f AD |
1 | /* Intel Ethernet Switch Host Interface Driver |
2 | * Copyright(c) 2013 - 2014 Intel Corporation. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * The full GNU General Public License is included in this distribution in | |
14 | * the file called "COPYING". | |
15 | * | |
16 | * Contact Information: | |
17 | * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | |
18 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
19 | */ | |
20 | ||
21 | #include "fm10k_pf.h" | |
22 | ||
23 | /** | |
24 | * fm10k_reset_hw_pf - PF hardware reset | |
25 | * @hw: pointer to hardware structure | |
26 | * | |
27 | * This function should return the hardware to a state similar to the | |
28 | * one it is in after being powered on. | |
29 | **/ | |
30 | static s32 fm10k_reset_hw_pf(struct fm10k_hw *hw) | |
31 | { | |
32 | s32 err; | |
33 | u32 reg; | |
34 | u16 i; | |
35 | ||
36 | /* Disable interrupts */ | |
37 | fm10k_write_reg(hw, FM10K_EIMR, FM10K_EIMR_DISABLE(ALL)); | |
38 | ||
39 | /* Lock ITR2 reg 0 into itself and disable interrupt moderation */ | |
40 | fm10k_write_reg(hw, FM10K_ITR2(0), 0); | |
41 | fm10k_write_reg(hw, FM10K_INT_CTRL, 0); | |
42 | ||
43 | /* We assume here Tx and Rx queue 0 are owned by the PF */ | |
44 | ||
45 | /* Shut off VF access to their queues forcing them to queue 0 */ | |
46 | for (i = 0; i < FM10K_TQMAP_TABLE_SIZE; i++) { | |
47 | fm10k_write_reg(hw, FM10K_TQMAP(i), 0); | |
48 | fm10k_write_reg(hw, FM10K_RQMAP(i), 0); | |
49 | } | |
50 | ||
51 | /* shut down all rings */ | |
52 | err = fm10k_disable_queues_generic(hw, FM10K_MAX_QUEUES); | |
53 | if (err) | |
54 | return err; | |
55 | ||
56 | /* Verify that DMA is no longer active */ | |
57 | reg = fm10k_read_reg(hw, FM10K_DMA_CTRL); | |
58 | if (reg & (FM10K_DMA_CTRL_TX_ACTIVE | FM10K_DMA_CTRL_RX_ACTIVE)) | |
59 | return FM10K_ERR_DMA_PENDING; | |
60 | ||
61 | /* Inititate data path reset */ | |
62 | reg |= FM10K_DMA_CTRL_DATAPATH_RESET; | |
63 | fm10k_write_reg(hw, FM10K_DMA_CTRL, reg); | |
64 | ||
65 | /* Flush write and allow 100us for reset to complete */ | |
66 | fm10k_write_flush(hw); | |
67 | udelay(FM10K_RESET_TIMEOUT); | |
68 | ||
69 | /* Verify we made it out of reset */ | |
70 | reg = fm10k_read_reg(hw, FM10K_IP); | |
71 | if (!(reg & FM10K_IP_NOTINRESET)) | |
72 | err = FM10K_ERR_RESET_FAILED; | |
73 | ||
74 | return err; | |
75 | } | |
76 | ||
77 | /** | |
78 | * fm10k_init_hw_pf - PF hardware initialization | |
79 | * @hw: pointer to hardware structure | |
80 | * | |
81 | **/ | |
82 | static s32 fm10k_init_hw_pf(struct fm10k_hw *hw) | |
83 | { | |
84 | u32 dma_ctrl, txqctl; | |
85 | u16 i; | |
86 | ||
87 | /* Establish default VSI as valid */ | |
88 | fm10k_write_reg(hw, FM10K_DGLORTDEC(fm10k_dglort_default), 0); | |
89 | fm10k_write_reg(hw, FM10K_DGLORTMAP(fm10k_dglort_default), | |
90 | FM10K_DGLORTMAP_ANY); | |
91 | ||
92 | /* Invalidate all other GLORT entries */ | |
93 | for (i = 1; i < FM10K_DGLORT_COUNT; i++) | |
94 | fm10k_write_reg(hw, FM10K_DGLORTMAP(i), FM10K_DGLORTMAP_NONE); | |
95 | ||
96 | /* reset ITR2(0) to point to itself */ | |
97 | fm10k_write_reg(hw, FM10K_ITR2(0), 0); | |
98 | ||
99 | /* reset VF ITR2(0) to point to 0 avoid PF registers */ | |
100 | fm10k_write_reg(hw, FM10K_ITR2(FM10K_ITR_REG_COUNT_PF), 0); | |
101 | ||
102 | /* loop through all PF ITR2 registers pointing them to the previous */ | |
103 | for (i = 1; i < FM10K_ITR_REG_COUNT_PF; i++) | |
104 | fm10k_write_reg(hw, FM10K_ITR2(i), i - 1); | |
105 | ||
106 | /* Enable interrupt moderator if not already enabled */ | |
107 | fm10k_write_reg(hw, FM10K_INT_CTRL, FM10K_INT_CTRL_ENABLEMODERATOR); | |
108 | ||
109 | /* compute the default txqctl configuration */ | |
110 | txqctl = FM10K_TXQCTL_PF | FM10K_TXQCTL_UNLIMITED_BW | | |
111 | (hw->mac.default_vid << FM10K_TXQCTL_VID_SHIFT); | |
112 | ||
113 | for (i = 0; i < FM10K_MAX_QUEUES; i++) { | |
114 | /* configure rings for 256 Queue / 32 Descriptor cache mode */ | |
115 | fm10k_write_reg(hw, FM10K_TQDLOC(i), | |
116 | (i * FM10K_TQDLOC_BASE_32_DESC) | | |
117 | FM10K_TQDLOC_SIZE_32_DESC); | |
118 | fm10k_write_reg(hw, FM10K_TXQCTL(i), txqctl); | |
119 | ||
120 | /* configure rings to provide TPH processing hints */ | |
121 | fm10k_write_reg(hw, FM10K_TPH_TXCTRL(i), | |
122 | FM10K_TPH_TXCTRL_DESC_TPHEN | | |
123 | FM10K_TPH_TXCTRL_DESC_RROEN | | |
124 | FM10K_TPH_TXCTRL_DESC_WROEN | | |
125 | FM10K_TPH_TXCTRL_DATA_RROEN); | |
126 | fm10k_write_reg(hw, FM10K_TPH_RXCTRL(i), | |
127 | FM10K_TPH_RXCTRL_DESC_TPHEN | | |
128 | FM10K_TPH_RXCTRL_DESC_RROEN | | |
129 | FM10K_TPH_RXCTRL_DATA_WROEN | | |
130 | FM10K_TPH_RXCTRL_HDR_WROEN); | |
131 | } | |
132 | ||
133 | /* set max hold interval to align with 1.024 usec in all modes */ | |
134 | switch (hw->bus.speed) { | |
135 | case fm10k_bus_speed_2500: | |
136 | dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1; | |
137 | break; | |
138 | case fm10k_bus_speed_5000: | |
139 | dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2; | |
140 | break; | |
141 | case fm10k_bus_speed_8000: | |
142 | dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3; | |
143 | break; | |
144 | default: | |
145 | dma_ctrl = 0; | |
146 | break; | |
147 | } | |
148 | ||
149 | /* Configure TSO flags */ | |
150 | fm10k_write_reg(hw, FM10K_DTXTCPFLGL, FM10K_TSO_FLAGS_LOW); | |
151 | fm10k_write_reg(hw, FM10K_DTXTCPFLGH, FM10K_TSO_FLAGS_HI); | |
152 | ||
153 | /* Enable DMA engine | |
154 | * Set Rx Descriptor size to 32 | |
155 | * Set Minimum MSS to 64 | |
156 | * Set Maximum number of Rx queues to 256 / 32 Descriptor | |
157 | */ | |
158 | dma_ctrl |= FM10K_DMA_CTRL_TX_ENABLE | FM10K_DMA_CTRL_RX_ENABLE | | |
159 | FM10K_DMA_CTRL_RX_DESC_SIZE | FM10K_DMA_CTRL_MINMSS_64 | | |
160 | FM10K_DMA_CTRL_32_DESC; | |
161 | ||
162 | fm10k_write_reg(hw, FM10K_DMA_CTRL, dma_ctrl); | |
163 | ||
164 | /* record maximum queue count, we limit ourselves to 128 */ | |
165 | hw->mac.max_queues = FM10K_MAX_QUEUES_PF; | |
166 | ||
167 | return 0; | |
168 | } | |
169 | ||
170 | /** | |
171 | * fm10k_is_slot_appropriate_pf - Indicate appropriate slot for this SKU | |
172 | * @hw: pointer to hardware structure | |
173 | * | |
174 | * Looks at the PCIe bus info to confirm whether or not this slot can support | |
175 | * the necessary bandwidth for this device. | |
176 | **/ | |
177 | static bool fm10k_is_slot_appropriate_pf(struct fm10k_hw *hw) | |
178 | { | |
179 | return (hw->bus.speed == hw->bus_caps.speed) && | |
180 | (hw->bus.width == hw->bus_caps.width); | |
181 | } | |
182 | ||
183 | /** | |
184 | * fm10k_read_mac_addr_pf - Read device MAC address | |
185 | * @hw: pointer to the HW structure | |
186 | * | |
187 | * Reads the device MAC address from the SM_AREA and stores the value. | |
188 | **/ | |
189 | static s32 fm10k_read_mac_addr_pf(struct fm10k_hw *hw) | |
190 | { | |
191 | u8 perm_addr[ETH_ALEN]; | |
192 | u32 serial_num; | |
193 | int i; | |
194 | ||
195 | serial_num = fm10k_read_reg(hw, FM10K_SM_AREA(1)); | |
196 | ||
197 | /* last byte should be all 1's */ | |
198 | if ((~serial_num) << 24) | |
199 | return FM10K_ERR_INVALID_MAC_ADDR; | |
200 | ||
201 | perm_addr[0] = (u8)(serial_num >> 24); | |
202 | perm_addr[1] = (u8)(serial_num >> 16); | |
203 | perm_addr[2] = (u8)(serial_num >> 8); | |
204 | ||
205 | serial_num = fm10k_read_reg(hw, FM10K_SM_AREA(0)); | |
206 | ||
207 | /* first byte should be all 1's */ | |
208 | if ((~serial_num) >> 24) | |
209 | return FM10K_ERR_INVALID_MAC_ADDR; | |
210 | ||
211 | perm_addr[3] = (u8)(serial_num >> 16); | |
212 | perm_addr[4] = (u8)(serial_num >> 8); | |
213 | perm_addr[5] = (u8)(serial_num); | |
214 | ||
215 | for (i = 0; i < ETH_ALEN; i++) { | |
216 | hw->mac.perm_addr[i] = perm_addr[i]; | |
217 | hw->mac.addr[i] = perm_addr[i]; | |
218 | } | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
223 | /** | |
224 | * fm10k_update_stats_hw_pf - Updates hardware related statistics of PF | |
225 | * @hw: pointer to hardware structure | |
226 | * @stats: pointer to the stats structure to update | |
227 | * | |
228 | * This function collects and aggregates global and per queue hardware | |
229 | * statistics. | |
230 | **/ | |
231 | static void fm10k_update_hw_stats_pf(struct fm10k_hw *hw, | |
232 | struct fm10k_hw_stats *stats) | |
233 | { | |
234 | u32 timeout, ur, ca, um, xec, vlan_drop, loopback_drop, nodesc_drop; | |
235 | u32 id, id_prev; | |
236 | ||
237 | /* Use Tx queue 0 as a canary to detect a reset */ | |
238 | id = fm10k_read_reg(hw, FM10K_TXQCTL(0)); | |
239 | ||
240 | /* Read Global Statistics */ | |
241 | do { | |
242 | timeout = fm10k_read_hw_stats_32b(hw, FM10K_STATS_TIMEOUT, | |
243 | &stats->timeout); | |
244 | ur = fm10k_read_hw_stats_32b(hw, FM10K_STATS_UR, &stats->ur); | |
245 | ca = fm10k_read_hw_stats_32b(hw, FM10K_STATS_CA, &stats->ca); | |
246 | um = fm10k_read_hw_stats_32b(hw, FM10K_STATS_UM, &stats->um); | |
247 | xec = fm10k_read_hw_stats_32b(hw, FM10K_STATS_XEC, &stats->xec); | |
248 | vlan_drop = fm10k_read_hw_stats_32b(hw, FM10K_STATS_VLAN_DROP, | |
249 | &stats->vlan_drop); | |
250 | loopback_drop = fm10k_read_hw_stats_32b(hw, | |
251 | FM10K_STATS_LOOPBACK_DROP, | |
252 | &stats->loopback_drop); | |
253 | nodesc_drop = fm10k_read_hw_stats_32b(hw, | |
254 | FM10K_STATS_NODESC_DROP, | |
255 | &stats->nodesc_drop); | |
256 | ||
257 | /* if value has not changed then we have consistent data */ | |
258 | id_prev = id; | |
259 | id = fm10k_read_reg(hw, FM10K_TXQCTL(0)); | |
260 | } while ((id ^ id_prev) & FM10K_TXQCTL_ID_MASK); | |
261 | ||
262 | /* drop non-ID bits and set VALID ID bit */ | |
263 | id &= FM10K_TXQCTL_ID_MASK; | |
264 | id |= FM10K_STAT_VALID; | |
265 | ||
266 | /* Update Global Statistics */ | |
267 | if (stats->stats_idx == id) { | |
268 | stats->timeout.count += timeout; | |
269 | stats->ur.count += ur; | |
270 | stats->ca.count += ca; | |
271 | stats->um.count += um; | |
272 | stats->xec.count += xec; | |
273 | stats->vlan_drop.count += vlan_drop; | |
274 | stats->loopback_drop.count += loopback_drop; | |
275 | stats->nodesc_drop.count += nodesc_drop; | |
276 | } | |
277 | ||
278 | /* Update bases and record current PF id */ | |
279 | fm10k_update_hw_base_32b(&stats->timeout, timeout); | |
280 | fm10k_update_hw_base_32b(&stats->ur, ur); | |
281 | fm10k_update_hw_base_32b(&stats->ca, ca); | |
282 | fm10k_update_hw_base_32b(&stats->um, um); | |
283 | fm10k_update_hw_base_32b(&stats->xec, xec); | |
284 | fm10k_update_hw_base_32b(&stats->vlan_drop, vlan_drop); | |
285 | fm10k_update_hw_base_32b(&stats->loopback_drop, loopback_drop); | |
286 | fm10k_update_hw_base_32b(&stats->nodesc_drop, nodesc_drop); | |
287 | stats->stats_idx = id; | |
288 | ||
289 | /* Update Queue Statistics */ | |
290 | fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues); | |
291 | } | |
292 | ||
293 | /** | |
294 | * fm10k_rebind_hw_stats_pf - Resets base for hardware statistics of PF | |
295 | * @hw: pointer to hardware structure | |
296 | * @stats: pointer to the stats structure to update | |
297 | * | |
298 | * This function resets the base for global and per queue hardware | |
299 | * statistics. | |
300 | **/ | |
301 | static void fm10k_rebind_hw_stats_pf(struct fm10k_hw *hw, | |
302 | struct fm10k_hw_stats *stats) | |
303 | { | |
304 | /* Unbind Global Statistics */ | |
305 | fm10k_unbind_hw_stats_32b(&stats->timeout); | |
306 | fm10k_unbind_hw_stats_32b(&stats->ur); | |
307 | fm10k_unbind_hw_stats_32b(&stats->ca); | |
308 | fm10k_unbind_hw_stats_32b(&stats->um); | |
309 | fm10k_unbind_hw_stats_32b(&stats->xec); | |
310 | fm10k_unbind_hw_stats_32b(&stats->vlan_drop); | |
311 | fm10k_unbind_hw_stats_32b(&stats->loopback_drop); | |
312 | fm10k_unbind_hw_stats_32b(&stats->nodesc_drop); | |
313 | ||
314 | /* Unbind Queue Statistics */ | |
315 | fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues); | |
316 | ||
317 | /* Reinitialize bases for all stats */ | |
318 | fm10k_update_hw_stats_pf(hw, stats); | |
319 | } | |
320 | ||
321 | /** | |
322 | * fm10k_get_fault_pf - Record a fault in one of the interface units | |
323 | * @hw: pointer to hardware structure | |
324 | * @type: pointer to fault type register offset | |
325 | * @fault: pointer to memory location to record the fault | |
326 | * | |
327 | * Record the fault register contents to the fault data structure and | |
328 | * clear the entry from the register. | |
329 | * | |
330 | * Returns ERR_PARAM if invalid register is specified or no error is present. | |
331 | **/ | |
332 | static s32 fm10k_get_fault_pf(struct fm10k_hw *hw, int type, | |
333 | struct fm10k_fault *fault) | |
334 | { | |
335 | u32 func; | |
336 | ||
337 | /* verify the fault register is in range and is aligned */ | |
338 | switch (type) { | |
339 | case FM10K_PCA_FAULT: | |
340 | case FM10K_THI_FAULT: | |
341 | case FM10K_FUM_FAULT: | |
342 | break; | |
343 | default: | |
344 | return FM10K_ERR_PARAM; | |
345 | } | |
346 | ||
347 | /* only service faults that are valid */ | |
348 | func = fm10k_read_reg(hw, type + FM10K_FAULT_FUNC); | |
349 | if (!(func & FM10K_FAULT_FUNC_VALID)) | |
350 | return FM10K_ERR_PARAM; | |
351 | ||
352 | /* read remaining fields */ | |
353 | fault->address = fm10k_read_reg(hw, type + FM10K_FAULT_ADDR_HI); | |
354 | fault->address <<= 32; | |
355 | fault->address = fm10k_read_reg(hw, type + FM10K_FAULT_ADDR_LO); | |
356 | fault->specinfo = fm10k_read_reg(hw, type + FM10K_FAULT_SPECINFO); | |
357 | ||
358 | /* clear valid bit to allow for next error */ | |
359 | fm10k_write_reg(hw, type + FM10K_FAULT_FUNC, FM10K_FAULT_FUNC_VALID); | |
360 | ||
361 | /* Record which function triggered the error */ | |
362 | if (func & FM10K_FAULT_FUNC_PF) | |
363 | fault->func = 0; | |
364 | else | |
365 | fault->func = 1 + ((func & FM10K_FAULT_FUNC_VF_MASK) >> | |
366 | FM10K_FAULT_FUNC_VF_SHIFT); | |
367 | ||
368 | /* record fault type */ | |
369 | fault->type = func & FM10K_FAULT_FUNC_TYPE_MASK; | |
370 | ||
371 | return 0; | |
372 | } | |
373 | ||
374 | static struct fm10k_mac_ops mac_ops_pf = { | |
375 | .get_bus_info = &fm10k_get_bus_info_generic, | |
376 | .reset_hw = &fm10k_reset_hw_pf, | |
377 | .init_hw = &fm10k_init_hw_pf, | |
378 | .start_hw = &fm10k_start_hw_generic, | |
379 | .stop_hw = &fm10k_stop_hw_generic, | |
380 | .is_slot_appropriate = &fm10k_is_slot_appropriate_pf, | |
381 | .read_mac_addr = &fm10k_read_mac_addr_pf, | |
382 | .update_hw_stats = &fm10k_update_hw_stats_pf, | |
383 | .rebind_hw_stats = &fm10k_rebind_hw_stats_pf, | |
384 | .get_fault = &fm10k_get_fault_pf, | |
385 | .get_host_state = &fm10k_get_host_state_generic, | |
386 | }; | |
387 | ||
388 | struct fm10k_info fm10k_pf_info = { | |
389 | .mac = fm10k_mac_pf, | |
390 | .get_invariants = &fm10k_get_invariants_generic, | |
391 | .mac_ops = &mac_ops_pf, | |
392 | }; |