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 | ||
52 | const char alx_drv_name[] = "alx"; | |
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; | |
663 | alx->descmem.virt = dma_zalloc_coherent(&alx->hw.pdev->dev, | |
664 | alx->descmem.size, | |
665 | &alx->descmem.dma, | |
666 | GFP_KERNEL); | |
667 | if (!alx->descmem.virt) | |
8c2a4c8e | 668 | return -ENOMEM; |
ab69bde6 | 669 | |
8c2a4c8e | 670 | /* alignment requirements */ |
ab69bde6 | 671 | BUILD_BUG_ON(sizeof(struct alx_txd) % 8); |
ab69bde6 JB |
672 | BUILD_BUG_ON(sizeof(struct alx_rrd) % 8); |
673 | ||
a4076d34 TR |
674 | for (i = 0; i < alx->num_txq; i++) { |
675 | offset = alx_alloc_tx_ring(alx, alx->qnapi[i]->txq, offset); | |
676 | if (offset < 0) { | |
677 | netdev_err(alx->dev, "Allocation of tx buffer failed!\n"); | |
678 | return -ENOMEM; | |
679 | } | |
8c2a4c8e | 680 | } |
ab69bde6 | 681 | |
702e8418 | 682 | offset = alx_alloc_rx_ring(alx, alx->qnapi[0]->rxq, offset); |
8c2a4c8e TR |
683 | if (offset < 0) { |
684 | netdev_err(alx->dev, "Allocation of rx buffer failed!\n"); | |
b0999223 | 685 | return -ENOMEM; |
8c2a4c8e | 686 | } |
ab69bde6 | 687 | |
ab69bde6 JB |
688 | return 0; |
689 | } | |
690 | ||
691 | static void alx_free_rings(struct alx_priv *alx) | |
692 | { | |
a4076d34 | 693 | int i; |
702e8418 | 694 | |
ab69bde6 JB |
695 | alx_free_buffers(alx); |
696 | ||
a4076d34 TR |
697 | for (i = 0; i < alx->num_txq; i++) |
698 | if (alx->qnapi[i] && alx->qnapi[i]->txq) | |
699 | kfree(alx->qnapi[i]->txq->bufs); | |
700 | ||
701 | if (alx->qnapi[0] && alx->qnapi[0]->rxq) | |
702 | kfree(alx->qnapi[0]->rxq->bufs); | |
ab69bde6 | 703 | |
f1db5c10 | 704 | if (alx->descmem.virt) |
b0999223 TR |
705 | dma_free_coherent(&alx->hw.pdev->dev, |
706 | alx->descmem.size, | |
707 | alx->descmem.virt, | |
708 | alx->descmem.dma); | |
709 | } | |
710 | ||
711 | static void alx_free_napis(struct alx_priv *alx) | |
712 | { | |
713 | struct alx_napi *np; | |
a4076d34 | 714 | int i; |
b0999223 | 715 | |
a4076d34 TR |
716 | for (i = 0; i < alx->num_napi; i++) { |
717 | np = alx->qnapi[i]; | |
718 | if (!np) | |
719 | continue; | |
720 | ||
721 | netif_napi_del(&np->napi); | |
722 | kfree(np->txq); | |
723 | kfree(np->rxq); | |
724 | kfree(np); | |
725 | alx->qnapi[i] = NULL; | |
726 | } | |
b0999223 TR |
727 | } |
728 | ||
2e06826b TR |
729 | static const u16 tx_pidx_reg[] = {ALX_TPD_PRI0_PIDX, ALX_TPD_PRI1_PIDX, |
730 | ALX_TPD_PRI2_PIDX, ALX_TPD_PRI3_PIDX}; | |
731 | static const u16 tx_cidx_reg[] = {ALX_TPD_PRI0_CIDX, ALX_TPD_PRI1_CIDX, | |
732 | ALX_TPD_PRI2_CIDX, ALX_TPD_PRI3_CIDX}; | |
e0eac254 TR |
733 | static const u32 tx_vect_mask[] = {ALX_ISR_TX_Q0, ALX_ISR_TX_Q1, |
734 | ALX_ISR_TX_Q2, ALX_ISR_TX_Q3}; | |
735 | static const u32 rx_vect_mask[] = {ALX_ISR_RX_Q0, ALX_ISR_RX_Q1, | |
736 | ALX_ISR_RX_Q2, ALX_ISR_RX_Q3, | |
737 | ALX_ISR_RX_Q4, ALX_ISR_RX_Q5, | |
738 | ALX_ISR_RX_Q6, ALX_ISR_RX_Q7}; | |
739 | ||
b0999223 TR |
740 | static int alx_alloc_napis(struct alx_priv *alx) |
741 | { | |
742 | struct alx_napi *np; | |
743 | struct alx_rx_queue *rxq; | |
744 | struct alx_tx_queue *txq; | |
a4076d34 | 745 | int i; |
b0999223 TR |
746 | |
747 | alx->int_mask &= ~ALX_ISR_ALL_QUEUES; | |
b0999223 TR |
748 | |
749 | /* allocate alx_napi structures */ | |
a4076d34 TR |
750 | for (i = 0; i < alx->num_napi; i++) { |
751 | np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL); | |
752 | if (!np) | |
753 | goto err_out; | |
b0999223 | 754 | |
a4076d34 TR |
755 | np->alx = alx; |
756 | netif_napi_add(alx->dev, &np->napi, alx_poll, 64); | |
757 | alx->qnapi[i] = np; | |
758 | } | |
b0999223 TR |
759 | |
760 | /* allocate tx queues */ | |
a4076d34 TR |
761 | for (i = 0; i < alx->num_txq; i++) { |
762 | np = alx->qnapi[i]; | |
763 | txq = kzalloc(sizeof(*txq), GFP_KERNEL); | |
764 | if (!txq) | |
765 | goto err_out; | |
766 | ||
767 | np->txq = txq; | |
2e06826b TR |
768 | txq->p_reg = tx_pidx_reg[i]; |
769 | txq->c_reg = tx_cidx_reg[i]; | |
a4076d34 TR |
770 | txq->queue_idx = i; |
771 | txq->count = alx->tx_ringsz; | |
772 | txq->netdev = alx->dev; | |
773 | txq->dev = &alx->hw.pdev->dev; | |
774 | np->vec_mask |= tx_vect_mask[i]; | |
775 | alx->int_mask |= tx_vect_mask[i]; | |
776 | } | |
b0999223 TR |
777 | |
778 | /* allocate rx queues */ | |
779 | np = alx->qnapi[0]; | |
780 | rxq = kzalloc(sizeof(*rxq), GFP_KERNEL); | |
781 | if (!rxq) | |
782 | goto err_out; | |
783 | ||
784 | np->rxq = rxq; | |
785 | rxq->np = alx->qnapi[0]; | |
e0eac254 | 786 | rxq->queue_idx = 0; |
b0999223 TR |
787 | rxq->count = alx->rx_ringsz; |
788 | rxq->netdev = alx->dev; | |
789 | rxq->dev = &alx->hw.pdev->dev; | |
e0eac254 TR |
790 | np->vec_mask |= rx_vect_mask[0]; |
791 | alx->int_mask |= rx_vect_mask[0]; | |
b0999223 TR |
792 | |
793 | return 0; | |
794 | ||
795 | err_out: | |
796 | netdev_err(alx->dev, "error allocating internal structures\n"); | |
797 | alx_free_napis(alx); | |
798 | return -ENOMEM; | |
ab69bde6 JB |
799 | } |
800 | ||
e0eac254 TR |
801 | static const int txq_vec_mapping_shift[] = { |
802 | 0, ALX_MSI_MAP_TBL1_TXQ0_SHIFT, | |
803 | 0, ALX_MSI_MAP_TBL1_TXQ1_SHIFT, | |
804 | 1, ALX_MSI_MAP_TBL2_TXQ2_SHIFT, | |
805 | 1, ALX_MSI_MAP_TBL2_TXQ3_SHIFT, | |
806 | }; | |
807 | ||
ab69bde6 JB |
808 | static void alx_config_vector_mapping(struct alx_priv *alx) |
809 | { | |
810 | struct alx_hw *hw = &alx->hw; | |
e0eac254 TR |
811 | u32 tbl[2] = {0, 0}; |
812 | int i, vector, idx, shift; | |
dc39a78b | 813 | |
f3297f68 | 814 | if (alx->hw.pdev->msix_enabled) { |
e0eac254 TR |
815 | /* tx mappings */ |
816 | for (i = 0, vector = 1; i < alx->num_txq; i++, vector++) { | |
817 | idx = txq_vec_mapping_shift[i * 2]; | |
818 | shift = txq_vec_mapping_shift[i * 2 + 1]; | |
819 | tbl[idx] |= vector << shift; | |
820 | } | |
821 | ||
822 | /* rx mapping */ | |
823 | tbl[0] |= 1 << ALX_MSI_MAP_TBL1_RXQ0_SHIFT; | |
dc39a78b | 824 | } |
ab69bde6 | 825 | |
e0eac254 TR |
826 | alx_write_mem32(hw, ALX_MSI_MAP_TBL1, tbl[0]); |
827 | alx_write_mem32(hw, ALX_MSI_MAP_TBL2, tbl[1]); | |
ab69bde6 JB |
828 | alx_write_mem32(hw, ALX_MSI_ID_MAP, 0); |
829 | } | |
830 | ||
f3297f68 | 831 | static int alx_enable_msix(struct alx_priv *alx) |
dc39a78b | 832 | { |
f3297f68 | 833 | int err, num_vec, num_txq, num_rxq; |
e0eac254 | 834 | |
d768319c | 835 | num_txq = min_t(int, num_online_cpus(), ALX_MAX_TX_QUEUES); |
e0eac254 TR |
836 | num_rxq = 1; |
837 | num_vec = max_t(int, num_txq, num_rxq) + 1; | |
dc39a78b | 838 | |
f3297f68 CH |
839 | err = pci_alloc_irq_vectors(alx->hw.pdev, num_vec, num_vec, |
840 | PCI_IRQ_MSIX); | |
2c041afc | 841 | if (err < 0) { |
dc39a78b | 842 | netdev_warn(alx->dev, "Enabling MSI-X interrupts failed!\n"); |
f3297f68 | 843 | return err; |
dc39a78b TR |
844 | } |
845 | ||
846 | alx->num_vec = num_vec; | |
e0eac254 TR |
847 | alx->num_napi = num_vec - 1; |
848 | alx->num_txq = num_txq; | |
849 | alx->num_rxq = num_rxq; | |
850 | ||
f3297f68 | 851 | return err; |
dc39a78b TR |
852 | } |
853 | ||
854 | static int alx_request_msix(struct alx_priv *alx) | |
855 | { | |
856 | struct net_device *netdev = alx->dev; | |
857 | int i, err, vector = 0, free_vector = 0; | |
858 | ||
f3297f68 | 859 | err = request_irq(pci_irq_vector(alx->hw.pdev, 0), alx_intr_msix_misc, |
dc39a78b TR |
860 | 0, netdev->name, alx); |
861 | if (err) | |
862 | goto out_err; | |
863 | ||
e0eac254 TR |
864 | for (i = 0; i < alx->num_napi; i++) { |
865 | struct alx_napi *np = alx->qnapi[i]; | |
866 | ||
867 | vector++; | |
868 | ||
869 | if (np->txq && np->rxq) | |
870 | sprintf(np->irq_lbl, "%s-TxRx-%u", netdev->name, | |
871 | np->txq->queue_idx); | |
872 | else if (np->txq) | |
873 | sprintf(np->irq_lbl, "%s-tx-%u", netdev->name, | |
874 | np->txq->queue_idx); | |
875 | else if (np->rxq) | |
876 | sprintf(np->irq_lbl, "%s-rx-%u", netdev->name, | |
877 | np->rxq->queue_idx); | |
878 | else | |
879 | sprintf(np->irq_lbl, "%s-unused", netdev->name); | |
880 | ||
881 | np->vec_idx = vector; | |
f3297f68 | 882 | err = request_irq(pci_irq_vector(alx->hw.pdev, vector), |
e0eac254 | 883 | alx_intr_msix_ring, 0, np->irq_lbl, np); |
dc39a78b TR |
884 | if (err) |
885 | goto out_free; | |
e0eac254 | 886 | } |
dc39a78b TR |
887 | return 0; |
888 | ||
889 | out_free: | |
f3297f68 | 890 | free_irq(pci_irq_vector(alx->hw.pdev, free_vector++), alx); |
dc39a78b TR |
891 | |
892 | vector--; | |
893 | for (i = 0; i < vector; i++) | |
f3297f68 | 894 | free_irq(pci_irq_vector(alx->hw.pdev,free_vector++), |
e0eac254 | 895 | alx->qnapi[i]); |
dc39a78b TR |
896 | |
897 | out_err: | |
898 | return err; | |
899 | } | |
900 | ||
f3297f68 | 901 | static int alx_init_intr(struct alx_priv *alx) |
9ee7b683 | 902 | { |
f3297f68 | 903 | int ret; |
dc39a78b | 904 | |
f3297f68 CH |
905 | ret = pci_alloc_irq_vectors(alx->hw.pdev, 1, 1, |
906 | PCI_IRQ_MSI | PCI_IRQ_LEGACY); | |
2c041afc | 907 | if (ret < 0) |
f3297f68 | 908 | return ret; |
dc39a78b | 909 | |
f3297f68 CH |
910 | alx->num_vec = 1; |
911 | alx->num_napi = 1; | |
912 | alx->num_txq = 1; | |
913 | alx->num_rxq = 1; | |
914 | return 0; | |
9ee7b683 TR |
915 | } |
916 | ||
ab69bde6 JB |
917 | static void alx_irq_enable(struct alx_priv *alx) |
918 | { | |
919 | struct alx_hw *hw = &alx->hw; | |
dc39a78b | 920 | int i; |
ab69bde6 JB |
921 | |
922 | /* level-1 interrupt switch */ | |
923 | alx_write_mem32(hw, ALX_ISR, 0); | |
924 | alx_write_mem32(hw, ALX_IMR, alx->int_mask); | |
925 | alx_post_write(hw); | |
dc39a78b | 926 | |
f3297f68 | 927 | if (alx->hw.pdev->msix_enabled) { |
dc39a78b TR |
928 | /* enable all msix irqs */ |
929 | for (i = 0; i < alx->num_vec; i++) | |
930 | alx_mask_msix(hw, i, false); | |
f3297f68 | 931 | } |
ab69bde6 JB |
932 | } |
933 | ||
934 | static void alx_irq_disable(struct alx_priv *alx) | |
935 | { | |
936 | struct alx_hw *hw = &alx->hw; | |
dc39a78b | 937 | int i; |
ab69bde6 JB |
938 | |
939 | alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS); | |
940 | alx_write_mem32(hw, ALX_IMR, 0); | |
941 | alx_post_write(hw); | |
942 | ||
f3297f68 | 943 | if (alx->hw.pdev->msix_enabled) { |
dc39a78b TR |
944 | for (i = 0; i < alx->num_vec; i++) { |
945 | alx_mask_msix(hw, i, true); | |
f3297f68 | 946 | synchronize_irq(pci_irq_vector(alx->hw.pdev, i)); |
dc39a78b TR |
947 | } |
948 | } else { | |
f3297f68 | 949 | synchronize_irq(pci_irq_vector(alx->hw.pdev, 0)); |
dc39a78b | 950 | } |
ab69bde6 JB |
951 | } |
952 | ||
e0eac254 TR |
953 | static int alx_realloc_resources(struct alx_priv *alx) |
954 | { | |
955 | int err; | |
956 | ||
957 | alx_free_rings(alx); | |
958 | alx_free_napis(alx); | |
f3297f68 CH |
959 | pci_free_irq_vectors(alx->hw.pdev); |
960 | ||
961 | err = alx_init_intr(alx); | |
962 | if (err) | |
963 | return err; | |
e0eac254 TR |
964 | |
965 | err = alx_alloc_napis(alx); | |
966 | if (err) | |
967 | return err; | |
968 | ||
969 | err = alx_alloc_rings(alx); | |
970 | if (err) | |
971 | return err; | |
972 | ||
973 | return 0; | |
974 | } | |
975 | ||
ab69bde6 JB |
976 | static int alx_request_irq(struct alx_priv *alx) |
977 | { | |
978 | struct pci_dev *pdev = alx->hw.pdev; | |
979 | struct alx_hw *hw = &alx->hw; | |
980 | int err; | |
981 | u32 msi_ctrl; | |
982 | ||
983 | msi_ctrl = (hw->imt >> 1) << ALX_MSI_RETRANS_TM_SHIFT; | |
984 | ||
f3297f68 | 985 | if (alx->hw.pdev->msix_enabled) { |
dc39a78b TR |
986 | alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, msi_ctrl); |
987 | err = alx_request_msix(alx); | |
988 | if (!err) | |
989 | goto out; | |
990 | ||
991 | /* msix request failed, realloc resources */ | |
e0eac254 TR |
992 | err = alx_realloc_resources(alx); |
993 | if (err) | |
994 | goto out; | |
dc39a78b TR |
995 | } |
996 | ||
f3297f68 | 997 | if (alx->hw.pdev->msi_enabled) { |
ab69bde6 JB |
998 | alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, |
999 | msi_ctrl | ALX_MSI_MASK_SEL_LINE); | |
f3297f68 | 1000 | err = request_irq(pci_irq_vector(pdev, 0), alx_intr_msi, 0, |
ab69bde6 JB |
1001 | alx->dev->name, alx); |
1002 | if (!err) | |
1003 | goto out; | |
f3297f68 | 1004 | |
ab69bde6 | 1005 | /* fall back to legacy interrupt */ |
f3297f68 | 1006 | pci_free_irq_vectors(alx->hw.pdev); |
ab69bde6 JB |
1007 | } |
1008 | ||
1009 | alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, 0); | |
f3297f68 | 1010 | err = request_irq(pci_irq_vector(pdev, 0), alx_intr_legacy, IRQF_SHARED, |
ab69bde6 JB |
1011 | alx->dev->name, alx); |
1012 | out: | |
1013 | if (!err) | |
1014 | alx_config_vector_mapping(alx); | |
dc39a78b TR |
1015 | else |
1016 | netdev_err(alx->dev, "IRQ registration failed!\n"); | |
ab69bde6 JB |
1017 | return err; |
1018 | } | |
1019 | ||
1020 | static void alx_free_irq(struct alx_priv *alx) | |
1021 | { | |
1022 | struct pci_dev *pdev = alx->hw.pdev; | |
f3297f68 | 1023 | int i; |
ab69bde6 | 1024 | |
f3297f68 CH |
1025 | free_irq(pci_irq_vector(pdev, 0), alx); |
1026 | if (alx->hw.pdev->msix_enabled) { | |
e0eac254 | 1027 | for (i = 0; i < alx->num_napi; i++) |
f3297f68 | 1028 | free_irq(pci_irq_vector(pdev, i + 1), alx->qnapi[i]); |
dc39a78b | 1029 | } |
ab69bde6 | 1030 | |
f3297f68 | 1031 | pci_free_irq_vectors(pdev); |
ab69bde6 JB |
1032 | } |
1033 | ||
1034 | static int alx_identify_hw(struct alx_priv *alx) | |
1035 | { | |
1036 | struct alx_hw *hw = &alx->hw; | |
1037 | int rev = alx_hw_revision(hw); | |
1038 | ||
1039 | if (rev > ALX_REV_C0) | |
1040 | return -EINVAL; | |
1041 | ||
1042 | hw->max_dma_chnl = rev >= ALX_REV_B0 ? 4 : 2; | |
1043 | ||
1044 | return 0; | |
1045 | } | |
1046 | ||
1047 | static int alx_init_sw(struct alx_priv *alx) | |
1048 | { | |
1049 | struct pci_dev *pdev = alx->hw.pdev; | |
1050 | struct alx_hw *hw = &alx->hw; | |
1051 | int err; | |
1052 | ||
1053 | err = alx_identify_hw(alx); | |
1054 | if (err) { | |
1055 | dev_err(&pdev->dev, "unrecognized chip, aborting\n"); | |
1056 | return err; | |
1057 | } | |
1058 | ||
1059 | alx->hw.lnk_patch = | |
1060 | pdev->device == ALX_DEV_ID_AR8161 && | |
1061 | pdev->subsystem_vendor == PCI_VENDOR_ID_ATTANSIC && | |
1062 | pdev->subsystem_device == 0x0091 && | |
1063 | pdev->revision == 0; | |
1064 | ||
1065 | hw->smb_timer = 400; | |
1066 | hw->mtu = alx->dev->mtu; | |
c406700c | 1067 | alx->rxbuf_size = ALX_MAX_FRAME_LEN(hw->mtu); |
67bef942 JW |
1068 | /* MTU range: 34 - 9256 */ |
1069 | alx->dev->min_mtu = 34; | |
1070 | alx->dev->max_mtu = ALX_MAX_FRAME_LEN(ALX_MAX_FRAME_SIZE); | |
ab69bde6 JB |
1071 | alx->tx_ringsz = 256; |
1072 | alx->rx_ringsz = 512; | |
ab69bde6 JB |
1073 | hw->imt = 200; |
1074 | alx->int_mask = ALX_ISR_MISC; | |
1075 | hw->dma_chnl = hw->max_dma_chnl; | |
1076 | hw->ith_tpd = alx->tx_ringsz / 3; | |
1077 | hw->link_speed = SPEED_UNKNOWN; | |
a5b87cc9 | 1078 | hw->duplex = DUPLEX_UNKNOWN; |
ab69bde6 JB |
1079 | hw->adv_cfg = ADVERTISED_Autoneg | |
1080 | ADVERTISED_10baseT_Half | | |
1081 | ADVERTISED_10baseT_Full | | |
1082 | ADVERTISED_100baseT_Full | | |
1083 | ADVERTISED_100baseT_Half | | |
1084 | ADVERTISED_1000baseT_Full; | |
1085 | hw->flowctrl = ALX_FC_ANEG | ALX_FC_RX | ALX_FC_TX; | |
1086 | ||
1087 | hw->rx_ctrl = ALX_MAC_CTRL_WOLSPED_SWEN | | |
1088 | ALX_MAC_CTRL_MHASH_ALG_HI5B | | |
1089 | ALX_MAC_CTRL_BRD_EN | | |
1090 | ALX_MAC_CTRL_PCRCE | | |
1091 | ALX_MAC_CTRL_CRCE | | |
1092 | ALX_MAC_CTRL_RXFC_EN | | |
1093 | ALX_MAC_CTRL_TXFC_EN | | |
1094 | 7 << ALX_MAC_CTRL_PRMBLEN_SHIFT; | |
1095 | ||
1096 | return err; | |
1097 | } | |
1098 | ||
1099 | ||
1100 | static netdev_features_t alx_fix_features(struct net_device *netdev, | |
1101 | netdev_features_t features) | |
1102 | { | |
1103 | if (netdev->mtu > ALX_MAX_TSO_PKT_SIZE) | |
1104 | features &= ~(NETIF_F_TSO | NETIF_F_TSO6); | |
1105 | ||
1106 | return features; | |
1107 | } | |
1108 | ||
1109 | static void alx_netif_stop(struct alx_priv *alx) | |
1110 | { | |
a4076d34 TR |
1111 | int i; |
1112 | ||
860e9538 | 1113 | netif_trans_update(alx->dev); |
ab69bde6 JB |
1114 | if (netif_carrier_ok(alx->dev)) { |
1115 | netif_carrier_off(alx->dev); | |
1116 | netif_tx_disable(alx->dev); | |
a4076d34 TR |
1117 | for (i = 0; i < alx->num_napi; i++) |
1118 | napi_disable(&alx->qnapi[i]->napi); | |
ab69bde6 JB |
1119 | } |
1120 | } | |
1121 | ||
1122 | static void alx_halt(struct alx_priv *alx) | |
1123 | { | |
1124 | struct alx_hw *hw = &alx->hw; | |
1125 | ||
1126 | alx_netif_stop(alx); | |
1127 | hw->link_speed = SPEED_UNKNOWN; | |
a5b87cc9 | 1128 | hw->duplex = DUPLEX_UNKNOWN; |
ab69bde6 JB |
1129 | |
1130 | alx_reset_mac(hw); | |
1131 | ||
1132 | /* disable l0s/l1 */ | |
1133 | alx_enable_aspm(hw, false, false); | |
1134 | alx_irq_disable(alx); | |
1135 | alx_free_buffers(alx); | |
1136 | } | |
1137 | ||
1138 | static void alx_configure(struct alx_priv *alx) | |
1139 | { | |
1140 | struct alx_hw *hw = &alx->hw; | |
1141 | ||
1142 | alx_configure_basic(hw); | |
1143 | alx_disable_rss(hw); | |
1144 | __alx_set_rx_mode(alx->dev); | |
1145 | ||
1146 | alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); | |
1147 | } | |
1148 | ||
1149 | static void alx_activate(struct alx_priv *alx) | |
1150 | { | |
1151 | /* hardware setting lost, restore it */ | |
1152 | alx_reinit_rings(alx); | |
1153 | alx_configure(alx); | |
1154 | ||
1155 | /* clear old interrupts */ | |
1156 | alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS); | |
1157 | ||
1158 | alx_irq_enable(alx); | |
1159 | ||
1160 | alx_schedule_link_check(alx); | |
1161 | } | |
1162 | ||
1163 | static void alx_reinit(struct alx_priv *alx) | |
1164 | { | |
1165 | ASSERT_RTNL(); | |
1166 | ||
1167 | alx_halt(alx); | |
1168 | alx_activate(alx); | |
1169 | } | |
1170 | ||
1171 | static int alx_change_mtu(struct net_device *netdev, int mtu) | |
1172 | { | |
1173 | struct alx_priv *alx = netdev_priv(netdev); | |
c406700c | 1174 | int max_frame = ALX_MAX_FRAME_LEN(mtu); |
ab69bde6 | 1175 | |
ab69bde6 JB |
1176 | netdev->mtu = mtu; |
1177 | alx->hw.mtu = mtu; | |
c406700c | 1178 | alx->rxbuf_size = max(max_frame, ALX_DEF_RXBUF_SIZE); |
ab69bde6 JB |
1179 | netdev_update_features(netdev); |
1180 | if (netif_running(netdev)) | |
1181 | alx_reinit(alx); | |
1182 | return 0; | |
1183 | } | |
1184 | ||
1185 | static void alx_netif_start(struct alx_priv *alx) | |
1186 | { | |
a4076d34 TR |
1187 | int i; |
1188 | ||
ab69bde6 | 1189 | netif_tx_wake_all_queues(alx->dev); |
a4076d34 TR |
1190 | for (i = 0; i < alx->num_napi; i++) |
1191 | napi_enable(&alx->qnapi[i]->napi); | |
ab69bde6 JB |
1192 | netif_carrier_on(alx->dev); |
1193 | } | |
1194 | ||
1195 | static int __alx_open(struct alx_priv *alx, bool resume) | |
1196 | { | |
1197 | int err; | |
1198 | ||
f3297f68 CH |
1199 | err = alx_enable_msix(alx); |
1200 | if (err < 0) { | |
1201 | err = alx_init_intr(alx); | |
1202 | if (err) | |
1203 | return err; | |
1204 | } | |
9ee7b683 | 1205 | |
ab69bde6 JB |
1206 | if (!resume) |
1207 | netif_carrier_off(alx->dev); | |
1208 | ||
b0999223 | 1209 | err = alx_alloc_napis(alx); |
ab69bde6 | 1210 | if (err) |
0ca4e20b | 1211 | goto out_disable_adv_intr; |
ab69bde6 | 1212 | |
b0999223 TR |
1213 | err = alx_alloc_rings(alx); |
1214 | if (err) | |
1215 | goto out_free_rings; | |
1216 | ||
ab69bde6 JB |
1217 | alx_configure(alx); |
1218 | ||
1219 | err = alx_request_irq(alx); | |
1220 | if (err) | |
1221 | goto out_free_rings; | |
1222 | ||
185aceef TR |
1223 | /* must be called after alx_request_irq because the chip stops working |
1224 | * if we copy the dma addresses in alx_init_ring_ptrs twice when | |
1225 | * requesting msi-x interrupts failed | |
1226 | */ | |
1227 | alx_reinit_rings(alx); | |
1228 | ||
d768319c TR |
1229 | netif_set_real_num_tx_queues(alx->dev, alx->num_txq); |
1230 | netif_set_real_num_rx_queues(alx->dev, alx->num_rxq); | |
1231 | ||
ab69bde6 JB |
1232 | /* clear old interrupts */ |
1233 | alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS); | |
1234 | ||
1235 | alx_irq_enable(alx); | |
1236 | ||
1237 | if (!resume) | |
1238 | netif_tx_start_all_queues(alx->dev); | |
1239 | ||
1240 | alx_schedule_link_check(alx); | |
1241 | return 0; | |
1242 | ||
1243 | out_free_rings: | |
1244 | alx_free_rings(alx); | |
b0999223 | 1245 | alx_free_napis(alx); |
0ca4e20b | 1246 | out_disable_adv_intr: |
f3297f68 | 1247 | pci_free_irq_vectors(alx->hw.pdev); |
ab69bde6 JB |
1248 | return err; |
1249 | } | |
1250 | ||
1251 | static void __alx_stop(struct alx_priv *alx) | |
1252 | { | |
1253 | alx_halt(alx); | |
1254 | alx_free_irq(alx); | |
1255 | alx_free_rings(alx); | |
b0999223 | 1256 | alx_free_napis(alx); |
ab69bde6 JB |
1257 | } |
1258 | ||
a5b87cc9 | 1259 | static const char *alx_speed_desc(struct alx_hw *hw) |
ab69bde6 | 1260 | { |
a5b87cc9 JB |
1261 | switch (alx_speed_to_ethadv(hw->link_speed, hw->duplex)) { |
1262 | case ADVERTISED_1000baseT_Full: | |
ab69bde6 | 1263 | return "1 Gbps Full"; |
a5b87cc9 | 1264 | case ADVERTISED_100baseT_Full: |
ab69bde6 | 1265 | return "100 Mbps Full"; |
a5b87cc9 | 1266 | case ADVERTISED_100baseT_Half: |
ab69bde6 | 1267 | return "100 Mbps Half"; |
a5b87cc9 | 1268 | case ADVERTISED_10baseT_Full: |
ab69bde6 | 1269 | return "10 Mbps Full"; |
a5b87cc9 | 1270 | case ADVERTISED_10baseT_Half: |
ab69bde6 JB |
1271 | return "10 Mbps Half"; |
1272 | default: | |
1273 | return "Unknown speed"; | |
1274 | } | |
1275 | } | |
1276 | ||
1277 | static void alx_check_link(struct alx_priv *alx) | |
1278 | { | |
1279 | struct alx_hw *hw = &alx->hw; | |
1280 | unsigned long flags; | |
a5b87cc9 JB |
1281 | int old_speed; |
1282 | u8 old_duplex; | |
ab69bde6 JB |
1283 | int err; |
1284 | ||
1285 | /* clear PHY internal interrupt status, otherwise the main | |
1286 | * interrupt status will be asserted forever | |
1287 | */ | |
1288 | alx_clear_phy_intr(hw); | |
1289 | ||
a5b87cc9 JB |
1290 | old_speed = hw->link_speed; |
1291 | old_duplex = hw->duplex; | |
1292 | err = alx_read_phy_link(hw); | |
ab69bde6 JB |
1293 | if (err < 0) |
1294 | goto reset; | |
1295 | ||
1296 | spin_lock_irqsave(&alx->irq_lock, flags); | |
1297 | alx->int_mask |= ALX_ISR_PHY; | |
1298 | alx_write_mem32(hw, ALX_IMR, alx->int_mask); | |
1299 | spin_unlock_irqrestore(&alx->irq_lock, flags); | |
1300 | ||
a5b87cc9 | 1301 | if (old_speed == hw->link_speed) |
ab69bde6 | 1302 | return; |
ab69bde6 | 1303 | |
a5b87cc9 | 1304 | if (hw->link_speed != SPEED_UNKNOWN) { |
ab69bde6 | 1305 | netif_info(alx, link, alx->dev, |
a5b87cc9 | 1306 | "NIC Up: %s\n", alx_speed_desc(hw)); |
ab69bde6 JB |
1307 | alx_post_phy_link(hw); |
1308 | alx_enable_aspm(hw, true, true); | |
1309 | alx_start_mac(hw); | |
1310 | ||
1311 | if (old_speed == SPEED_UNKNOWN) | |
1312 | alx_netif_start(alx); | |
1313 | } else { | |
1314 | /* link is now down */ | |
1315 | alx_netif_stop(alx); | |
1316 | netif_info(alx, link, alx->dev, "Link Down\n"); | |
1317 | err = alx_reset_mac(hw); | |
1318 | if (err) | |
1319 | goto reset; | |
1320 | alx_irq_disable(alx); | |
1321 | ||
1322 | /* MAC reset causes all HW settings to be lost, restore all */ | |
1323 | err = alx_reinit_rings(alx); | |
1324 | if (err) | |
1325 | goto reset; | |
1326 | alx_configure(alx); | |
1327 | alx_enable_aspm(hw, false, true); | |
1328 | alx_post_phy_link(hw); | |
1329 | alx_irq_enable(alx); | |
1330 | } | |
1331 | ||
1332 | return; | |
1333 | ||
1334 | reset: | |
1335 | alx_schedule_reset(alx); | |
1336 | } | |
1337 | ||
1338 | static int alx_open(struct net_device *netdev) | |
1339 | { | |
1340 | return __alx_open(netdev_priv(netdev), false); | |
1341 | } | |
1342 | ||
1343 | static int alx_stop(struct net_device *netdev) | |
1344 | { | |
1345 | __alx_stop(netdev_priv(netdev)); | |
1346 | return 0; | |
1347 | } | |
1348 | ||
ab69bde6 JB |
1349 | static void alx_link_check(struct work_struct *work) |
1350 | { | |
1351 | struct alx_priv *alx; | |
1352 | ||
1353 | alx = container_of(work, struct alx_priv, link_check_wk); | |
1354 | ||
1355 | rtnl_lock(); | |
1356 | alx_check_link(alx); | |
1357 | rtnl_unlock(); | |
1358 | } | |
1359 | ||
1360 | static void alx_reset(struct work_struct *work) | |
1361 | { | |
1362 | struct alx_priv *alx = container_of(work, struct alx_priv, reset_wk); | |
1363 | ||
1364 | rtnl_lock(); | |
1365 | alx_reinit(alx); | |
1366 | rtnl_unlock(); | |
1367 | } | |
1368 | ||
ab725983 TR |
1369 | static int alx_tpd_req(struct sk_buff *skb) |
1370 | { | |
1371 | int num; | |
1372 | ||
1373 | num = skb_shinfo(skb)->nr_frags + 1; | |
1374 | /* we need one extra descriptor for LSOv2 */ | |
1375 | if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) | |
1376 | num++; | |
1377 | ||
1378 | return num; | |
1379 | } | |
1380 | ||
ab69bde6 JB |
1381 | static int alx_tx_csum(struct sk_buff *skb, struct alx_txd *first) |
1382 | { | |
1383 | u8 cso, css; | |
1384 | ||
1385 | if (skb->ip_summed != CHECKSUM_PARTIAL) | |
1386 | return 0; | |
1387 | ||
1388 | cso = skb_checksum_start_offset(skb); | |
1389 | if (cso & 1) | |
1390 | return -EINVAL; | |
1391 | ||
1392 | css = cso + skb->csum_offset; | |
1393 | first->word1 |= cpu_to_le32((cso >> 1) << TPD_CXSUMSTART_SHIFT); | |
1394 | first->word1 |= cpu_to_le32((css >> 1) << TPD_CXSUMOFFSET_SHIFT); | |
1395 | first->word1 |= cpu_to_le32(1 << TPD_CXSUM_EN_SHIFT); | |
1396 | ||
1397 | return 0; | |
1398 | } | |
1399 | ||
ab725983 TR |
1400 | static int alx_tso(struct sk_buff *skb, struct alx_txd *first) |
1401 | { | |
1402 | int err; | |
1403 | ||
1404 | if (skb->ip_summed != CHECKSUM_PARTIAL) | |
1405 | return 0; | |
1406 | ||
1407 | if (!skb_is_gso(skb)) | |
1408 | return 0; | |
1409 | ||
1410 | err = skb_cow_head(skb, 0); | |
1411 | if (err < 0) | |
1412 | return err; | |
1413 | ||
1414 | if (skb->protocol == htons(ETH_P_IP)) { | |
1415 | struct iphdr *iph = ip_hdr(skb); | |
1416 | ||
1417 | iph->check = 0; | |
1418 | tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | |
1419 | 0, IPPROTO_TCP, 0); | |
1420 | first->word1 |= 1 << TPD_IPV4_SHIFT; | |
1421 | } else if (skb_is_gso_v6(skb)) { | |
1422 | ipv6_hdr(skb)->payload_len = 0; | |
1423 | tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | |
1424 | &ipv6_hdr(skb)->daddr, | |
1425 | 0, IPPROTO_TCP, 0); | |
1426 | /* LSOv2: the first TPD only provides the packet length */ | |
1427 | first->adrl.l.pkt_len = skb->len; | |
1428 | first->word1 |= 1 << TPD_LSO_V2_SHIFT; | |
1429 | } | |
1430 | ||
1431 | first->word1 |= 1 << TPD_LSO_EN_SHIFT; | |
1432 | first->word1 |= (skb_transport_offset(skb) & | |
1433 | TPD_L4HDROFFSET_MASK) << TPD_L4HDROFFSET_SHIFT; | |
1434 | first->word1 |= (skb_shinfo(skb)->gso_size & | |
1435 | TPD_MSS_MASK) << TPD_MSS_SHIFT; | |
1436 | return 1; | |
1437 | } | |
1438 | ||
702e8418 | 1439 | static int alx_map_tx_skb(struct alx_tx_queue *txq, struct sk_buff *skb) |
ab69bde6 | 1440 | { |
ab69bde6 JB |
1441 | struct alx_txd *tpd, *first_tpd; |
1442 | dma_addr_t dma; | |
1443 | int maplen, f, first_idx = txq->write_idx; | |
1444 | ||
1445 | first_tpd = &txq->tpd[txq->write_idx]; | |
1446 | tpd = first_tpd; | |
1447 | ||
ab725983 | 1448 | if (tpd->word1 & (1 << TPD_LSO_V2_SHIFT)) { |
702e8418 | 1449 | if (++txq->write_idx == txq->count) |
ab725983 TR |
1450 | txq->write_idx = 0; |
1451 | ||
1452 | tpd = &txq->tpd[txq->write_idx]; | |
1453 | tpd->len = first_tpd->len; | |
1454 | tpd->vlan_tag = first_tpd->vlan_tag; | |
1455 | tpd->word1 = first_tpd->word1; | |
1456 | } | |
1457 | ||
ab69bde6 | 1458 | maplen = skb_headlen(skb); |
702e8418 | 1459 | dma = dma_map_single(txq->dev, skb->data, maplen, |
ab69bde6 | 1460 | DMA_TO_DEVICE); |
702e8418 | 1461 | if (dma_mapping_error(txq->dev, dma)) |
ab69bde6 JB |
1462 | goto err_dma; |
1463 | ||
1464 | dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen); | |
1465 | dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma); | |
1466 | ||
1467 | tpd->adrl.addr = cpu_to_le64(dma); | |
1468 | tpd->len = cpu_to_le16(maplen); | |
1469 | ||
1470 | for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { | |
1471 | struct skb_frag_struct *frag; | |
1472 | ||
1473 | frag = &skb_shinfo(skb)->frags[f]; | |
1474 | ||
702e8418 | 1475 | if (++txq->write_idx == txq->count) |
ab69bde6 JB |
1476 | txq->write_idx = 0; |
1477 | tpd = &txq->tpd[txq->write_idx]; | |
1478 | ||
1479 | tpd->word1 = first_tpd->word1; | |
1480 | ||
1481 | maplen = skb_frag_size(frag); | |
702e8418 | 1482 | dma = skb_frag_dma_map(txq->dev, frag, 0, |
ab69bde6 | 1483 | maplen, DMA_TO_DEVICE); |
702e8418 | 1484 | if (dma_mapping_error(txq->dev, dma)) |
ab69bde6 JB |
1485 | goto err_dma; |
1486 | dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen); | |
1487 | dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma); | |
1488 | ||
1489 | tpd->adrl.addr = cpu_to_le64(dma); | |
1490 | tpd->len = cpu_to_le16(maplen); | |
1491 | } | |
1492 | ||
1493 | /* last TPD, set EOP flag and store skb */ | |
1494 | tpd->word1 |= cpu_to_le32(1 << TPD_EOP_SHIFT); | |
1495 | txq->bufs[txq->write_idx].skb = skb; | |
1496 | ||
702e8418 | 1497 | if (++txq->write_idx == txq->count) |
ab69bde6 JB |
1498 | txq->write_idx = 0; |
1499 | ||
1500 | return 0; | |
1501 | ||
1502 | err_dma: | |
1503 | f = first_idx; | |
1504 | while (f != txq->write_idx) { | |
702e8418 TR |
1505 | alx_free_txbuf(txq, f); |
1506 | if (++f == txq->count) | |
ab69bde6 JB |
1507 | f = 0; |
1508 | } | |
1509 | return -ENOMEM; | |
1510 | } | |
1511 | ||
2e06826b TR |
1512 | static netdev_tx_t alx_start_xmit_ring(struct sk_buff *skb, |
1513 | struct alx_tx_queue *txq) | |
ab69bde6 | 1514 | { |
2e06826b | 1515 | struct alx_priv *alx; |
ab69bde6 | 1516 | struct alx_txd *first; |
ab725983 | 1517 | int tso; |
ab69bde6 | 1518 | |
2e06826b TR |
1519 | alx = netdev_priv(txq->netdev); |
1520 | ||
702e8418 | 1521 | if (alx_tpd_avail(txq) < alx_tpd_req(skb)) { |
2e06826b | 1522 | netif_tx_stop_queue(alx_get_tx_queue(txq)); |
ab69bde6 JB |
1523 | goto drop; |
1524 | } | |
1525 | ||
1526 | first = &txq->tpd[txq->write_idx]; | |
1527 | memset(first, 0, sizeof(*first)); | |
1528 | ||
ab725983 TR |
1529 | tso = alx_tso(skb, first); |
1530 | if (tso < 0) | |
1531 | goto drop; | |
1532 | else if (!tso && alx_tx_csum(skb, first)) | |
ab69bde6 JB |
1533 | goto drop; |
1534 | ||
702e8418 | 1535 | if (alx_map_tx_skb(txq, skb) < 0) |
ab69bde6 JB |
1536 | goto drop; |
1537 | ||
2e06826b | 1538 | netdev_tx_sent_queue(alx_get_tx_queue(txq), skb->len); |
ab69bde6 JB |
1539 | |
1540 | /* flush updates before updating hardware */ | |
1541 | wmb(); | |
2e06826b | 1542 | alx_write_mem16(&alx->hw, txq->p_reg, txq->write_idx); |
ab69bde6 | 1543 | |
702e8418 | 1544 | if (alx_tpd_avail(txq) < txq->count / 8) |
2e06826b | 1545 | netif_tx_stop_queue(alx_get_tx_queue(txq)); |
ab69bde6 JB |
1546 | |
1547 | return NETDEV_TX_OK; | |
1548 | ||
1549 | drop: | |
548ff1ed | 1550 | dev_kfree_skb_any(skb); |
ab69bde6 JB |
1551 | return NETDEV_TX_OK; |
1552 | } | |
1553 | ||
2e06826b TR |
1554 | static netdev_tx_t alx_start_xmit(struct sk_buff *skb, |
1555 | struct net_device *netdev) | |
1556 | { | |
1557 | struct alx_priv *alx = netdev_priv(netdev); | |
1558 | return alx_start_xmit_ring(skb, alx_tx_queue_mapping(alx, skb)); | |
1559 | } | |
1560 | ||
ab69bde6 JB |
1561 | static void alx_tx_timeout(struct net_device *dev) |
1562 | { | |
1563 | struct alx_priv *alx = netdev_priv(dev); | |
1564 | ||
1565 | alx_schedule_reset(alx); | |
1566 | } | |
1567 | ||
1568 | static int alx_mdio_read(struct net_device *netdev, | |
1569 | int prtad, int devad, u16 addr) | |
1570 | { | |
1571 | struct alx_priv *alx = netdev_priv(netdev); | |
1572 | struct alx_hw *hw = &alx->hw; | |
1573 | u16 val; | |
1574 | int err; | |
1575 | ||
1576 | if (prtad != hw->mdio.prtad) | |
1577 | return -EINVAL; | |
1578 | ||
1579 | if (devad == MDIO_DEVAD_NONE) | |
1580 | err = alx_read_phy_reg(hw, addr, &val); | |
1581 | else | |
1582 | err = alx_read_phy_ext(hw, devad, addr, &val); | |
1583 | ||
1584 | if (err) | |
1585 | return err; | |
1586 | return val; | |
1587 | } | |
1588 | ||
1589 | static int alx_mdio_write(struct net_device *netdev, | |
1590 | int prtad, int devad, u16 addr, u16 val) | |
1591 | { | |
1592 | struct alx_priv *alx = netdev_priv(netdev); | |
1593 | struct alx_hw *hw = &alx->hw; | |
1594 | ||
1595 | if (prtad != hw->mdio.prtad) | |
1596 | return -EINVAL; | |
1597 | ||
1598 | if (devad == MDIO_DEVAD_NONE) | |
1599 | return alx_write_phy_reg(hw, addr, val); | |
1600 | ||
1601 | return alx_write_phy_ext(hw, devad, addr, val); | |
1602 | } | |
1603 | ||
1604 | static int alx_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) | |
1605 | { | |
1606 | struct alx_priv *alx = netdev_priv(netdev); | |
1607 | ||
1608 | if (!netif_running(netdev)) | |
1609 | return -EAGAIN; | |
1610 | ||
1611 | return mdio_mii_ioctl(&alx->hw.mdio, if_mii(ifr), cmd); | |
1612 | } | |
1613 | ||
1614 | #ifdef CONFIG_NET_POLL_CONTROLLER | |
1615 | static void alx_poll_controller(struct net_device *netdev) | |
1616 | { | |
1617 | struct alx_priv *alx = netdev_priv(netdev); | |
e0eac254 | 1618 | int i; |
ab69bde6 | 1619 | |
f3297f68 | 1620 | if (alx->hw.pdev->msix_enabled) { |
dc39a78b | 1621 | alx_intr_msix_misc(0, alx); |
e0eac254 TR |
1622 | for (i = 0; i < alx->num_txq; i++) |
1623 | alx_intr_msix_ring(0, alx->qnapi[i]); | |
f3297f68 | 1624 | } else if (alx->hw.pdev->msi_enabled) |
ab69bde6 JB |
1625 | alx_intr_msi(0, alx); |
1626 | else | |
1627 | alx_intr_legacy(0, alx); | |
1628 | } | |
1629 | #endif | |
1630 | ||
bc1f4470 | 1631 | static void alx_get_stats64(struct net_device *dev, |
1632 | struct rtnl_link_stats64 *net_stats) | |
f1b6b106 SD |
1633 | { |
1634 | struct alx_priv *alx = netdev_priv(dev); | |
1635 | struct alx_hw_stats *hw_stats = &alx->hw.stats; | |
1636 | ||
1637 | spin_lock(&alx->stats_lock); | |
1638 | ||
1639 | alx_update_hw_stats(&alx->hw); | |
1640 | ||
1641 | net_stats->tx_bytes = hw_stats->tx_byte_cnt; | |
1642 | net_stats->rx_bytes = hw_stats->rx_byte_cnt; | |
1643 | net_stats->multicast = hw_stats->rx_mcast; | |
1644 | net_stats->collisions = hw_stats->tx_single_col + | |
1645 | hw_stats->tx_multi_col + | |
1646 | hw_stats->tx_late_col + | |
1647 | hw_stats->tx_abort_col; | |
1648 | ||
1649 | net_stats->rx_errors = hw_stats->rx_frag + | |
1650 | hw_stats->rx_fcs_err + | |
1651 | hw_stats->rx_len_err + | |
1652 | hw_stats->rx_ov_sz + | |
1653 | hw_stats->rx_ov_rrd + | |
1654 | hw_stats->rx_align_err + | |
1655 | hw_stats->rx_ov_rxf; | |
1656 | ||
1657 | net_stats->rx_fifo_errors = hw_stats->rx_ov_rxf; | |
1658 | net_stats->rx_length_errors = hw_stats->rx_len_err; | |
1659 | net_stats->rx_crc_errors = hw_stats->rx_fcs_err; | |
1660 | net_stats->rx_frame_errors = hw_stats->rx_align_err; | |
1661 | net_stats->rx_dropped = hw_stats->rx_ov_rrd; | |
1662 | ||
1663 | net_stats->tx_errors = hw_stats->tx_late_col + | |
1664 | hw_stats->tx_abort_col + | |
1665 | hw_stats->tx_underrun + | |
1666 | hw_stats->tx_trunc; | |
1667 | ||
1668 | net_stats->tx_aborted_errors = hw_stats->tx_abort_col; | |
1669 | net_stats->tx_fifo_errors = hw_stats->tx_underrun; | |
1670 | net_stats->tx_window_errors = hw_stats->tx_late_col; | |
1671 | ||
1672 | net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors; | |
1673 | net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors; | |
1674 | ||
1675 | spin_unlock(&alx->stats_lock); | |
f1b6b106 SD |
1676 | } |
1677 | ||
ab69bde6 JB |
1678 | static const struct net_device_ops alx_netdev_ops = { |
1679 | .ndo_open = alx_open, | |
1680 | .ndo_stop = alx_stop, | |
1681 | .ndo_start_xmit = alx_start_xmit, | |
f1b6b106 | 1682 | .ndo_get_stats64 = alx_get_stats64, |
ab69bde6 JB |
1683 | .ndo_set_rx_mode = alx_set_rx_mode, |
1684 | .ndo_validate_addr = eth_validate_addr, | |
1685 | .ndo_set_mac_address = alx_set_mac_address, | |
1686 | .ndo_change_mtu = alx_change_mtu, | |
1687 | .ndo_do_ioctl = alx_ioctl, | |
1688 | .ndo_tx_timeout = alx_tx_timeout, | |
1689 | .ndo_fix_features = alx_fix_features, | |
1690 | #ifdef CONFIG_NET_POLL_CONTROLLER | |
1691 | .ndo_poll_controller = alx_poll_controller, | |
1692 | #endif | |
1693 | }; | |
1694 | ||
1695 | static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |
1696 | { | |
1697 | struct net_device *netdev; | |
1698 | struct alx_priv *alx; | |
1699 | struct alx_hw *hw; | |
1700 | bool phy_configured; | |
caa8e932 | 1701 | int err; |
ab69bde6 JB |
1702 | |
1703 | err = pci_enable_device_mem(pdev); | |
1704 | if (err) | |
1705 | return err; | |
1706 | ||
1707 | /* The alx chip can DMA to 64-bit addresses, but it uses a single | |
1708 | * shared register for the high 32 bits, so only a single, aligned, | |
1709 | * 4 GB physical address range can be used for descriptors. | |
1710 | */ | |
8d7f1fbf | 1711 | if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { |
ab69bde6 JB |
1712 | dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n"); |
1713 | } else { | |
8d7f1fbf | 1714 | err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); |
ab69bde6 | 1715 | if (err) { |
8d7f1fbf PST |
1716 | dev_err(&pdev->dev, "No usable DMA config, aborting\n"); |
1717 | goto out_pci_disable; | |
ab69bde6 JB |
1718 | } |
1719 | } | |
1720 | ||
caa8e932 | 1721 | err = pci_request_mem_regions(pdev, alx_drv_name); |
ab69bde6 JB |
1722 | if (err) { |
1723 | dev_err(&pdev->dev, | |
caa8e932 | 1724 | "pci_request_mem_regions failed\n"); |
ab69bde6 JB |
1725 | goto out_pci_disable; |
1726 | } | |
1727 | ||
1728 | pci_enable_pcie_error_reporting(pdev); | |
1729 | pci_set_master(pdev); | |
1730 | ||
c3eb7a77 | 1731 | if (!pdev->pm_cap) { |
ab69bde6 JB |
1732 | dev_err(&pdev->dev, |
1733 | "Can't find power management capability, aborting\n"); | |
1734 | err = -EIO; | |
1735 | goto out_pci_release; | |
1736 | } | |
1737 | ||
d768319c TR |
1738 | netdev = alloc_etherdev_mqs(sizeof(*alx), |
1739 | ALX_MAX_TX_QUEUES, 1); | |
ab69bde6 JB |
1740 | if (!netdev) { |
1741 | err = -ENOMEM; | |
1742 | goto out_pci_release; | |
1743 | } | |
1744 | ||
1745 | SET_NETDEV_DEV(netdev, &pdev->dev); | |
1746 | alx = netdev_priv(netdev); | |
a8798a5c ML |
1747 | spin_lock_init(&alx->hw.mdio_lock); |
1748 | spin_lock_init(&alx->irq_lock); | |
3e5ccc29 | 1749 | spin_lock_init(&alx->stats_lock); |
ab69bde6 JB |
1750 | alx->dev = netdev; |
1751 | alx->hw.pdev = pdev; | |
1752 | alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP | | |
1753 | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR | NETIF_MSG_WOL; | |
1754 | hw = &alx->hw; | |
1755 | pci_set_drvdata(pdev, alx); | |
1756 | ||
1757 | hw->hw_addr = pci_ioremap_bar(pdev, 0); | |
1758 | if (!hw->hw_addr) { | |
1759 | dev_err(&pdev->dev, "cannot map device registers\n"); | |
1760 | err = -EIO; | |
1761 | goto out_free_netdev; | |
1762 | } | |
1763 | ||
1764 | netdev->netdev_ops = &alx_netdev_ops; | |
7ad24ea4 | 1765 | netdev->ethtool_ops = &alx_ethtool_ops; |
f3297f68 | 1766 | netdev->irq = pci_irq_vector(pdev, 0); |
ab69bde6 JB |
1767 | netdev->watchdog_timeo = ALX_WATCHDOG_TIME; |
1768 | ||
1769 | if (ent->driver_data & ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG) | |
1770 | pdev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; | |
1771 | ||
1772 | err = alx_init_sw(alx); | |
1773 | if (err) { | |
1774 | dev_err(&pdev->dev, "net device private data init failed\n"); | |
1775 | goto out_unmap; | |
1776 | } | |
1777 | ||
1778 | alx_reset_pcie(hw); | |
1779 | ||
1780 | phy_configured = alx_phy_configured(hw); | |
1781 | ||
1782 | if (!phy_configured) | |
1783 | alx_reset_phy(hw); | |
1784 | ||
1785 | err = alx_reset_mac(hw); | |
1786 | if (err) { | |
1787 | dev_err(&pdev->dev, "MAC Reset failed, error = %d\n", err); | |
1788 | goto out_unmap; | |
1789 | } | |
1790 | ||
1791 | /* setup link to put it in a known good starting state */ | |
1792 | if (!phy_configured) { | |
1793 | err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl); | |
1794 | if (err) { | |
1795 | dev_err(&pdev->dev, | |
1796 | "failed to configure PHY speed/duplex (err=%d)\n", | |
1797 | err); | |
1798 | goto out_unmap; | |
1799 | } | |
1800 | } | |
1801 | ||
ab725983 TR |
1802 | netdev->hw_features = NETIF_F_SG | |
1803 | NETIF_F_HW_CSUM | | |
3a7f75e5 | 1804 | NETIF_F_RXCSUM | |
ab725983 TR |
1805 | NETIF_F_TSO | |
1806 | NETIF_F_TSO6; | |
ab69bde6 JB |
1807 | |
1808 | if (alx_get_perm_macaddr(hw, hw->perm_addr)) { | |
1809 | dev_warn(&pdev->dev, | |
1810 | "Invalid permanent address programmed, using random one\n"); | |
1811 | eth_hw_addr_random(netdev); | |
1812 | memcpy(hw->perm_addr, netdev->dev_addr, netdev->addr_len); | |
1813 | } | |
1814 | ||
1815 | memcpy(hw->mac_addr, hw->perm_addr, ETH_ALEN); | |
1816 | memcpy(netdev->dev_addr, hw->mac_addr, ETH_ALEN); | |
1817 | memcpy(netdev->perm_addr, hw->perm_addr, ETH_ALEN); | |
1818 | ||
1819 | hw->mdio.prtad = 0; | |
1820 | hw->mdio.mmds = 0; | |
1821 | hw->mdio.dev = netdev; | |
1822 | hw->mdio.mode_support = MDIO_SUPPORTS_C45 | | |
1823 | MDIO_SUPPORTS_C22 | | |
1824 | MDIO_EMULATE_C22; | |
1825 | hw->mdio.mdio_read = alx_mdio_read; | |
1826 | hw->mdio.mdio_write = alx_mdio_write; | |
1827 | ||
1828 | if (!alx_get_phy_info(hw)) { | |
1829 | dev_err(&pdev->dev, "failed to identify PHY\n"); | |
1830 | err = -EIO; | |
1831 | goto out_unmap; | |
1832 | } | |
1833 | ||
1834 | INIT_WORK(&alx->link_check_wk, alx_link_check); | |
1835 | INIT_WORK(&alx->reset_wk, alx_reset); | |
ab69bde6 JB |
1836 | netif_carrier_off(netdev); |
1837 | ||
1838 | err = register_netdev(netdev); | |
1839 | if (err) { | |
1840 | dev_err(&pdev->dev, "register netdevice failed\n"); | |
1841 | goto out_unmap; | |
1842 | } | |
1843 | ||
ab69bde6 JB |
1844 | netdev_info(netdev, |
1845 | "Qualcomm Atheros AR816x/AR817x Ethernet [%pM]\n", | |
1846 | netdev->dev_addr); | |
1847 | ||
1848 | return 0; | |
1849 | ||
1850 | out_unmap: | |
1851 | iounmap(hw->hw_addr); | |
1852 | out_free_netdev: | |
1853 | free_netdev(netdev); | |
1854 | out_pci_release: | |
caa8e932 | 1855 | pci_release_mem_regions(pdev); |
ab69bde6 JB |
1856 | out_pci_disable: |
1857 | pci_disable_device(pdev); | |
1858 | return err; | |
1859 | } | |
1860 | ||
1861 | static void alx_remove(struct pci_dev *pdev) | |
1862 | { | |
1863 | struct alx_priv *alx = pci_get_drvdata(pdev); | |
1864 | struct alx_hw *hw = &alx->hw; | |
1865 | ||
1866 | cancel_work_sync(&alx->link_check_wk); | |
1867 | cancel_work_sync(&alx->reset_wk); | |
1868 | ||
1869 | /* restore permanent mac address */ | |
1870 | alx_set_macaddr(hw, hw->perm_addr); | |
1871 | ||
1872 | unregister_netdev(alx->dev); | |
1873 | iounmap(hw->hw_addr); | |
caa8e932 | 1874 | pci_release_mem_regions(pdev); |
ab69bde6 JB |
1875 | |
1876 | pci_disable_pcie_error_reporting(pdev); | |
1877 | pci_disable_device(pdev); | |
ab69bde6 JB |
1878 | |
1879 | free_netdev(alx->dev); | |
1880 | } | |
1881 | ||
1882 | #ifdef CONFIG_PM_SLEEP | |
1883 | static int alx_suspend(struct device *dev) | |
1884 | { | |
1885 | struct pci_dev *pdev = to_pci_dev(dev); | |
bc2bebe8 | 1886 | struct alx_priv *alx = pci_get_drvdata(pdev); |
ab69bde6 | 1887 | |
bc2bebe8 JB |
1888 | if (!netif_running(alx->dev)) |
1889 | return 0; | |
1890 | netif_device_detach(alx->dev); | |
1891 | __alx_stop(alx); | |
ab69bde6 JB |
1892 | return 0; |
1893 | } | |
1894 | ||
1895 | static int alx_resume(struct device *dev) | |
1896 | { | |
1897 | struct pci_dev *pdev = to_pci_dev(dev); | |
1898 | struct alx_priv *alx = pci_get_drvdata(pdev); | |
b54629e2 | 1899 | struct alx_hw *hw = &alx->hw; |
1900 | ||
1901 | alx_reset_phy(hw); | |
ab69bde6 | 1902 | |
bc2bebe8 JB |
1903 | if (!netif_running(alx->dev)) |
1904 | return 0; | |
1905 | netif_device_attach(alx->dev); | |
1906 | return __alx_open(alx, true); | |
ab69bde6 | 1907 | } |
bc2bebe8 JB |
1908 | |
1909 | static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume); | |
1910 | #define ALX_PM_OPS (&alx_pm_ops) | |
1911 | #else | |
1912 | #define ALX_PM_OPS NULL | |
ab69bde6 JB |
1913 | #endif |
1914 | ||
bc2bebe8 | 1915 | |
ab69bde6 JB |
1916 | static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev, |
1917 | pci_channel_state_t state) | |
1918 | { | |
1919 | struct alx_priv *alx = pci_get_drvdata(pdev); | |
1920 | struct net_device *netdev = alx->dev; | |
1921 | pci_ers_result_t rc = PCI_ERS_RESULT_NEED_RESET; | |
1922 | ||
1923 | dev_info(&pdev->dev, "pci error detected\n"); | |
1924 | ||
1925 | rtnl_lock(); | |
1926 | ||
1927 | if (netif_running(netdev)) { | |
1928 | netif_device_detach(netdev); | |
1929 | alx_halt(alx); | |
1930 | } | |
1931 | ||
1932 | if (state == pci_channel_io_perm_failure) | |
1933 | rc = PCI_ERS_RESULT_DISCONNECT; | |
1934 | else | |
1935 | pci_disable_device(pdev); | |
1936 | ||
1937 | rtnl_unlock(); | |
1938 | ||
1939 | return rc; | |
1940 | } | |
1941 | ||
1942 | static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev) | |
1943 | { | |
1944 | struct alx_priv *alx = pci_get_drvdata(pdev); | |
1945 | struct alx_hw *hw = &alx->hw; | |
1946 | pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; | |
1947 | ||
1948 | dev_info(&pdev->dev, "pci error slot reset\n"); | |
1949 | ||
1950 | rtnl_lock(); | |
1951 | ||
1952 | if (pci_enable_device(pdev)) { | |
1953 | dev_err(&pdev->dev, "Failed to re-enable PCI device after reset\n"); | |
1954 | goto out; | |
1955 | } | |
1956 | ||
1957 | pci_set_master(pdev); | |
ab69bde6 JB |
1958 | |
1959 | alx_reset_pcie(hw); | |
1960 | if (!alx_reset_mac(hw)) | |
1961 | rc = PCI_ERS_RESULT_RECOVERED; | |
1962 | out: | |
1963 | pci_cleanup_aer_uncorrect_error_status(pdev); | |
1964 | ||
1965 | rtnl_unlock(); | |
1966 | ||
1967 | return rc; | |
1968 | } | |
1969 | ||
1970 | static void alx_pci_error_resume(struct pci_dev *pdev) | |
1971 | { | |
1972 | struct alx_priv *alx = pci_get_drvdata(pdev); | |
1973 | struct net_device *netdev = alx->dev; | |
1974 | ||
1975 | dev_info(&pdev->dev, "pci error resume\n"); | |
1976 | ||
1977 | rtnl_lock(); | |
1978 | ||
1979 | if (netif_running(netdev)) { | |
1980 | alx_activate(alx); | |
1981 | netif_device_attach(netdev); | |
1982 | } | |
1983 | ||
1984 | rtnl_unlock(); | |
1985 | } | |
1986 | ||
1987 | static const struct pci_error_handlers alx_err_handlers = { | |
1988 | .error_detected = alx_pci_error_detected, | |
1989 | .slot_reset = alx_pci_error_slot_reset, | |
1990 | .resume = alx_pci_error_resume, | |
1991 | }; | |
1992 | ||
9baa3c34 | 1993 | static const struct pci_device_id alx_pci_tbl[] = { |
ab69bde6 JB |
1994 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8161), |
1995 | .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, | |
1996 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200), | |
1997 | .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, | |
0208e951 BP |
1998 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2400), |
1999 | .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, | |
b99b43bb OL |
2000 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2500), |
2001 | .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, | |
ab69bde6 JB |
2002 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162), |
2003 | .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, | |
2004 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) }, | |
2005 | { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8172) }, | |
2006 | {} | |
2007 | }; | |
2008 | ||
2009 | static struct pci_driver alx_driver = { | |
2010 | .name = alx_drv_name, | |
2011 | .id_table = alx_pci_tbl, | |
2012 | .probe = alx_probe, | |
2013 | .remove = alx_remove, | |
ab69bde6 JB |
2014 | .err_handler = &alx_err_handlers, |
2015 | .driver.pm = ALX_PM_OPS, | |
2016 | }; | |
2017 | ||
2018 | module_pci_driver(alx_driver); | |
2019 | MODULE_DEVICE_TABLE(pci, alx_pci_tbl); | |
2020 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | |
2021 | MODULE_AUTHOR("Qualcomm Corporation, <nic-devel@qualcomm.com>"); | |
2022 | MODULE_DESCRIPTION( | |
2023 | "Qualcomm Atheros(R) AR816x/AR817x PCI-E Ethernet Network Driver"); | |
2024 | MODULE_LICENSE("GPL"); |