1ab69bde6SJohannes Berg /*
24a5fe57eSJohannes Berg * Copyright (c) 2013, 2021 Johannes Berg <johannes@sipsolutions.net>
3ab69bde6SJohannes Berg *
4ab69bde6SJohannes Berg * This file is free software: you may copy, redistribute and/or modify it
5ab69bde6SJohannes Berg * under the terms of the GNU General Public License as published by the
6ab69bde6SJohannes Berg * Free Software Foundation, either version 2 of the License, or (at your
7ab69bde6SJohannes Berg * option) any later version.
8ab69bde6SJohannes Berg *
9ab69bde6SJohannes Berg * This file is distributed in the hope that it will be useful, but
10ab69bde6SJohannes Berg * WITHOUT ANY WARRANTY; without even the implied warranty of
11ab69bde6SJohannes Berg * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12ab69bde6SJohannes Berg * General Public License for more details.
13ab69bde6SJohannes Berg *
14ab69bde6SJohannes Berg * You should have received a copy of the GNU General Public License
15ab69bde6SJohannes Berg * along with this program. If not, see <http://www.gnu.org/licenses/>.
16ab69bde6SJohannes Berg *
17ab69bde6SJohannes Berg * This file incorporates work covered by the following copyright and
18ab69bde6SJohannes Berg * permission notice:
19ab69bde6SJohannes Berg *
20ab69bde6SJohannes Berg * Copyright (c) 2012 Qualcomm Atheros, Inc.
21ab69bde6SJohannes Berg *
22ab69bde6SJohannes Berg * Permission to use, copy, modify, and/or distribute this software for any
23ab69bde6SJohannes Berg * purpose with or without fee is hereby granted, provided that the above
24ab69bde6SJohannes Berg * copyright notice and this permission notice appear in all copies.
25ab69bde6SJohannes Berg *
26ab69bde6SJohannes Berg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
27ab69bde6SJohannes Berg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
28ab69bde6SJohannes Berg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
29ab69bde6SJohannes Berg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
30ab69bde6SJohannes Berg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
31ab69bde6SJohannes Berg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
32ab69bde6SJohannes Berg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33ab69bde6SJohannes Berg */
34ab69bde6SJohannes Berg
35ab69bde6SJohannes Berg #include <linux/module.h>
36ab69bde6SJohannes Berg #include <linux/pci.h>
37ab69bde6SJohannes Berg #include <linux/interrupt.h>
38ab69bde6SJohannes Berg #include <linux/ip.h>
39ab69bde6SJohannes Berg #include <linux/ipv6.h>
40ab69bde6SJohannes Berg #include <linux/if_vlan.h>
41ab69bde6SJohannes Berg #include <linux/mdio.h>
42ab69bde6SJohannes Berg #include <linux/bitops.h>
43ab69bde6SJohannes Berg #include <linux/netdevice.h>
44ab69bde6SJohannes Berg #include <linux/etherdevice.h>
45ab69bde6SJohannes Berg #include <net/ip6_checksum.h>
46ab69bde6SJohannes Berg #include <linux/crc32.h>
47ab69bde6SJohannes Berg #include "alx.h"
48ab69bde6SJohannes Berg #include "hw.h"
49ab69bde6SJohannes Berg #include "reg.h"
50ab69bde6SJohannes Berg
5171311931SRasmus Villemoes static const char alx_drv_name[] = "alx";
52ab69bde6SJohannes Berg
alx_free_txbuf(struct alx_tx_queue * txq,int entry)53702e8418STobias Regnery static void alx_free_txbuf(struct alx_tx_queue *txq, int entry)
54ab69bde6SJohannes Berg {
55702e8418STobias Regnery struct alx_buffer *txb = &txq->bufs[entry];
56ab69bde6SJohannes Berg
57ab69bde6SJohannes Berg if (dma_unmap_len(txb, size)) {
58702e8418STobias Regnery dma_unmap_single(txq->dev,
59ab69bde6SJohannes Berg dma_unmap_addr(txb, dma),
60ab69bde6SJohannes Berg dma_unmap_len(txb, size),
61ab69bde6SJohannes Berg DMA_TO_DEVICE);
62ab69bde6SJohannes Berg dma_unmap_len_set(txb, size, 0);
63ab69bde6SJohannes Berg }
64ab69bde6SJohannes Berg
65ab69bde6SJohannes Berg if (txb->skb) {
66ab69bde6SJohannes Berg dev_kfree_skb_any(txb->skb);
67ab69bde6SJohannes Berg txb->skb = NULL;
68ab69bde6SJohannes Berg }
69ab69bde6SJohannes Berg }
70ab69bde6SJohannes Berg
alx_refill_rx_ring(struct alx_priv * alx,gfp_t gfp)71ab69bde6SJohannes Berg static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp)
72ab69bde6SJohannes Berg {
73702e8418STobias Regnery struct alx_rx_queue *rxq = alx->qnapi[0]->rxq;
74ab69bde6SJohannes Berg struct sk_buff *skb;
75ab69bde6SJohannes Berg struct alx_buffer *cur_buf;
76ab69bde6SJohannes Berg dma_addr_t dma;
77ab69bde6SJohannes Berg u16 cur, next, count = 0;
78ab69bde6SJohannes Berg
79ab69bde6SJohannes Berg next = cur = rxq->write_idx;
80ab69bde6SJohannes Berg if (++next == alx->rx_ringsz)
81ab69bde6SJohannes Berg next = 0;
82ab69bde6SJohannes Berg cur_buf = &rxq->bufs[cur];
83ab69bde6SJohannes Berg
84ab69bde6SJohannes Berg while (!cur_buf->skb && next != rxq->read_idx) {
85ab69bde6SJohannes Berg struct alx_rfd *rfd = &rxq->rfd[cur];
86ab69bde6SJohannes Berg
87881d0327SFeng Tang /*
88881d0327SFeng Tang * When DMA RX address is set to something like
89881d0327SFeng Tang * 0x....fc0, it will be very likely to cause DMA
90881d0327SFeng Tang * RFD overflow issue.
91881d0327SFeng Tang *
92881d0327SFeng Tang * To work around it, we apply rx skb with 64 bytes
93881d0327SFeng Tang * longer space, and offset the address whenever
94881d0327SFeng Tang * 0x....fc0 is detected.
95881d0327SFeng Tang */
96881d0327SFeng Tang skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size + 64, gfp);
97ab69bde6SJohannes Berg if (!skb)
98ab69bde6SJohannes Berg break;
99881d0327SFeng Tang
100881d0327SFeng Tang if (((unsigned long)skb->data & 0xfff) == 0xfc0)
101881d0327SFeng Tang skb_reserve(skb, 64);
102881d0327SFeng Tang
103ab69bde6SJohannes Berg dma = dma_map_single(&alx->hw.pdev->dev,
104ab69bde6SJohannes Berg skb->data, alx->rxbuf_size,
105ab69bde6SJohannes Berg DMA_FROM_DEVICE);
106ab69bde6SJohannes Berg if (dma_mapping_error(&alx->hw.pdev->dev, dma)) {
107ab69bde6SJohannes Berg dev_kfree_skb(skb);
108ab69bde6SJohannes Berg break;
109ab69bde6SJohannes Berg }
110ab69bde6SJohannes Berg
111ab69bde6SJohannes Berg /* Unfortunately, RX descriptor buffers must be 4-byte
112ab69bde6SJohannes Berg * aligned, so we can't use IP alignment.
113ab69bde6SJohannes Berg */
114ab69bde6SJohannes Berg if (WARN_ON(dma & 3)) {
115ab69bde6SJohannes Berg dev_kfree_skb(skb);
116ab69bde6SJohannes Berg break;
117ab69bde6SJohannes Berg }
118ab69bde6SJohannes Berg
119ab69bde6SJohannes Berg cur_buf->skb = skb;
120ab69bde6SJohannes Berg dma_unmap_len_set(cur_buf, size, alx->rxbuf_size);
121ab69bde6SJohannes Berg dma_unmap_addr_set(cur_buf, dma, dma);
122ab69bde6SJohannes Berg rfd->addr = cpu_to_le64(dma);
123ab69bde6SJohannes Berg
124ab69bde6SJohannes Berg cur = next;
125ab69bde6SJohannes Berg if (++next == alx->rx_ringsz)
126ab69bde6SJohannes Berg next = 0;
127ab69bde6SJohannes Berg cur_buf = &rxq->bufs[cur];
128ab69bde6SJohannes Berg count++;
129ab69bde6SJohannes Berg }
130ab69bde6SJohannes Berg
131ab69bde6SJohannes Berg if (count) {
132ab69bde6SJohannes Berg /* flush all updates before updating hardware */
133ab69bde6SJohannes Berg wmb();
134ab69bde6SJohannes Berg rxq->write_idx = cur;
135ab69bde6SJohannes Berg alx_write_mem16(&alx->hw, ALX_RFD_PIDX, cur);
136ab69bde6SJohannes Berg }
137ab69bde6SJohannes Berg
138ab69bde6SJohannes Berg return count;
139ab69bde6SJohannes Berg }
140ab69bde6SJohannes Berg
alx_tx_queue_mapping(struct alx_priv * alx,struct sk_buff * skb)1412e06826bSTobias Regnery static struct alx_tx_queue *alx_tx_queue_mapping(struct alx_priv *alx,
1422e06826bSTobias Regnery struct sk_buff *skb)
1432e06826bSTobias Regnery {
1442e06826bSTobias Regnery unsigned int r_idx = skb->queue_mapping;
1452e06826bSTobias Regnery
1462e06826bSTobias Regnery if (r_idx >= alx->num_txq)
1472e06826bSTobias Regnery r_idx = r_idx % alx->num_txq;
1482e06826bSTobias Regnery
1492e06826bSTobias Regnery return alx->qnapi[r_idx]->txq;
1502e06826bSTobias Regnery }
1512e06826bSTobias Regnery
alx_get_tx_queue(const struct alx_tx_queue * txq)1522e06826bSTobias Regnery static struct netdev_queue *alx_get_tx_queue(const struct alx_tx_queue *txq)
1532e06826bSTobias Regnery {
1542e06826bSTobias Regnery return netdev_get_tx_queue(txq->netdev, txq->queue_idx);
1552e06826bSTobias Regnery }
1562e06826bSTobias Regnery
alx_tpd_avail(struct alx_tx_queue * txq)157702e8418STobias Regnery static inline int alx_tpd_avail(struct alx_tx_queue *txq)
158ab69bde6SJohannes Berg {
159ab69bde6SJohannes Berg if (txq->write_idx >= txq->read_idx)
160702e8418STobias Regnery return txq->count + txq->read_idx - txq->write_idx - 1;
161ab69bde6SJohannes Berg return txq->read_idx - txq->write_idx - 1;
162ab69bde6SJohannes Berg }
163ab69bde6SJohannes Berg
alx_clean_tx_irq(struct alx_tx_queue * txq)164702e8418STobias Regnery static bool alx_clean_tx_irq(struct alx_tx_queue *txq)
165ab69bde6SJohannes Berg {
166702e8418STobias Regnery struct alx_priv *alx;
1672e06826bSTobias Regnery struct netdev_queue *tx_queue;
168ab69bde6SJohannes Berg u16 hw_read_idx, sw_read_idx;
169ab69bde6SJohannes Berg unsigned int total_bytes = 0, total_packets = 0;
170ab69bde6SJohannes Berg int budget = ALX_DEFAULT_TX_WORK;
171ab69bde6SJohannes Berg
172702e8418STobias Regnery alx = netdev_priv(txq->netdev);
1732e06826bSTobias Regnery tx_queue = alx_get_tx_queue(txq);
174702e8418STobias Regnery
175ab69bde6SJohannes Berg sw_read_idx = txq->read_idx;
1762e06826bSTobias Regnery hw_read_idx = alx_read_mem16(&alx->hw, txq->c_reg);
177ab69bde6SJohannes Berg
178ab69bde6SJohannes Berg if (sw_read_idx != hw_read_idx) {
179ab69bde6SJohannes Berg while (sw_read_idx != hw_read_idx && budget > 0) {
180ab69bde6SJohannes Berg struct sk_buff *skb;
181ab69bde6SJohannes Berg
182ab69bde6SJohannes Berg skb = txq->bufs[sw_read_idx].skb;
183ab69bde6SJohannes Berg if (skb) {
184ab69bde6SJohannes Berg total_bytes += skb->len;
185ab69bde6SJohannes Berg total_packets++;
186ab69bde6SJohannes Berg budget--;
187ab69bde6SJohannes Berg }
188ab69bde6SJohannes Berg
189702e8418STobias Regnery alx_free_txbuf(txq, sw_read_idx);
190ab69bde6SJohannes Berg
191702e8418STobias Regnery if (++sw_read_idx == txq->count)
192ab69bde6SJohannes Berg sw_read_idx = 0;
193ab69bde6SJohannes Berg }
194ab69bde6SJohannes Berg txq->read_idx = sw_read_idx;
195ab69bde6SJohannes Berg
1962e06826bSTobias Regnery netdev_tx_completed_queue(tx_queue, total_packets, total_bytes);
197ab69bde6SJohannes Berg }
198ab69bde6SJohannes Berg
1992e06826bSTobias Regnery if (netif_tx_queue_stopped(tx_queue) && netif_carrier_ok(alx->dev) &&
200702e8418STobias Regnery alx_tpd_avail(txq) > txq->count / 4)
2012e06826bSTobias Regnery netif_tx_wake_queue(tx_queue);
202ab69bde6SJohannes Berg
203ab69bde6SJohannes Berg return sw_read_idx == hw_read_idx;
204ab69bde6SJohannes Berg }
205ab69bde6SJohannes Berg
alx_schedule_link_check(struct alx_priv * alx)206ab69bde6SJohannes Berg static void alx_schedule_link_check(struct alx_priv *alx)
207ab69bde6SJohannes Berg {
208ab69bde6SJohannes Berg schedule_work(&alx->link_check_wk);
209ab69bde6SJohannes Berg }
210ab69bde6SJohannes Berg
alx_schedule_reset(struct alx_priv * alx)211ab69bde6SJohannes Berg static void alx_schedule_reset(struct alx_priv *alx)
212ab69bde6SJohannes Berg {
213ab69bde6SJohannes Berg schedule_work(&alx->reset_wk);
214ab69bde6SJohannes Berg }
215ab69bde6SJohannes Berg
alx_clean_rx_irq(struct alx_rx_queue * rxq,int budget)216702e8418STobias Regnery static int alx_clean_rx_irq(struct alx_rx_queue *rxq, int budget)
217ab69bde6SJohannes Berg {
218702e8418STobias Regnery struct alx_priv *alx;
219ab69bde6SJohannes Berg struct alx_rrd *rrd;
220ab69bde6SJohannes Berg struct alx_buffer *rxb;
221ab69bde6SJohannes Berg struct sk_buff *skb;
222ab69bde6SJohannes Berg u16 length, rfd_cleaned = 0;
2237a05dc64SEric Dumazet int work = 0;
224ab69bde6SJohannes Berg
225702e8418STobias Regnery alx = netdev_priv(rxq->netdev);
226702e8418STobias Regnery
2277a05dc64SEric Dumazet while (work < budget) {
228ab69bde6SJohannes Berg rrd = &rxq->rrd[rxq->rrd_read_idx];
229ab69bde6SJohannes Berg if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT)))
230ab69bde6SJohannes Berg break;
231ab69bde6SJohannes Berg rrd->word3 &= ~cpu_to_le32(1 << RRD_UPDATED_SHIFT);
232ab69bde6SJohannes Berg
233ab69bde6SJohannes Berg if (ALX_GET_FIELD(le32_to_cpu(rrd->word0),
234ab69bde6SJohannes Berg RRD_SI) != rxq->read_idx ||
235ab69bde6SJohannes Berg ALX_GET_FIELD(le32_to_cpu(rrd->word0),
236ab69bde6SJohannes Berg RRD_NOR) != 1) {
237ab69bde6SJohannes Berg alx_schedule_reset(alx);
2387a05dc64SEric Dumazet return work;
239ab69bde6SJohannes Berg }
240ab69bde6SJohannes Berg
241ab69bde6SJohannes Berg rxb = &rxq->bufs[rxq->read_idx];
242702e8418STobias Regnery dma_unmap_single(rxq->dev,
243ab69bde6SJohannes Berg dma_unmap_addr(rxb, dma),
244ab69bde6SJohannes Berg dma_unmap_len(rxb, size),
245ab69bde6SJohannes Berg DMA_FROM_DEVICE);
246ab69bde6SJohannes Berg dma_unmap_len_set(rxb, size, 0);
247ab69bde6SJohannes Berg skb = rxb->skb;
248ab69bde6SJohannes Berg rxb->skb = NULL;
249ab69bde6SJohannes Berg
250ab69bde6SJohannes Berg if (rrd->word3 & cpu_to_le32(1 << RRD_ERR_RES_SHIFT) ||
251ab69bde6SJohannes Berg rrd->word3 & cpu_to_le32(1 << RRD_ERR_LEN_SHIFT)) {
252ab69bde6SJohannes Berg rrd->word3 = 0;
253ab69bde6SJohannes Berg dev_kfree_skb_any(skb);
254ab69bde6SJohannes Berg goto next_pkt;
255ab69bde6SJohannes Berg }
256ab69bde6SJohannes Berg
257ab69bde6SJohannes Berg length = ALX_GET_FIELD(le32_to_cpu(rrd->word3),
258ab69bde6SJohannes Berg RRD_PKTLEN) - ETH_FCS_LEN;
259ab69bde6SJohannes Berg skb_put(skb, length);
260702e8418STobias Regnery skb->protocol = eth_type_trans(skb, rxq->netdev);
261ab69bde6SJohannes Berg
262ab69bde6SJohannes Berg skb_checksum_none_assert(skb);
263ab69bde6SJohannes Berg if (alx->dev->features & NETIF_F_RXCSUM &&
264ab69bde6SJohannes Berg !(rrd->word3 & (cpu_to_le32(1 << RRD_ERR_L4_SHIFT) |
265ab69bde6SJohannes Berg cpu_to_le32(1 << RRD_ERR_IPV4_SHIFT)))) {
266ab69bde6SJohannes Berg switch (ALX_GET_FIELD(le32_to_cpu(rrd->word2),
267ab69bde6SJohannes Berg RRD_PID)) {
268ab69bde6SJohannes Berg case RRD_PID_IPV6UDP:
269ab69bde6SJohannes Berg case RRD_PID_IPV4UDP:
270ab69bde6SJohannes Berg case RRD_PID_IPV4TCP:
271ab69bde6SJohannes Berg case RRD_PID_IPV6TCP:
272ab69bde6SJohannes Berg skb->ip_summed = CHECKSUM_UNNECESSARY;
273ab69bde6SJohannes Berg break;
274ab69bde6SJohannes Berg }
275ab69bde6SJohannes Berg }
276ab69bde6SJohannes Berg
277702e8418STobias Regnery napi_gro_receive(&rxq->np->napi, skb);
2787a05dc64SEric Dumazet work++;
279ab69bde6SJohannes Berg
280ab69bde6SJohannes Berg next_pkt:
281702e8418STobias Regnery if (++rxq->read_idx == rxq->count)
282ab69bde6SJohannes Berg rxq->read_idx = 0;
283702e8418STobias Regnery if (++rxq->rrd_read_idx == rxq->count)
284ab69bde6SJohannes Berg rxq->rrd_read_idx = 0;
285ab69bde6SJohannes Berg
286ab69bde6SJohannes Berg if (++rfd_cleaned > ALX_RX_ALLOC_THRESH)
287ab69bde6SJohannes Berg rfd_cleaned -= alx_refill_rx_ring(alx, GFP_ATOMIC);
288ab69bde6SJohannes Berg }
289ab69bde6SJohannes Berg
290ab69bde6SJohannes Berg if (rfd_cleaned)
291ab69bde6SJohannes Berg alx_refill_rx_ring(alx, GFP_ATOMIC);
292ab69bde6SJohannes Berg
2937a05dc64SEric Dumazet return work;
294ab69bde6SJohannes Berg }
295ab69bde6SJohannes Berg
alx_poll(struct napi_struct * napi,int budget)296ab69bde6SJohannes Berg static int alx_poll(struct napi_struct *napi, int budget)
297ab69bde6SJohannes Berg {
298702e8418STobias Regnery struct alx_napi *np = container_of(napi, struct alx_napi, napi);
299702e8418STobias Regnery struct alx_priv *alx = np->alx;
300ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
301ab69bde6SJohannes Berg unsigned long flags;
302e0eac254STobias Regnery bool tx_complete = true;
303e0eac254STobias Regnery int work = 0;
304ab69bde6SJohannes Berg
305e0eac254STobias Regnery if (np->txq)
306702e8418STobias Regnery tx_complete = alx_clean_tx_irq(np->txq);
307e0eac254STobias Regnery if (np->rxq)
308702e8418STobias Regnery work = alx_clean_rx_irq(np->rxq, budget);
309ab69bde6SJohannes Berg
3107a05dc64SEric Dumazet if (!tx_complete || work == budget)
3117a05dc64SEric Dumazet return budget;
312ab69bde6SJohannes Berg
3136ad20165SEric Dumazet napi_complete_done(&np->napi, work);
314ab69bde6SJohannes Berg
315ab69bde6SJohannes Berg /* enable interrupt */
316f3297f68SChristoph Hellwig if (alx->hw.pdev->msix_enabled) {
317e0eac254STobias Regnery alx_mask_msix(hw, np->vec_idx, false);
318dc39a78bSTobias Regnery } else {
319ab69bde6SJohannes Berg spin_lock_irqsave(&alx->irq_lock, flags);
320ab69bde6SJohannes Berg alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0;
321ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_IMR, alx->int_mask);
322ab69bde6SJohannes Berg spin_unlock_irqrestore(&alx->irq_lock, flags);
323dc39a78bSTobias Regnery }
324ab69bde6SJohannes Berg
325ab69bde6SJohannes Berg alx_post_write(hw);
326ab69bde6SJohannes Berg
3277a05dc64SEric Dumazet return work;
328ab69bde6SJohannes Berg }
329ab69bde6SJohannes Berg
alx_intr_handle_misc(struct alx_priv * alx,u32 intr)330a0373aefSTobias Regnery static bool alx_intr_handle_misc(struct alx_priv *alx, u32 intr)
331ab69bde6SJohannes Berg {
332ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
333ab69bde6SJohannes Berg
334ab69bde6SJohannes Berg if (intr & ALX_ISR_FATAL) {
335ab69bde6SJohannes Berg netif_warn(alx, hw, alx->dev,
336ab69bde6SJohannes Berg "fatal interrupt 0x%x, resetting\n", intr);
337ab69bde6SJohannes Berg alx_schedule_reset(alx);
338a0373aefSTobias Regnery return true;
339ab69bde6SJohannes Berg }
340ab69bde6SJohannes Berg
341ab69bde6SJohannes Berg if (intr & ALX_ISR_ALERT)
342ab69bde6SJohannes Berg netdev_warn(alx->dev, "alert interrupt: 0x%x\n", intr);
343ab69bde6SJohannes Berg
344ab69bde6SJohannes Berg if (intr & ALX_ISR_PHY) {
345ab69bde6SJohannes Berg /* suppress PHY interrupt, because the source
346ab69bde6SJohannes Berg * is from PHY internal. only the internal status
347ab69bde6SJohannes Berg * is cleared, the interrupt status could be cleared.
348ab69bde6SJohannes Berg */
349ab69bde6SJohannes Berg alx->int_mask &= ~ALX_ISR_PHY;
350a0373aefSTobias Regnery alx_write_mem32(hw, ALX_IMR, alx->int_mask);
351ab69bde6SJohannes Berg alx_schedule_link_check(alx);
352ab69bde6SJohannes Berg }
353ab69bde6SJohannes Berg
354a0373aefSTobias Regnery return false;
355a0373aefSTobias Regnery }
356a0373aefSTobias Regnery
alx_intr_handle(struct alx_priv * alx,u32 intr)357a0373aefSTobias Regnery static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
358a0373aefSTobias Regnery {
359a0373aefSTobias Regnery struct alx_hw *hw = &alx->hw;
360a0373aefSTobias Regnery
361a0373aefSTobias Regnery spin_lock(&alx->irq_lock);
362a0373aefSTobias Regnery
363a0373aefSTobias Regnery /* ACK interrupt */
364a0373aefSTobias Regnery alx_write_mem32(hw, ALX_ISR, intr | ALX_ISR_DIS);
365a0373aefSTobias Regnery intr &= alx->int_mask;
366a0373aefSTobias Regnery
367a0373aefSTobias Regnery if (alx_intr_handle_misc(alx, intr))
368a0373aefSTobias Regnery goto out;
369a0373aefSTobias Regnery
370ab69bde6SJohannes Berg if (intr & (ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0)) {
371702e8418STobias Regnery napi_schedule(&alx->qnapi[0]->napi);
372ab69bde6SJohannes Berg /* mask rx/tx interrupt, enable them when napi complete */
373ab69bde6SJohannes Berg alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
374ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_IMR, alx->int_mask);
375a0373aefSTobias Regnery }
376ab69bde6SJohannes Berg
377ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_ISR, 0);
378ab69bde6SJohannes Berg
379ab69bde6SJohannes Berg out:
380ab69bde6SJohannes Berg spin_unlock(&alx->irq_lock);
381ab69bde6SJohannes Berg return IRQ_HANDLED;
382ab69bde6SJohannes Berg }
383ab69bde6SJohannes Berg
alx_intr_msix_ring(int irq,void * data)384dc39a78bSTobias Regnery static irqreturn_t alx_intr_msix_ring(int irq, void *data)
385dc39a78bSTobias Regnery {
386702e8418STobias Regnery struct alx_napi *np = data;
387702e8418STobias Regnery struct alx_hw *hw = &np->alx->hw;
388dc39a78bSTobias Regnery
389dc39a78bSTobias Regnery /* mask interrupt to ACK chip */
390e0eac254STobias Regnery alx_mask_msix(hw, np->vec_idx, true);
391dc39a78bSTobias Regnery /* clear interrupt status */
392e0eac254STobias Regnery alx_write_mem32(hw, ALX_ISR, np->vec_mask);
393dc39a78bSTobias Regnery
394702e8418STobias Regnery napi_schedule(&np->napi);
395dc39a78bSTobias Regnery
396dc39a78bSTobias Regnery return IRQ_HANDLED;
397dc39a78bSTobias Regnery }
398dc39a78bSTobias Regnery
alx_intr_msix_misc(int irq,void * data)399dc39a78bSTobias Regnery static irqreturn_t alx_intr_msix_misc(int irq, void *data)
400dc39a78bSTobias Regnery {
401dc39a78bSTobias Regnery struct alx_priv *alx = data;
402dc39a78bSTobias Regnery struct alx_hw *hw = &alx->hw;
403dc39a78bSTobias Regnery u32 intr;
404dc39a78bSTobias Regnery
405dc39a78bSTobias Regnery /* mask interrupt to ACK chip */
406dc39a78bSTobias Regnery alx_mask_msix(hw, 0, true);
407dc39a78bSTobias Regnery
408dc39a78bSTobias Regnery /* read interrupt status */
409dc39a78bSTobias Regnery intr = alx_read_mem32(hw, ALX_ISR);
410dc39a78bSTobias Regnery intr &= (alx->int_mask & ~ALX_ISR_ALL_QUEUES);
411dc39a78bSTobias Regnery
412dc39a78bSTobias Regnery if (alx_intr_handle_misc(alx, intr))
413dc39a78bSTobias Regnery return IRQ_HANDLED;
414dc39a78bSTobias Regnery
415dc39a78bSTobias Regnery /* clear interrupt status */
416dc39a78bSTobias Regnery alx_write_mem32(hw, ALX_ISR, intr);
417dc39a78bSTobias Regnery
418dc39a78bSTobias Regnery /* enable interrupt again */
419dc39a78bSTobias Regnery alx_mask_msix(hw, 0, false);
420dc39a78bSTobias Regnery
421dc39a78bSTobias Regnery return IRQ_HANDLED;
422dc39a78bSTobias Regnery }
423dc39a78bSTobias Regnery
alx_intr_msi(int irq,void * data)424ab69bde6SJohannes Berg static irqreturn_t alx_intr_msi(int irq, void *data)
425ab69bde6SJohannes Berg {
426ab69bde6SJohannes Berg struct alx_priv *alx = data;
427ab69bde6SJohannes Berg
428ab69bde6SJohannes Berg return alx_intr_handle(alx, alx_read_mem32(&alx->hw, ALX_ISR));
429ab69bde6SJohannes Berg }
430ab69bde6SJohannes Berg
alx_intr_legacy(int irq,void * data)431ab69bde6SJohannes Berg static irqreturn_t alx_intr_legacy(int irq, void *data)
432ab69bde6SJohannes Berg {
433ab69bde6SJohannes Berg struct alx_priv *alx = data;
434ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
435ab69bde6SJohannes Berg u32 intr;
436ab69bde6SJohannes Berg
437ab69bde6SJohannes Berg intr = alx_read_mem32(hw, ALX_ISR);
438ab69bde6SJohannes Berg
439ab69bde6SJohannes Berg if (intr & ALX_ISR_DIS || !(intr & alx->int_mask))
440ab69bde6SJohannes Berg return IRQ_NONE;
441ab69bde6SJohannes Berg
442ab69bde6SJohannes Berg return alx_intr_handle(alx, intr);
443ab69bde6SJohannes Berg }
444ab69bde6SJohannes Berg
445a4076d34STobias Regnery static const u16 txring_header_reg[] = {ALX_TPD_PRI0_ADDR_LO,
446a4076d34STobias Regnery ALX_TPD_PRI1_ADDR_LO,
447a4076d34STobias Regnery ALX_TPD_PRI2_ADDR_LO,
448a4076d34STobias Regnery ALX_TPD_PRI3_ADDR_LO};
449a4076d34STobias Regnery
alx_init_ring_ptrs(struct alx_priv * alx)450ab69bde6SJohannes Berg static void alx_init_ring_ptrs(struct alx_priv *alx)
451ab69bde6SJohannes Berg {
452ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
453ab69bde6SJohannes Berg u32 addr_hi = ((u64)alx->descmem.dma) >> 32;
454a4076d34STobias Regnery struct alx_napi *np;
455a4076d34STobias Regnery int i;
456ab69bde6SJohannes Berg
457a4076d34STobias Regnery for (i = 0; i < alx->num_napi; i++) {
458a4076d34STobias Regnery np = alx->qnapi[i];
459a4076d34STobias Regnery if (np->txq) {
460a4076d34STobias Regnery np->txq->read_idx = 0;
461a4076d34STobias Regnery np->txq->write_idx = 0;
462a4076d34STobias Regnery alx_write_mem32(hw,
463a4076d34STobias Regnery txring_header_reg[np->txq->queue_idx],
464a4076d34STobias Regnery np->txq->tpd_dma);
465a4076d34STobias Regnery }
466a4076d34STobias Regnery
467a4076d34STobias Regnery if (np->rxq) {
468702e8418STobias Regnery np->rxq->read_idx = 0;
469702e8418STobias Regnery np->rxq->write_idx = 0;
470702e8418STobias Regnery np->rxq->rrd_read_idx = 0;
471702e8418STobias Regnery alx_write_mem32(hw, ALX_RRD_ADDR_LO, np->rxq->rrd_dma);
472702e8418STobias Regnery alx_write_mem32(hw, ALX_RFD_ADDR_LO, np->rxq->rfd_dma);
473a4076d34STobias Regnery }
474a4076d34STobias Regnery }
475a4076d34STobias Regnery
476a4076d34STobias Regnery alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi);
477a4076d34STobias Regnery alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz);
478a4076d34STobias Regnery
479a4076d34STobias Regnery alx_write_mem32(hw, ALX_RX_BASE_ADDR_HI, addr_hi);
480a4076d34STobias Regnery alx_write_mem32(hw, ALX_RRD_RING_SZ, alx->rx_ringsz);
481ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_RFD_RING_SZ, alx->rx_ringsz);
482ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_RFD_BUF_SZ, alx->rxbuf_size);
483ab69bde6SJohannes Berg
484ab69bde6SJohannes Berg /* load these pointers into the chip */
485ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_SRAM9, ALX_SRAM_LOAD_PTR);
486ab69bde6SJohannes Berg }
487ab69bde6SJohannes Berg
alx_free_txring_buf(struct alx_tx_queue * txq)488702e8418STobias Regnery static void alx_free_txring_buf(struct alx_tx_queue *txq)
489ab69bde6SJohannes Berg {
490ab69bde6SJohannes Berg int i;
491ab69bde6SJohannes Berg
492ab69bde6SJohannes Berg if (!txq->bufs)
493ab69bde6SJohannes Berg return;
494ab69bde6SJohannes Berg
495702e8418STobias Regnery for (i = 0; i < txq->count; i++)
496702e8418STobias Regnery alx_free_txbuf(txq, i);
497ab69bde6SJohannes Berg
498702e8418STobias Regnery memset(txq->bufs, 0, txq->count * sizeof(struct alx_buffer));
499702e8418STobias Regnery memset(txq->tpd, 0, txq->count * sizeof(struct alx_txd));
500ab69bde6SJohannes Berg txq->write_idx = 0;
501ab69bde6SJohannes Berg txq->read_idx = 0;
502ab69bde6SJohannes Berg
5032e06826bSTobias Regnery netdev_tx_reset_queue(alx_get_tx_queue(txq));
504ab69bde6SJohannes Berg }
505ab69bde6SJohannes Berg
alx_free_rxring_buf(struct alx_rx_queue * rxq)506702e8418STobias Regnery static void alx_free_rxring_buf(struct alx_rx_queue *rxq)
507ab69bde6SJohannes Berg {
508ab69bde6SJohannes Berg struct alx_buffer *cur_buf;
509ab69bde6SJohannes Berg u16 i;
510ab69bde6SJohannes Berg
511a4076d34STobias Regnery if (!rxq->bufs)
512ab69bde6SJohannes Berg return;
513ab69bde6SJohannes Berg
514702e8418STobias Regnery for (i = 0; i < rxq->count; i++) {
515ab69bde6SJohannes Berg cur_buf = rxq->bufs + i;
516ab69bde6SJohannes Berg if (cur_buf->skb) {
517702e8418STobias Regnery dma_unmap_single(rxq->dev,
518ab69bde6SJohannes Berg dma_unmap_addr(cur_buf, dma),
519ab69bde6SJohannes Berg dma_unmap_len(cur_buf, size),
520ab69bde6SJohannes Berg DMA_FROM_DEVICE);
521ab69bde6SJohannes Berg dev_kfree_skb(cur_buf->skb);
522ab69bde6SJohannes Berg cur_buf->skb = NULL;
523ab69bde6SJohannes Berg dma_unmap_len_set(cur_buf, size, 0);
524ab69bde6SJohannes Berg dma_unmap_addr_set(cur_buf, dma, 0);
525ab69bde6SJohannes Berg }
526ab69bde6SJohannes Berg }
527ab69bde6SJohannes Berg
528ab69bde6SJohannes Berg rxq->write_idx = 0;
529ab69bde6SJohannes Berg rxq->read_idx = 0;
530ab69bde6SJohannes Berg rxq->rrd_read_idx = 0;
531ab69bde6SJohannes Berg }
532ab69bde6SJohannes Berg
alx_free_buffers(struct alx_priv * alx)533ab69bde6SJohannes Berg static void alx_free_buffers(struct alx_priv *alx)
534ab69bde6SJohannes Berg {
535a4076d34STobias Regnery int i;
536a4076d34STobias Regnery
537a4076d34STobias Regnery for (i = 0; i < alx->num_txq; i++)
538a4076d34STobias Regnery if (alx->qnapi[i] && alx->qnapi[i]->txq)
539a4076d34STobias Regnery alx_free_txring_buf(alx->qnapi[i]->txq);
540a4076d34STobias Regnery
541a4076d34STobias Regnery if (alx->qnapi[0] && alx->qnapi[0]->rxq)
542702e8418STobias Regnery alx_free_rxring_buf(alx->qnapi[0]->rxq);
543ab69bde6SJohannes Berg }
544ab69bde6SJohannes Berg
alx_reinit_rings(struct alx_priv * alx)545ab69bde6SJohannes Berg static int alx_reinit_rings(struct alx_priv *alx)
546ab69bde6SJohannes Berg {
547ab69bde6SJohannes Berg alx_free_buffers(alx);
548ab69bde6SJohannes Berg
549ab69bde6SJohannes Berg alx_init_ring_ptrs(alx);
550ab69bde6SJohannes Berg
551ab69bde6SJohannes Berg if (!alx_refill_rx_ring(alx, GFP_KERNEL))
552ab69bde6SJohannes Berg return -ENOMEM;
553ab69bde6SJohannes Berg
554ab69bde6SJohannes Berg return 0;
555ab69bde6SJohannes Berg }
556ab69bde6SJohannes Berg
alx_add_mc_addr(struct alx_hw * hw,const u8 * addr,u32 * mc_hash)557ab69bde6SJohannes Berg static void alx_add_mc_addr(struct alx_hw *hw, const u8 *addr, u32 *mc_hash)
558ab69bde6SJohannes Berg {
559ab69bde6SJohannes Berg u32 crc32, bit, reg;
560ab69bde6SJohannes Berg
561ab69bde6SJohannes Berg crc32 = ether_crc(ETH_ALEN, addr);
562ab69bde6SJohannes Berg reg = (crc32 >> 31) & 0x1;
563ab69bde6SJohannes Berg bit = (crc32 >> 26) & 0x1F;
564ab69bde6SJohannes Berg
565ab69bde6SJohannes Berg mc_hash[reg] |= BIT(bit);
566ab69bde6SJohannes Berg }
567ab69bde6SJohannes Berg
__alx_set_rx_mode(struct net_device * netdev)568ab69bde6SJohannes Berg static void __alx_set_rx_mode(struct net_device *netdev)
569ab69bde6SJohannes Berg {
570ab69bde6SJohannes Berg struct alx_priv *alx = netdev_priv(netdev);
571ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
572ab69bde6SJohannes Berg struct netdev_hw_addr *ha;
573ab69bde6SJohannes Berg u32 mc_hash[2] = {};
574ab69bde6SJohannes Berg
575ab69bde6SJohannes Berg if (!(netdev->flags & IFF_ALLMULTI)) {
576ab69bde6SJohannes Berg netdev_for_each_mc_addr(ha, netdev)
577ab69bde6SJohannes Berg alx_add_mc_addr(hw, ha->addr, mc_hash);
578ab69bde6SJohannes Berg
579ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_HASH_TBL0, mc_hash[0]);
580ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_HASH_TBL1, mc_hash[1]);
581ab69bde6SJohannes Berg }
582ab69bde6SJohannes Berg
583ab69bde6SJohannes Berg hw->rx_ctrl &= ~(ALX_MAC_CTRL_MULTIALL_EN | ALX_MAC_CTRL_PROMISC_EN);
584ab69bde6SJohannes Berg if (netdev->flags & IFF_PROMISC)
585ab69bde6SJohannes Berg hw->rx_ctrl |= ALX_MAC_CTRL_PROMISC_EN;
586ab69bde6SJohannes Berg if (netdev->flags & IFF_ALLMULTI)
587ab69bde6SJohannes Berg hw->rx_ctrl |= ALX_MAC_CTRL_MULTIALL_EN;
588ab69bde6SJohannes Berg
589ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
590ab69bde6SJohannes Berg }
591ab69bde6SJohannes Berg
alx_set_rx_mode(struct net_device * netdev)592ab69bde6SJohannes Berg static void alx_set_rx_mode(struct net_device *netdev)
593ab69bde6SJohannes Berg {
594ab69bde6SJohannes Berg __alx_set_rx_mode(netdev);
595ab69bde6SJohannes Berg }
596ab69bde6SJohannes Berg
alx_set_mac_address(struct net_device * netdev,void * data)597ab69bde6SJohannes Berg static int alx_set_mac_address(struct net_device *netdev, void *data)
598ab69bde6SJohannes Berg {
599ab69bde6SJohannes Berg struct alx_priv *alx = netdev_priv(netdev);
600ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
601ab69bde6SJohannes Berg struct sockaddr *addr = data;
602ab69bde6SJohannes Berg
603ab69bde6SJohannes Berg if (!is_valid_ether_addr(addr->sa_data))
604ab69bde6SJohannes Berg return -EADDRNOTAVAIL;
605ab69bde6SJohannes Berg
606ab69bde6SJohannes Berg if (netdev->addr_assign_type & NET_ADDR_RANDOM)
607ab69bde6SJohannes Berg netdev->addr_assign_type ^= NET_ADDR_RANDOM;
608ab69bde6SJohannes Berg
609a05e4c0aSJakub Kicinski eth_hw_addr_set(netdev, addr->sa_data);
610ab69bde6SJohannes Berg memcpy(hw->mac_addr, addr->sa_data, netdev->addr_len);
611ab69bde6SJohannes Berg alx_set_macaddr(hw, hw->mac_addr);
612ab69bde6SJohannes Berg
613ab69bde6SJohannes Berg return 0;
614ab69bde6SJohannes Berg }
615ab69bde6SJohannes Berg
alx_alloc_tx_ring(struct alx_priv * alx,struct alx_tx_queue * txq,int offset)6168c2a4c8eSTobias Regnery static int alx_alloc_tx_ring(struct alx_priv *alx, struct alx_tx_queue *txq,
6178c2a4c8eSTobias Regnery int offset)
618ab69bde6SJohannes Berg {
619702e8418STobias Regnery txq->bufs = kcalloc(txq->count, sizeof(struct alx_buffer), GFP_KERNEL);
6208c2a4c8eSTobias Regnery if (!txq->bufs)
621ab69bde6SJohannes Berg return -ENOMEM;
622ab69bde6SJohannes Berg
6238c2a4c8eSTobias Regnery txq->tpd = alx->descmem.virt + offset;
6248c2a4c8eSTobias Regnery txq->tpd_dma = alx->descmem.dma + offset;
625702e8418STobias Regnery offset += sizeof(struct alx_txd) * txq->count;
6268c2a4c8eSTobias Regnery
6278c2a4c8eSTobias Regnery return offset;
6288c2a4c8eSTobias Regnery }
6298c2a4c8eSTobias Regnery
alx_alloc_rx_ring(struct alx_priv * alx,struct alx_rx_queue * rxq,int offset)6308c2a4c8eSTobias Regnery static int alx_alloc_rx_ring(struct alx_priv *alx, struct alx_rx_queue *rxq,
6318c2a4c8eSTobias Regnery int offset)
6328c2a4c8eSTobias Regnery {
633702e8418STobias Regnery rxq->bufs = kcalloc(rxq->count, sizeof(struct alx_buffer), GFP_KERNEL);
6348c2a4c8eSTobias Regnery if (!rxq->bufs)
6358c2a4c8eSTobias Regnery return -ENOMEM;
6368c2a4c8eSTobias Regnery
6378c2a4c8eSTobias Regnery rxq->rrd = alx->descmem.virt + offset;
6388c2a4c8eSTobias Regnery rxq->rrd_dma = alx->descmem.dma + offset;
639702e8418STobias Regnery offset += sizeof(struct alx_rrd) * rxq->count;
6408c2a4c8eSTobias Regnery
6418c2a4c8eSTobias Regnery rxq->rfd = alx->descmem.virt + offset;
6428c2a4c8eSTobias Regnery rxq->rfd_dma = alx->descmem.dma + offset;
643702e8418STobias Regnery offset += sizeof(struct alx_rfd) * rxq->count;
6448c2a4c8eSTobias Regnery
6458c2a4c8eSTobias Regnery return offset;
6468c2a4c8eSTobias Regnery }
6478c2a4c8eSTobias Regnery
alx_alloc_rings(struct alx_priv * alx)6488c2a4c8eSTobias Regnery static int alx_alloc_rings(struct alx_priv *alx)
6498c2a4c8eSTobias Regnery {
650a4076d34STobias Regnery int i, offset = 0;
651ab69bde6SJohannes Berg
652ab69bde6SJohannes Berg /* physical tx/rx ring descriptors
653ab69bde6SJohannes Berg *
654ab69bde6SJohannes Berg * Allocate them as a single chunk because they must not cross a
655ab69bde6SJohannes Berg * 4G boundary (hardware has a single register for high 32 bits
656ab69bde6SJohannes Berg * of addresses only)
657ab69bde6SJohannes Berg */
658a4076d34STobias Regnery alx->descmem.size = sizeof(struct alx_txd) * alx->tx_ringsz *
659a4076d34STobias Regnery alx->num_txq +
660ab69bde6SJohannes Berg sizeof(struct alx_rrd) * alx->rx_ringsz +
661ab69bde6SJohannes Berg sizeof(struct alx_rfd) * alx->rx_ringsz;
662750afb08SLuis Chamberlain alx->descmem.virt = dma_alloc_coherent(&alx->hw.pdev->dev,
663ab69bde6SJohannes Berg alx->descmem.size,
664750afb08SLuis Chamberlain &alx->descmem.dma, GFP_KERNEL);
665ab69bde6SJohannes Berg if (!alx->descmem.virt)
6668c2a4c8eSTobias Regnery return -ENOMEM;
667ab69bde6SJohannes Berg
6688c2a4c8eSTobias Regnery /* alignment requirements */
669ab69bde6SJohannes Berg BUILD_BUG_ON(sizeof(struct alx_txd) % 8);
670ab69bde6SJohannes Berg BUILD_BUG_ON(sizeof(struct alx_rrd) % 8);
671ab69bde6SJohannes Berg
672a4076d34STobias Regnery for (i = 0; i < alx->num_txq; i++) {
673a4076d34STobias Regnery offset = alx_alloc_tx_ring(alx, alx->qnapi[i]->txq, offset);
6748c2a4c8eSTobias Regnery if (offset < 0) {
6758c2a4c8eSTobias Regnery netdev_err(alx->dev, "Allocation of tx buffer failed!\n");
676b0999223STobias Regnery return -ENOMEM;
677ab69bde6SJohannes Berg }
678a4076d34STobias Regnery }
679ab69bde6SJohannes Berg
680702e8418STobias Regnery offset = alx_alloc_rx_ring(alx, alx->qnapi[0]->rxq, offset);
6818c2a4c8eSTobias Regnery if (offset < 0) {
6828c2a4c8eSTobias Regnery netdev_err(alx->dev, "Allocation of rx buffer failed!\n");
683b0999223STobias Regnery return -ENOMEM;
6848c2a4c8eSTobias Regnery }
685ab69bde6SJohannes Berg
686ab69bde6SJohannes Berg return 0;
687ab69bde6SJohannes Berg }
688ab69bde6SJohannes Berg
alx_free_rings(struct alx_priv * alx)689ab69bde6SJohannes Berg static void alx_free_rings(struct alx_priv *alx)
690ab69bde6SJohannes Berg {
691a4076d34STobias Regnery int i;
692702e8418STobias Regnery
693ab69bde6SJohannes Berg alx_free_buffers(alx);
694ab69bde6SJohannes Berg
695a4076d34STobias Regnery for (i = 0; i < alx->num_txq; i++)
696a4076d34STobias Regnery if (alx->qnapi[i] && alx->qnapi[i]->txq)
697a4076d34STobias Regnery kfree(alx->qnapi[i]->txq->bufs);
698a4076d34STobias Regnery
699a4076d34STobias Regnery if (alx->qnapi[0] && alx->qnapi[0]->rxq)
700702e8418STobias Regnery kfree(alx->qnapi[0]->rxq->bufs);
701ab69bde6SJohannes Berg
702f1db5c10STobias Regnery if (alx->descmem.virt)
703ab69bde6SJohannes Berg dma_free_coherent(&alx->hw.pdev->dev,
704ab69bde6SJohannes Berg alx->descmem.size,
705ab69bde6SJohannes Berg alx->descmem.virt,
706ab69bde6SJohannes Berg alx->descmem.dma);
707ab69bde6SJohannes Berg }
708ab69bde6SJohannes Berg
alx_free_napis(struct alx_priv * alx)709b0999223STobias Regnery static void alx_free_napis(struct alx_priv *alx)
710b0999223STobias Regnery {
711b0999223STobias Regnery struct alx_napi *np;
712a4076d34STobias Regnery int i;
713b0999223STobias Regnery
714a4076d34STobias Regnery for (i = 0; i < alx->num_napi; i++) {
715a4076d34STobias Regnery np = alx->qnapi[i];
716b0999223STobias Regnery if (!np)
717a4076d34STobias Regnery continue;
718b0999223STobias Regnery
719702e8418STobias Regnery netif_napi_del(&np->napi);
720b0999223STobias Regnery kfree(np->txq);
721b0999223STobias Regnery kfree(np->rxq);
722b0999223STobias Regnery kfree(np);
723a4076d34STobias Regnery alx->qnapi[i] = NULL;
724a4076d34STobias Regnery }
725b0999223STobias Regnery }
726b0999223STobias Regnery
7272e06826bSTobias Regnery static const u16 tx_pidx_reg[] = {ALX_TPD_PRI0_PIDX, ALX_TPD_PRI1_PIDX,
7282e06826bSTobias Regnery ALX_TPD_PRI2_PIDX, ALX_TPD_PRI3_PIDX};
7292e06826bSTobias Regnery static const u16 tx_cidx_reg[] = {ALX_TPD_PRI0_CIDX, ALX_TPD_PRI1_CIDX,
7302e06826bSTobias Regnery ALX_TPD_PRI2_CIDX, ALX_TPD_PRI3_CIDX};
731e0eac254STobias Regnery static const u32 tx_vect_mask[] = {ALX_ISR_TX_Q0, ALX_ISR_TX_Q1,
732e0eac254STobias Regnery ALX_ISR_TX_Q2, ALX_ISR_TX_Q3};
733e0eac254STobias Regnery static const u32 rx_vect_mask[] = {ALX_ISR_RX_Q0, ALX_ISR_RX_Q1,
734e0eac254STobias Regnery ALX_ISR_RX_Q2, ALX_ISR_RX_Q3,
735e0eac254STobias Regnery ALX_ISR_RX_Q4, ALX_ISR_RX_Q5,
736e0eac254STobias Regnery ALX_ISR_RX_Q6, ALX_ISR_RX_Q7};
737e0eac254STobias Regnery
alx_alloc_napis(struct alx_priv * alx)738b0999223STobias Regnery static int alx_alloc_napis(struct alx_priv *alx)
739b0999223STobias Regnery {
740b0999223STobias Regnery struct alx_napi *np;
741b0999223STobias Regnery struct alx_rx_queue *rxq;
742b0999223STobias Regnery struct alx_tx_queue *txq;
743a4076d34STobias Regnery int i;
744b0999223STobias Regnery
745b0999223STobias Regnery alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
746b0999223STobias Regnery
747b0999223STobias Regnery /* allocate alx_napi structures */
748a4076d34STobias Regnery for (i = 0; i < alx->num_napi; i++) {
749b0999223STobias Regnery np = kzalloc(sizeof(struct alx_napi), GFP_KERNEL);
750b0999223STobias Regnery if (!np)
751b0999223STobias Regnery goto err_out;
752b0999223STobias Regnery
753b0999223STobias Regnery np->alx = alx;
754b48b89f9SJakub Kicinski netif_napi_add(alx->dev, &np->napi, alx_poll);
755a4076d34STobias Regnery alx->qnapi[i] = np;
756a4076d34STobias Regnery }
757b0999223STobias Regnery
758b0999223STobias Regnery /* allocate tx queues */
759a4076d34STobias Regnery for (i = 0; i < alx->num_txq; i++) {
760a4076d34STobias Regnery np = alx->qnapi[i];
761b0999223STobias Regnery txq = kzalloc(sizeof(*txq), GFP_KERNEL);
762b0999223STobias Regnery if (!txq)
763b0999223STobias Regnery goto err_out;
764b0999223STobias Regnery
765b0999223STobias Regnery np->txq = txq;
7662e06826bSTobias Regnery txq->p_reg = tx_pidx_reg[i];
7672e06826bSTobias Regnery txq->c_reg = tx_cidx_reg[i];
768a4076d34STobias Regnery txq->queue_idx = i;
769b0999223STobias Regnery txq->count = alx->tx_ringsz;
770b0999223STobias Regnery txq->netdev = alx->dev;
771b0999223STobias Regnery txq->dev = &alx->hw.pdev->dev;
772a4076d34STobias Regnery np->vec_mask |= tx_vect_mask[i];
773a4076d34STobias Regnery alx->int_mask |= tx_vect_mask[i];
774a4076d34STobias Regnery }
775b0999223STobias Regnery
776b0999223STobias Regnery /* allocate rx queues */
777b0999223STobias Regnery np = alx->qnapi[0];
778b0999223STobias Regnery rxq = kzalloc(sizeof(*rxq), GFP_KERNEL);
779b0999223STobias Regnery if (!rxq)
780b0999223STobias Regnery goto err_out;
781b0999223STobias Regnery
782b0999223STobias Regnery np->rxq = rxq;
783b0999223STobias Regnery rxq->np = alx->qnapi[0];
784e0eac254STobias Regnery rxq->queue_idx = 0;
785b0999223STobias Regnery rxq->count = alx->rx_ringsz;
786b0999223STobias Regnery rxq->netdev = alx->dev;
787b0999223STobias Regnery rxq->dev = &alx->hw.pdev->dev;
788e0eac254STobias Regnery np->vec_mask |= rx_vect_mask[0];
789e0eac254STobias Regnery alx->int_mask |= rx_vect_mask[0];
790b0999223STobias Regnery
791b0999223STobias Regnery return 0;
792b0999223STobias Regnery
793b0999223STobias Regnery err_out:
794b0999223STobias Regnery netdev_err(alx->dev, "error allocating internal structures\n");
795b0999223STobias Regnery alx_free_napis(alx);
796b0999223STobias Regnery return -ENOMEM;
797b0999223STobias Regnery }
798b0999223STobias Regnery
799e0eac254STobias Regnery static const int txq_vec_mapping_shift[] = {
800e0eac254STobias Regnery 0, ALX_MSI_MAP_TBL1_TXQ0_SHIFT,
801e0eac254STobias Regnery 0, ALX_MSI_MAP_TBL1_TXQ1_SHIFT,
802e0eac254STobias Regnery 1, ALX_MSI_MAP_TBL2_TXQ2_SHIFT,
803e0eac254STobias Regnery 1, ALX_MSI_MAP_TBL2_TXQ3_SHIFT,
804e0eac254STobias Regnery };
805e0eac254STobias Regnery
alx_config_vector_mapping(struct alx_priv * alx)806ab69bde6SJohannes Berg static void alx_config_vector_mapping(struct alx_priv *alx)
807ab69bde6SJohannes Berg {
808ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
809e0eac254STobias Regnery u32 tbl[2] = {0, 0};
810e0eac254STobias Regnery int i, vector, idx, shift;
811ab69bde6SJohannes Berg
812f3297f68SChristoph Hellwig if (alx->hw.pdev->msix_enabled) {
813e0eac254STobias Regnery /* tx mappings */
814e0eac254STobias Regnery for (i = 0, vector = 1; i < alx->num_txq; i++, vector++) {
815e0eac254STobias Regnery idx = txq_vec_mapping_shift[i * 2];
816e0eac254STobias Regnery shift = txq_vec_mapping_shift[i * 2 + 1];
817e0eac254STobias Regnery tbl[idx] |= vector << shift;
818dc39a78bSTobias Regnery }
819dc39a78bSTobias Regnery
820e0eac254STobias Regnery /* rx mapping */
821e0eac254STobias Regnery tbl[0] |= 1 << ALX_MSI_MAP_TBL1_RXQ0_SHIFT;
822e0eac254STobias Regnery }
823e0eac254STobias Regnery
824e0eac254STobias Regnery alx_write_mem32(hw, ALX_MSI_MAP_TBL1, tbl[0]);
825e0eac254STobias Regnery alx_write_mem32(hw, ALX_MSI_MAP_TBL2, tbl[1]);
826ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_MSI_ID_MAP, 0);
827ab69bde6SJohannes Berg }
828ab69bde6SJohannes Berg
alx_enable_msix(struct alx_priv * alx)829f3297f68SChristoph Hellwig static int alx_enable_msix(struct alx_priv *alx)
830dc39a78bSTobias Regnery {
831f3297f68SChristoph Hellwig int err, num_vec, num_txq, num_rxq;
832e0eac254STobias Regnery
833d768319cSTobias Regnery num_txq = min_t(int, num_online_cpus(), ALX_MAX_TX_QUEUES);
834e0eac254STobias Regnery num_rxq = 1;
835e0eac254STobias Regnery num_vec = max_t(int, num_txq, num_rxq) + 1;
836dc39a78bSTobias Regnery
837f3297f68SChristoph Hellwig err = pci_alloc_irq_vectors(alx->hw.pdev, num_vec, num_vec,
838f3297f68SChristoph Hellwig PCI_IRQ_MSIX);
8392c041afcSRakesh Pandit if (err < 0) {
840dc39a78bSTobias Regnery netdev_warn(alx->dev, "Enabling MSI-X interrupts failed!\n");
841f3297f68SChristoph Hellwig return err;
842dc39a78bSTobias Regnery }
843dc39a78bSTobias Regnery
844dc39a78bSTobias Regnery alx->num_vec = num_vec;
845e0eac254STobias Regnery alx->num_napi = num_vec - 1;
846e0eac254STobias Regnery alx->num_txq = num_txq;
847e0eac254STobias Regnery alx->num_rxq = num_rxq;
848e0eac254STobias Regnery
849f3297f68SChristoph Hellwig return err;
850dc39a78bSTobias Regnery }
851dc39a78bSTobias Regnery
alx_request_msix(struct alx_priv * alx)852dc39a78bSTobias Regnery static int alx_request_msix(struct alx_priv *alx)
853dc39a78bSTobias Regnery {
854dc39a78bSTobias Regnery struct net_device *netdev = alx->dev;
855dc39a78bSTobias Regnery int i, err, vector = 0, free_vector = 0;
856dc39a78bSTobias Regnery
857f3297f68SChristoph Hellwig err = request_irq(pci_irq_vector(alx->hw.pdev, 0), alx_intr_msix_misc,
858dc39a78bSTobias Regnery 0, netdev->name, alx);
859dc39a78bSTobias Regnery if (err)
860dc39a78bSTobias Regnery goto out_err;
861dc39a78bSTobias Regnery
862e0eac254STobias Regnery for (i = 0; i < alx->num_napi; i++) {
863e0eac254STobias Regnery struct alx_napi *np = alx->qnapi[i];
864dc39a78bSTobias Regnery
865e0eac254STobias Regnery vector++;
866e0eac254STobias Regnery
867e0eac254STobias Regnery if (np->txq && np->rxq)
868e0eac254STobias Regnery sprintf(np->irq_lbl, "%s-TxRx-%u", netdev->name,
869e0eac254STobias Regnery np->txq->queue_idx);
870e0eac254STobias Regnery else if (np->txq)
871e0eac254STobias Regnery sprintf(np->irq_lbl, "%s-tx-%u", netdev->name,
872e0eac254STobias Regnery np->txq->queue_idx);
873e0eac254STobias Regnery else if (np->rxq)
874e0eac254STobias Regnery sprintf(np->irq_lbl, "%s-rx-%u", netdev->name,
875e0eac254STobias Regnery np->rxq->queue_idx);
876e0eac254STobias Regnery else
877e0eac254STobias Regnery sprintf(np->irq_lbl, "%s-unused", netdev->name);
878e0eac254STobias Regnery
879e0eac254STobias Regnery np->vec_idx = vector;
880f3297f68SChristoph Hellwig err = request_irq(pci_irq_vector(alx->hw.pdev, vector),
881702e8418STobias Regnery alx_intr_msix_ring, 0, np->irq_lbl, np);
882dc39a78bSTobias Regnery if (err)
883dc39a78bSTobias Regnery goto out_free;
884e0eac254STobias Regnery }
885dc39a78bSTobias Regnery return 0;
886dc39a78bSTobias Regnery
887dc39a78bSTobias Regnery out_free:
888f3297f68SChristoph Hellwig free_irq(pci_irq_vector(alx->hw.pdev, free_vector++), alx);
889dc39a78bSTobias Regnery
890dc39a78bSTobias Regnery vector--;
891dc39a78bSTobias Regnery for (i = 0; i < vector; i++)
892f3297f68SChristoph Hellwig free_irq(pci_irq_vector(alx->hw.pdev,free_vector++),
893e0eac254STobias Regnery alx->qnapi[i]);
894dc39a78bSTobias Regnery
895dc39a78bSTobias Regnery out_err:
896dc39a78bSTobias Regnery return err;
897dc39a78bSTobias Regnery }
898dc39a78bSTobias Regnery
alx_init_intr(struct alx_priv * alx)899f3297f68SChristoph Hellwig static int alx_init_intr(struct alx_priv *alx)
9009ee7b683STobias Regnery {
901f3297f68SChristoph Hellwig int ret;
902dc39a78bSTobias Regnery
903f3297f68SChristoph Hellwig ret = pci_alloc_irq_vectors(alx->hw.pdev, 1, 1,
904f3297f68SChristoph Hellwig PCI_IRQ_MSI | PCI_IRQ_LEGACY);
9052c041afcSRakesh Pandit if (ret < 0)
906f3297f68SChristoph Hellwig return ret;
907f3297f68SChristoph Hellwig
908dc39a78bSTobias Regnery alx->num_vec = 1;
909e0eac254STobias Regnery alx->num_napi = 1;
910e0eac254STobias Regnery alx->num_txq = 1;
911e0eac254STobias Regnery alx->num_rxq = 1;
912f3297f68SChristoph Hellwig return 0;
9139ee7b683STobias Regnery }
9149ee7b683STobias Regnery
alx_irq_enable(struct alx_priv * alx)915ab69bde6SJohannes Berg static void alx_irq_enable(struct alx_priv *alx)
916ab69bde6SJohannes Berg {
917ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
918dc39a78bSTobias Regnery int i;
919ab69bde6SJohannes Berg
920ab69bde6SJohannes Berg /* level-1 interrupt switch */
921ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_ISR, 0);
922ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_IMR, alx->int_mask);
923ab69bde6SJohannes Berg alx_post_write(hw);
924dc39a78bSTobias Regnery
925f3297f68SChristoph Hellwig if (alx->hw.pdev->msix_enabled) {
926dc39a78bSTobias Regnery /* enable all msix irqs */
927dc39a78bSTobias Regnery for (i = 0; i < alx->num_vec; i++)
928dc39a78bSTobias Regnery alx_mask_msix(hw, i, false);
929ab69bde6SJohannes Berg }
930f3297f68SChristoph Hellwig }
931ab69bde6SJohannes Berg
alx_irq_disable(struct alx_priv * alx)932ab69bde6SJohannes Berg static void alx_irq_disable(struct alx_priv *alx)
933ab69bde6SJohannes Berg {
934ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
935dc39a78bSTobias Regnery int i;
936ab69bde6SJohannes Berg
937ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS);
938ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_IMR, 0);
939ab69bde6SJohannes Berg alx_post_write(hw);
940ab69bde6SJohannes Berg
941f3297f68SChristoph Hellwig if (alx->hw.pdev->msix_enabled) {
942dc39a78bSTobias Regnery for (i = 0; i < alx->num_vec; i++) {
943dc39a78bSTobias Regnery alx_mask_msix(hw, i, true);
944f3297f68SChristoph Hellwig synchronize_irq(pci_irq_vector(alx->hw.pdev, i));
945dc39a78bSTobias Regnery }
946dc39a78bSTobias Regnery } else {
947f3297f68SChristoph Hellwig synchronize_irq(pci_irq_vector(alx->hw.pdev, 0));
948ab69bde6SJohannes Berg }
949dc39a78bSTobias Regnery }
950ab69bde6SJohannes Berg
alx_realloc_resources(struct alx_priv * alx)951e0eac254STobias Regnery static int alx_realloc_resources(struct alx_priv *alx)
952e0eac254STobias Regnery {
953e0eac254STobias Regnery int err;
954e0eac254STobias Regnery
955e0eac254STobias Regnery alx_free_rings(alx);
956e0eac254STobias Regnery alx_free_napis(alx);
957f3297f68SChristoph Hellwig pci_free_irq_vectors(alx->hw.pdev);
958f3297f68SChristoph Hellwig
959f3297f68SChristoph Hellwig err = alx_init_intr(alx);
960f3297f68SChristoph Hellwig if (err)
961f3297f68SChristoph Hellwig return err;
962e0eac254STobias Regnery
963e0eac254STobias Regnery err = alx_alloc_napis(alx);
964e0eac254STobias Regnery if (err)
965e0eac254STobias Regnery return err;
966e0eac254STobias Regnery
967e0eac254STobias Regnery err = alx_alloc_rings(alx);
968e0eac254STobias Regnery if (err)
969e0eac254STobias Regnery return err;
970e0eac254STobias Regnery
971e0eac254STobias Regnery return 0;
972e0eac254STobias Regnery }
973e0eac254STobias Regnery
alx_request_irq(struct alx_priv * alx)974ab69bde6SJohannes Berg static int alx_request_irq(struct alx_priv *alx)
975ab69bde6SJohannes Berg {
976ab69bde6SJohannes Berg struct pci_dev *pdev = alx->hw.pdev;
977ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
978ab69bde6SJohannes Berg int err;
979ab69bde6SJohannes Berg u32 msi_ctrl;
980ab69bde6SJohannes Berg
981ab69bde6SJohannes Berg msi_ctrl = (hw->imt >> 1) << ALX_MSI_RETRANS_TM_SHIFT;
982ab69bde6SJohannes Berg
983f3297f68SChristoph Hellwig if (alx->hw.pdev->msix_enabled) {
984dc39a78bSTobias Regnery alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, msi_ctrl);
985dc39a78bSTobias Regnery err = alx_request_msix(alx);
986dc39a78bSTobias Regnery if (!err)
987dc39a78bSTobias Regnery goto out;
988dc39a78bSTobias Regnery
989dc39a78bSTobias Regnery /* msix request failed, realloc resources */
990e0eac254STobias Regnery err = alx_realloc_resources(alx);
991e0eac254STobias Regnery if (err)
992e0eac254STobias Regnery goto out;
993dc39a78bSTobias Regnery }
994dc39a78bSTobias Regnery
995f3297f68SChristoph Hellwig if (alx->hw.pdev->msi_enabled) {
996ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER,
997ab69bde6SJohannes Berg msi_ctrl | ALX_MSI_MASK_SEL_LINE);
998f3297f68SChristoph Hellwig err = request_irq(pci_irq_vector(pdev, 0), alx_intr_msi, 0,
999ab69bde6SJohannes Berg alx->dev->name, alx);
1000ab69bde6SJohannes Berg if (!err)
1001ab69bde6SJohannes Berg goto out;
1002f3297f68SChristoph Hellwig
1003ab69bde6SJohannes Berg /* fall back to legacy interrupt */
1004f3297f68SChristoph Hellwig pci_free_irq_vectors(alx->hw.pdev);
1005ab69bde6SJohannes Berg }
1006ab69bde6SJohannes Berg
1007ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, 0);
1008f3297f68SChristoph Hellwig err = request_irq(pci_irq_vector(pdev, 0), alx_intr_legacy, IRQF_SHARED,
1009ab69bde6SJohannes Berg alx->dev->name, alx);
1010ab69bde6SJohannes Berg out:
1011ab69bde6SJohannes Berg if (!err)
1012ab69bde6SJohannes Berg alx_config_vector_mapping(alx);
1013dc39a78bSTobias Regnery else
1014dc39a78bSTobias Regnery netdev_err(alx->dev, "IRQ registration failed!\n");
1015ab69bde6SJohannes Berg return err;
1016ab69bde6SJohannes Berg }
1017ab69bde6SJohannes Berg
alx_free_irq(struct alx_priv * alx)1018ab69bde6SJohannes Berg static void alx_free_irq(struct alx_priv *alx)
1019ab69bde6SJohannes Berg {
1020ab69bde6SJohannes Berg struct pci_dev *pdev = alx->hw.pdev;
1021f3297f68SChristoph Hellwig int i;
1022ab69bde6SJohannes Berg
1023f3297f68SChristoph Hellwig free_irq(pci_irq_vector(pdev, 0), alx);
1024f3297f68SChristoph Hellwig if (alx->hw.pdev->msix_enabled) {
1025e0eac254STobias Regnery for (i = 0; i < alx->num_napi; i++)
1026f3297f68SChristoph Hellwig free_irq(pci_irq_vector(pdev, i + 1), alx->qnapi[i]);
1027dc39a78bSTobias Regnery }
1028ab69bde6SJohannes Berg
1029f3297f68SChristoph Hellwig pci_free_irq_vectors(pdev);
1030ab69bde6SJohannes Berg }
1031ab69bde6SJohannes Berg
alx_identify_hw(struct alx_priv * alx)1032ab69bde6SJohannes Berg static int alx_identify_hw(struct alx_priv *alx)
1033ab69bde6SJohannes Berg {
1034ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
1035ab69bde6SJohannes Berg int rev = alx_hw_revision(hw);
1036ab69bde6SJohannes Berg
1037ab69bde6SJohannes Berg if (rev > ALX_REV_C0)
1038ab69bde6SJohannes Berg return -EINVAL;
1039ab69bde6SJohannes Berg
1040ab69bde6SJohannes Berg hw->max_dma_chnl = rev >= ALX_REV_B0 ? 4 : 2;
1041ab69bde6SJohannes Berg
1042ab69bde6SJohannes Berg return 0;
1043ab69bde6SJohannes Berg }
1044ab69bde6SJohannes Berg
alx_init_sw(struct alx_priv * alx)1045ab69bde6SJohannes Berg static int alx_init_sw(struct alx_priv *alx)
1046ab69bde6SJohannes Berg {
1047ab69bde6SJohannes Berg struct pci_dev *pdev = alx->hw.pdev;
1048ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
1049ab69bde6SJohannes Berg int err;
1050ab69bde6SJohannes Berg
1051ab69bde6SJohannes Berg err = alx_identify_hw(alx);
1052ab69bde6SJohannes Berg if (err) {
1053ab69bde6SJohannes Berg dev_err(&pdev->dev, "unrecognized chip, aborting\n");
1054ab69bde6SJohannes Berg return err;
1055ab69bde6SJohannes Berg }
1056ab69bde6SJohannes Berg
1057ab69bde6SJohannes Berg alx->hw.lnk_patch =
1058ab69bde6SJohannes Berg pdev->device == ALX_DEV_ID_AR8161 &&
1059ab69bde6SJohannes Berg pdev->subsystem_vendor == PCI_VENDOR_ID_ATTANSIC &&
1060ab69bde6SJohannes Berg pdev->subsystem_device == 0x0091 &&
1061ab69bde6SJohannes Berg pdev->revision == 0;
1062ab69bde6SJohannes Berg
1063ab69bde6SJohannes Berg hw->smb_timer = 400;
1064ab69bde6SJohannes Berg hw->mtu = alx->dev->mtu;
1065c406700cSJarod Wilson alx->rxbuf_size = ALX_MAX_FRAME_LEN(hw->mtu);
106667bef942SJarod Wilson /* MTU range: 34 - 9256 */
106767bef942SJarod Wilson alx->dev->min_mtu = 34;
106867bef942SJarod Wilson alx->dev->max_mtu = ALX_MAX_FRAME_LEN(ALX_MAX_FRAME_SIZE);
1069ab69bde6SJohannes Berg alx->tx_ringsz = 256;
1070ab69bde6SJohannes Berg alx->rx_ringsz = 512;
1071ab69bde6SJohannes Berg hw->imt = 200;
1072ab69bde6SJohannes Berg alx->int_mask = ALX_ISR_MISC;
1073ab69bde6SJohannes Berg hw->dma_chnl = hw->max_dma_chnl;
1074ab69bde6SJohannes Berg hw->ith_tpd = alx->tx_ringsz / 3;
1075ab69bde6SJohannes Berg hw->link_speed = SPEED_UNKNOWN;
1076a5b87cc9SJohannes Berg hw->duplex = DUPLEX_UNKNOWN;
1077ab69bde6SJohannes Berg hw->adv_cfg = ADVERTISED_Autoneg |
1078ab69bde6SJohannes Berg ADVERTISED_10baseT_Half |
1079ab69bde6SJohannes Berg ADVERTISED_10baseT_Full |
1080ab69bde6SJohannes Berg ADVERTISED_100baseT_Full |
1081ab69bde6SJohannes Berg ADVERTISED_100baseT_Half |
1082ab69bde6SJohannes Berg ADVERTISED_1000baseT_Full;
1083ab69bde6SJohannes Berg hw->flowctrl = ALX_FC_ANEG | ALX_FC_RX | ALX_FC_TX;
1084ab69bde6SJohannes Berg
1085ab69bde6SJohannes Berg hw->rx_ctrl = ALX_MAC_CTRL_WOLSPED_SWEN |
1086ab69bde6SJohannes Berg ALX_MAC_CTRL_MHASH_ALG_HI5B |
1087ab69bde6SJohannes Berg ALX_MAC_CTRL_BRD_EN |
1088ab69bde6SJohannes Berg ALX_MAC_CTRL_PCRCE |
1089ab69bde6SJohannes Berg ALX_MAC_CTRL_CRCE |
1090ab69bde6SJohannes Berg ALX_MAC_CTRL_RXFC_EN |
1091ab69bde6SJohannes Berg ALX_MAC_CTRL_TXFC_EN |
1092ab69bde6SJohannes Berg 7 << ALX_MAC_CTRL_PRMBLEN_SHIFT;
10934a5fe57eSJohannes Berg mutex_init(&alx->mtx);
1094ab69bde6SJohannes Berg
10954a5fe57eSJohannes Berg return 0;
1096ab69bde6SJohannes Berg }
1097ab69bde6SJohannes Berg
1098ab69bde6SJohannes Berg
alx_fix_features(struct net_device * netdev,netdev_features_t features)1099ab69bde6SJohannes Berg static netdev_features_t alx_fix_features(struct net_device *netdev,
1100ab69bde6SJohannes Berg netdev_features_t features)
1101ab69bde6SJohannes Berg {
1102ab69bde6SJohannes Berg if (netdev->mtu > ALX_MAX_TSO_PKT_SIZE)
1103ab69bde6SJohannes Berg features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
1104ab69bde6SJohannes Berg
1105ab69bde6SJohannes Berg return features;
1106ab69bde6SJohannes Berg }
1107ab69bde6SJohannes Berg
alx_netif_stop(struct alx_priv * alx)1108ab69bde6SJohannes Berg static void alx_netif_stop(struct alx_priv *alx)
1109ab69bde6SJohannes Berg {
1110a4076d34STobias Regnery int i;
1111a4076d34STobias Regnery
1112860e9538SFlorian Westphal netif_trans_update(alx->dev);
1113ab69bde6SJohannes Berg if (netif_carrier_ok(alx->dev)) {
1114ab69bde6SJohannes Berg netif_carrier_off(alx->dev);
1115ab69bde6SJohannes Berg netif_tx_disable(alx->dev);
1116a4076d34STobias Regnery for (i = 0; i < alx->num_napi; i++)
1117a4076d34STobias Regnery napi_disable(&alx->qnapi[i]->napi);
1118ab69bde6SJohannes Berg }
1119ab69bde6SJohannes Berg }
1120ab69bde6SJohannes Berg
alx_halt(struct alx_priv * alx)1121ab69bde6SJohannes Berg static void alx_halt(struct alx_priv *alx)
1122ab69bde6SJohannes Berg {
1123ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
1124ab69bde6SJohannes Berg
11254a5fe57eSJohannes Berg lockdep_assert_held(&alx->mtx);
11264a5fe57eSJohannes Berg
1127ab69bde6SJohannes Berg alx_netif_stop(alx);
1128ab69bde6SJohannes Berg hw->link_speed = SPEED_UNKNOWN;
1129a5b87cc9SJohannes Berg hw->duplex = DUPLEX_UNKNOWN;
1130ab69bde6SJohannes Berg
1131ab69bde6SJohannes Berg alx_reset_mac(hw);
1132ab69bde6SJohannes Berg
1133ab69bde6SJohannes Berg /* disable l0s/l1 */
1134ab69bde6SJohannes Berg alx_enable_aspm(hw, false, false);
1135ab69bde6SJohannes Berg alx_irq_disable(alx);
1136ab69bde6SJohannes Berg alx_free_buffers(alx);
1137ab69bde6SJohannes Berg }
1138ab69bde6SJohannes Berg
alx_configure(struct alx_priv * alx)1139ab69bde6SJohannes Berg static void alx_configure(struct alx_priv *alx)
1140ab69bde6SJohannes Berg {
1141ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
1142ab69bde6SJohannes Berg
1143ab69bde6SJohannes Berg alx_configure_basic(hw);
1144ab69bde6SJohannes Berg alx_disable_rss(hw);
1145ab69bde6SJohannes Berg __alx_set_rx_mode(alx->dev);
1146ab69bde6SJohannes Berg
1147ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
1148ab69bde6SJohannes Berg }
1149ab69bde6SJohannes Berg
alx_activate(struct alx_priv * alx)1150ab69bde6SJohannes Berg static void alx_activate(struct alx_priv *alx)
1151ab69bde6SJohannes Berg {
11524a5fe57eSJohannes Berg lockdep_assert_held(&alx->mtx);
11534a5fe57eSJohannes Berg
1154ab69bde6SJohannes Berg /* hardware setting lost, restore it */
1155ab69bde6SJohannes Berg alx_reinit_rings(alx);
1156ab69bde6SJohannes Berg alx_configure(alx);
1157ab69bde6SJohannes Berg
1158ab69bde6SJohannes Berg /* clear old interrupts */
1159ab69bde6SJohannes Berg alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS);
1160ab69bde6SJohannes Berg
1161ab69bde6SJohannes Berg alx_irq_enable(alx);
1162ab69bde6SJohannes Berg
1163ab69bde6SJohannes Berg alx_schedule_link_check(alx);
1164ab69bde6SJohannes Berg }
1165ab69bde6SJohannes Berg
alx_reinit(struct alx_priv * alx)1166ab69bde6SJohannes Berg static void alx_reinit(struct alx_priv *alx)
1167ab69bde6SJohannes Berg {
11684a5fe57eSJohannes Berg lockdep_assert_held(&alx->mtx);
1169ab69bde6SJohannes Berg
1170ab69bde6SJohannes Berg alx_halt(alx);
1171ab69bde6SJohannes Berg alx_activate(alx);
1172ab69bde6SJohannes Berg }
1173ab69bde6SJohannes Berg
alx_change_mtu(struct net_device * netdev,int mtu)1174ab69bde6SJohannes Berg static int alx_change_mtu(struct net_device *netdev, int mtu)
1175ab69bde6SJohannes Berg {
1176ab69bde6SJohannes Berg struct alx_priv *alx = netdev_priv(netdev);
1177c406700cSJarod Wilson int max_frame = ALX_MAX_FRAME_LEN(mtu);
1178ab69bde6SJohannes Berg
1179ab69bde6SJohannes Berg netdev->mtu = mtu;
1180ab69bde6SJohannes Berg alx->hw.mtu = mtu;
1181c406700cSJarod Wilson alx->rxbuf_size = max(max_frame, ALX_DEF_RXBUF_SIZE);
1182ab69bde6SJohannes Berg netdev_update_features(netdev);
118346b348fdSNiels Dossche if (netif_running(netdev)) {
118446b348fdSNiels Dossche mutex_lock(&alx->mtx);
1185ab69bde6SJohannes Berg alx_reinit(alx);
118646b348fdSNiels Dossche mutex_unlock(&alx->mtx);
118746b348fdSNiels Dossche }
1188ab69bde6SJohannes Berg return 0;
1189ab69bde6SJohannes Berg }
1190ab69bde6SJohannes Berg
alx_netif_start(struct alx_priv * alx)1191ab69bde6SJohannes Berg static void alx_netif_start(struct alx_priv *alx)
1192ab69bde6SJohannes Berg {
1193a4076d34STobias Regnery int i;
1194a4076d34STobias Regnery
1195ab69bde6SJohannes Berg netif_tx_wake_all_queues(alx->dev);
1196a4076d34STobias Regnery for (i = 0; i < alx->num_napi; i++)
1197a4076d34STobias Regnery napi_enable(&alx->qnapi[i]->napi);
1198ab69bde6SJohannes Berg netif_carrier_on(alx->dev);
1199ab69bde6SJohannes Berg }
1200ab69bde6SJohannes Berg
__alx_open(struct alx_priv * alx,bool resume)1201ab69bde6SJohannes Berg static int __alx_open(struct alx_priv *alx, bool resume)
1202ab69bde6SJohannes Berg {
1203ab69bde6SJohannes Berg int err;
1204ab69bde6SJohannes Berg
1205f3297f68SChristoph Hellwig err = alx_enable_msix(alx);
1206f3297f68SChristoph Hellwig if (err < 0) {
1207f3297f68SChristoph Hellwig err = alx_init_intr(alx);
1208f3297f68SChristoph Hellwig if (err)
1209f3297f68SChristoph Hellwig return err;
1210f3297f68SChristoph Hellwig }
12119ee7b683STobias Regnery
1212ab69bde6SJohannes Berg if (!resume)
1213ab69bde6SJohannes Berg netif_carrier_off(alx->dev);
1214ab69bde6SJohannes Berg
1215b0999223STobias Regnery err = alx_alloc_napis(alx);
1216ab69bde6SJohannes Berg if (err)
12170ca4e20bSTobias Regnery goto out_disable_adv_intr;
1218ab69bde6SJohannes Berg
1219b0999223STobias Regnery err = alx_alloc_rings(alx);
1220b0999223STobias Regnery if (err)
1221b0999223STobias Regnery goto out_free_rings;
1222b0999223STobias Regnery
1223ab69bde6SJohannes Berg alx_configure(alx);
1224ab69bde6SJohannes Berg
1225ab69bde6SJohannes Berg err = alx_request_irq(alx);
1226ab69bde6SJohannes Berg if (err)
1227ab69bde6SJohannes Berg goto out_free_rings;
1228ab69bde6SJohannes Berg
1229185aceefSTobias Regnery /* must be called after alx_request_irq because the chip stops working
1230185aceefSTobias Regnery * if we copy the dma addresses in alx_init_ring_ptrs twice when
1231185aceefSTobias Regnery * requesting msi-x interrupts failed
1232185aceefSTobias Regnery */
1233185aceefSTobias Regnery alx_reinit_rings(alx);
1234185aceefSTobias Regnery
1235d768319cSTobias Regnery netif_set_real_num_tx_queues(alx->dev, alx->num_txq);
1236d768319cSTobias Regnery netif_set_real_num_rx_queues(alx->dev, alx->num_rxq);
1237d768319cSTobias Regnery
1238ab69bde6SJohannes Berg /* clear old interrupts */
1239ab69bde6SJohannes Berg alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS);
1240ab69bde6SJohannes Berg
1241ab69bde6SJohannes Berg alx_irq_enable(alx);
1242ab69bde6SJohannes Berg
1243ab69bde6SJohannes Berg if (!resume)
1244ab69bde6SJohannes Berg netif_tx_start_all_queues(alx->dev);
1245ab69bde6SJohannes Berg
1246ab69bde6SJohannes Berg alx_schedule_link_check(alx);
1247ab69bde6SJohannes Berg return 0;
1248ab69bde6SJohannes Berg
1249ab69bde6SJohannes Berg out_free_rings:
1250ab69bde6SJohannes Berg alx_free_rings(alx);
1251b0999223STobias Regnery alx_free_napis(alx);
12520ca4e20bSTobias Regnery out_disable_adv_intr:
1253f3297f68SChristoph Hellwig pci_free_irq_vectors(alx->hw.pdev);
1254ab69bde6SJohannes Berg return err;
1255ab69bde6SJohannes Berg }
1256ab69bde6SJohannes Berg
__alx_stop(struct alx_priv * alx)1257ab69bde6SJohannes Berg static void __alx_stop(struct alx_priv *alx)
1258ab69bde6SJohannes Berg {
12594a5fe57eSJohannes Berg lockdep_assert_held(&alx->mtx);
12604a5fe57eSJohannes Berg
1261ab69bde6SJohannes Berg alx_free_irq(alx);
1262e89df5c4SZekun Shen
1263e89df5c4SZekun Shen cancel_work_sync(&alx->link_check_wk);
1264e89df5c4SZekun Shen cancel_work_sync(&alx->reset_wk);
1265e89df5c4SZekun Shen
1266e89df5c4SZekun Shen alx_halt(alx);
1267ab69bde6SJohannes Berg alx_free_rings(alx);
1268b0999223STobias Regnery alx_free_napis(alx);
1269ab69bde6SJohannes Berg }
1270ab69bde6SJohannes Berg
alx_speed_desc(struct alx_hw * hw)1271a5b87cc9SJohannes Berg static const char *alx_speed_desc(struct alx_hw *hw)
1272ab69bde6SJohannes Berg {
1273a5b87cc9SJohannes Berg switch (alx_speed_to_ethadv(hw->link_speed, hw->duplex)) {
1274a5b87cc9SJohannes Berg case ADVERTISED_1000baseT_Full:
1275ab69bde6SJohannes Berg return "1 Gbps Full";
1276a5b87cc9SJohannes Berg case ADVERTISED_100baseT_Full:
1277ab69bde6SJohannes Berg return "100 Mbps Full";
1278a5b87cc9SJohannes Berg case ADVERTISED_100baseT_Half:
1279ab69bde6SJohannes Berg return "100 Mbps Half";
1280a5b87cc9SJohannes Berg case ADVERTISED_10baseT_Full:
1281ab69bde6SJohannes Berg return "10 Mbps Full";
1282a5b87cc9SJohannes Berg case ADVERTISED_10baseT_Half:
1283ab69bde6SJohannes Berg return "10 Mbps Half";
1284ab69bde6SJohannes Berg default:
1285ab69bde6SJohannes Berg return "Unknown speed";
1286ab69bde6SJohannes Berg }
1287ab69bde6SJohannes Berg }
1288ab69bde6SJohannes Berg
alx_check_link(struct alx_priv * alx)1289ab69bde6SJohannes Berg static void alx_check_link(struct alx_priv *alx)
1290ab69bde6SJohannes Berg {
1291ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
1292ab69bde6SJohannes Berg unsigned long flags;
1293a5b87cc9SJohannes Berg int old_speed;
1294ab69bde6SJohannes Berg int err;
1295ab69bde6SJohannes Berg
12964a5fe57eSJohannes Berg lockdep_assert_held(&alx->mtx);
12974a5fe57eSJohannes Berg
1298ab69bde6SJohannes Berg /* clear PHY internal interrupt status, otherwise the main
1299ab69bde6SJohannes Berg * interrupt status will be asserted forever
1300ab69bde6SJohannes Berg */
1301ab69bde6SJohannes Berg alx_clear_phy_intr(hw);
1302ab69bde6SJohannes Berg
1303a5b87cc9SJohannes Berg old_speed = hw->link_speed;
1304a5b87cc9SJohannes Berg err = alx_read_phy_link(hw);
1305ab69bde6SJohannes Berg if (err < 0)
1306ab69bde6SJohannes Berg goto reset;
1307ab69bde6SJohannes Berg
1308ab69bde6SJohannes Berg spin_lock_irqsave(&alx->irq_lock, flags);
1309ab69bde6SJohannes Berg alx->int_mask |= ALX_ISR_PHY;
1310ab69bde6SJohannes Berg alx_write_mem32(hw, ALX_IMR, alx->int_mask);
1311ab69bde6SJohannes Berg spin_unlock_irqrestore(&alx->irq_lock, flags);
1312ab69bde6SJohannes Berg
1313a5b87cc9SJohannes Berg if (old_speed == hw->link_speed)
1314ab69bde6SJohannes Berg return;
1315ab69bde6SJohannes Berg
1316a5b87cc9SJohannes Berg if (hw->link_speed != SPEED_UNKNOWN) {
1317ab69bde6SJohannes Berg netif_info(alx, link, alx->dev,
1318a5b87cc9SJohannes Berg "NIC Up: %s\n", alx_speed_desc(hw));
1319ab69bde6SJohannes Berg alx_post_phy_link(hw);
1320ab69bde6SJohannes Berg alx_enable_aspm(hw, true, true);
1321ab69bde6SJohannes Berg alx_start_mac(hw);
1322ab69bde6SJohannes Berg
1323ab69bde6SJohannes Berg if (old_speed == SPEED_UNKNOWN)
1324ab69bde6SJohannes Berg alx_netif_start(alx);
1325ab69bde6SJohannes Berg } else {
1326ab69bde6SJohannes Berg /* link is now down */
1327ab69bde6SJohannes Berg alx_netif_stop(alx);
1328ab69bde6SJohannes Berg netif_info(alx, link, alx->dev, "Link Down\n");
1329ab69bde6SJohannes Berg err = alx_reset_mac(hw);
1330ab69bde6SJohannes Berg if (err)
1331ab69bde6SJohannes Berg goto reset;
1332ab69bde6SJohannes Berg alx_irq_disable(alx);
1333ab69bde6SJohannes Berg
1334ab69bde6SJohannes Berg /* MAC reset causes all HW settings to be lost, restore all */
1335ab69bde6SJohannes Berg err = alx_reinit_rings(alx);
1336ab69bde6SJohannes Berg if (err)
1337ab69bde6SJohannes Berg goto reset;
1338ab69bde6SJohannes Berg alx_configure(alx);
1339ab69bde6SJohannes Berg alx_enable_aspm(hw, false, true);
1340ab69bde6SJohannes Berg alx_post_phy_link(hw);
1341ab69bde6SJohannes Berg alx_irq_enable(alx);
1342ab69bde6SJohannes Berg }
1343ab69bde6SJohannes Berg
1344ab69bde6SJohannes Berg return;
1345ab69bde6SJohannes Berg
1346ab69bde6SJohannes Berg reset:
1347ab69bde6SJohannes Berg alx_schedule_reset(alx);
1348ab69bde6SJohannes Berg }
1349ab69bde6SJohannes Berg
alx_open(struct net_device * netdev)1350ab69bde6SJohannes Berg static int alx_open(struct net_device *netdev)
1351ab69bde6SJohannes Berg {
13524a5fe57eSJohannes Berg struct alx_priv *alx = netdev_priv(netdev);
13534a5fe57eSJohannes Berg int ret;
13544a5fe57eSJohannes Berg
13554a5fe57eSJohannes Berg mutex_lock(&alx->mtx);
13564a5fe57eSJohannes Berg ret = __alx_open(alx, false);
13574a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
13584a5fe57eSJohannes Berg
13594a5fe57eSJohannes Berg return ret;
1360ab69bde6SJohannes Berg }
1361ab69bde6SJohannes Berg
alx_stop(struct net_device * netdev)1362ab69bde6SJohannes Berg static int alx_stop(struct net_device *netdev)
1363ab69bde6SJohannes Berg {
13644a5fe57eSJohannes Berg struct alx_priv *alx = netdev_priv(netdev);
13654a5fe57eSJohannes Berg
13664a5fe57eSJohannes Berg mutex_lock(&alx->mtx);
13674a5fe57eSJohannes Berg __alx_stop(alx);
13684a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
13694a5fe57eSJohannes Berg
1370ab69bde6SJohannes Berg return 0;
1371ab69bde6SJohannes Berg }
1372ab69bde6SJohannes Berg
alx_link_check(struct work_struct * work)1373ab69bde6SJohannes Berg static void alx_link_check(struct work_struct *work)
1374ab69bde6SJohannes Berg {
1375ab69bde6SJohannes Berg struct alx_priv *alx;
1376ab69bde6SJohannes Berg
1377ab69bde6SJohannes Berg alx = container_of(work, struct alx_priv, link_check_wk);
1378ab69bde6SJohannes Berg
13794a5fe57eSJohannes Berg mutex_lock(&alx->mtx);
1380ab69bde6SJohannes Berg alx_check_link(alx);
13814a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
1382ab69bde6SJohannes Berg }
1383ab69bde6SJohannes Berg
alx_reset(struct work_struct * work)1384ab69bde6SJohannes Berg static void alx_reset(struct work_struct *work)
1385ab69bde6SJohannes Berg {
1386ab69bde6SJohannes Berg struct alx_priv *alx = container_of(work, struct alx_priv, reset_wk);
1387ab69bde6SJohannes Berg
13884a5fe57eSJohannes Berg mutex_lock(&alx->mtx);
1389ab69bde6SJohannes Berg alx_reinit(alx);
13904a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
1391ab69bde6SJohannes Berg }
1392ab69bde6SJohannes Berg
alx_tpd_req(struct sk_buff * skb)1393ab725983STobias Regnery static int alx_tpd_req(struct sk_buff *skb)
1394ab725983STobias Regnery {
1395ab725983STobias Regnery int num;
1396ab725983STobias Regnery
1397ab725983STobias Regnery num = skb_shinfo(skb)->nr_frags + 1;
1398ab725983STobias Regnery /* we need one extra descriptor for LSOv2 */
1399ab725983STobias Regnery if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
1400ab725983STobias Regnery num++;
1401ab725983STobias Regnery
1402ab725983STobias Regnery return num;
1403ab725983STobias Regnery }
1404ab725983STobias Regnery
alx_tx_csum(struct sk_buff * skb,struct alx_txd * first)1405ab69bde6SJohannes Berg static int alx_tx_csum(struct sk_buff *skb, struct alx_txd *first)
1406ab69bde6SJohannes Berg {
1407ab69bde6SJohannes Berg u8 cso, css;
1408ab69bde6SJohannes Berg
1409ab69bde6SJohannes Berg if (skb->ip_summed != CHECKSUM_PARTIAL)
1410ab69bde6SJohannes Berg return 0;
1411ab69bde6SJohannes Berg
1412ab69bde6SJohannes Berg cso = skb_checksum_start_offset(skb);
1413ab69bde6SJohannes Berg if (cso & 1)
1414ab69bde6SJohannes Berg return -EINVAL;
1415ab69bde6SJohannes Berg
1416ab69bde6SJohannes Berg css = cso + skb->csum_offset;
1417ab69bde6SJohannes Berg first->word1 |= cpu_to_le32((cso >> 1) << TPD_CXSUMSTART_SHIFT);
1418ab69bde6SJohannes Berg first->word1 |= cpu_to_le32((css >> 1) << TPD_CXSUMOFFSET_SHIFT);
1419ab69bde6SJohannes Berg first->word1 |= cpu_to_le32(1 << TPD_CXSUM_EN_SHIFT);
1420ab69bde6SJohannes Berg
1421ab69bde6SJohannes Berg return 0;
1422ab69bde6SJohannes Berg }
1423ab69bde6SJohannes Berg
alx_tso(struct sk_buff * skb,struct alx_txd * first)1424ab725983STobias Regnery static int alx_tso(struct sk_buff *skb, struct alx_txd *first)
1425ab725983STobias Regnery {
1426ab725983STobias Regnery int err;
1427ab725983STobias Regnery
1428ab725983STobias Regnery if (skb->ip_summed != CHECKSUM_PARTIAL)
1429ab725983STobias Regnery return 0;
1430ab725983STobias Regnery
1431ab725983STobias Regnery if (!skb_is_gso(skb))
1432ab725983STobias Regnery return 0;
1433ab725983STobias Regnery
1434ab725983STobias Regnery err = skb_cow_head(skb, 0);
1435ab725983STobias Regnery if (err < 0)
1436ab725983STobias Regnery return err;
1437ab725983STobias Regnery
1438ab725983STobias Regnery if (skb->protocol == htons(ETH_P_IP)) {
1439ab725983STobias Regnery struct iphdr *iph = ip_hdr(skb);
1440ab725983STobias Regnery
1441ab725983STobias Regnery iph->check = 0;
1442ab725983STobias Regnery tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
1443ab725983STobias Regnery 0, IPPROTO_TCP, 0);
1444ab725983STobias Regnery first->word1 |= 1 << TPD_IPV4_SHIFT;
1445ab725983STobias Regnery } else if (skb_is_gso_v6(skb)) {
14464d4c3783SHeiner Kallweit tcp_v6_gso_csum_prep(skb);
1447ab725983STobias Regnery /* LSOv2: the first TPD only provides the packet length */
1448ab725983STobias Regnery first->adrl.l.pkt_len = skb->len;
1449ab725983STobias Regnery first->word1 |= 1 << TPD_LSO_V2_SHIFT;
1450ab725983STobias Regnery }
1451ab725983STobias Regnery
1452ab725983STobias Regnery first->word1 |= 1 << TPD_LSO_EN_SHIFT;
1453ab725983STobias Regnery first->word1 |= (skb_transport_offset(skb) &
1454ab725983STobias Regnery TPD_L4HDROFFSET_MASK) << TPD_L4HDROFFSET_SHIFT;
1455ab725983STobias Regnery first->word1 |= (skb_shinfo(skb)->gso_size &
1456ab725983STobias Regnery TPD_MSS_MASK) << TPD_MSS_SHIFT;
1457ab725983STobias Regnery return 1;
1458ab725983STobias Regnery }
1459ab725983STobias Regnery
alx_map_tx_skb(struct alx_tx_queue * txq,struct sk_buff * skb)1460702e8418STobias Regnery static int alx_map_tx_skb(struct alx_tx_queue *txq, struct sk_buff *skb)
1461ab69bde6SJohannes Berg {
1462ab69bde6SJohannes Berg struct alx_txd *tpd, *first_tpd;
1463ab69bde6SJohannes Berg dma_addr_t dma;
1464ab69bde6SJohannes Berg int maplen, f, first_idx = txq->write_idx;
1465ab69bde6SJohannes Berg
1466ab69bde6SJohannes Berg first_tpd = &txq->tpd[txq->write_idx];
1467ab69bde6SJohannes Berg tpd = first_tpd;
1468ab69bde6SJohannes Berg
1469ab725983STobias Regnery if (tpd->word1 & (1 << TPD_LSO_V2_SHIFT)) {
1470702e8418STobias Regnery if (++txq->write_idx == txq->count)
1471ab725983STobias Regnery txq->write_idx = 0;
1472ab725983STobias Regnery
1473ab725983STobias Regnery tpd = &txq->tpd[txq->write_idx];
1474ab725983STobias Regnery tpd->len = first_tpd->len;
1475ab725983STobias Regnery tpd->vlan_tag = first_tpd->vlan_tag;
1476ab725983STobias Regnery tpd->word1 = first_tpd->word1;
1477ab725983STobias Regnery }
1478ab725983STobias Regnery
1479ab69bde6SJohannes Berg maplen = skb_headlen(skb);
1480702e8418STobias Regnery dma = dma_map_single(txq->dev, skb->data, maplen,
1481ab69bde6SJohannes Berg DMA_TO_DEVICE);
1482702e8418STobias Regnery if (dma_mapping_error(txq->dev, dma))
1483ab69bde6SJohannes Berg goto err_dma;
1484ab69bde6SJohannes Berg
1485ab69bde6SJohannes Berg dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen);
1486ab69bde6SJohannes Berg dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma);
1487ab69bde6SJohannes Berg
1488ab69bde6SJohannes Berg tpd->adrl.addr = cpu_to_le64(dma);
1489ab69bde6SJohannes Berg tpd->len = cpu_to_le16(maplen);
1490ab69bde6SJohannes Berg
1491ab69bde6SJohannes Berg for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
1492d7840976SMatthew Wilcox (Oracle) skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
1493ab69bde6SJohannes Berg
1494702e8418STobias Regnery if (++txq->write_idx == txq->count)
1495ab69bde6SJohannes Berg txq->write_idx = 0;
1496ab69bde6SJohannes Berg tpd = &txq->tpd[txq->write_idx];
1497ab69bde6SJohannes Berg
1498ab69bde6SJohannes Berg tpd->word1 = first_tpd->word1;
1499ab69bde6SJohannes Berg
1500ab69bde6SJohannes Berg maplen = skb_frag_size(frag);
1501702e8418STobias Regnery dma = skb_frag_dma_map(txq->dev, frag, 0,
1502ab69bde6SJohannes Berg maplen, DMA_TO_DEVICE);
1503702e8418STobias Regnery if (dma_mapping_error(txq->dev, dma))
1504ab69bde6SJohannes Berg goto err_dma;
1505ab69bde6SJohannes Berg dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen);
1506ab69bde6SJohannes Berg dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma);
1507ab69bde6SJohannes Berg
1508ab69bde6SJohannes Berg tpd->adrl.addr = cpu_to_le64(dma);
1509ab69bde6SJohannes Berg tpd->len = cpu_to_le16(maplen);
1510ab69bde6SJohannes Berg }
1511ab69bde6SJohannes Berg
1512ab69bde6SJohannes Berg /* last TPD, set EOP flag and store skb */
1513ab69bde6SJohannes Berg tpd->word1 |= cpu_to_le32(1 << TPD_EOP_SHIFT);
1514ab69bde6SJohannes Berg txq->bufs[txq->write_idx].skb = skb;
1515ab69bde6SJohannes Berg
1516702e8418STobias Regnery if (++txq->write_idx == txq->count)
1517ab69bde6SJohannes Berg txq->write_idx = 0;
1518ab69bde6SJohannes Berg
1519ab69bde6SJohannes Berg return 0;
1520ab69bde6SJohannes Berg
1521ab69bde6SJohannes Berg err_dma:
1522ab69bde6SJohannes Berg f = first_idx;
1523ab69bde6SJohannes Berg while (f != txq->write_idx) {
1524702e8418STobias Regnery alx_free_txbuf(txq, f);
1525702e8418STobias Regnery if (++f == txq->count)
1526ab69bde6SJohannes Berg f = 0;
1527ab69bde6SJohannes Berg }
1528ab69bde6SJohannes Berg return -ENOMEM;
1529ab69bde6SJohannes Berg }
1530ab69bde6SJohannes Berg
alx_start_xmit_ring(struct sk_buff * skb,struct alx_tx_queue * txq)15312e06826bSTobias Regnery static netdev_tx_t alx_start_xmit_ring(struct sk_buff *skb,
15322e06826bSTobias Regnery struct alx_tx_queue *txq)
1533ab69bde6SJohannes Berg {
15342e06826bSTobias Regnery struct alx_priv *alx;
1535ab69bde6SJohannes Berg struct alx_txd *first;
1536ab725983STobias Regnery int tso;
1537ab69bde6SJohannes Berg
15382e06826bSTobias Regnery alx = netdev_priv(txq->netdev);
15392e06826bSTobias Regnery
1540702e8418STobias Regnery if (alx_tpd_avail(txq) < alx_tpd_req(skb)) {
15412e06826bSTobias Regnery netif_tx_stop_queue(alx_get_tx_queue(txq));
1542ab69bde6SJohannes Berg goto drop;
1543ab69bde6SJohannes Berg }
1544ab69bde6SJohannes Berg
1545ab69bde6SJohannes Berg first = &txq->tpd[txq->write_idx];
1546ab69bde6SJohannes Berg memset(first, 0, sizeof(*first));
1547ab69bde6SJohannes Berg
1548ab725983STobias Regnery tso = alx_tso(skb, first);
1549ab725983STobias Regnery if (tso < 0)
1550ab725983STobias Regnery goto drop;
1551ab725983STobias Regnery else if (!tso && alx_tx_csum(skb, first))
1552ab69bde6SJohannes Berg goto drop;
1553ab69bde6SJohannes Berg
1554702e8418STobias Regnery if (alx_map_tx_skb(txq, skb) < 0)
1555ab69bde6SJohannes Berg goto drop;
1556ab69bde6SJohannes Berg
15572e06826bSTobias Regnery netdev_tx_sent_queue(alx_get_tx_queue(txq), skb->len);
1558ab69bde6SJohannes Berg
1559ab69bde6SJohannes Berg /* flush updates before updating hardware */
1560ab69bde6SJohannes Berg wmb();
15612e06826bSTobias Regnery alx_write_mem16(&alx->hw, txq->p_reg, txq->write_idx);
1562ab69bde6SJohannes Berg
1563702e8418STobias Regnery if (alx_tpd_avail(txq) < txq->count / 8)
15642e06826bSTobias Regnery netif_tx_stop_queue(alx_get_tx_queue(txq));
1565ab69bde6SJohannes Berg
1566ab69bde6SJohannes Berg return NETDEV_TX_OK;
1567ab69bde6SJohannes Berg
1568ab69bde6SJohannes Berg drop:
1569548ff1edSEric W. Biederman dev_kfree_skb_any(skb);
1570ab69bde6SJohannes Berg return NETDEV_TX_OK;
1571ab69bde6SJohannes Berg }
1572ab69bde6SJohannes Berg
alx_start_xmit(struct sk_buff * skb,struct net_device * netdev)15732e06826bSTobias Regnery static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
15742e06826bSTobias Regnery struct net_device *netdev)
15752e06826bSTobias Regnery {
15762e06826bSTobias Regnery struct alx_priv *alx = netdev_priv(netdev);
15772e06826bSTobias Regnery return alx_start_xmit_ring(skb, alx_tx_queue_mapping(alx, skb));
15782e06826bSTobias Regnery }
15792e06826bSTobias Regnery
alx_tx_timeout(struct net_device * dev,unsigned int txqueue)15800290bd29SMichael S. Tsirkin static void alx_tx_timeout(struct net_device *dev, unsigned int txqueue)
1581ab69bde6SJohannes Berg {
1582ab69bde6SJohannes Berg struct alx_priv *alx = netdev_priv(dev);
1583ab69bde6SJohannes Berg
1584ab69bde6SJohannes Berg alx_schedule_reset(alx);
1585ab69bde6SJohannes Berg }
1586ab69bde6SJohannes Berg
alx_mdio_read(struct net_device * netdev,int prtad,int devad,u16 addr)1587ab69bde6SJohannes Berg static int alx_mdio_read(struct net_device *netdev,
1588ab69bde6SJohannes Berg int prtad, int devad, u16 addr)
1589ab69bde6SJohannes Berg {
1590ab69bde6SJohannes Berg struct alx_priv *alx = netdev_priv(netdev);
1591ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
1592ab69bde6SJohannes Berg u16 val;
1593ab69bde6SJohannes Berg int err;
1594ab69bde6SJohannes Berg
1595ab69bde6SJohannes Berg if (prtad != hw->mdio.prtad)
1596ab69bde6SJohannes Berg return -EINVAL;
1597ab69bde6SJohannes Berg
1598ab69bde6SJohannes Berg if (devad == MDIO_DEVAD_NONE)
1599ab69bde6SJohannes Berg err = alx_read_phy_reg(hw, addr, &val);
1600ab69bde6SJohannes Berg else
1601ab69bde6SJohannes Berg err = alx_read_phy_ext(hw, devad, addr, &val);
1602ab69bde6SJohannes Berg
1603ab69bde6SJohannes Berg if (err)
1604ab69bde6SJohannes Berg return err;
1605ab69bde6SJohannes Berg return val;
1606ab69bde6SJohannes Berg }
1607ab69bde6SJohannes Berg
alx_mdio_write(struct net_device * netdev,int prtad,int devad,u16 addr,u16 val)1608ab69bde6SJohannes Berg static int alx_mdio_write(struct net_device *netdev,
1609ab69bde6SJohannes Berg int prtad, int devad, u16 addr, u16 val)
1610ab69bde6SJohannes Berg {
1611ab69bde6SJohannes Berg struct alx_priv *alx = netdev_priv(netdev);
1612ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
1613ab69bde6SJohannes Berg
1614ab69bde6SJohannes Berg if (prtad != hw->mdio.prtad)
1615ab69bde6SJohannes Berg return -EINVAL;
1616ab69bde6SJohannes Berg
1617ab69bde6SJohannes Berg if (devad == MDIO_DEVAD_NONE)
1618ab69bde6SJohannes Berg return alx_write_phy_reg(hw, addr, val);
1619ab69bde6SJohannes Berg
1620ab69bde6SJohannes Berg return alx_write_phy_ext(hw, devad, addr, val);
1621ab69bde6SJohannes Berg }
1622ab69bde6SJohannes Berg
alx_ioctl(struct net_device * netdev,struct ifreq * ifr,int cmd)1623ab69bde6SJohannes Berg static int alx_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
1624ab69bde6SJohannes Berg {
1625ab69bde6SJohannes Berg struct alx_priv *alx = netdev_priv(netdev);
1626ab69bde6SJohannes Berg
1627ab69bde6SJohannes Berg if (!netif_running(netdev))
1628ab69bde6SJohannes Berg return -EAGAIN;
1629ab69bde6SJohannes Berg
1630ab69bde6SJohannes Berg return mdio_mii_ioctl(&alx->hw.mdio, if_mii(ifr), cmd);
1631ab69bde6SJohannes Berg }
1632ab69bde6SJohannes Berg
1633ab69bde6SJohannes Berg #ifdef CONFIG_NET_POLL_CONTROLLER
alx_poll_controller(struct net_device * netdev)1634ab69bde6SJohannes Berg static void alx_poll_controller(struct net_device *netdev)
1635ab69bde6SJohannes Berg {
1636ab69bde6SJohannes Berg struct alx_priv *alx = netdev_priv(netdev);
1637e0eac254STobias Regnery int i;
1638ab69bde6SJohannes Berg
1639f3297f68SChristoph Hellwig if (alx->hw.pdev->msix_enabled) {
1640dc39a78bSTobias Regnery alx_intr_msix_misc(0, alx);
1641e0eac254STobias Regnery for (i = 0; i < alx->num_txq; i++)
1642e0eac254STobias Regnery alx_intr_msix_ring(0, alx->qnapi[i]);
1643f3297f68SChristoph Hellwig } else if (alx->hw.pdev->msi_enabled)
1644ab69bde6SJohannes Berg alx_intr_msi(0, alx);
1645ab69bde6SJohannes Berg else
1646ab69bde6SJohannes Berg alx_intr_legacy(0, alx);
1647ab69bde6SJohannes Berg }
1648ab69bde6SJohannes Berg #endif
1649ab69bde6SJohannes Berg
alx_get_stats64(struct net_device * dev,struct rtnl_link_stats64 * net_stats)1650bc1f4470Sstephen hemminger static void alx_get_stats64(struct net_device *dev,
1651f1b6b106SSabrina Dubroca struct rtnl_link_stats64 *net_stats)
1652f1b6b106SSabrina Dubroca {
1653f1b6b106SSabrina Dubroca struct alx_priv *alx = netdev_priv(dev);
1654f1b6b106SSabrina Dubroca struct alx_hw_stats *hw_stats = &alx->hw.stats;
1655f1b6b106SSabrina Dubroca
1656f1b6b106SSabrina Dubroca spin_lock(&alx->stats_lock);
1657f1b6b106SSabrina Dubroca
1658f1b6b106SSabrina Dubroca alx_update_hw_stats(&alx->hw);
1659f1b6b106SSabrina Dubroca
1660f1b6b106SSabrina Dubroca net_stats->tx_bytes = hw_stats->tx_byte_cnt;
1661f1b6b106SSabrina Dubroca net_stats->rx_bytes = hw_stats->rx_byte_cnt;
1662f1b6b106SSabrina Dubroca net_stats->multicast = hw_stats->rx_mcast;
1663f1b6b106SSabrina Dubroca net_stats->collisions = hw_stats->tx_single_col +
1664f1b6b106SSabrina Dubroca hw_stats->tx_multi_col +
1665f1b6b106SSabrina Dubroca hw_stats->tx_late_col +
1666f1b6b106SSabrina Dubroca hw_stats->tx_abort_col;
1667f1b6b106SSabrina Dubroca
1668f1b6b106SSabrina Dubroca net_stats->rx_errors = hw_stats->rx_frag +
1669f1b6b106SSabrina Dubroca hw_stats->rx_fcs_err +
1670f1b6b106SSabrina Dubroca hw_stats->rx_len_err +
1671f1b6b106SSabrina Dubroca hw_stats->rx_ov_sz +
1672f1b6b106SSabrina Dubroca hw_stats->rx_ov_rrd +
1673f1b6b106SSabrina Dubroca hw_stats->rx_align_err +
1674f1b6b106SSabrina Dubroca hw_stats->rx_ov_rxf;
1675f1b6b106SSabrina Dubroca
1676f1b6b106SSabrina Dubroca net_stats->rx_fifo_errors = hw_stats->rx_ov_rxf;
1677f1b6b106SSabrina Dubroca net_stats->rx_length_errors = hw_stats->rx_len_err;
1678f1b6b106SSabrina Dubroca net_stats->rx_crc_errors = hw_stats->rx_fcs_err;
1679f1b6b106SSabrina Dubroca net_stats->rx_frame_errors = hw_stats->rx_align_err;
1680f1b6b106SSabrina Dubroca net_stats->rx_dropped = hw_stats->rx_ov_rrd;
1681f1b6b106SSabrina Dubroca
1682f1b6b106SSabrina Dubroca net_stats->tx_errors = hw_stats->tx_late_col +
1683f1b6b106SSabrina Dubroca hw_stats->tx_abort_col +
1684f1b6b106SSabrina Dubroca hw_stats->tx_underrun +
1685f1b6b106SSabrina Dubroca hw_stats->tx_trunc;
1686f1b6b106SSabrina Dubroca
1687f1b6b106SSabrina Dubroca net_stats->tx_aborted_errors = hw_stats->tx_abort_col;
1688f1b6b106SSabrina Dubroca net_stats->tx_fifo_errors = hw_stats->tx_underrun;
1689f1b6b106SSabrina Dubroca net_stats->tx_window_errors = hw_stats->tx_late_col;
1690f1b6b106SSabrina Dubroca
1691f1b6b106SSabrina Dubroca net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors;
1692f1b6b106SSabrina Dubroca net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors;
1693f1b6b106SSabrina Dubroca
1694f1b6b106SSabrina Dubroca spin_unlock(&alx->stats_lock);
1695f1b6b106SSabrina Dubroca }
1696f1b6b106SSabrina Dubroca
1697ab69bde6SJohannes Berg static const struct net_device_ops alx_netdev_ops = {
1698ab69bde6SJohannes Berg .ndo_open = alx_open,
1699ab69bde6SJohannes Berg .ndo_stop = alx_stop,
1700ab69bde6SJohannes Berg .ndo_start_xmit = alx_start_xmit,
1701f1b6b106SSabrina Dubroca .ndo_get_stats64 = alx_get_stats64,
1702ab69bde6SJohannes Berg .ndo_set_rx_mode = alx_set_rx_mode,
1703ab69bde6SJohannes Berg .ndo_validate_addr = eth_validate_addr,
1704ab69bde6SJohannes Berg .ndo_set_mac_address = alx_set_mac_address,
1705ab69bde6SJohannes Berg .ndo_change_mtu = alx_change_mtu,
1706a7605370SArnd Bergmann .ndo_eth_ioctl = alx_ioctl,
1707ab69bde6SJohannes Berg .ndo_tx_timeout = alx_tx_timeout,
1708ab69bde6SJohannes Berg .ndo_fix_features = alx_fix_features,
1709ab69bde6SJohannes Berg #ifdef CONFIG_NET_POLL_CONTROLLER
1710ab69bde6SJohannes Berg .ndo_poll_controller = alx_poll_controller,
1711ab69bde6SJohannes Berg #endif
1712ab69bde6SJohannes Berg };
1713ab69bde6SJohannes Berg
alx_probe(struct pci_dev * pdev,const struct pci_device_id * ent)1714ab69bde6SJohannes Berg static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1715ab69bde6SJohannes Berg {
1716ab69bde6SJohannes Berg struct net_device *netdev;
1717ab69bde6SJohannes Berg struct alx_priv *alx;
1718ab69bde6SJohannes Berg struct alx_hw *hw;
1719ab69bde6SJohannes Berg bool phy_configured;
1720caa8e932SJohannes Thumshirn int err;
1721ab69bde6SJohannes Berg
1722ab69bde6SJohannes Berg err = pci_enable_device_mem(pdev);
1723ab69bde6SJohannes Berg if (err)
1724ab69bde6SJohannes Berg return err;
1725ab69bde6SJohannes Berg
1726ab69bde6SJohannes Berg /* The alx chip can DMA to 64-bit addresses, but it uses a single
1727ab69bde6SJohannes Berg * shared register for the high 32 bits, so only a single, aligned,
1728ab69bde6SJohannes Berg * 4 GB physical address range can be used for descriptors.
1729ab69bde6SJohannes Berg */
17308d7f1fbfSPeter Senna Tschudin if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
1731ab69bde6SJohannes Berg dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n");
1732ab69bde6SJohannes Berg } else {
17338d7f1fbfSPeter Senna Tschudin err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
1734ab69bde6SJohannes Berg if (err) {
17358d7f1fbfSPeter Senna Tschudin dev_err(&pdev->dev, "No usable DMA config, aborting\n");
1736ab69bde6SJohannes Berg goto out_pci_disable;
1737ab69bde6SJohannes Berg }
1738ab69bde6SJohannes Berg }
1739ab69bde6SJohannes Berg
1740caa8e932SJohannes Thumshirn err = pci_request_mem_regions(pdev, alx_drv_name);
1741ab69bde6SJohannes Berg if (err) {
1742ab69bde6SJohannes Berg dev_err(&pdev->dev,
1743caa8e932SJohannes Thumshirn "pci_request_mem_regions failed\n");
1744ab69bde6SJohannes Berg goto out_pci_disable;
1745ab69bde6SJohannes Berg }
1746ab69bde6SJohannes Berg
1747ab69bde6SJohannes Berg pci_set_master(pdev);
1748ab69bde6SJohannes Berg
1749c3eb7a77SYijing Wang if (!pdev->pm_cap) {
1750ab69bde6SJohannes Berg dev_err(&pdev->dev,
1751ab69bde6SJohannes Berg "Can't find power management capability, aborting\n");
1752ab69bde6SJohannes Berg err = -EIO;
1753ab69bde6SJohannes Berg goto out_pci_release;
1754ab69bde6SJohannes Berg }
1755ab69bde6SJohannes Berg
1756d768319cSTobias Regnery netdev = alloc_etherdev_mqs(sizeof(*alx),
1757d768319cSTobias Regnery ALX_MAX_TX_QUEUES, 1);
1758ab69bde6SJohannes Berg if (!netdev) {
1759ab69bde6SJohannes Berg err = -ENOMEM;
1760ab69bde6SJohannes Berg goto out_pci_release;
1761ab69bde6SJohannes Berg }
1762ab69bde6SJohannes Berg
1763ab69bde6SJohannes Berg SET_NETDEV_DEV(netdev, &pdev->dev);
1764ab69bde6SJohannes Berg alx = netdev_priv(netdev);
1765a8798a5cSMaarten Lankhorst spin_lock_init(&alx->hw.mdio_lock);
1766a8798a5cSMaarten Lankhorst spin_lock_init(&alx->irq_lock);
17673e5ccc29SJohn Greene spin_lock_init(&alx->stats_lock);
1768ab69bde6SJohannes Berg alx->dev = netdev;
1769ab69bde6SJohannes Berg alx->hw.pdev = pdev;
1770ab69bde6SJohannes Berg alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP |
1771ab69bde6SJohannes Berg NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR | NETIF_MSG_WOL;
1772ab69bde6SJohannes Berg hw = &alx->hw;
1773ab69bde6SJohannes Berg pci_set_drvdata(pdev, alx);
1774ab69bde6SJohannes Berg
1775ab69bde6SJohannes Berg hw->hw_addr = pci_ioremap_bar(pdev, 0);
1776ab69bde6SJohannes Berg if (!hw->hw_addr) {
1777ab69bde6SJohannes Berg dev_err(&pdev->dev, "cannot map device registers\n");
1778ab69bde6SJohannes Berg err = -EIO;
1779ab69bde6SJohannes Berg goto out_free_netdev;
1780ab69bde6SJohannes Berg }
1781ab69bde6SJohannes Berg
1782ab69bde6SJohannes Berg netdev->netdev_ops = &alx_netdev_ops;
17837ad24ea4SWilfried Klaebe netdev->ethtool_ops = &alx_ethtool_ops;
1784f3297f68SChristoph Hellwig netdev->irq = pci_irq_vector(pdev, 0);
1785ab69bde6SJohannes Berg netdev->watchdog_timeo = ALX_WATCHDOG_TIME;
1786ab69bde6SJohannes Berg
1787ab69bde6SJohannes Berg if (ent->driver_data & ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG)
1788ab69bde6SJohannes Berg pdev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
1789ab69bde6SJohannes Berg
1790ab69bde6SJohannes Berg err = alx_init_sw(alx);
1791ab69bde6SJohannes Berg if (err) {
1792ab69bde6SJohannes Berg dev_err(&pdev->dev, "net device private data init failed\n");
1793ab69bde6SJohannes Berg goto out_unmap;
1794ab69bde6SJohannes Berg }
1795ab69bde6SJohannes Berg
17964a5fe57eSJohannes Berg mutex_lock(&alx->mtx);
17974a5fe57eSJohannes Berg
1798ab69bde6SJohannes Berg alx_reset_pcie(hw);
1799ab69bde6SJohannes Berg
1800ab69bde6SJohannes Berg phy_configured = alx_phy_configured(hw);
1801ab69bde6SJohannes Berg
1802ab69bde6SJohannes Berg if (!phy_configured)
1803ab69bde6SJohannes Berg alx_reset_phy(hw);
1804ab69bde6SJohannes Berg
1805ab69bde6SJohannes Berg err = alx_reset_mac(hw);
1806ab69bde6SJohannes Berg if (err) {
1807ab69bde6SJohannes Berg dev_err(&pdev->dev, "MAC Reset failed, error = %d\n", err);
18084a5fe57eSJohannes Berg goto out_unlock;
1809ab69bde6SJohannes Berg }
1810ab69bde6SJohannes Berg
1811ab69bde6SJohannes Berg /* setup link to put it in a known good starting state */
1812ab69bde6SJohannes Berg if (!phy_configured) {
1813ab69bde6SJohannes Berg err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl);
1814ab69bde6SJohannes Berg if (err) {
1815ab69bde6SJohannes Berg dev_err(&pdev->dev,
1816ab69bde6SJohannes Berg "failed to configure PHY speed/duplex (err=%d)\n",
1817ab69bde6SJohannes Berg err);
18184a5fe57eSJohannes Berg goto out_unlock;
1819ab69bde6SJohannes Berg }
1820ab69bde6SJohannes Berg }
1821ab69bde6SJohannes Berg
1822ab725983STobias Regnery netdev->hw_features = NETIF_F_SG |
1823ab725983STobias Regnery NETIF_F_HW_CSUM |
18243a7f75e5STobias Regnery NETIF_F_RXCSUM |
1825ab725983STobias Regnery NETIF_F_TSO |
1826ab725983STobias Regnery NETIF_F_TSO6;
1827ab69bde6SJohannes Berg
1828ab69bde6SJohannes Berg if (alx_get_perm_macaddr(hw, hw->perm_addr)) {
1829ab69bde6SJohannes Berg dev_warn(&pdev->dev,
1830ab69bde6SJohannes Berg "Invalid permanent address programmed, using random one\n");
1831ab69bde6SJohannes Berg eth_hw_addr_random(netdev);
1832ab69bde6SJohannes Berg memcpy(hw->perm_addr, netdev->dev_addr, netdev->addr_len);
1833ab69bde6SJohannes Berg }
1834ab69bde6SJohannes Berg
1835ab69bde6SJohannes Berg memcpy(hw->mac_addr, hw->perm_addr, ETH_ALEN);
1836a96d317fSJakub Kicinski eth_hw_addr_set(netdev, hw->mac_addr);
1837ab69bde6SJohannes Berg memcpy(netdev->perm_addr, hw->perm_addr, ETH_ALEN);
1838ab69bde6SJohannes Berg
1839ab69bde6SJohannes Berg hw->mdio.prtad = 0;
1840ab69bde6SJohannes Berg hw->mdio.mmds = 0;
1841ab69bde6SJohannes Berg hw->mdio.dev = netdev;
1842ab69bde6SJohannes Berg hw->mdio.mode_support = MDIO_SUPPORTS_C45 |
1843ab69bde6SJohannes Berg MDIO_SUPPORTS_C22 |
1844ab69bde6SJohannes Berg MDIO_EMULATE_C22;
1845ab69bde6SJohannes Berg hw->mdio.mdio_read = alx_mdio_read;
1846ab69bde6SJohannes Berg hw->mdio.mdio_write = alx_mdio_write;
1847ab69bde6SJohannes Berg
1848ab69bde6SJohannes Berg if (!alx_get_phy_info(hw)) {
1849ab69bde6SJohannes Berg dev_err(&pdev->dev, "failed to identify PHY\n");
1850ab69bde6SJohannes Berg err = -EIO;
18514a5fe57eSJohannes Berg goto out_unlock;
1852ab69bde6SJohannes Berg }
1853ab69bde6SJohannes Berg
18544a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
18554a5fe57eSJohannes Berg
1856ab69bde6SJohannes Berg INIT_WORK(&alx->link_check_wk, alx_link_check);
1857ab69bde6SJohannes Berg INIT_WORK(&alx->reset_wk, alx_reset);
1858ab69bde6SJohannes Berg netif_carrier_off(netdev);
1859ab69bde6SJohannes Berg
1860ab69bde6SJohannes Berg err = register_netdev(netdev);
1861ab69bde6SJohannes Berg if (err) {
1862ab69bde6SJohannes Berg dev_err(&pdev->dev, "register netdevice failed\n");
18639d8a29aeSDan Carpenter goto out_unmap;
1864ab69bde6SJohannes Berg }
1865ab69bde6SJohannes Berg
1866ab69bde6SJohannes Berg netdev_info(netdev,
1867ab69bde6SJohannes Berg "Qualcomm Atheros AR816x/AR817x Ethernet [%pM]\n",
1868ab69bde6SJohannes Berg netdev->dev_addr);
1869ab69bde6SJohannes Berg
1870ab69bde6SJohannes Berg return 0;
1871ab69bde6SJohannes Berg
18724a5fe57eSJohannes Berg out_unlock:
18734a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
1874ab69bde6SJohannes Berg out_unmap:
1875ab69bde6SJohannes Berg iounmap(hw->hw_addr);
1876ab69bde6SJohannes Berg out_free_netdev:
1877ab69bde6SJohannes Berg free_netdev(netdev);
1878ab69bde6SJohannes Berg out_pci_release:
1879caa8e932SJohannes Thumshirn pci_release_mem_regions(pdev);
1880ab69bde6SJohannes Berg out_pci_disable:
1881ab69bde6SJohannes Berg pci_disable_device(pdev);
1882ab69bde6SJohannes Berg return err;
1883ab69bde6SJohannes Berg }
1884ab69bde6SJohannes Berg
alx_remove(struct pci_dev * pdev)1885ab69bde6SJohannes Berg static void alx_remove(struct pci_dev *pdev)
1886ab69bde6SJohannes Berg {
1887ab69bde6SJohannes Berg struct alx_priv *alx = pci_get_drvdata(pdev);
1888ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
1889ab69bde6SJohannes Berg
1890ab69bde6SJohannes Berg /* restore permanent mac address */
1891ab69bde6SJohannes Berg alx_set_macaddr(hw, hw->perm_addr);
1892ab69bde6SJohannes Berg
1893ab69bde6SJohannes Berg unregister_netdev(alx->dev);
1894ab69bde6SJohannes Berg iounmap(hw->hw_addr);
1895caa8e932SJohannes Thumshirn pci_release_mem_regions(pdev);
1896ab69bde6SJohannes Berg
1897ab69bde6SJohannes Berg pci_disable_device(pdev);
1898ab69bde6SJohannes Berg
18994a5fe57eSJohannes Berg mutex_destroy(&alx->mtx);
19004a5fe57eSJohannes Berg
1901ab69bde6SJohannes Berg free_netdev(alx->dev);
1902ab69bde6SJohannes Berg }
1903ab69bde6SJohannes Berg
alx_suspend(struct device * dev)1904ab69bde6SJohannes Berg static int alx_suspend(struct device *dev)
1905ab69bde6SJohannes Berg {
1906f54b0fc8SChuhong Yuan struct alx_priv *alx = dev_get_drvdata(dev);
1907ab69bde6SJohannes Berg
1908bc2bebe8SJohannes Berg if (!netif_running(alx->dev))
1909bc2bebe8SJohannes Berg return 0;
19106ad1c94eSJakub Kicinski
19116ad1c94eSJakub Kicinski rtnl_lock();
1912bc2bebe8SJohannes Berg netif_device_detach(alx->dev);
19134a5fe57eSJohannes Berg
19144a5fe57eSJohannes Berg mutex_lock(&alx->mtx);
1915bc2bebe8SJohannes Berg __alx_stop(alx);
19164a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
19176ad1c94eSJakub Kicinski rtnl_unlock();
19184a5fe57eSJohannes Berg
1919ab69bde6SJohannes Berg return 0;
1920ab69bde6SJohannes Berg }
1921ab69bde6SJohannes Berg
alx_resume(struct device * dev)1922ab69bde6SJohannes Berg static int alx_resume(struct device *dev)
1923ab69bde6SJohannes Berg {
1924f54b0fc8SChuhong Yuan struct alx_priv *alx = dev_get_drvdata(dev);
1925b54629e2Shahnjo struct alx_hw *hw = &alx->hw;
1926bc800e8bSSabrina Dubroca int err;
1927b54629e2Shahnjo
19286ad1c94eSJakub Kicinski rtnl_lock();
19294a5fe57eSJohannes Berg mutex_lock(&alx->mtx);
1930b54629e2Shahnjo alx_reset_phy(hw);
1931ab69bde6SJohannes Berg
19324a5fe57eSJohannes Berg if (!netif_running(alx->dev)) {
19334a5fe57eSJohannes Berg err = 0;
19344a5fe57eSJohannes Berg goto unlock;
19354a5fe57eSJohannes Berg }
1936bc800e8bSSabrina Dubroca
1937bc800e8bSSabrina Dubroca err = __alx_open(alx, true);
1938a4dcfbc4SJakub Kicinski if (err)
19394a5fe57eSJohannes Berg goto unlock;
1940a4dcfbc4SJakub Kicinski
1941a4dcfbc4SJakub Kicinski netif_device_attach(alx->dev);
1942a4dcfbc4SJakub Kicinski
19434a5fe57eSJohannes Berg unlock:
19444a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
19456ad1c94eSJakub Kicinski rtnl_unlock();
19464a5fe57eSJohannes Berg return err;
1947ab69bde6SJohannes Berg }
1948ab69bde6SJohannes Berg
1949*1d330d4fSChristoph Heiss static DEFINE_SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume);
1950bc2bebe8SJohannes Berg
alx_pci_error_detected(struct pci_dev * pdev,pci_channel_state_t state)1951ab69bde6SJohannes Berg static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev,
1952ab69bde6SJohannes Berg pci_channel_state_t state)
1953ab69bde6SJohannes Berg {
1954ab69bde6SJohannes Berg struct alx_priv *alx = pci_get_drvdata(pdev);
1955ab69bde6SJohannes Berg struct net_device *netdev = alx->dev;
1956ab69bde6SJohannes Berg pci_ers_result_t rc = PCI_ERS_RESULT_NEED_RESET;
1957ab69bde6SJohannes Berg
1958ab69bde6SJohannes Berg dev_info(&pdev->dev, "pci error detected\n");
1959ab69bde6SJohannes Berg
19604a5fe57eSJohannes Berg mutex_lock(&alx->mtx);
1961ab69bde6SJohannes Berg
1962ab69bde6SJohannes Berg if (netif_running(netdev)) {
1963ab69bde6SJohannes Berg netif_device_detach(netdev);
1964ab69bde6SJohannes Berg alx_halt(alx);
1965ab69bde6SJohannes Berg }
1966ab69bde6SJohannes Berg
1967ab69bde6SJohannes Berg if (state == pci_channel_io_perm_failure)
1968ab69bde6SJohannes Berg rc = PCI_ERS_RESULT_DISCONNECT;
1969ab69bde6SJohannes Berg else
1970ab69bde6SJohannes Berg pci_disable_device(pdev);
1971ab69bde6SJohannes Berg
19724a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
1973ab69bde6SJohannes Berg
1974ab69bde6SJohannes Berg return rc;
1975ab69bde6SJohannes Berg }
1976ab69bde6SJohannes Berg
alx_pci_error_slot_reset(struct pci_dev * pdev)1977ab69bde6SJohannes Berg static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev)
1978ab69bde6SJohannes Berg {
1979ab69bde6SJohannes Berg struct alx_priv *alx = pci_get_drvdata(pdev);
1980ab69bde6SJohannes Berg struct alx_hw *hw = &alx->hw;
1981ab69bde6SJohannes Berg pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT;
1982ab69bde6SJohannes Berg
1983ab69bde6SJohannes Berg dev_info(&pdev->dev, "pci error slot reset\n");
1984ab69bde6SJohannes Berg
19854a5fe57eSJohannes Berg mutex_lock(&alx->mtx);
1986ab69bde6SJohannes Berg
1987ab69bde6SJohannes Berg if (pci_enable_device(pdev)) {
1988ab69bde6SJohannes Berg dev_err(&pdev->dev, "Failed to re-enable PCI device after reset\n");
1989ab69bde6SJohannes Berg goto out;
1990ab69bde6SJohannes Berg }
1991ab69bde6SJohannes Berg
1992ab69bde6SJohannes Berg pci_set_master(pdev);
1993ab69bde6SJohannes Berg
1994ab69bde6SJohannes Berg alx_reset_pcie(hw);
1995ab69bde6SJohannes Berg if (!alx_reset_mac(hw))
1996ab69bde6SJohannes Berg rc = PCI_ERS_RESULT_RECOVERED;
1997ab69bde6SJohannes Berg out:
19984a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
1999ab69bde6SJohannes Berg
2000ab69bde6SJohannes Berg return rc;
2001ab69bde6SJohannes Berg }
2002ab69bde6SJohannes Berg
alx_pci_error_resume(struct pci_dev * pdev)2003ab69bde6SJohannes Berg static void alx_pci_error_resume(struct pci_dev *pdev)
2004ab69bde6SJohannes Berg {
2005ab69bde6SJohannes Berg struct alx_priv *alx = pci_get_drvdata(pdev);
2006ab69bde6SJohannes Berg struct net_device *netdev = alx->dev;
2007ab69bde6SJohannes Berg
2008ab69bde6SJohannes Berg dev_info(&pdev->dev, "pci error resume\n");
2009ab69bde6SJohannes Berg
20104a5fe57eSJohannes Berg mutex_lock(&alx->mtx);
2011ab69bde6SJohannes Berg
2012ab69bde6SJohannes Berg if (netif_running(netdev)) {
2013ab69bde6SJohannes Berg alx_activate(alx);
2014ab69bde6SJohannes Berg netif_device_attach(netdev);
2015ab69bde6SJohannes Berg }
2016ab69bde6SJohannes Berg
20174a5fe57eSJohannes Berg mutex_unlock(&alx->mtx);
2018ab69bde6SJohannes Berg }
2019ab69bde6SJohannes Berg
2020ab69bde6SJohannes Berg static const struct pci_error_handlers alx_err_handlers = {
2021ab69bde6SJohannes Berg .error_detected = alx_pci_error_detected,
2022ab69bde6SJohannes Berg .slot_reset = alx_pci_error_slot_reset,
2023ab69bde6SJohannes Berg .resume = alx_pci_error_resume,
2024ab69bde6SJohannes Berg };
2025ab69bde6SJohannes Berg
20269baa3c34SBenoit Taine static const struct pci_device_id alx_pci_tbl[] = {
2027ab69bde6SJohannes Berg { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8161),
2028ab69bde6SJohannes Berg .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
2029ab69bde6SJohannes Berg { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200),
2030ab69bde6SJohannes Berg .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
20310208e951SBen Pope { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2400),
20320208e951SBen Pope .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
2033b99b43bbSOwen Lin { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2500),
2034b99b43bbSOwen Lin .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
2035ab69bde6SJohannes Berg { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162),
2036ab69bde6SJohannes Berg .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
2037ab69bde6SJohannes Berg { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) },
2038ab69bde6SJohannes Berg { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8172) },
2039ab69bde6SJohannes Berg {}
2040ab69bde6SJohannes Berg };
2041ab69bde6SJohannes Berg
2042ab69bde6SJohannes Berg static struct pci_driver alx_driver = {
2043ab69bde6SJohannes Berg .name = alx_drv_name,
2044ab69bde6SJohannes Berg .id_table = alx_pci_tbl,
2045ab69bde6SJohannes Berg .probe = alx_probe,
2046ab69bde6SJohannes Berg .remove = alx_remove,
2047ab69bde6SJohannes Berg .err_handler = &alx_err_handlers,
2048*1d330d4fSChristoph Heiss .driver.pm = pm_sleep_ptr(&alx_pm_ops),
2049ab69bde6SJohannes Berg };
2050ab69bde6SJohannes Berg
2051ab69bde6SJohannes Berg module_pci_driver(alx_driver);
2052ab69bde6SJohannes Berg MODULE_DEVICE_TABLE(pci, alx_pci_tbl);
2053ab69bde6SJohannes Berg MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
2054a57d3d48SJohannes Berg MODULE_AUTHOR("Qualcomm Corporation");
2055ab69bde6SJohannes Berg MODULE_DESCRIPTION(
2056ab69bde6SJohannes Berg "Qualcomm Atheros(R) AR816x/AR817x PCI-E Ethernet Network Driver");
2057ab69bde6SJohannes Berg MODULE_LICENSE("GPL");
2058