Commit | Line | Data |
---|---|---|
ab69bde6 JB |
1 | /* |
2 | * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net> | |
3 | * | |
4 | * This file is free software: you may copy, redistribute and/or modify it | |
5 | * under the terms of the GNU General Public License as published by the | |
6 | * Free Software Foundation, either version 2 of the License, or (at your | |
7 | * option) any later version. | |
8 | * | |
9 | * This file is distributed in the hope that it will be useful, but | |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | * General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | * | |
17 | * This file incorporates work covered by the following copyright and | |
18 | * permission notice: | |
19 | * | |
20 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | |
21 | * | |
22 | * Permission to use, copy, modify, and/or distribute this software for any | |
23 | * purpose with or without fee is hereby granted, provided that the above | |
24 | * copyright notice and this permission notice appear in all copies. | |
25 | * | |
26 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
27 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
28 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
29 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
30 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
31 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
32 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
33 | */ | |
34 | ||
35 | #include <linux/module.h> | |
36 | #include <linux/pci.h> | |
37 | #include <linux/interrupt.h> | |
38 | #include <linux/ip.h> | |
39 | #include <linux/ipv6.h> | |
40 | #include <linux/if_vlan.h> | |
41 | #include <linux/mdio.h> | |
42 | #include <linux/aer.h> | |
43 | #include <linux/bitops.h> | |
44 | #include <linux/netdevice.h> | |
45 | #include <linux/etherdevice.h> | |
46 | #include <net/ip6_checksum.h> | |
47 | #include <linux/crc32.h> | |
48 | #include "alx.h" | |
49 | #include "hw.h" | |
50 | #include "reg.h" | |
51 | ||
71311931 | 52 | static const char alx_drv_name[] = "alx"; |
ab69bde6 | 53 | |
702e8418 | 54 | static void alx_free_txbuf(struct alx_tx_queue *txq, int entry) |
ab69bde6 | 55 | { |
702e8418 | 56 | struct alx_buffer *txb = &txq->bufs[entry]; |
ab69bde6 JB |
57 | |
58 | if (dma_unmap_len(txb, size)) { | |
702e8418 | 59 | dma_unmap_single(txq->dev, |
ab69bde6 JB |
60 | dma_unmap_addr(txb, dma), |
61 | dma_unmap_len(txb, size), | |
62 | DMA_TO_DEVICE); | |
63 | dma_unmap_len_set(txb, size, 0); | |
64 | } | |
65 | ||
66 | if (txb->skb) { | |
67 | dev_kfree_skb_any(txb->skb); | |
68 | txb->skb = NULL; | |
69 | } | |
70 | } | |
71 | ||
72 | static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) | |
73 | { | |
702e8418 | 74 | struct alx_rx_queue *rxq = alx->qnapi[0]->rxq; |
ab69bde6 JB |
75 | struct sk_buff *skb; |
76 | struct alx_buffer *cur_buf; | |
77 | dma_addr_t dma; | |
78 | u16 cur, next, count = 0; | |
79 | ||
80 | next = cur = rxq->write_idx; | |
81 | if (++next == alx->rx_ringsz) | |
82 | next = 0; | |
83 | cur_buf = &rxq->bufs[cur]; | |
84 | ||
85 | while (!cur_buf->skb && next != rxq->read_idx) { | |
86 | struct alx_rfd *rfd = &rxq->rfd[cur]; | |
87 | ||
881d0327 FT |
88 | /* |
89 | * When DMA RX address is set to something like | |
90 | * 0x....fc0, it will be very likely to cause DMA | |
91 | * RFD overflow issue. | |
92 | * | |
93 | * To work around it, we apply rx skb with 64 bytes | |
94 | * longer space, and offset the address whenever | |
95 | * 0x....fc0 is detected. | |
96 | */ | |
97 | skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size + 64, gfp); | |
ab69bde6 JB |
98 | if (!skb) |
99 | break; | |
881d0327 FT |
100 | |
101 | if (((unsigned long)skb->data & 0xfff) == 0xfc0) | |
102 | skb_reserve(skb, 64); | |
103 | ||
ab69bde6 JB |
104 | dma = dma_map_single(&alx->hw.pdev->dev, |
105 | skb->data, alx->rxbuf_size, | |
106 | DMA_FROM_DEVICE); | |
107 | if (dma_mapping_error(&alx->hw.pdev->dev, dma)) { | |
108 | dev_kfree_skb(skb); | |
109 | break; | |
110 | } | |
111 | ||
112 | /* Unfortunately, RX descriptor buffers must be 4-byte | |
113 | * aligned, so we can't use IP alignment. | |
114 | */ | |
115 | if (WARN_ON(dma & 3)) { | |
116 | dev_kfree_skb(skb); | |
117 | break; | |
118 | } | |
119 | ||
120 | cur_buf->skb = skb; | |
121 | dma_unmap_len_set(cur_buf, size, alx->rxbuf_size); | |
122 | dma_unmap_addr_set(cur_buf, dma, dma); | |
123 | rfd->addr = cpu_to_le64(dma); | |
124 | ||
125 | cur = next; | |
126 | if (++next == alx->rx_ringsz) | |
127 | next = 0; | |
128 | cur_buf = &rxq->bufs[cur]; | |
129 | count++; | |
130 | } | |
131 | ||
132 | if (count) { | |
133 | /* flush all updates before updating hardware */ | |
134 | wmb(); | |
135 | rxq->write_idx = cur; | |
136 | alx_write_mem16(&alx->hw, ALX_RFD_PIDX, cur); | |
137 | } | |
138 | ||
139 | return count; | |
140 | } | |
141 | ||
2e06826b TR |
142 | static struct alx_tx_queue *alx_tx_queue_mapping(struct alx_priv *alx, |
143 | struct sk_buff *skb) | |
144 | { | |
145 | unsigned int r_idx = skb->queue_mapping; | |
146 | ||
147 | if (r_idx >= alx->num_txq) | |
148 | r_idx = r_idx % alx->num_txq; | |
149 | ||
150 | return alx->qnapi[r_idx]->txq; | |
151 | } | |
152 | ||
153 | static struct netdev_queue *alx_get_tx_queue(const struct alx_tx_queue *txq) | |
154 | { | |
155 | return netdev_get_tx_queue(txq->netdev, txq->queue_idx); | |
156 | } | |
157 | ||
702e8418 | 158 | static inline int alx_tpd_avail(struct alx_tx_queue *txq) |
ab69bde6 | 159 | { |
ab69bde6 | 160 | if (txq->write_idx >= txq->read_idx) |
702e8418 | 161 | return txq->count + txq->read_idx - txq->write_idx - 1; |
ab69bde6 JB |
162 | return txq->read_idx - txq->write_idx - 1; |
163 | } | |
164 | ||
702e8418 | 165 | static bool alx_clean_tx_irq(struct alx_tx_queue *txq) |
ab69bde6 | 166 | { |
702e8418 | 167 | struct alx_priv *alx; |
2e06826b | 168 | struct netdev_queue *tx_queue; |
ab69bde6 JB |
169 | u16 hw_read_idx, sw_read_idx; |
170 | unsigned int total_bytes = 0, total_packets = 0; | |
171 | int budget = ALX_DEFAULT_TX_WORK; | |
172 | ||
702e8418 | 173 | alx = netdev_priv(txq->netdev); |
2e06826b | 174 | tx_queue = alx_get_tx_queue(txq); |
702e8418 | 175 | |
ab69bde6 | 176 | sw_read_idx = txq->read_idx; |
2e06826b | 177 | hw_read_idx = alx_read_mem16(&alx->hw, txq->c_reg); |
ab69bde6 JB |
178 | |
179 | if (sw_read_idx != hw_read_idx) { | |
180 | while (sw_read_idx != hw_read_idx && budget > 0) { | |
181 | struct sk_buff *skb; | |
182 | ||
183 | skb = txq->bufs[sw_read_idx].skb; | |
184 | if (skb) { | |
185 | total_bytes += skb->len; | |
186 | total_packets++; | |
187 | budget--; | |
188 | } | |
189 | ||
702e8418 | 190 | alx_free_txbuf(txq, sw_read_idx); |
ab69bde6 | 191 | |
702e8418 | 192 | if (++sw_read_idx == txq->count) |
ab69bde6 JB |
193 | sw_read_idx = 0; |
194 | } | |
195 | txq->read_idx = sw_read_idx; | |
196 | ||
2e06826b | 197 | netdev_tx_completed_queue(tx_queue, total_packets, total_bytes); |
ab69bde6 JB |
198 | } |
199 | ||
2e06826b | 200 | if (netif_tx_queue_stopped(tx_queue) && netif_carrier_ok(alx->dev) && |
702e8418 | 201 | alx_tpd_avail(txq) > txq->count / 4) |
2e06826b | 202 | netif_tx_wake_queue(tx_queue); |
ab69bde6 JB |
203 | |
204 | return sw_read_idx == hw_read_idx; | |
205 | } | |
206 | ||
207 | static void alx_schedule_link_check(struct alx_priv *alx) | |
208 | { | |
209 | schedule_work(&alx->link_check_wk); | |
210 | } | |
211 | ||
212 | static void alx_schedule_reset(struct alx_priv *alx) | |
213 | { | |
214 | schedule_work(&alx->reset_wk); | |
215 | } | |
216 | ||
702e8418 | 217 | static int alx_clean_rx_irq(struct alx_rx_queue *rxq, int budget) |
ab69bde6 | 218 | { |
702e8418 | 219 | struct alx_priv *alx; |
ab69bde6 JB |
220 | struct alx_rrd *rrd; |
221 | struct alx_buffer *rxb; | |
222 | struct sk_buff *skb; | |
223 | u16 length, rfd_cleaned = 0; | |
7a05dc64 | 224 | int work = 0; |
ab69bde6 | 225 | |
702e8418 TR |
226 | alx = netdev_priv(rxq->netdev); |
227 | ||
7a05dc64 | 228 | while (work < budget) { |
ab69bde6 JB |
229 | rrd = &rxq->rrd[rxq->rrd_read_idx]; |
230 | if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT))) | |
231 | break; | |
232 | rrd->word3 &= ~cpu_to_le32(1 << RRD_UPDATED_SHIFT); | |
233 | ||
234 | if (ALX_GET_FIELD(le32_to_cpu(rrd->word0), | |
235 | RRD_SI) != rxq->read_idx || | |
236 | ALX_GET_FIELD(le32_to_cpu(rrd->word0), | |
237 | RRD_NOR) != 1) { | |
238 | alx_schedule_reset(alx); | |
7a05dc64 | 239 | return work; |
ab69bde6 JB |
240 | } |
241 | ||
242 | rxb = &rxq->bufs[rxq->read_idx]; | |
702e8418 | 243 | dma_unmap_single(rxq->dev, |
ab69bde6 JB |
244 | dma_unmap_addr(rxb, dma), |
245 | dma_unmap_len(rxb, size), | |
246 | DMA_FROM_DEVICE); | |
247 | dma_unmap_len_set(rxb, size, 0); | |
248 | skb = rxb->skb; | |
249 | rxb->skb = NULL; | |
250 | ||
251 | if (rrd->word3 & cpu_to_le32(1 << RRD_ERR_RES_SHIFT) || | |
252 | rrd->word3 & cpu_to_le32(1 << RRD_ERR_LEN_SHIFT)) { | |
253 | rrd->word3 = 0; | |
254 | dev_kfree_skb_any(skb); | |
255 | goto next_pkt; | |
256 | } | |
257 | ||
258 | length = ALX_GET_FIELD(le32_to_cpu(rrd->word3), | |
259 | RRD_PKTLEN) - ETH_FCS_LEN; | |
260 | skb_put(skb, length); | |
702e8418 | 261 | skb->protocol = eth_type_trans(skb, rxq->netdev); |
ab69bde6 JB |
262 | |
263 | skb_checksum_none_assert(skb); | |
264 | if (alx->dev->features & NETIF_F_RXCSUM && | |
265 | !(rrd->word3 & (cpu_to_le32(1 << RRD_ERR_L4_SHIFT) | | |
266 | cpu_to_le32(1 << RRD_ERR_IPV4_SHIFT)))) { | |
267 | switch (ALX_GET_FIELD(le32_to_cpu(rrd->word2), | |
268 | RRD_PID)) { | |
269 | case RRD_PID_IPV6UDP: | |
270 | case RRD_PID_IPV4UDP: | |
271 | case RRD_PID_IPV4TCP: | |
272 | case RRD_PID_IPV6TCP: | |
273 | skb->ip_summed = CHECKSUM_UNNECESSARY; | |
274 | break; | |
275 | } | |
276 | } | |
277 | ||
702e8418 | 278 | napi_gro_receive(&rxq->np->napi, skb); |
7a05dc64 | 279 | work++; |
ab69bde6 JB |
280 | |
281 | next_pkt: | |
702e8418 | 282 | if (++rxq->read_idx == rxq->count) |
ab69bde6 | 283 | rxq->read_idx = 0; |
702e8418 | 284 | if (++rxq->rrd_read_idx == rxq->count) |
ab69bde6 JB |
285 | rxq->rrd_read_idx = 0; |
286 | ||
287 | if (++rfd_cleaned > ALX_RX_ALLOC_THRESH) | |
288 | rfd_cleaned -= alx_refill_rx_ring(alx, GFP_ATOMIC); | |
289 | } | |
290 | ||
291 | if (rfd_cleaned) | |
292 | alx_refill_rx_ring(alx, GFP_ATOMIC); | |
293 | ||
7a05dc64 | 294 | return work; |
ab69bde6 JB |
295 | } |
296 | ||
297 | static int alx_poll(struct napi_struct *napi, int budget) | |
298 | { | |
702e8418 TR |
299 | struct alx_napi *np = container_of(napi, struct alx_napi, napi); |
300 | struct alx_priv *alx = np->alx; | |
ab69bde6 | 301 | struct alx_hw *hw = &alx->hw; |
ab69bde6 | 302 | unsigned long flags; |
e0eac254 TR |
303 | bool tx_complete = true; |
304 | int work = 0; | |
ab69bde6 | 305 | |
e0eac254 TR |
306 | if (np->txq) |
307 | tx_complete = alx_clean_tx_irq(np->txq); | |
308 | if (np->rxq) | |
309 | work = alx_clean_rx_irq(np->rxq, budget); | |
ab69bde6 | 310 | |
7a05dc64 ED |
311 | if (!tx_complete || work == budget) |
312 | return budget; | |
ab69bde6 | 313 | |
6ad20165 | 314 | napi_complete_done(&np->napi, work); |
ab69bde6 JB |
315 | |
316 | /* enable interrupt */ | |
f3297f68 | 317 | if (alx->hw.pdev->msix_enabled) { |
e0eac254 | 318 | alx_mask_msix(hw, np->vec_idx, false); |
dc39a78b TR |
319 | } else { |
320 | spin_lock_irqsave(&alx->irq_lock, flags); | |
321 | alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0; | |
322 | alx_write_mem32(hw, ALX_IMR, alx->int_mask); | |
323 | spin_unlock_irqrestore(&alx->irq_lock, flags); | |
324 | } | |
ab69bde6 JB |
325 | |
326 | alx_post_write(hw); | |
327 | ||
7a05dc64 | 328 | return work; |
ab69bde6 JB |
329 | } |
330 | ||
a0373aef | 331 | static bool alx_intr_handle_misc(struct alx_priv *alx, u32 intr) |
ab69bde6 JB |
332 | { |
333 | struct alx_hw *hw = &alx->hw; | |
ab69bde6 JB |
334 | |
335 | if (intr & ALX_ISR_FATAL) { | |
336 | netif_warn(alx, hw, alx->dev, | |
337 | "fatal interrupt 0x%x, resetting\n", intr); | |
338 | alx_schedule_reset(alx); | |
a0373aef | 339 | return true; |
ab69bde6 JB |
340 | } |
341 | ||
342 | if (intr & ALX_ISR_ALERT) | |
343 | netdev_warn(alx->dev, "alert interrupt: 0x%x\n", intr); | |
344 | ||
345 | if (intr & ALX_ISR_PHY) { | |
346 | /* suppress PHY interrupt, because the source | |
347 | * is from PHY internal. only the internal status | |
348 | * is cleared, the interrupt status could be cleared. | |
349 | */ | |
350 | alx->int_mask &= ~ALX_ISR_PHY; | |
a0373aef | 351 | alx_write_mem32(hw, ALX_IMR, alx->int_mask); |
ab69bde6 JB |
352 | alx_schedule_link_check(alx); |
353 | } | |
354 | ||
a0373aef TR |
355 | return false; |
356 | } | |
357 | ||
358 | static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr) | |
359 | { | |
360 | struct alx_hw *hw = &alx->hw; | |
361 | ||
362 | spin_lock(&alx->irq_lock); | |
363 | ||
364 | /* ACK interrupt */ | |
365 | alx_write_mem32(hw, ALX_ISR, intr | ALX_ISR_DIS); | |
366 | intr &= alx->int_mask; | |
367 | ||
368 | if (alx_intr_handle_misc(alx, intr)) | |
369 | goto out; | |
370 | ||
ab69bde6 | 371 | if (intr & (ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0)) { |
702e8418 | 372 | napi_schedule(&alx->qnapi[0]->napi); |
ab69bde6 JB |
373 | /* mask rx/tx interrupt, enable them when napi complete */ |
374 | alx->int_mask &= ~ALX_ISR_ALL_QUEUES; | |
ab69bde6 | 375 | alx_write_mem32(hw, ALX_IMR, alx->int_mask); |
a0373aef | 376 | } |
ab69bde6 JB |
377 | |
378 | alx_write_mem32(hw, ALX_ISR, 0); | |
379 | ||
380 | out: | |
381 | spin_unlock(&alx->irq_lock); | |
382 | return IRQ_HANDLED; | |
383 | } | |
384 | ||
dc39a78b TR |
385 | static irqreturn_t alx_intr_msix_ring(int irq, void *data) |
386 | { | |
702e8418 TR |
387 | struct alx_napi *np = data; |
388 | struct alx_hw *hw = &np->alx->hw; | |
dc39a78b TR |
389 | |
390 | /* mask interrupt to ACK chip */ | |
e0eac254 | 391 | alx_mask_msix(hw, np->vec_idx, true); |
dc39a78b | 392 | /* clear interrupt status */ |
e0eac254 | 393 | alx_write_mem32(hw, ALX_ISR, np->vec_mask); |
dc39a78b | 394 | |
702e8418 | 395 | napi_schedule(&np->napi); |
dc39a78b TR |
396 | |
397 | return IRQ_HANDLED; | |
398 | } | |
399 | ||
400 | static irqreturn_t alx_intr_msix_misc(int irq, void *data) | |
401 | { | |
402 | struct alx_priv *alx = data; | |
403 | struct alx_hw *hw = &alx->hw; | |
404 | u32 intr; | |
405 | ||
406 | /* mask interrupt to ACK chip */ | |
407 | alx_mask_msix(hw, 0, true); | |
408 | ||
409 | /* read interrupt status */ | |
410 | intr = alx_read_mem32(hw, ALX_ISR); | |
411 | intr &= (alx->int_mask & ~ALX_ISR_ALL_QUEUES); | |
412 | ||
413 | if (alx_intr_handle_misc(alx, intr)) | |
414 | return IRQ_HANDLED; | |
415 | ||
416 | /* clear interrupt status */ | |
417 | alx_write_mem32(hw, ALX_ISR, intr); | |
418 | ||
419 | /* enable interrupt again */ | |
420 | alx_mask_msix(hw, 0, false); | |
421 | ||
422 | return IRQ_HANDLED; | |
423 | } | |
424 | ||
ab69bde6 JB |
425 | static irqreturn_t alx_intr_msi(int irq, void *data) |
426 | { | |
427 | struct alx_priv *alx = data; | |
428 | ||
429 | return alx_intr_handle(alx, alx_read_mem32(&alx->hw, ALX_ISR)); | |
430 | } | |
431 | ||
432 | static irqreturn_t alx_intr_legacy(int irq, void *data) | |
433 | { | |
434 | struct alx_priv *alx = data; | |
435 | struct alx_hw *hw = &alx->hw; | |
436 | u32 intr; | |
437 | ||
438 | intr = alx_read_mem32(hw, ALX_ISR); | |
439 | ||
440 | if (intr & ALX_ISR_DIS || !(intr & alx->int_mask)) | |
441 | return IRQ_NONE; | |
442 | ||
443 | return alx_intr_handle(alx, intr); | |
444 | } | |
445 | ||
a4076d34 TR |
446 | static const u16 txring_header_reg[] = {ALX_TPD_PRI0_ADDR_LO, |
447 | ALX_TPD_PRI1_ADDR_LO, | |
448 | ALX_TPD_PRI2_ADDR_LO, | |
449 | ALX_TPD_PRI3_ADDR_LO}; | |
450 | ||
ab69bde6 JB |
451 | static void alx_init_ring_ptrs(struct alx_priv *alx) |
452 | { | |
453 | struct alx_hw *hw = &alx->hw; | |
454 | u32 addr_hi = ((u64)alx->descmem.dma) >> 32; | |
a4076d34 TR |
455 | struct alx_napi *np; |
456 | int i; | |
457 | ||
458 | for (i = 0; i < alx->num_napi; i++) { | |
459 | np = alx->qnapi[i]; | |
460 | if (np->txq) { | |
461 | np->txq->read_idx = 0; | |
462 | np->txq->write_idx = 0; | |
463 | alx_write_mem32(hw, | |
464 | txring_header_reg[np->txq->queue_idx], | |
465 | np->txq->tpd_dma); | |
466 | } | |
467 | ||
468 | if (np->rxq) { | |
469 | np->rxq->read_idx = 0; | |
470 | np->rxq->write_idx = 0; | |
471 | np->rxq->rrd_read_idx = 0; | |
472 | alx_write_mem32(hw, ALX_RRD_ADDR_LO, np->rxq->rrd_dma); | |
473 | alx_write_mem32(hw, ALX_RFD_ADDR_LO, np->rxq->rfd_dma); | |
474 | } | |
475 | } | |
476 | ||
477 | alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi); | |
478 | alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz); | |
ab69bde6 | 479 | |
ab69bde6 | 480 | alx_write_mem32(hw, ALX_RX_BASE_ADDR_HI, addr_hi); |
ab69bde6 | 481 | alx_write_mem32(hw, ALX_RRD_RING_SZ, alx->rx_ringsz); |
ab69bde6 JB |
482 | alx_write_mem32(hw, ALX_RFD_RING_SZ, alx->rx_ringsz); |
483 | alx_write_mem32(hw, ALX_RFD_BUF_SZ, alx->rxbuf_size); | |
484 | ||
ab69bde6 JB |
485 | /* load these pointers into the chip */ |
486 | alx_write_mem32(hw, ALX_SRAM9, ALX_SRAM_LOAD_PTR); | |
487 | } | |
488 | ||
702e8418 | 489 | static void alx_free_txring_buf(struct alx_tx_queue *txq) |
ab69bde6 | 490 | { |
ab69bde6 JB |
491 | int i; |
492 | ||
493 | if (!txq->bufs) | |
494 | return; | |
495 | ||
702e8418 TR |
496 | for (i = 0; i < txq->count; i++) |
497 | alx_free_txbuf(txq, i); | |
ab69bde6 | 498 | |
702e8418 TR |
499 | memset(txq->bufs, 0, txq->count * sizeof(struct alx_buffer)); |
500 | memset(txq->tpd, 0, txq->count * sizeof(struct alx_txd)); | |
ab69bde6 JB |
501 | txq->write_idx = 0; |
502 | txq->read_idx = 0; | |
503 | ||
2e06826b | 504 | netdev_tx_reset_queue(alx_get_tx_queue(txq)); |
ab69bde6 JB |
505 | } |
506 | ||
702e8418 | 507 | static void alx_free_rxring_buf(struct alx_rx_queue *rxq) |
ab69bde6 | 508 | { |
ab69bde6 JB |
509 | struct alx_buffer *cur_buf; |
510 | u16 i; | |
511 | ||
a4076d34 | 512 | if (!rxq->bufs) |
ab69bde6 JB |
513 | return; |
514 | ||
702e8418 | 515 | for (i = 0; i < rxq->count; i++) { |
ab69bde6 JB |
516 | cur_buf = rxq->bufs + i; |
517 | if (cur_buf->skb) { | |
702e8418 | 518 | dma_unmap_single(rxq->dev, |
ab69bde6 JB |
519 | dma_unmap_addr(cur_buf, dma), |
520 | dma_unmap_len(cur_buf, size), | |
521 | DMA_FROM_DEVICE); | |
522 | dev_kfree_skb(cur_buf->skb); | |
523 | cur_buf->skb = NULL; | |
524 | dma_unmap_len_set(cur_buf, size, 0); | |
525 | dma_unmap_addr_set(cur_buf, dma, 0); | |
526 | } | |
527 | } | |
528 | ||
529 | rxq->write_idx = 0; | |
530 | rxq->read_idx = 0; | |
531 | rxq->rrd_read_idx = 0; | |
532 | } | |
533 | ||
534 | static void alx_free_buffers(struct alx_priv *alx) | |
535 | { | |
a4076d34 TR |
536 | int i; |
537 | ||
538 | for (i = 0; i < alx->num_txq; i++) | |
539 | if (alx->qnapi[i] && alx->qnapi[i]->txq) | |
540 | alx_free_txring_buf(alx->qnapi[i]->txq); | |
541 | ||
542 | if (alx->qnapi[0] && alx->qnapi[0]->rxq) | |
543 | alx_free_rxring_buf(alx->qnapi[0]->rxq); | |
ab69bde6 JB |
544 | } |
545 | ||
546 | static int alx_reinit_rings(struct alx_priv *alx) | |
547 | { | |
548 | alx_free_buffers(alx); | |
549 | ||
550 | alx_init_ring_ptrs(alx); | |
551 | ||
552 | if (!alx_refill_rx_ring(alx, GFP_KERNEL)) | |
553 | return -ENOMEM; | |
554 | ||
555 | return 0; | |
556 | } | |
557 | ||
558 | static void alx_add_mc_addr(struct alx_hw *hw, const u8 *addr, u32 *mc_hash) | |
559 | { | |
560 | u32 crc32, bit, reg; | |
561 | ||
562 | crc32 = ether_crc(ETH_ALEN, addr); | |
563 | reg = (crc32 >> 31) & 0x1; | |
564 | bit = (crc32 >> 26) & 0x1F; | |
565 | ||
566 | mc_hash[reg] |= BIT(bit); | |
567 | } | |
568 | ||
569 | static void __alx_set_rx_mode(struct net_device *netdev) | |
570 | { | |
571 | struct alx_priv *alx = netdev_priv(netdev); | |
572 | struct alx_hw *hw = &alx->hw; | |
573 | struct netdev_hw_addr *ha; | |
574 | u32 mc_hash[2] = {}; | |
575 | ||
576 | if (!(netdev->flags & IFF_ALLMULTI)) { | |
577 | netdev_for_each_mc_addr(ha, netdev) | |
578 | alx_add_mc_addr(hw, ha->addr, mc_hash); | |
579 | ||
580 | alx_write_mem32(hw, ALX_HASH_TBL0, mc_hash[0]); | |
581 | alx_write_mem32(hw, ALX_HASH_TBL1, mc_hash[1]); | |
582 | } | |
583 | ||
584 | hw->rx_ctrl &= ~(ALX_MAC_CTRL_MULTIALL_EN | ALX_MAC_CTRL_PROMISC_EN); | |
585 | if (netdev->flags & IFF_PROMISC) | |
586 | hw->rx_ctrl |= ALX_MAC_CTRL_PROMISC_EN; | |
587 | if (netdev->flags & IFF_ALLMULTI) | |
588 | hw->rx_ctrl |= ALX_MAC_CTRL_MULTIALL_EN; | |
589 | ||
590 | alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); | |
591 | } | |
592 | ||
593 | static void alx_set_rx_mode(struct net_device *netdev) | |
594 | { | |
595 | __alx_set_rx_mode(netdev); | |
596 | } | |
597 | ||
598 | static int alx_set_mac_address(struct net_device *netdev, void *data) | |
599 | { | |
600 | struct alx_priv *alx = netdev_priv(netdev); | |
601 | struct alx_hw *hw = &alx->hw; | |
602 | struct sockaddr *addr = data; | |
603 | ||
604 | if (!is_valid_ether_addr(addr->sa_data)) | |
605 | return -EADDRNOTAVAIL; | |
606 | ||
607 | if (netdev->addr_assign_type & NET_ADDR_RANDOM) | |
608 | netdev->addr_assign_type ^= NET_ADDR_RANDOM; | |
609 | ||
610 | memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | |
611 | memcpy(hw->mac_addr, addr->sa_data, netdev->addr_len); | |
612 | alx_set_macaddr(hw, hw->mac_addr); | |
613 | ||
614 | return 0; | |
615 | } | |
616 | ||
8c2a4c8e TR |
617 | static int alx_alloc_tx_ring(struct alx_priv *alx, struct alx_tx_queue *txq, |
618 | int offset) | |
ab69bde6 | 619 | { |
702e8418 | 620 | txq->bufs = kcalloc(txq->count, sizeof(struct alx_buffer), GFP_KERNEL); |
8c2a4c8e | 621 | if (!txq->bufs) |
ab69bde6 JB |
622 | return -ENOMEM; |
623 | ||
8c2a4c8e TR |
624 | txq->tpd = alx->descmem.virt + offset; |
625 | txq->tpd_dma = alx->descmem.dma + offset; | |
702e8418 | 626 | offset += sizeof(struct alx_txd) * txq->count; |
8c2a4c8e TR |
627 | |
628 | return offset; | |
629 | } | |
630 | ||
631 | static int alx_alloc_rx_ring(struct alx_priv *alx, struct alx_rx_queue *rxq, | |
632 | int offset) | |
633 | { | |
702e8418 | 634 | rxq->bufs = kcalloc(rxq->count, sizeof(struct alx_buffer), GFP_KERNEL); |
8c2a4c8e TR |
635 | if (!rxq->bufs) |
636 | return -ENOMEM; | |
637 | ||
638 | rxq->rrd = alx->descmem.virt + offset; | |
639 | rxq->rrd_dma = alx->descmem.dma + offset; | |
702e8418 | 640 | offset += sizeof(struct alx_rrd) * rxq->count; |
8c2a4c8e TR |
641 | |
642 | rxq->rfd = alx->descmem.virt + offset; | |
643 | rxq->rfd_dma = alx->descmem.dma + offset; | |
702e8418 | 644 | offset += sizeof(struct alx_rfd) * rxq->count; |
8c2a4c8e TR |
645 | |
646 | return offset; | |
647 | } | |
648 | ||
649 | static int alx_alloc_rings(struct alx_priv *alx) | |
650 | { | |
a4076d34 | 651 | int i, offset = 0; |
ab69bde6 JB |
652 | |
653 | /* physical tx/rx ring descriptors | |
654 | * | |
655 | * Allocate them as a single chunk because they must not cross a | |
656 | * 4G boundary (hardware has a single register for high 32 bits | |
657 | * of addresses only) | |
658 | */ | |
a4076d34 TR |
659 | alx->descmem.size = sizeof(struct alx_txd) * alx->tx_ringsz * |
660 | alx->num_txq + | |
ab69bde6 JB |
661 | sizeof(struct alx_rrd) * alx->rx_ringsz + |
662 | sizeof(struct alx_rfd) * alx->rx_ringsz; | |
750afb08 LC |
663 | alx->descmem.virt = dma_alloc_coherent(&alx->hw.pdev->dev, |
664 | alx->descmem.size, | |
665 | &alx->descmem.dma, GFP_KERNEL); | |
ab69bde6 | 666 | if (!alx->descmem.virt) |
8c2a4c8e | 667 | return -ENOMEM; |
ab69bde6 | 668 | |
8c2a4c8e | 669 | /* alignment requirements */ |
ab69bde6 | 670 | BUILD_BUG_ON(sizeof(struct alx_txd) % 8); |
ab69bde6 JB |
671 | BUILD_BUG_ON(sizeof(struct alx_rrd) % 8); |
672 | ||
a4076d34 TR |
673 | for (i = 0; i < alx->num_txq; i++) { |
674 | offset = alx_alloc_tx_ring(alx, alx->qnapi[i]->txq, offset); | |
675 | if (offset < 0) { | |
676 | netdev_err(alx->dev, "Allocation of tx buffer failed!\n"); | |
677 | return -ENOMEM; | |
678 | } | |
8c2a4c8e | 679 | } |
ab69bde6 | 680 | |
702e8418 | 681 | offset = alx_alloc_rx_ring(alx, alx->qnapi[0]->rxq, offset); |
8c2a4c8e TR |
682 | if (offset < 0) { |
683 | netdev_err(alx->dev, "Allocation of rx buffer failed!\n"); | |
b0999223 | 684 | return -ENOMEM; |
8c2a4c8e | 685 | } |
ab69bde6 | 686 | |
ab69bde6 JB |
687 | return 0; |
688 | } | |
689 | ||
690 | static void alx_free_rings(struct alx_priv *alx) | |
691 | { | |
a4076d34 | 692 | int i; |
702e8418 | 693 | |
ab69bde6 JB |
694 | alx_free_buffers(alx); |
695 | ||
a4076d34 TR |
696 | for (i = 0; i < alx->num_txq; i++) |
697 | if (alx->qnapi[i] && alx->qnapi[i]->txq) | |
698 | kfree(alx->qnapi[i]->txq->bufs); | |
699 | ||
700 | if (alx->qnapi[0] && alx->qnapi[0]->rxq) | |
701 | kfree(alx->qnapi[0]->rxq->bufs); | |
ab69bde6 | 702 | |
f1db5c10 | 703 | if (alx->descmem.virt) |
b0999223 TR |
704 | dma_free_coherent(&alx->hw.pdev->dev, |
705 | alx->descmem.size, | |
706 | alx->descmem.virt, | |
707 | alx->descmem.dma); | |
708 | } | |
709 | ||
710 | static void alx_free_napis(struct alx_priv *alx) | |
711 | { | |
712 | struct alx_napi *np; | |
a4076d34 | 713 | int i; |
b0999223 | 714 | |
a4076d34 TR |
715 | for (i = 0; i < alx->num_napi; i++) { |
716 | np = alx->qnapi[i]; | |
717 | if (!np) | |
718 | continue; | |
719 | ||
720 | netif_napi_del(&np->napi); | |
721 | kfree(np->txq); | |
722 | kfree(np->rxq); | |
723 | kfree(np); | |
724 | alx->qnapi[i] = NULL; | |
725 | } | |
b0999223 TR |
726 | } |
727 | ||
2e06826b TR |
728 | static const u16 tx_pidx_reg[] = {ALX_TPD_PRI0_PIDX, ALX_TPD_PRI1_PIDX, |
729 | ALX_TPD_PRI2_PIDX, ALX_TPD_PRI3_PIDX}; | |
730 | static const u16 tx_cidx_reg[] = {ALX_TPD_PRI0_CIDX, ALX_TPD_PRI1_CIDX, | |
731 | ALX_TPD_PRI2_CIDX, ALX_TPD_PRI3_CIDX}; | |
e0eac254 TR |
732 | static const u32 tx_vect_mask[] = {ALX_ISR_TX_Q0, ALX_ISR_TX_Q1, |
733 | ALX_ISR_TX_Q2, ALX_ISR_TX_Q3}; | |
734 | static const u32 rx_vect_mask[] = {ALX_ISR_RX_Q0, ALX_ISR_RX_Q1, | |
735 | ALX_ISR_RX_Q2, ALX_ISR_RX_Q3, | |
736 | ALX_ISR_RX_Q4, ALX_ISR_RX_Q5, | |
737 | ALX_ISR_RX_Q6, ALX_ISR_RX_Q7}; | |
738 | ||
b0999223 TR |
739 | static int alx_alloc_napis(struct alx_priv *alx) |
740 | { | |
741 | struct alx_napi *np; | |
742 | struct alx_rx_queue *rxq; | |
743 | struct alx_tx_queue *txq; | |
a4076d34 | 744 | int i; |
b0999223 TR |
745 | |
746 | alx->int_mask &= ~ALX_ISR_ALL_QUEUES; | |
b0999223 TR |
747 | |
748 | /* allocate alx_napi structures */ | |
a4076d34 TR |
749 | for (i = 0; i < alx->num_napi; i++) { |
750 | np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL); | |
751 | if (!np) | |
752 | goto err_out; | |
b0999223 | 753 | |
a4076d34 TR |
754 | np->alx = alx; |
755 | netif_napi_add(alx->dev, &np->napi, alx_poll, 64); | |
756 | alx->qnapi[i] = np; | |
757 | } | |
b0999223 TR |
758 | |
759 | /* allocate tx queues */ | |
a4076d34 TR |
760 | for (i = 0; i < alx->num_txq; i++) { |
761 | np = alx->qnapi[i]; | |
762 | txq = kzalloc(sizeof(*txq), GFP_KERNEL); | |
763 | if (!txq) | |
764 | goto err_out; | |
765 | ||
766 | np->txq = txq; | |
2e06826b TR |
767 | txq->p_reg = tx_pidx_reg[i]; |
768 | txq->c_reg = tx_cidx_reg[i]; | |
a4076d34 TR |
769 | txq->queue_idx = i; |
770 | txq->count = alx->tx_ringsz; | |
771 | txq->netdev = alx->dev; | |
772 | txq->dev = &alx->hw.pdev->dev; | |
773 | np->vec_mask |= tx_vect_mask[i]; | |
774 | alx->int_mask |= tx_vect_mask[i]; | |
775 | } | |
b0999223 TR |
776 | |
777 | /* allocate rx queues */ | |
778 | np = alx->qnapi[0]; | |
779 | rxq = kzalloc(sizeof(*rxq), GFP_KERNEL); | |
780 | if (!rxq) | |
781 | goto err_out; | |
782 | ||
783 | np->rxq = rxq; | |
784 | rxq->np = alx->qnapi[0]; | |
e0eac254 | 785 | rxq->queue_idx = 0; |
b0999223 TR |
786 | rxq->count = alx->rx_ringsz; |
787 | rxq->netdev = alx->dev; | |
788 | rxq->dev = &alx->hw.pdev->dev; | |
e0eac254 TR |
789 | np->vec_mask |= rx_vect_mask[0]; |
790 | alx->int_mask |= rx_vect_mask[0]; | |
b0999223 TR |
791 | |
792 | return 0; | |
793 | ||
794 | err_out: | |
795 | netdev_err(alx->dev, "error allocating internal structures\n"); | |
796 | alx_free_napis(alx); | |
797 | return -ENOMEM; | |
ab69bde6 JB |
798 | } |
799 | ||
e0eac254 TR |
800 | static const int txq_vec_mapping_shift[] = { |
801 | 0, ALX_MSI_MAP_TBL1_TXQ0_SHIFT, | |
802 | 0, ALX_MSI_MAP_TBL1_TXQ1_SHIFT, | |
803 | 1, ALX_MSI_MAP_TBL2_TXQ2_SHIFT, | |
804 | 1, ALX_MSI_MAP_TBL2_TXQ3_SHIFT, | |
805 | }; | |
806 | ||
ab69bde6 JB |
807 | static void alx_config_vector_mapping(struct alx_priv *alx) |
808 | { | |
809 | struct alx_hw *hw = &alx->hw; | |
e0eac254 TR |
810 | u32 tbl[2] = {0, 0}; |
811 | int i, vector, idx, shift; | |
dc39a78b | 812 | |
f3297f68 | 813 | if (alx->hw.pdev->msix_enabled) { |
e0eac254 TR |
814 | /* tx mappings */ |
815 | for (i = 0, vector = 1; i < alx->num_txq; i++, vector++) { | |
816 | idx = txq_vec_mapping_shift[i * 2]; | |
817 | shift = txq_vec_mapping_shift[i * 2 + 1]; | |
818 | tbl[idx] |= vector << shift; | |
819 | } | |
820 | ||
821 | /* rx mapping */ | |
822 | tbl[0] |= 1 << ALX_MSI_MAP_TBL1_RXQ0_SHIFT; | |
dc39a78b | 823 | } |
ab69bde6 | 824 | |
e0eac254 TR |
825 | alx_write_mem32(hw, ALX_MSI_MAP_TBL1, tbl[0]); |
826 | alx_write_mem32(hw, ALX_MSI_MAP_TBL2, tbl[1]); | |
ab69bde6 JB |
827 | alx_write_mem32(hw, ALX_MSI_ID_MAP, 0); |
828 | } | |
829 | ||
f3297f68 | 830 | static int alx_enable_msix(struct alx_priv *alx) |
dc39a78b | 831 | { |
f3297f68 | 832 | int err, num_vec, num_txq, num_rxq; |
e0eac254 | 833 | |
d768319c | 834 | num_txq = min_t(int, num_online_cpus(), ALX_MAX_TX_QUEUES); |
e0eac254 TR |
835 | num_rxq = 1; |
836 | num_vec = max_t(int, num_txq, num_rxq) + 1; | |
dc39a78b | 837 | |
f3297f68 CH |
838 | err = pci_alloc_irq_vectors(alx->hw.pdev, num_vec, num_vec, |
839 | PCI_IRQ_MSIX); | |
2c041afc | 840 | if (err < 0) { |
dc39a78b | 841 | netdev_warn(alx->dev, "Enabling MSI-X interrupts failed!\n"); |
f3297f68 | 842 | return err; |
dc39a78b TR |
843 | } |
844 | ||
845 | alx->num_vec = num_vec; | |
e0eac254 TR |
846 | alx->num_napi = num_vec - 1; |
847 | alx->num_txq = num_txq; | |
848 | alx->num_rxq = num_rxq; | |
849 | ||
f3297f68 | 850 | return err; |
dc39a78b TR |
851 | } |
852 | ||
853 | static int alx_request_msix(struct alx_priv *alx) | |
854 | { | |
855 | struct net_device *netdev = alx->dev; | |
856 | int i, err, vector = 0, free_vector = 0; | |
857 | ||
f3297f68 | 858 | err = request_irq(pci_irq_vector(alx->hw.pdev, 0), alx_intr_msix_misc, |
dc39a78b TR |
859 | 0, netdev->name, alx); |
860 | if (err) | |
861 | goto out_err; | |
862 | ||
e0eac254 TR |
863 | for (i = 0; i < alx->num_napi; i++) { |
864 | struct alx_napi *np = alx->qnapi[i]; | |
865 | ||
866 | vector++; | |
867 | ||
868 | if (np->txq && np->rxq) | |
869 | sprintf(np->irq_lbl, "%s-TxRx-%u", netdev->name, | |
870 | np->txq->queue_idx); | |
871 | else if (np->txq) | |
872 | sprintf(np->irq_lbl, "%s-tx-%u", netdev->name, | |
873 | np->txq->queue_idx); | |
874 | else if (np->rxq) | |
875 | sprintf(np->irq_lbl, "%s-rx-%u", netdev->name, | |
876 | np->rxq->queue_idx); | |
877 | else | |
878 | sprintf(np->irq_lbl, "%s-unused", netdev->name); | |
879 | ||
880 | np->vec_idx = vector; | |
f3297f68 | 881 | err = request_irq(pci_irq_vector(alx->hw.pdev, vector), |
e0eac254 | 882 | alx_intr_msix_ring, 0, np->irq_lbl, np); |
dc39a78b TR |
883 | if (err) |
884 | goto out_free; | |
e0eac254 | 885 | } |
dc39a78b TR |
886 | return 0; |
887 | ||
888 | out_free: | |
f3297f68 | 889 | free_irq(pci_irq_vector(alx->hw.pdev, free_vector++), alx); |
dc39a78b TR |
890 | |
891 | vector--; | |
892 | for (i = 0; i < vector; i++) | |
f3297f68 | 893 | free_irq(pci_irq_vector(alx->hw.pdev,free_vector++), |
e0eac254 | 894 | alx->qnapi[i]); |
dc39a78b TR |
895 | |
896 | out_err: | |
897 | return err; | |
898 | } | |
899 | ||
f3297f68 | 900 | static int alx_init_intr(struct alx_priv *alx) |
9ee7b683 | 901 | { |
f3297f68 | 902 | int ret; |
dc39a78b | 903 | |
f3297f68 CH |
904 | ret = pci_alloc_irq_vectors(alx->hw.pdev, 1, 1, |
905 | PCI_IRQ_MSI | PCI_IRQ_LEGACY); | |
2c041afc | 906 | if (ret < 0) |
f3297f68 | 907 | return ret; |
dc39a78b | 908 | |
f3297f68 CH |
909 | alx->num_vec = 1; |
910 | alx->num_napi = 1; | |
911 | alx->num_txq = 1; | |
912 | alx->num_rxq = 1; | |
913 | return 0; | |
9ee7b683 TR |
914 | } |
915 | ||
ab69bde6 JB |
916 | static void alx_irq_enable(struct alx_priv *alx) |
917 | { | |
918 | struct alx_hw *hw = &alx->hw; | |
dc39a78b | 919 | int i; |
ab69bde6 JB |
920 | |
921 | /* level-1 interrupt switch */ | |
922 | alx_write_mem32(hw, ALX_ISR, 0); | |
923 | alx_write_mem32(hw, ALX_IMR, alx->int_mask); | |
924 | alx_post_write(hw); | |
dc39a78b | 925 | |
f3297f68 | 926 | if (alx->hw.pdev->msix_enabled) { |
dc39a78b TR |
927 | /* enable all msix irqs */ |
928 | for (i = 0; i < alx->num_vec; i++) | |
929 | alx_mask_msix(hw, i, false); | |
f3297f68 | 930 | } |
ab69bde6 JB |
931 | } |
932 | ||
933 | static void alx_irq_disable(struct alx_priv *alx) | |
934 | { | |
935 | struct alx_hw *hw = &alx->hw; | |
dc39a78b | 936 | int i; |
ab69bde6 JB |
937 | |
938 | alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS); | |
939 | alx_write_mem32(hw, ALX_IMR, 0); | |
940 | alx_post_write(hw); | |
941 | ||
f3297f68 | 942 | if (alx->hw.pdev->msix_enabled) { |
dc39a78b TR |
943 | for (i = 0; i < alx->num_vec; i++) { |
944 | alx_mask_msix(hw, i, true); | |
f3297f68 | 945 | synchronize_irq(pci_irq_vector(alx->hw.pdev, i)); |
dc39a78b TR |
946 | } |
947 | } else { | |
f3297f68 | 948 | synchronize_irq(pci_irq_vector(alx->hw.pdev, 0)); |
dc39a78b | 949 | } |
ab69bde6 JB |
950 | } |
951 | ||
e0eac254 TR |
952 | static int alx_realloc_resources(struct alx_priv *alx) |
953 | { | |
954 | int err; | |
955 | ||
956 | alx_free_rings(alx); | |
957 | alx_free_napis(alx); | |
f3297f68 CH |
958 | pci_free_irq_vectors(alx->hw.pdev); |
959 | ||
960 | err = alx_init_intr(alx); | |
961 | if (err) | |
962 | return err; | |
e0eac254 TR |
963 | |
964 | err = alx_alloc_napis(alx); | |
965 | if (err) | |
966 | return err; | |
967 | ||
968 | err = alx_alloc_rings(alx); | |
969 | if (err) | |
970 | return err; | |
971 | ||
972 | return 0; | |
973 | } | |
974 | ||
ab69bde6 JB |
975 | static int alx_request_irq(struct alx_priv *alx) |
976 | { | |
977 | struct pci_dev *pdev = alx->hw.pdev; | |
978 | struct alx_hw *hw = &alx->hw; | |
979 | int err; | |
980 | u32 msi_ctrl; | |
981 | ||
982 | msi_ctrl = (hw->imt >> 1) << ALX_MSI_RETRANS_TM_SHIFT; | |
983 | ||
f3297f68 | 984 | if (alx->hw.pdev->msix_enabled) { |
dc39a78b TR |
985 | alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, msi_ctrl); |
986 | err = alx_request_msix(alx); | |
987 | if (!err) | |
988 | goto out; | |
989 | ||
990 | /* msix request failed, realloc resources */ | |
e0eac254 TR |
991 | err = alx_realloc_resources(alx); |
992 | if (err) | |
993 | goto out; | |
dc39a78b TR |
994 | } |
995 | ||
f3297f68 | 996 | if (alx->hw.pdev->msi_enabled) { |
ab69bde6 JB |
997 | alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, |
998 | msi_ctrl | ALX_MSI_MASK_SEL_LINE); | |
f3297f68 | 999 | err = request_irq(pci_irq_vector(pdev, 0), alx_intr_msi, 0, |
ab69bde6 JB |
1000 | alx->dev->name, alx); |
1001 | if (!err) | |
1002 | goto out; | |
f3297f68 | 1003 | |
ab69bde6 | 1004 | /* fall back to legacy interrupt */ |
f3297f68 | 1005 | pci_free_irq_vectors(alx->hw.pdev); |
ab69bde6 JB |
1006 | } |
1007 | ||
1008 | alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, 0); | |
f3297f68 | 1009 | err = request_irq(pci_irq_vector(pdev, 0), alx_intr_legacy, IRQF_SHARED, |
ab69bde6 JB |
1010 | alx->dev->name, alx); |
1011 | out: | |
1012 | if (!err) | |
1013 | alx_config_vector_mapping(alx); | |
dc39a78b TR |
1014 | else |
1015 | netdev_err(alx->dev, "IRQ registration failed!\n"); | |
ab69bde6 JB |
1016 | return err; |
1017 | } | |
1018 | ||
1019 | static void alx_free_irq(struct alx_priv *alx) | |
1020 | { | |
1021 | struct pci_dev *pdev = alx->hw.pdev; | |
f3297f68 | 1022 | int i; |
ab69bde6 | 1023 | |
f3297f68 CH |
1024 | free_irq(pci_irq_vector(pdev, 0), alx); |
1025 | if (alx->hw.pdev->msix_enabled) { | |
e0eac254 | 1026 | for (i = 0; i < alx->num_napi; i++) |
f3297f68 | 1027 | free_irq(pci_irq_vector(pdev, i + 1), alx->qnapi[i]); |
dc39a78b | 1028 | } |
ab69bde6 | 1029 | |
f3297f68 | 1030 | pci_free_irq_vectors(pdev); |
ab69bde6 JB |
1031 | } |
1032 | ||
1033 | static int alx_identify_hw(struct alx_priv *alx) | |
1034 | { | |
1035 | struct alx_hw *hw = &alx->hw; | |
1036 | int rev = alx_hw_revision(hw); | |
1037 | ||
1038 | if (rev > ALX_REV_C0) | |
1039 | return -EINVAL; | |
1040 | ||
1041 | hw->max_dma_chnl = rev >= ALX_REV_B0 ? 4 : 2; | |
1042 | ||
1043 | return 0; | |
1044 | } | |
1045 | ||
1046 | static int alx_init_sw(struct alx_priv *alx) | |
1047 | { | |
1048 | struct pci_dev *pdev = alx->hw.pdev; | |
1049 | struct alx_hw *hw = &alx->hw; | |
1050 | int err; | |
1051 | ||
1052 | err = alx_identify_hw(alx); | |
1053 | if (err) { | |
1054 | dev_err(&pdev->dev, "unrecognized chip, aborting\n"); | |
1055 | return err; | |
1056 | } | |
1057 | ||
1058 | alx->hw.lnk_patch = | |
1059 | pdev->device == ALX_DEV_ID_AR8161 && | |
1060 | pdev->subsystem_vendor == PCI_VENDOR_ID_ATTANSIC && | |
1061 | pdev->subsystem_device == 0x0091 && | |
1062 | pdev->revision == 0; | |
1063 | ||
1064 | hw->smb_timer = 400; | |
1065 | hw->mtu = alx->dev->mtu; | |
c406700c | 1066 | alx->rxbuf_size = ALX_MAX_FRAME_LEN(hw->mtu); |
67bef942 JW |
1067 | /* MTU range: 34 - 9256 */ |
1068 | alx->dev->min_mtu = 34; | |
1069 | alx->dev->max_mtu = ALX_MAX_FRAME_LEN(ALX_MAX_FRAME_SIZE); | |
ab69bde6 JB |
1070 | alx->tx_ringsz = 256; |
1071 | alx->rx_ringsz = 512; | |
ab69bde6 JB |
1072 | hw->imt = 200; |
1073 | alx->int_mask = ALX_ISR_MISC; | |
1074 | hw->dma_chnl = hw->max_dma_chnl; | |
1075 | hw->ith_tpd = alx->tx_ringsz / 3; | |
1076 | hw->link_speed = SPEED_UNKNOWN; | |
a5b87cc9 | 1077 | hw->duplex = DUPLEX_UNKNOWN; |
ab69bde6 JB |
1078 | hw->adv_cfg = ADVERTISED_Autoneg | |
1079 | ADVERTISED_10baseT_Half | | |
1080 | ADVERTISED_10baseT_Full | | |
1081 | ADVERTISED_100baseT_Full | | |
1082 | ADVERTISED_100baseT_Half | | |
1083 | ADVERTISED_1000baseT_Full; | |
1084 | hw->flowctrl = ALX_FC_ANEG | ALX_FC_RX | ALX_FC_TX; | |
1085 | ||
1086 | hw->rx_ctrl = ALX_MAC_CTRL_WOLSPED_SWEN | | |
1087 | ALX_MAC_CTRL_MHASH_ALG_HI5B | | |
1088 | ALX_MAC_CTRL_BRD_EN | | |
1089 | ALX_MAC_CTRL_PCRCE | | |
1090 | ALX_MAC_CTRL_CRCE | | |
1091 | ALX_MAC_CTRL_RXFC_EN | | |
1092 | ALX_MAC_CTRL_TXFC_EN | | |
1093 | 7 << ALX_MAC_CTRL_PRMBLEN_SHIFT; | |
1094 | ||
1095 | return err; | |
1096 | } | |
1097 | ||
1098 | ||
1099 | static netdev_features_t alx_fix_features(struct net_device *netdev, | |
1100 | netdev_features_t features) | |
1101 | { | |
1102 | if (netdev->mtu > ALX_MAX_TSO_PKT_SIZE) | |
1103 | features &= ~(NETIF_F_TSO | NETIF_F_TSO6); | |
1104 | ||
1105 | return features; | |
1106 | } | |
1107 | ||
1108 | static void alx_netif_stop(struct alx_priv *alx) | |
1109 | { | |
a4076d34 TR |
1110 | int i; |
1111 | ||
860e9538 | 1112 | netif_trans_update(alx->dev); |
ab69bde6 JB |
1113 | if (netif_carrier_ok(alx->dev)) { |
1114 | netif_carrier_off(alx->dev); | |
1115 | netif_tx_disable(alx->dev); | |
a4076d34 TR |
1116 | for (i = 0; i < alx->num_napi; i++) |
1117 | napi_disable(&alx->qnapi[i]->napi); | |
ab69bde6 JB |
1118 | } |
1119 | } | |
1120 | ||
1121 | static void alx_halt(struct alx_priv *alx) | |
1122 | { | |
1123 | struct alx_hw *hw = &alx->hw; | |
1124 | ||
1125 | alx_netif_stop(alx); | |
1126 | hw->link_speed = SPEED_UNKNOWN; | |
a5b87cc9 | 1127 | hw->duplex = DUPLEX_UNKNOWN; |
ab69bde6 JB |
1128 | |
1129 | alx_reset_mac(hw); | |
1130 | ||
1131 | /* disable l0s/l1 */ | |
1132 | alx_enable_aspm(hw, false, false); | |
1133 | alx_irq_disable(alx); | |
1134 | alx_free_buffers(alx); | |
1135 | } | |
1136 | ||
1137 | static void alx_configure(struct alx_priv *alx) | |
1138 | { | |
1139 | struct alx_hw *hw = &alx->hw; | |
1140 | ||
1141 | alx_configure_basic(hw); | |
1142 | alx_disable_rss(hw); | |
1143 | __alx_set_rx_mode(alx->dev); | |
1144 | ||
1145 | alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); | |
1146 | } | |
1147 | ||
1148 | static void alx_activate(struct alx_priv *alx) | |
1149 | { | |
1150 | /* hardware setting lost, restore it */ | |
1151 | alx_reinit_rings(alx); | |
1152 | alx_configure(alx); | |
1153 | ||
1154 | /* clear old interrupts */ | |
1155 | alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS); | |
1156 | ||
1157 | alx_irq_enable(alx); | |
1158 | ||
1159 | alx_schedule_link_check(alx); | |
1160 | } | |
1161 | ||
1162 | static void alx_reinit(struct alx_priv *alx) | |
1163 | { | |
1164 | ASSERT_RTNL(); | |
1165 | ||
1166 | alx_halt(alx); | |
1167 | alx_activate(alx); | |
1168 | } | |
1169 | ||
1170 | static int alx_change_mtu(struct net_device *netdev, int mtu) | |
1171 | { | |
1172 | struct alx_priv *alx = netdev_priv(netdev); | |
c406700c | 1173 | int max_frame = ALX_MAX_FRAME_LEN(mtu); |
ab69bde6 | 1174 | |
ab69bde6 JB |
1175 | netdev->mtu = mtu; |
1176 | alx->hw.mtu = mtu; | |
c406700c | 1177 | alx->rxbuf_size = max(max_frame, ALX_DEF_RXBUF_SIZE); |
ab69bde6 JB |
1178 | netdev_update_features(netdev); |
1179 | if (netif_running(netdev)) | |
1180 | alx_reinit(alx); | |
1181 | return 0; | |
1182 | } | |
1183 | ||
1184 | static void alx_netif_start(struct alx_priv *alx) | |
1185 | { | |
a4076d34 TR |
1186 | int i; |
1187 | ||
ab69bde6 | 1188 | netif_tx_wake_all_queues(alx->dev); |
a4076d34 TR |
1189 | for (i = 0; i < alx->num_napi; i++) |
1190 | napi_enable(&alx->qnapi[i]->napi); | |
ab69bde6 JB |
1191 | netif_carrier_on(alx->dev); |
1192 | } | |
1193 | ||
1194 | static int __alx_open(struct alx_priv *alx, bool resume) | |
1195 | { | |
1196 | int err; | |
1197 | ||
f3297f68 CH |
1198 | err = alx_enable_msix(alx); |
1199 | if (err < 0) { | |
1200 | err = alx_init_intr(alx); | |
1201 | if (err) | |
1202 | return err; | |
1203 | } | |
9ee7b683 | 1204 | |
ab69bde6 JB |
1205 | if (!resume) |
1206 | netif_carrier_off(alx->dev); | |
1207 | ||
b0999223 | 1208 | err = alx_alloc_napis(alx); |
ab69bde6 | 1209 | if (err) |
0ca4e20b | 1210 | goto out_disable_adv_intr; |
ab69bde6 | 1211 | |
b0999223 TR |
1212 | err = alx_alloc_rings(alx); |
1213 | if (err) | |
1214 | goto out_free_rings; | |
1215 | ||
ab69bde6 JB |
1216 | alx_configure(alx); |
1217 | ||
1218 | err = alx_request_irq(alx); | |
1219 | if (err) | |
1220 | goto out_free_rings; | |
1221 | ||
185aceef TR |
1222 | /* must be called after alx_request_irq because the chip stops working |
1223 | * if we copy the dma addresses in alx_init_ring_ptrs twice when | |
1224 | * requesting msi-x interrupts failed | |
1225 | */ | |
1226 | alx_reinit_rings(alx); | |
1227 | ||
d768319c TR |
1228 | netif_set_real_num_tx_queues(alx->dev, alx->num_txq); |
1229 | netif_set_real_num_rx_queues(alx->dev, alx->num_rxq); | |
1230 | ||
ab69bde6 JB |
1231 | /* clear old interrupts */ |
1232 | alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS); | |
1233 | ||
1234 | alx_irq_enable(alx); | |
1235 | ||
1236 | if (!resume) | |
1237 | netif_tx_start_all_queues(alx->dev); | |
1238 | ||
1239 | alx_schedule_link_check(alx); | |
1240 | return 0; | |
1241 | ||
1242 | out_free_rings: | |
1243 | alx_free_rings(alx); | |
b0999223 | 1244 | alx_free_napis(alx); |
0ca4e20b | 1245 | out_disable_adv_intr: |
f3297f68 | 1246 | pci_free_irq_vectors(alx->hw.pdev); |
ab69bde6 JB |
1247 | return err; |
1248 | } | |
1249 | ||
1250 | static void __alx_stop(struct alx_priv *alx) | |
1251 | { | |
1252 | alx_halt(alx); | |
1253 | alx_free_irq(alx); | |
1254 | alx_free_rings(alx); | |
b0999223 | 1255 | alx_free_napis(alx); |
ab69bde6 JB |
1256 | } |
1257 | ||
a5b87cc9 | 1258 | static const char *alx_speed_desc(struct alx_hw *hw) |
ab69bde6 | 1259 | { |
a5b87cc9 JB |
1260 | switch (alx_speed_to_ethadv(hw->link_speed, hw->duplex)) { |
1261 | case ADVERTISED_1000baseT_Full: | |
ab69bde6 | 1262 | return "1 Gbps Full"; |
a5b87cc9 | 1263 | case ADVERTISED_100baseT_Full: |
ab69bde6 | 1264 | return "100 Mbps Full"; |
a5b87cc9 | 1265 | case ADVERTISED_100baseT_Half: |
ab69bde6 | 1266 | return "100 Mbps Half"; |
a5b87cc9 | 1267 | case ADVERTISED_10baseT_Full: |
ab69bde6 | 1268 | return "10 Mbps Full"; |
a5b87cc9 | 1269 | case ADVERTISED_10baseT_Half: |
ab69bde6 JB |
1270 | return "10 Mbps Half"; |
1271 | default: | |
1272 | return "Unknown speed"; | |
1273 | } | |
1274 | } | |
1275 | ||
1276 | static void alx_check_link(struct alx_priv *alx) | |
1277 | { | |
1278 | struct alx_hw *hw = &alx->hw; | |
1279 | unsigned long flags; | |
a5b87cc9 | 1280 | int old_speed; |
ab69bde6 JB |
1281 | int err; |
1282 | ||
1283 | /* clear PHY internal interrupt status, otherwise the main | |
1284 | * interrupt status will be asserted forever | |
1285 | */ | |
1286 | alx_clear_phy_intr(hw); | |
1287 | ||
a5b87cc9 | 1288 | old_speed = hw->link_speed; |
a5b87cc9 | 1289 | err = alx_read_phy_link(hw); |
ab69bde6 JB |
1290 | if (err < 0) |
1291 | goto reset; | |
1292 | ||
1293 | spin_lock_irqsave(&alx->irq_lock, flags); | |
1294 | alx->int_mask |= ALX_ISR_PHY; | |
1295 | alx_write_mem32(hw, ALX_IMR, alx->int_mask); | |
1296 | spin_unlock_irqrestore(&alx->irq_lock, flags); | |
1297 | ||
a5b87cc9 | 1298 | if (old_speed == hw->link_speed) |
ab69bde6 | 1299 | return; |
ab69bde6 | 1300 | |
a5b87cc9 | 1301 | if (hw->link_speed != SPEED_UNKNOWN) { |
ab69bde6 | 1302 | netif_info(alx, link, alx->dev, |
a5b87cc9 | 1303 | "NIC Up: %s\n", alx_speed_desc(hw)); |
ab69bde6 JB |
1304 | alx_post_phy_link(hw); |
1305 | alx_enable_aspm(hw, true, true); | |
1306 | alx_start_mac(hw); | |
1307 | ||
1308 | if (old_speed == SPEED_UNKNOWN) | |
1309 | alx_netif_start(alx); | |
1310 | } else { | |
1311 | /* link is now down */ | |
1312 | alx_netif_stop(alx); | |
1313 | netif_info(alx, link, alx->dev, "Link Down\n"); | |
1314 | err = alx_reset_mac(hw); | |
1315 | if (err) | |
1316 | goto reset; | |
1317 | alx_irq_disable(alx); | |
1318 | ||
1319 | /* MAC reset causes all HW settings to be lost, restore all */ | |
1320 | err = alx_reinit_rings(alx); | |
1321 | if (err) | |
1322 | goto reset; | |
1323 | alx_configure(alx); | |
1324 | alx_enable_aspm(hw, false, true); | |
1325 | alx_post_phy_link(hw); | |
1326 | alx_irq_enable(alx); | |
1327 | } | |
1328 | ||
1329 | return; | |
1330 | ||
1331 | reset: | |
1332 | alx_schedule_reset(alx); | |
1333 | } | |
1334 | ||
1335 | static int alx_open(struct net_device *netdev) | |
1336 | { | |
1337 | return __alx_open(netdev_priv(netdev), false); | |
1338 | } | |
1339 | ||
1340 | static int alx_stop(struct net_device *netdev) | |
1341 | { | |
1342 | __alx_stop(netdev_priv(netdev)); | |
1343 | return 0; | |
1344 | } | |
1345 | ||
ab69bde6 JB |
1346 | static void alx_link_check(struct work_struct *work) |
1347 | { | |
1348 | struct alx_priv *alx; | |
1349 | ||
1350 | alx = container_of(work, struct alx_priv, link_check_wk); | |
1351 | ||
1352 | rtnl_lock(); | |
1353 | alx_check_link(alx); | |
1354 | rtnl_unlock(); | |
1355 | } | |
1356 | ||
1357 | static void alx_reset(struct work_struct *work) | |
1358 | { | |
1359 | struct alx_priv *alx = container_of(work, struct alx_priv, reset_wk); | |
1360 | ||
1361 | rtnl_lock(); | |
1362 | alx_reinit(alx); | |
1363 | rtnl_unlock(); | |
1364 | } | |
1365 | ||
ab725983 TR |
1366 | static int alx_tpd_req(struct sk_buff *skb) |
1367 | { | |
1368 | int num; | |
1369 | ||
1370 | num = skb_shinfo(skb)->nr_frags + 1; | |
1371 | /* we need one extra descriptor for LSOv2 */ | |
1372 | if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) | |
1373 | num++; | |
1374 | ||
1375 | return num; | |
1376 | } | |
1377 | ||
ab69bde6 JB |
1378 | static int alx_tx_csum(struct sk_buff *skb, struct alx_txd *first) |
1379 | { | |
1380 | u8 cso, css; | |
1381 | ||
1382 | if (skb->ip_summed != CHECKSUM_PARTIAL) | |
1383 | return 0; | |
1384 | ||
1385 | cso = skb_checksum_start_offset(skb); | |
1386 | if (cso & 1) | |
1387 | return -EINVAL; | |
1388 | ||
1389 | css = cso + skb->csum_offset; | |
1390 | first->word1 |= cpu_to_le32((cso >> 1) << TPD_CXSUMSTART_SHIFT); | |
1391 | first->word1 |= cpu_to_le32((css >> 1) << TPD_CXSUMOFFSET_SHIFT); | |
1392 | first->word1 |= cpu_to_le32(1 << TPD_CXSUM_EN_SHIFT); | |
1393 | ||
1394 | return 0; | |
1395 | } | |
1396 | ||
ab725983 TR |
1397 | static int alx_tso(struct sk_buff *skb, struct alx_txd *first) |
1398 | { | |
1399 | int err; | |
1400 | ||
1401 | if (skb->ip_summed != CHECKSUM_PARTIAL) | |
1402 | return 0; | |
1403 | ||
1404 | if (!skb_is_gso(skb)) | |
1405 | return 0; | |
1406 | ||
1407 | err = skb_cow_head(skb, 0); | |
1408 | if (err < 0) | |
1409 | return err; | |
1410 | ||
1411 | if (skb->protocol == htons(ETH_P_IP)) { | |
1412 | struct iphdr *iph = ip_hdr(skb); | |
1413 | ||
1414 | iph->check = 0; | |
1415 | tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | |
1416 | 0, IPPROTO_TCP, 0); | |
1417 | first->word1 |= 1 << TPD_IPV4_SHIFT; | |
1418 | } else if (skb_is_gso_v6(skb)) { | |
1419 | ipv6_hdr(skb)->payload_len = 0; | |
1420 | tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | |
1421 | &ipv6_hdr(skb)->daddr, | |
1422 | 0, IPPROTO_TCP, 0); | |
1423 | /* LSOv2: the first TPD only provides the packet length */ | |
1424 | first->adrl.l.pkt_len = skb->len; | |
1425 | first->word1 |= 1 << TPD_LSO_V2_SHIFT; | |
1426 | } | |
1427 | ||
1428 | first->word1 |= 1 << TPD_LSO_EN_SHIFT; | |
1429 | first->word1 |= (skb_transport_offset(skb) & | |
1430 | TPD_L4HDROFFSET_MASK) << TPD_L4HDROFFSET_SHIFT; | |
1431 | first->word1 |= (skb_shinfo(skb)->gso_size & | |
1432 | TPD_MSS_MASK) << TPD_MSS_SHIFT; | |
1433 | return 1; | |
1434 | } | |
1435 | ||
702e8418 | 1436 | static int alx_map_tx_skb(struct alx_tx_queue *txq, struct sk_buff *skb) |
ab69bde6 | 1437 | { |
ab69bde6 JB |
1438 | struct alx_txd *tpd, *first_tpd; |
1439 | dma_addr_t dma; | |
1440 | int maplen, f, first_idx = txq->write_idx; | |
1441 | ||
1442 | first_tpd = &txq->tpd[txq->write_idx]; | |
1443 | tpd = first_tpd; | |
1444 | ||
ab725983 | 1445 | if (tpd->word1 & (1 << TPD_LSO_V2_SHIFT)) { |
702e8418 | 1446 | if (++txq->write_idx == txq->count) |
ab725983 TR |
1447 | txq->write_idx = 0; |
1448 | ||
1449 | tpd = &txq->tpd[txq->write_idx]; | |
1450 | tpd->len = first_tpd->len; | |
1451 | tpd->vlan_tag = first_tpd->vlan_tag; | |
1452 | tpd->word1 = first_tpd->word1; | |
1453 | } | |
1454 | ||
ab69bde6 | 1455 | maplen = skb_headlen(skb); |
702e8418 | 1456 | dma = dma_map_single(txq->dev, skb->data, maplen, |
ab69bde6 | 1457 | DMA_TO_DEVICE); |
702e8418 | 1458 | if (dma_mapping_error(txq->dev, dma)) |
ab69bde6 JB |
1459 | goto err_dma; |
1460 | ||
1461 | dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen); | |
1462 | dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma); | |
1463 | ||
1464 | tpd->adrl.addr = cpu_to_le64(dma); | |
1465 | tpd->len = cpu_to_le16(maplen); | |
1466 | ||
1467 | for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { | |
1468 | struct skb_frag_struct *frag; | |
1469 | ||
1470 | frag = &skb_shinfo(skb)->frags[f]; | |
1471 | ||
702e8418 | 1472 | if (++txq->write_idx == txq->count) |
ab69bde6 JB |
1473 | txq->write_idx = 0; |
1474 | tpd = &txq->tpd[txq->write_idx]; | |
1475 | ||
1476 | tpd->word1 = first_tpd->word1; | |
1477 | ||
1478 | maplen = skb_frag_size(frag); | |
702e8418 | 1479 | dma = skb_frag_dma_map(txq->dev, frag, 0, |
ab69bde6 | 1480 | maplen, DMA_TO_DEVICE); |
702e8418 | 1481 | if (dma_mapping_error(txq->dev, dma)) |
ab69bde6 JB |
1482 | goto err_dma; |
1483 | dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen); | |
1484 | dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma); | |
1485 | ||
1486 | tpd->adrl.addr = cpu_to_le64(dma); | |
1487 | tpd->len = cpu_to_le16(maplen); | |
1488 | } | |
1489 | ||
1490 | /* last TPD, set EOP flag and store skb */ | |
1491 | tpd->word1 |= cpu_to_le32(1 << TPD_EOP_SHIFT); | |
1492 | txq->bufs[txq->write_idx].skb = skb; | |
1493 | ||
702e8418 | 1494 | if (++txq->write_idx == txq->count) |
ab69bde6 JB |
1495 | txq->write_idx = 0; |
1496 | ||
1497 | return 0; | |
1498 | ||
1499 | err_dma: | |
1500 | f = first_idx; | |
1501 | while (f != txq->write_idx) { | |
702e8418 TR |
1502 | alx_free_txbuf(txq, f); |
1503 | if (++f == txq->count) | |
ab69bde6 JB |
1504 | f = 0; |
1505 | } | |
1506 | return -ENOMEM; | |
1507 | } | |
1508 | ||
2e06826b TR |
1509 | static netdev_tx_t alx_start_xmit_ring(struct sk_buff *skb, |
1510 | struct alx_tx_queue *txq) | |
ab69bde6 | 1511 | { |
2e06826b | 1512 | struct alx_priv *alx; |
ab69bde6 | 1513 | struct alx_txd *first; |
ab725983 | 1514 | int tso; |
ab69bde6 | 1515 | |
2e06826b TR |
1516 | alx = netdev_priv(txq->netdev); |
1517 | ||
702e8418 | 1518 | if (alx_tpd_avail(txq) < alx_tpd_req(skb)) { |
2e06826b | 1519 | netif_tx_stop_queue(alx_get_tx_queue(txq)); |
ab69bde6 JB |
1520 | goto drop; |
1521 | } | |
1522 | ||
1523 | first = &txq->tpd[txq->write_idx]; | |
1524 | memset(first, 0, sizeof(*first)); | |
1525 | ||
ab725983 TR |
1526 | tso = alx_tso(skb, first); |
1527 | if (tso < 0) | |
1528 | goto drop; | |
1529 | else if (!tso && alx_tx_csum(skb, first)) | |
ab69bde6 JB |
1530 | goto drop; |
1531 | ||
702e8418 | 1532 | if (alx_map_tx_skb(txq, skb) < 0) |
ab69bde6 JB |
1533 | goto drop; |
1534 | ||
2e06826b | 1535 | netdev_tx_sent_queue(alx_get_tx_queue(txq), skb->len); |
ab69bde6 JB |
1536 | |
1537 | /* flush updates before updating hardware */ | |
1538 | wmb(); | |
2e06826b | 1539 | alx_write_mem16(&alx->hw, txq->p_reg, txq->write_idx); |
ab69bde6 | 1540 | |
702e8418 | 1541 | if (alx_tpd_avail(txq) < txq->count / 8) |
2e06826b | 1542 | netif_tx_stop_queue(alx_get_tx_queue(txq)); |
ab69bde6 JB |
1543 | |
1544 | return NETDEV_TX_OK; | |
1545 | ||
1546 | drop: | |
548ff1ed | 1547 | dev_kfree_skb_any(skb); |
ab69bde6 JB |
1548 | return NETDEV_TX_OK; |
1549 | } | |
1550 | ||
2e06826b TR |
1551 | static netdev_tx_t alx_start_xmit(struct sk_buff *skb, |
1552 | struct net_device *netdev) | |
1553 | { | |
1554 | struct alx_priv *alx = netdev_priv(netdev); | |
1555 | return alx_start_xmit_ring(skb, alx_tx_queue_mapping(alx, skb)); | |
1556 | } | |
1557 | ||
ab69bde6 JB |
1558 | static void alx_tx_timeout(struct net_device *dev) |
1559 | { | |
1560 | struct alx_priv *alx = netdev_priv(dev); | |
1561 | ||
1562 | alx_schedule_reset(alx); | |
1563 | } | |
1564 | ||
1565 | static int alx_mdio_read(struct net_device *netdev, | |
1566 | int prtad, int devad, u16 addr) | |
1567 | { | |
1568 | struct alx_priv *alx = netdev_priv(netdev); | |
1569 | struct alx_hw *hw = &alx->hw; | |
1570 | u16 val; | |
1571 | int err; | |
1572 | ||
1573 | if (prtad != hw->mdio.prtad) | |
1574 | return -EINVAL; | |
1575 | ||
1576 | if (devad == MDIO_DEVAD_NONE) | |
1577 | err = alx_read_phy_reg(hw, addr, &val); | |
1578 | else | |
1579 | err = alx_read_phy_ext(hw, devad, addr, &val); | |
1580 | ||
1581 | if (err) | |
1582 | return err; | |
1583 | return val; | |
1584 | } | |
1585 | ||
1586 | static int alx_mdio_write(struct net_device *netdev, | |
1587 | int prtad, int devad, u16 addr, u16 val) | |
1588 | { | |
1589 | struct alx_priv *alx = netdev_priv(netdev); | |
1590 | struct alx_hw *hw = &alx->hw; | |
1591 | ||
1592 | if (prtad != hw->mdio.prtad) | |
1593 | return -EINVAL; | |
1594 | ||
1595 | if (devad == MDIO_DEVAD_NONE) | |
1596 | return alx_write_phy_reg(hw, addr, val); | |
1597 | ||
1598 | return alx_write_phy_ext(hw, devad, addr, val); | |
1599 | } | |
1600 | ||
1601 | static int alx_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) | |
1602 | { | |
1603 | struct alx_priv *alx = netdev_priv(netdev); | |
1604 | ||
1605 | if (!netif_running(netdev)) | |
1606 | return -EAGAIN; | |
1607 | ||
1608 | return mdio_mii_ioctl(&alx->hw.mdio, if_mii(ifr), cmd); | |
1609 | } | |
1610 | ||
1611 | #ifdef CONFIG_NET_POLL_CONTROLLER | |
1612 | static void alx_poll_controller(struct net_device *netdev) | |
1613 | { | |
1614 | struct alx_priv *alx = netdev_priv(netdev); | |
e0eac254 | 1615 | int i; |
ab69bde6 | 1616 | |
f3297f68 | 1617 | if (alx->hw.pdev->msix_enabled) { |
dc39a78b | 1618 | alx_intr_msix_misc(0, alx); |
e0eac254 TR |
1619 | for (i = 0; i < alx->num_txq; i++) |
1620 | alx_intr_msix_ring(0, alx->qnapi[i]); | |
f3297f68 | 1621 | } else if (alx->hw.pdev->msi_enabled) |
ab69bde6 JB |
1622 | alx_intr_msi(0, alx); |
1623 | else | |
1624 | alx_intr_legacy(0, alx); | |
1625 | } | |
1626 | #endif | |
1627 | ||
bc1f4470 | 1628 | static void alx_get_stats64(struct net_device *dev, |
1629 | struct rtnl_link_stats64 *net_stats) | |
f1b6b106 SD |
1630 | { |
1631 | struct alx_priv *alx = netdev_priv(dev); | |
1632 | struct alx_hw_stats *hw_stats = &alx->hw.stats; | |
1633 | ||
1634 | spin_lock(&alx->stats_lock); | |
1635 | ||
1636 | alx_update_hw_stats(&alx->hw); | |
1637 | ||
1638 | net_stats->tx_bytes = hw_stats->tx_byte_cnt; | |
1639 | net_stats->rx_bytes = hw_stats->rx_byte_cnt; | |
1640 | net_stats->multicast = hw_stats->rx_mcast; | |
1641 | net_stats->collisions = hw_stats->tx_single_col + | |
1642 | hw_stats->tx_multi_col + | |
1643 | hw_stats->tx_late_col + | |
1644 | hw_stats->tx_abort_col; | |
1645 | ||
1646 | net_stats->rx_errors = hw_stats->rx_frag + | |
1647 | hw_stats->rx_fcs_err + | |
1648 | hw_stats->rx_len_err + | |
1649 | hw_stats->rx_ov_sz + | |
1650 | hw_stats->rx_ov_rrd + | |
1651 | hw_stats->rx_align_err + | |
1652 | hw_stats->rx_ov_rxf; | |
1653 | ||
1654 | net_stats->rx_fifo_errors = hw_stats->rx_ov_rxf; | |
1655 | net_stats->rx_length_errors = hw_stats->rx_len_err; | |
1656 | net_stats->rx_crc_errors = hw_stats->rx_fcs_err; | |
1657 | net_stats->rx_frame_errors = hw_stats->rx_align_err; | |
1658 | net_stats->rx_dropped = hw_stats->rx_ov_rrd; | |
1659 | ||
1660 | net_stats->tx_errors = hw_stats->tx_late_col + | |
1661 | hw_stats->tx_abort_col + | |
1662 | hw_stats->tx_underrun + | |
1663 | hw_stats->tx_trunc; | |
1664 | ||
1665 | net_stats->tx_aborted_errors = hw_stats->tx_abort_col; | |
1666 | net_stats->tx_fifo_errors = hw_stats->tx_underrun; | |
1667 | net_stats->tx_window_errors = hw_stats->tx_late_col; | |
1668 | ||
1669 | net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors; | |
1670 | net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors; | |
1671 | ||
1672 | spin_unlock(&alx->stats_lock); | |
f1b6b106 SD |
1673 | } |
1674 | ||
ab69bde6 JB |
1675 | static const struct net_device_ops alx_netdev_ops = { |
1676 | .ndo_open = alx_open, | |
1677 | .ndo_stop = alx_stop, | |
1678 | .ndo_start_xmit = alx_start_xmit, | |
f1b6b106 | 1679 | .ndo_get_stats64 = alx_get_stats64, |
ab69bde6 JB |
1680 | .ndo_set_rx_mode = alx_set_rx_mode, |
1681 | .ndo_validate_addr = eth_validate_addr, | |
1682 | .ndo_set_mac_address = alx_set_mac_address, | |
1683 | .ndo_change_mtu = alx_change_mtu, | |
1684 | .ndo_do_ioctl = alx_ioctl, | |
1685 | .ndo_tx_timeout = alx_tx_timeout, | |
1686 | .ndo_fix_features = alx_fix_features, | |
1687 | #ifdef CONFIG_NET_POLL_CONTROLLER | |
1688 | .ndo_poll_controller = alx_poll_controller, | |
1689 | #endif | |
1690 | }; | |
1691 | ||
1692 | static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |
1693 | { | |
1694 | struct net_device *netdev; | |
1695 | struct alx_priv *alx; | |
1696 | struct alx_hw *hw; | |
1697 | bool phy_configured; | |
caa8e932 | 1698 | int err; |
ab69bde6 JB |
1699 | |
1700 | err = pci_enable_device_mem(pdev); | |
1701 | if (err) | |
1702 | return err; | |
1703 | ||
1704 | /* The alx chip can DMA to 64-bit addresses, but it uses a single | |
1705 | * shared register for the high 32 bits, so only a single, aligned, | |
1706 | * 4 GB physical address range can be used for descriptors. | |
1707 | */ | |
8d7f1fbf | 1708 | if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { |
ab69bde6 JB |
1709 | dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n"); |
1710 | } else { | |
8d7f1fbf | 1711 | err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); |
ab69bde6 | 1712 | if (err) { |
8d7f1fbf PST |
1713 | dev_err(&pdev->dev, "No usable DMA config, aborting\n"); |
1714 | goto out_pci_disable; | |
ab69bde6 JB |
1715 | } |
1716 | } | |
1717 | ||
caa8e932 | 1718 | err = pci_request_mem_regions(pdev, alx_drv_name); |
ab69bde6 JB |
1719 | if (err) { |
1720 | dev_err(&pdev->dev, | |
caa8e932 | 1721 | "pci_request_mem_regions failed\n"); |
ab69bde6 JB |
1722 | goto out_pci_disable; |
1723 | } | |
1724 | ||
1725 | pci_enable_pcie_error_reporting(pdev); | |
1726 | pci_set_master(pdev); | |
1727 | ||
c3eb7a77 | 1728 | if (!pdev->pm_cap) { |
ab69bde6 JB |
1729 | dev_err(&pdev->dev, |
1730 | "Can't find power management capability, aborting\n"); | |
1731 | err = -EIO; | |
1732 | goto out_pci_release; | |
1733 | } | |
1734 | ||
d768319c TR |
1735 | netdev = alloc_etherdev_mqs(sizeof(*alx), |
1736 | ALX_MAX_TX_QUEUES, 1); | |
ab69bde6 JB |
1737 | if (!netdev) { |
1738 | err = -ENOMEM; | |
1739 | goto out_pci_release; | |
1740 | } | |
1741 | ||
1742 | SET_NETDEV_DEV(netdev, &pdev->dev); | |
1743 | alx = netdev_priv(netdev); | |
a8798a5c ML |
1744 | spin_lock_init(&alx->hw.mdio_lock); |
1745 | spin_lock_init(&alx->irq_lock); | |
3e5ccc29 | 1746 | spin_lock_init(&alx->stats_lock); |
ab69bde6 JB |
1747 | alx->dev = netdev; |
1748 | alx->hw.pdev = pdev; | |
1749 | alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP | | |
1750 | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR | NETIF_MSG_WOL; | |
1751 | hw = &alx->hw; | |
1752 | pci_set_drvdata(pdev, alx); | |
1753 | ||
1754 | hw->hw_addr = pci_ioremap_bar(pdev, 0); | |
1755 | if (!hw->hw_addr) { | |
1756 | dev_err(&pdev->dev, "cannot map device registers\n"); | |
1757 | err = -EIO; | |
1758 | goto out_free_netdev; | |
1759 | } | |
1760 | ||
1761 | netdev->netdev_ops = &alx_netdev_ops; | |
7ad24ea4 | 1762 | netdev->ethtool_ops = &alx_ethtool_ops; |
f3297f68 | 1763 | netdev->irq = pci_irq_vector(pdev, 0); |
ab69bde6 JB |
1764 | netdev->watchdog_timeo = ALX_WATCHDOG_TIME; |
1765 | ||
1766 | if (ent->driver_data & ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG) | |
1767 | pdev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; | |
1768 | ||
1769 | err = alx_init_sw(alx); | |
1770 | if (err) { | |
1771 | dev_err(&pdev->dev, "net device private data init failed\n"); | |
1772 | goto out_unmap; | |
1773 | } | |
1774 | ||
1775 | alx_reset_pcie(hw); | |
1776 | ||
1777 | phy_configured = alx_phy_configured(hw); | |
1778 | ||
1779 | if (!phy_configured) | |
1780 | alx_reset_phy(hw); | |
1781 | ||
1782 | err = alx_reset_mac(hw); | |
1783 | if (err) { | |
1784 | dev_err(&pdev->dev, "MAC Reset failed, error = %d\n", err); | |
1785 | goto out_unmap; | |
1786 | } | |
1787 | ||
1788 | /* setup link to put it in a known good starting state */ | |
1789 | if (!phy_configured) { | |
1790 | err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl); | |
1791 | if (err) { | |
1792 | dev_err(&pdev->dev, | |
1793 | "failed to configure PHY speed/duplex (err=%d)\n", | |
1794 | err); | |
1795 | goto out_unmap; | |
1796 | } | |
1797 | } | |
1798 | ||
ab725983 TR |
1799 | netdev->hw_features = NETIF_F_SG | |
1800 | NETIF_F_HW_CSUM | | |
3a7f75e5 | 1801 | NETIF_F_RXCSUM | |
ab725983 TR |
1802 | NETIF_F_TSO | |
1803 | NETIF_F_TSO6; | |
ab69bde6 JB |
1804 | |
1805 | if (alx_get_perm_macaddr(hw, hw->perm_addr)) { | |
1806 | dev_warn(&pdev->dev, | |
1807 | "Invalid permanent address programmed, using random one\n"); | |
1808 | eth_hw_addr_random(netdev); | |
1809 | memcpy(hw->perm_addr, netdev->dev_addr, netdev->addr_len); | |
1810 | } | |
1811 | ||
1812 | memcpy(hw->mac_addr, hw->perm_addr, ETH_ALEN); | |
1813 | memcpy(netdev->dev_addr, hw->mac_addr, ETH_ALEN); | |
1814 | memcpy(netdev->perm_addr, hw->perm_addr, ETH_ALEN); | |
1815 | ||
1816 | hw->mdio.prtad = 0; | |
1817 | hw->mdio.mmds = 0; | |
1818 | hw->mdio.dev = netdev; | |
1819 | hw->mdio.mode_support = MDIO_SUPPORTS_C45 | | |
1820 | MDIO_SUPPORTS_C22 | | |
1821 | MDIO_EMULATE_C22; | |
1822 | hw->mdio.mdio_read = alx_mdio_read; | |
1823 | hw->mdio.mdio_write = alx_mdio_write; | |
1824 | ||
1825 | if (!alx_get_phy_info(hw)) { | |
1826 | dev_err(&pdev->dev, "failed to identify PHY\n"); | |
1827 | err = -EIO; | |
1828 | goto out_unmap; | |
1829 | } | |
1830 | ||
1831 | INIT_WORK(&alx->link_check_wk, alx_link_check); | |
1832 | INIT_WORK(&alx->reset_wk, alx_reset); | |
ab69bde6 JB |
1833 | netif_carrier_off(netdev); |
1834 | ||
1835 | err = register_netdev(netdev); | |
1836 | if (err) { | |
1837 | dev_err(&pdev->dev, "register netdevice failed\n"); | |
1838 | goto out_unmap; | |
1839 | } | |
1840 | ||
ab69bde6 JB |
1841 | netdev_info(netdev, |
1842 | "Qualcomm Atheros AR816x/AR817x Ethernet [%pM]\n", | |
1843 | netdev->dev_addr); | |
1844 | ||
1845 | return 0; | |
1846 | ||
1847 | out_unmap: | |
1848 | iounmap(hw->hw_addr); | |
1849 | out_free_netdev: | |
1850 | free_netdev(netdev); | |
1851 | out_pci_release: | |
caa8e932 | 1852 | pci_release_mem_regions(pdev); |
ab69bde6 JB |
1853 | out_pci_disable: |
1854 | pci_disable_device(pdev); | |
1855 | return err; | |
1856 | } | |
1857 | ||
1858 | static void alx_remove(struct pci_dev *pdev) | |
1859 | { | |
1860 | struct alx_priv *alx = pci_get_drvdata(pdev); | |
1861 | struct alx_hw *hw = &alx->hw; | |
1862 | ||
1863 | cancel_work_sync(&alx->link_check_wk); | |
1864 | cancel_work_sync(&alx->reset_wk); | |
1865 | ||
1866 | /* restore permanent mac address */ | |
1867 | alx_set_macaddr(hw, hw->perm_addr); | |
1868 | ||
1869 | unregister_netdev(alx->dev); | |
1870 | iounmap(hw->hw_addr); | |
caa8e932 | 1871 | pci_release_mem_regions(pdev); |
ab69bde6 JB |
1872 | |
1873 | pci_disable_pcie_error_reporting(pdev); | |
1874 | pci_disable_device(pdev); | |
ab69bde6 JB |
1875 | |
1876 | free_netdev(alx->dev); | |
1877 | } | |
1878 | ||
1879 | #ifdef CONFIG_PM_SLEEP | |
1880 | static int alx_suspend(struct device *dev) | |
1881 | { | |
1882 | struct pci_dev *pdev = to_pci_dev(dev); | |
bc2bebe8 | 1883 | struct alx_priv *alx = pci_get_drvdata(pdev); |
ab69bde6 | 1884 | |
bc2bebe8 JB |
1885 | if (!netif_running(alx->dev)) |
1886 | return 0; | |
1887 | netif_device_detach(alx->dev); | |
1888 | __alx_stop(alx); | |
ab69bde6 JB |
1889 | return 0; |
1890 | } | |
1891 | ||
1892 | static int alx_resume(struct device *dev) | |
1893 | { | |
1894 | struct pci_dev *pdev = to_pci_dev(dev); | |
1895 | struct alx_priv *alx = pci_get_drvdata(pdev); | |
b54629e2 | 1896 | struct alx_hw *hw = &alx->hw; |
bc800e8b | 1897 | int err; |
b54629e2 | 1898 | |
1899 | alx_reset_phy(hw); | |
ab69bde6 | 1900 | |
bc2bebe8 JB |
1901 | if (!netif_running(alx->dev)) |
1902 | return 0; | |
1903 | netif_device_attach(alx->dev); | |
bc800e8b SD |
1904 | |
1905 | rtnl_lock(); | |
1906 | err = __alx_open(alx, true); | |
1907 | rtnl_unlock(); | |
1908 | ||
1909 | return err; | |
ab69bde6 | 1910 | } |
bc2bebe8 JB |
1911 | |
1912 | static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume); | |
1913 | #define ALX_PM_OPS (&alx_pm_ops) | |
1914 | #else | |
1915 | #define ALX_PM_OPS NULL | |
ab69bde6 JB |
1916 | #endif |
1917 | ||
bc2bebe8 | 1918 | |
ab69bde6 JB |
1919 | static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev, |
1920 | pci_channel_state_t state) | |
1921 | { | |
1922 | struct alx_priv *alx = pci_get_drvdata(pdev); | |
1923 | struct net_device *netdev = alx->dev; | |
1924 | pci_ers_result_t rc = PCI_ERS_RESULT_NEED_RESET; | |
1925 | ||
1926 | dev_info(&pdev->dev, "pci error detected\n"); | |
1927 | ||
1928 | rtnl_lock(); | |
1929 | ||
1930 | if (netif_running(netdev)) { | |
1931 | netif_device_detach(netdev); | |
1932 | alx_halt(alx); | |
1933 | } | |
1934 | ||
1935 | if (state == pci_channel_io_perm_failure) | |
1936 | rc = PCI_ERS_RESULT_DISCONNECT; | |
1937 | else | |
1938 | pci_disable_device(pdev); | |
1939 | ||
1940 | rtnl_unlock(); | |
1941 | ||
1942 | return rc; | |
1943 | } | |
1944 | ||
1945 | static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev) | |
1946 | { | |
1947 | struct alx_priv *alx = pci_get_drvdata(pdev); | |
1948 | struct alx_hw *hw = &alx->hw; | |
1949 | pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; | |
1950 | ||
1951 | dev_info(&pdev->dev, "pci error slot reset\n"); | |
1952 | ||
1953 | rtnl_lock(); | |
1954 | ||
1955 | if (pci_enable_device(pdev)) { | |
1956 | dev_err(&pdev->dev, "Failed to re-enable PCI device after reset\n"); | |
1957 | goto out; | |
1958 | } | |
1959 | ||
1960 | pci_set_master(pdev); | |
ab69bde6 JB |
1961 | |
1962 | alx_reset_pcie(hw); | |
1963 | if (!alx_reset_mac(hw)) | |
1964 | rc = PCI_ERS_RESULT_RECOVERED; | |
1965 | out: | |
ab69bde6 JB |
1966 | rtnl_unlock(); |
1967 | ||
1968 | return rc; | |
1969 | } | |
1970 | ||
1971 | static void alx_pci_error_resume(struct pci_dev *pdev) | |
1972 | { | |
1973 | struct alx_priv *alx = pci_get_drvdata(pdev); | |
1974 | struct net_device *netdev = alx->dev; | |
1975 | ||
1976 | dev_info(&pdev->dev, "pci error resume\n"); | |
1977 | ||
1978 | rtnl_lock(); | |
1979 | ||
1980 | if (netif_running(netdev)) { | |
1981 | alx_activate(alx); | |
1982 | netif_device_attach(netdev); | |
1983 | } | |
1984 | ||
1985 | rtnl_unlock(); | |
1986 | } | |
1987 | ||
1988 | static const struct pci_error_handlers alx_err_handlers = { | |
1989 | .error_detected = alx_pci_error_detected, | |
1990 | .slot_reset = alx_pci_error_slot_reset, | |
1991 | .resume = alx_pci_error_resume, | |
1992 | }; | |
1993 | ||
9baa3c34 | 1994 | static const struct pci_device_id alx_pci_tbl[] = { |
ab69bde6 JB |
1995 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8161), |
1996 | .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, | |
1997 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200), | |
1998 | .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, | |
0208e951 BP |
1999 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2400), |
2000 | .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, | |
b99b43bb OL |
2001 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2500), |
2002 | .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, | |
ab69bde6 JB |
2003 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162), |
2004 | .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, | |
2005 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) }, | |
2006 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8172) }, | |
2007 | {} | |
2008 | }; | |
2009 | ||
2010 | static struct pci_driver alx_driver = { | |
2011 | .name = alx_drv_name, | |
2012 | .id_table = alx_pci_tbl, | |
2013 | .probe = alx_probe, | |
2014 | .remove = alx_remove, | |
ab69bde6 JB |
2015 | .err_handler = &alx_err_handlers, |
2016 | .driver.pm = ALX_PM_OPS, | |
2017 | }; | |
2018 | ||
2019 | module_pci_driver(alx_driver); | |
2020 | MODULE_DEVICE_TABLE(pci, alx_pci_tbl); | |
2021 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | |
2022 | MODULE_AUTHOR("Qualcomm Corporation, <nic-devel@qualcomm.com>"); | |
2023 | MODULE_DESCRIPTION( | |
2024 | "Qualcomm Atheros(R) AR816x/AR817x PCI-E Ethernet Network Driver"); | |
2025 | MODULE_LICENSE("GPL"); |