main.c revision 3e5ccc29f71b5dfdfb81dac8c19372af83923b7f
17f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan/* 2e7eacd36865ae0707f5efae8e4dda421ffcd1b66Ralph Campbell * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net> 37f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * 47f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * This file is free software: you may copy, redistribute and/or modify it 57f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * under the terms of the GNU General Public License as published by the 67f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * Free Software Foundation, either version 2 of the License, or (at your 77f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * option) any later version. 87f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * 97f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * This file is distributed in the hope that it will be useful, but 107f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * WITHOUT ANY WARRANTY; without even the implied warranty of 117f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 127f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * General Public License for more details. 137f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * 147f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * You should have received a copy of the GNU General Public License 157f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * along with this program. If not, see <http://www.gnu.org/licenses/>. 167f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * 177f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * This file incorporates work covered by the following copyright and 187f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * permission notice: 197f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * 207f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * Copyright (c) 2012 Qualcomm Atheros, Inc. 217f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * 227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * Permission to use, copy, modify, and/or distribute this software for any 237f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * purpose with or without fee is hereby granted, provided that the above 247f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * copyright notice and this permission notice appear in all copies. 257f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * 267f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 277f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 287f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 297f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 307f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 317f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 337f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan */ 347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#include <linux/module.h> 367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#include <linux/pci.h> 377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#include <linux/interrupt.h> 387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#include <linux/ip.h> 39124b4dcb1dd3a6fb80051f1785117a732d785f70Dave Olson#include <linux/ipv6.h> 40124b4dcb1dd3a6fb80051f1785117a732d785f70Dave Olson#include <linux/if_vlan.h> 41124b4dcb1dd3a6fb80051f1785117a732d785f70Dave Olson#include <linux/mdio.h> 42f2b9857eee17797541b845782ade4d7a9d50f843Jonathan Corbet#include <linux/aer.h> 437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#include <linux/bitops.h> 447f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#include <linux/netdevice.h> 457f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#include <linux/etherdevice.h> 4627b678dd04a636f2c351816f4b3042c8815d4e9dBryan O'Sullivan#include <net/ip6_checksum.h> 47124b4dcb1dd3a6fb80051f1785117a732d785f70Dave Olson#include <linux/crc32.h> 487f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#include "alx.h" 497f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#include "hw.h" 507f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#include "reg.h" 517f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 527f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanconst char alx_drv_name[] = "alx"; 53124b4dcb1dd3a6fb80051f1785117a732d785f70Dave Olson 54124b4dcb1dd3a6fb80051f1785117a732d785f70Dave Olson 557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_free_txbuf(struct alx_priv *alx, int entry) 567f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 577f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_buffer *txb = &alx->txq.bufs[entry]; 582b8693c0617e972fc0b2fd1ebf8de97e15b656c3Arjan van de Ven 597f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (dma_unmap_len(txb, size)) { 607f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_unmap_single(&alx->hw.pdev->dev, 61124b4dcb1dd3a6fb80051f1785117a732d785f70Dave Olson dma_unmap_addr(txb, dma), 627f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_unmap_len(txb, size), 637f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan DMA_TO_DEVICE); 647f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_unmap_len_set(txb, size, 0); 657f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 667f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (txb->skb) { 680a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell dev_kfree_skb_any(txb->skb); 690a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell txb->skb = NULL; 700a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell } 710a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell} 720a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell 730a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbellstatic int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) 740a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell{ 750a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell struct alx_rx_queue *rxq = &alx->rxq; 760a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell struct sk_buff *skb; 770a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell struct alx_buffer *cur_buf; 780a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell dma_addr_t dma; 790a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell u16 cur, next, count = 0; 800a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell 810a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell next = cur = rxq->write_idx; 820a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell if (++next == alx->rx_ringsz) 830a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell next = 0; 840a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell cur_buf = &rxq->bufs[cur]; 850a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell 869929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan while (!cur_buf->skb && next != rxq->read_idx) { 877f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_rfd *rfd = &rxq->rfd[cur]; 887f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 899929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size, gfp); 907f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!skb) 917f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan break; 927f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma = dma_map_single(&alx->hw.pdev->dev, 939929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan skb->data, alx->rxbuf_size, 949929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan DMA_FROM_DEVICE); 959929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (dma_mapping_error(&alx->hw.pdev->dev, dma)) { 969929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan dev_kfree_skb(skb); 979929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan break; 989929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } 999929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1009929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan /* Unfortunately, RX descriptor buffers must be 4-byte 1019929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan * aligned, so we can't use IP alignment. 1029929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan */ 1039929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (WARN_ON(dma & 3)) { 1049929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan dev_kfree_skb(skb); 1059929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan break; 1067f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 1079929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1089929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan cur_buf->skb = skb; 1099929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan dma_unmap_len_set(cur_buf, size, alx->rxbuf_size); 110c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage dma_unmap_addr_set(cur_buf, dma, dma); 1119929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan rfd->addr = cpu_to_le64(dma); 1127f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1139929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan cur = next; 1149929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (++next == alx->rx_ringsz) 1157f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan next = 0; 1167f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan cur_buf = &rxq->bufs[cur]; 1177f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan count++; 1187f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 1197f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1207f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (count) { 1217f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* flush all updates before updating hardware */ 1227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan wmb(); 1237f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan rxq->write_idx = cur; 1247f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem16(&alx->hw, ALX_RFD_PIDX, cur); 1257f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 1267f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1277f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return count; 1287f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 1297f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1307f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic inline int alx_tpd_avail(struct alx_priv *alx) 1317f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 1327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_tx_queue *txq = &alx->txq; 1337f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (txq->write_idx >= txq->read_idx) 1357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return alx->tx_ringsz + txq->read_idx - txq->write_idx - 1; 1367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return txq->read_idx - txq->write_idx - 1; 1377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 1387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1397f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic bool alx_clean_tx_irq(struct alx_priv *alx) 1407f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 1419929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct alx_tx_queue *txq = &alx->txq; 1429929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan u16 hw_read_idx, sw_read_idx; 1439929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan unsigned int total_bytes = 0, total_packets = 0; 1447f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int budget = ALX_DEFAULT_TX_WORK; 1457f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1467f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan sw_read_idx = txq->read_idx; 1477f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw_read_idx = alx_read_mem16(&alx->hw, ALX_TPD_PRI0_CIDX); 1487f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1497f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (sw_read_idx != hw_read_idx) { 1507f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan while (sw_read_idx != hw_read_idx && budget > 0) { 1517f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct sk_buff *skb; 1527f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1537f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan skb = txq->bufs[sw_read_idx].skb; 1547f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (skb) { 1557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan total_bytes += skb->len; 1567f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan total_packets++; 1577f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan budget--; 1587f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 1597f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1607f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_free_txbuf(alx, sw_read_idx); 1617f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1627f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (++sw_read_idx == alx->tx_ringsz) 1637f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan sw_read_idx = 0; 1647f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 1657f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan txq->read_idx = sw_read_idx; 1669929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1679929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan netdev_completed_queue(alx->dev, total_packets, total_bytes); 1687f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 1697f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1709929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (netif_queue_stopped(alx->dev) && netif_carrier_ok(alx->dev) && 1717f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_tpd_avail(alx) > alx->tx_ringsz/4) 1727f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netif_wake_queue(alx->dev); 1737f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1747f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return sw_read_idx == hw_read_idx; 1757f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 1769929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 177e2ab41cae418108f376ad1634d7507f56379f7a2Dave Olsonstatic void alx_schedule_link_check(struct alx_priv *alx) 1789929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan{ 1799929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan schedule_work(&alx->link_check_wk); 180a18e26ae442001de62f6b84a923e8613347dc35fRalph Campbell} 1819929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 182e2ab41cae418108f376ad1634d7507f56379f7a2Dave Olsonstatic void alx_schedule_reset(struct alx_priv *alx) 183e2ab41cae418108f376ad1634d7507f56379f7a2Dave Olson{ 1849929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan schedule_work(&alx->reset_wk); 1859929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan} 1869929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 187e2ab41cae418108f376ad1634d7507f56379f7a2Dave Olsonstatic bool alx_clean_rx_irq(struct alx_priv *alx, int budget) 1889929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan{ 1899929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct alx_rx_queue *rxq = &alx->rxq; 1907f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_rrd *rrd; 191e2ab41cae418108f376ad1634d7507f56379f7a2Dave Olson struct alx_buffer *rxb; 1929929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct sk_buff *skb; 1939929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan u16 length, rfd_cleaned = 0; 194c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 1951d7c2e529fb6d4143d294ade7d99e29cb6b3775fDave Olson while (budget > 0) { 196c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage rrd = &rxq->rrd[rxq->rrd_read_idx]; 197c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT))) 198a18e26ae442001de62f6b84a923e8613347dc35fRalph Campbell break; 199c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage rrd->word3 &= ~cpu_to_le32(1 << RRD_UPDATED_SHIFT); 200c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 201c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage if (ALX_GET_FIELD(le32_to_cpu(rrd->word0), 202c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage RRD_SI) != rxq->read_idx || 2030a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell ALX_GET_FIELD(le32_to_cpu(rrd->word0), 204c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage RRD_NOR) != 1) { 2059929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_schedule_reset(alx); 2060a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell return 0; 207c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage } 208947d7617a1d876c2c93f73017a734e070c64d43bRalph Campbell 2090a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell rxb = &rxq->bufs[rxq->read_idx]; 210c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage dma_unmap_single(&alx->hw.pdev->dev, 211c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage dma_unmap_addr(rxb, dma), 212c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage dma_unmap_len(rxb, size), 213c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage DMA_FROM_DEVICE); 214c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage dma_unmap_len_set(rxb, size, 0); 215c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage skb = rxb->skb; 216c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage rxb->skb = NULL; 217c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 218c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage if (rrd->word3 & cpu_to_le32(1 << RRD_ERR_RES_SHIFT) || 219c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage rrd->word3 & cpu_to_le32(1 << RRD_ERR_LEN_SHIFT)) { 220c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage rrd->word3 = 0; 221c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage dev_kfree_skb_any(skb); 222c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage goto next_pkt; 223c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage } 2249929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 2259929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan length = ALX_GET_FIELD(le32_to_cpu(rrd->word3), 2261bf7724e093cf3071d943d53bfa4de8b8e50426bDave Olson RRD_PKTLEN) - ETH_FCS_LEN; 2271bf7724e093cf3071d943d53bfa4de8b8e50426bDave Olson skb_put(skb, length); 2281bf7724e093cf3071d943d53bfa4de8b8e50426bDave Olson skb->protocol = eth_type_trans(skb, alx->dev); 2291bf7724e093cf3071d943d53bfa4de8b8e50426bDave Olson 2301bf7724e093cf3071d943d53bfa4de8b8e50426bDave Olson skb_checksum_none_assert(skb); 2311bf7724e093cf3071d943d53bfa4de8b8e50426bDave Olson if (alx->dev->features & NETIF_F_RXCSUM && 2321bf7724e093cf3071d943d53bfa4de8b8e50426bDave Olson !(rrd->word3 & (cpu_to_le32(1 << RRD_ERR_L4_SHIFT) | 2337f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan cpu_to_le32(1 << RRD_ERR_IPV4_SHIFT)))) { 2347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan switch (ALX_GET_FIELD(le32_to_cpu(rrd->word2), 2357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan RRD_PID)) { 236826d801009fb3c82832f2d92149446cce354bf61Dave Olson case RRD_PID_IPV6UDP: 237826d801009fb3c82832f2d92149446cce354bf61Dave Olson case RRD_PID_IPV4UDP: 238826d801009fb3c82832f2d92149446cce354bf61Dave Olson case RRD_PID_IPV4TCP: 239826d801009fb3c82832f2d92149446cce354bf61Dave Olson case RRD_PID_IPV6TCP: 240826d801009fb3c82832f2d92149446cce354bf61Dave Olson skb->ip_summed = CHECKSUM_UNNECESSARY; 241826d801009fb3c82832f2d92149446cce354bf61Dave Olson break; 2427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 2437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 2449929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 245eaf6733bc176742fb08def2269441684e963c275Bryan O'Sullivan napi_gro_receive(&alx->napi, skb); 2467f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan budget--; 2477f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2489929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivannext_pkt: 2499929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (++rxq->read_idx == alx->rx_ringsz) 2509929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan rxq->read_idx = 0; 2519929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (++rxq->rrd_read_idx == alx->rx_ringsz) 252c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage rxq->rrd_read_idx = 0; 253c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 2547f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (++rfd_cleaned > ALX_RX_ALLOC_THRESH) 2557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan rfd_cleaned -= alx_refill_rx_ring(alx, GFP_ATOMIC); 2567f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 2577f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2587f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (rfd_cleaned) 2597f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_refill_rx_ring(alx, GFP_ATOMIC); 2607f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2617f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return budget > 0; 2627f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 2637f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2649929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanstatic int alx_poll(struct napi_struct *napi, int budget) 2657f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 2667f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_priv *alx = container_of(napi, struct alx_priv, napi); 2677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 2687f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan bool complete = true; 2697f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan unsigned long flags; 2707f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2717f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan complete = alx_clean_tx_irq(alx) && 2727f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_clean_rx_irq(alx, budget); 2737f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2747f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!complete) 2757f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return 1; 2767f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2777f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan napi_complete(&alx->napi); 2787f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2797f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* enable interrupt */ 2807f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan spin_lock_irqsave(&alx->irq_lock, flags); 2817f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0; 2827f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_IMR, alx->int_mask); 2837f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan spin_unlock_irqrestore(&alx->irq_lock, flags); 2847f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2857f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_post_write(hw); 2867f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2879929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan return 0; 2887f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 2897f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2907f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr) 2919929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan{ 2927f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 2937f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan bool write_int_mask = false; 2947f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2957f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan spin_lock(&alx->irq_lock); 2967f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 2977f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* ACK interrupt */ 2987f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_ISR, intr | ALX_ISR_DIS); 2999929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan intr &= alx->int_mask; 3007f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3017f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (intr & ALX_ISR_FATAL) { 3027f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netif_warn(alx, hw, alx->dev, 3037f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan "fatal interrupt 0x%x, resetting\n", intr); 3047f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_schedule_reset(alx); 3057f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan goto out; 3067f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 3077f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3087f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (intr & ALX_ISR_ALERT) 3097f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netdev_warn(alx->dev, "alert interrupt: 0x%x\n", intr); 3107f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3117f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (intr & ALX_ISR_PHY) { 3127f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* suppress PHY interrupt, because the source 3137f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * is from PHY internal. only the internal status 3147f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * is cleared, the interrupt status could be cleared. 3157f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan */ 3169929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx->int_mask &= ~ALX_ISR_PHY; 3179929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan write_int_mask = true; 3189929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_schedule_link_check(alx); 3199929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } 3209929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 3219929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (intr & (ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0)) { 3229929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan napi_schedule(&alx->napi); 3239929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan /* mask rx/tx interrupt, enable them when napi complete */ 3249929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx->int_mask &= ~ALX_ISR_ALL_QUEUES; 3259929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan write_int_mask = true; 3269929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } 3279929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 3289929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (write_int_mask) 3299929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_write_mem32(hw, ALX_IMR, alx->int_mask); 3309929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 3319929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_write_mem32(hw, ALX_ISR, 0); 3329929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 3339929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan out: 3347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan spin_unlock(&alx->irq_lock); 3357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return IRQ_HANDLED; 3367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 3377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic irqreturn_t alx_intr_msi(int irq, void *data) 3399929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan{ 3409929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct alx_priv *alx = data; 3417f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return alx_intr_handle(alx, alx_read_mem32(&alx->hw, ALX_ISR)); 3437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 3447f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3457f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic irqreturn_t alx_intr_legacy(int irq, void *data) 3467f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 3477f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_priv *alx = data; 3487f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 3497f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan u32 intr; 3507f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3517f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan intr = alx_read_mem32(hw, ALX_ISR); 3527f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3537f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (intr & ALX_ISR_DIS || !(intr & alx->int_mask)) 3547f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return IRQ_NONE; 3557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3567f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return alx_intr_handle(alx, intr); 3577f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 3587f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3597f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_init_ring_ptrs(struct alx_priv *alx) 3607f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 3617f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 3627f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan u32 addr_hi = ((u64)alx->descmem.dma) >> 32; 3637f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3647f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rxq.read_idx = 0; 3657f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rxq.write_idx = 0; 3667f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rxq.rrd_read_idx = 0; 3677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_RX_BASE_ADDR_HI, addr_hi); 3687f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_RRD_ADDR_LO, alx->rxq.rrd_dma); 3697f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_RRD_RING_SZ, alx->rx_ringsz); 3707f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_RFD_ADDR_LO, alx->rxq.rfd_dma); 3717f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_RFD_RING_SZ, alx->rx_ringsz); 3727f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_RFD_BUF_SZ, alx->rxbuf_size); 3737f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3747f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->txq.read_idx = 0; 3757f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->txq.write_idx = 0; 3767f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi); 3777f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_TPD_PRI0_ADDR_LO, alx->txq.tpd_dma); 3787f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz); 3797f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3807f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* load these pointers into the chip */ 3817f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_SRAM9, ALX_SRAM_LOAD_PTR); 3827f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 3837f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3847f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_free_txring_buf(struct alx_priv *alx) 3857f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 3867f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_tx_queue *txq = &alx->txq; 3877f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int i; 3887f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3897f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!txq->bufs) 3907f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return; 3917f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3927f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan for (i = 0; i < alx->tx_ringsz; i++) 3937f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_free_txbuf(alx, i); 3947f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 3957f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan memset(txq->bufs, 0, alx->tx_ringsz * sizeof(struct alx_buffer)); 3967f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan memset(txq->tpd, 0, alx->tx_ringsz * sizeof(struct alx_txd)); 3977f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan txq->write_idx = 0; 3987f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan txq->read_idx = 0; 3997f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4009929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan netdev_reset_queue(alx->dev); 4017f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 4029929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 4037f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_free_rxring_buf(struct alx_priv *alx) 4047f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 4051fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan struct alx_rx_queue *rxq = &alx->rxq; 4061fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan struct alx_buffer *cur_buf; 4071fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan u16 i; 4087f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4097f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (rxq == NULL) 4107f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return; 4117f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4121fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan for (i = 0; i < alx->rx_ringsz; i++) { 4137f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan cur_buf = rxq->bufs + i; 4147f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (cur_buf->skb) { 4157f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_unmap_single(&alx->hw.pdev->dev, 4167f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_unmap_addr(cur_buf, dma), 4177f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_unmap_len(cur_buf, size), 418f716cdfe57f217966f41a7add190d6f5b9fd0769Joan Eslinger DMA_FROM_DEVICE); 419f716cdfe57f217966f41a7add190d6f5b9fd0769Joan Eslinger dev_kfree_skb(cur_buf->skb); 4207f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan cur_buf->skb = NULL; 4217f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_unmap_len_set(cur_buf, size, 0); 4227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_unmap_addr_set(cur_buf, dma, 0); 4237f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 4247f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 4257f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4267f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan rxq->write_idx = 0; 4277f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan rxq->read_idx = 0; 4287f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan rxq->rrd_read_idx = 0; 4297f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 4307f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4317f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_free_buffers(struct alx_priv *alx) 4327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 4337f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_free_txring_buf(alx); 4347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_free_rxring_buf(alx); 4357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 4367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_reinit_rings(struct alx_priv *alx) 4387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 4397f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_free_buffers(alx); 4407f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4417f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_init_ring_ptrs(alx); 4427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!alx_refill_rx_ring(alx, GFP_KERNEL)) 4447f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return -ENOMEM; 445f716cdfe57f217966f41a7add190d6f5b9fd0769Joan Eslinger 446f716cdfe57f217966f41a7add190d6f5b9fd0769Joan Eslinger return 0; 4477f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 4481fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan 4491fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivanstatic void alx_add_mc_addr(struct alx_hw *hw, const u8 *addr, u32 *mc_hash) 4501fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan{ 4517f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan u32 crc32, bit, reg; 4527f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4537f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan crc32 = ether_crc(ETH_ALEN, addr); 4547f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan reg = (crc32 >> 31) & 0x1; 4557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan bit = (crc32 >> 26) & 0x1F; 4567f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4577f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan mc_hash[reg] |= BIT(bit); 4587f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 4597f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4607f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void __alx_set_rx_mode(struct net_device *netdev) 4617f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 4627f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_priv *alx = netdev_priv(netdev); 4637f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 4647f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct netdev_hw_addr *ha; 4657f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan u32 mc_hash[2] = {}; 4667f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!(netdev->flags & IFF_ALLMULTI)) { 4687f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netdev_for_each_mc_addr(ha, netdev) 4697f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_add_mc_addr(hw, ha->addr, mc_hash); 4707f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4717f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_HASH_TBL0, mc_hash[0]); 4727f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_HASH_TBL1, mc_hash[1]); 4737f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 4747f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4759929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan hw->rx_ctrl &= ~(ALX_MAC_CTRL_MULTIALL_EN | ALX_MAC_CTRL_PROMISC_EN); 4769929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (netdev->flags & IFF_PROMISC) 4779929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan hw->rx_ctrl |= ALX_MAC_CTRL_PROMISC_EN; 4789929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (netdev->flags & IFF_ALLMULTI) 4797f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->rx_ctrl |= ALX_MAC_CTRL_MULTIALL_EN; 4807f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4817f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); 4827f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 4837f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4847f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_set_rx_mode(struct net_device *netdev) 4857f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 4867f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan __alx_set_rx_mode(netdev); 4877f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 4887f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4897f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_set_mac_address(struct net_device *netdev, void *data) 4907f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 4919929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct alx_priv *alx = netdev_priv(netdev); 4927f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 4937f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct sockaddr *addr = data; 4947f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4957f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!is_valid_ether_addr(addr->sa_data)) 4967f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return -EADDRNOTAVAIL; 4977f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 4987f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (netdev->addr_assign_type & NET_ADDR_RANDOM) 4997f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netdev->addr_assign_type ^= NET_ADDR_RANDOM; 5007f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5017f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); 5027f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan memcpy(hw->mac_addr, addr->sa_data, netdev->addr_len); 5037f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_set_macaddr(hw, hw->mac_addr); 5047f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5059929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan return 0; 5067f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 5077f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5087f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_alloc_descriptors(struct alx_priv *alx) 5097f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 5107f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->txq.bufs = kcalloc(alx->tx_ringsz, 5117f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan sizeof(struct alx_buffer), 5127f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan GFP_KERNEL); 5137f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!alx->txq.bufs) 5147f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return -ENOMEM; 5157f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5167f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rxq.bufs = kcalloc(alx->rx_ringsz, 5177f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan sizeof(struct alx_buffer), 5187f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan GFP_KERNEL); 5197f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!alx->rxq.bufs) 5207f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan goto out_free; 5217f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* physical tx/rx ring descriptors 5237f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * 5247f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * Allocate them as a single chunk because they must not cross a 5257f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * 4G boundary (hardware has a single register for high 32 bits 5269929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan * of addresses only) 5279929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan */ 5289929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx->descmem.size = sizeof(struct alx_txd) * alx->tx_ringsz + 5299929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan sizeof(struct alx_rrd) * alx->rx_ringsz + 5309929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan sizeof(struct alx_rfd) * alx->rx_ringsz; 5319929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx->descmem.virt = dma_zalloc_coherent(&alx->hw.pdev->dev, 5329929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx->descmem.size, 5339929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan &alx->descmem.dma, 5349929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan GFP_KERNEL); 5359929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (!alx->descmem.virt) 5367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan goto out_free; 5377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->txq.tpd = (void *)alx->descmem.virt; 5397f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->txq.tpd_dma = alx->descmem.dma; 5407f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5417f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* alignment requirement for next block */ 5427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan BUILD_BUG_ON(sizeof(struct alx_txd) % 8); 5437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5447f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rxq.rrd = 5457f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan (void *)((u8 *)alx->descmem.virt + 5467f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan sizeof(struct alx_txd) * alx->tx_ringsz); 5477f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rxq.rrd_dma = alx->descmem.dma + 5487f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan sizeof(struct alx_txd) * alx->tx_ringsz; 5497f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5507f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* alignment requirement for next block */ 5517f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan BUILD_BUG_ON(sizeof(struct alx_rrd) % 8); 5527f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5537f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rxq.rfd = 5547f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan (void *)((u8 *)alx->descmem.virt + 5557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan sizeof(struct alx_txd) * alx->tx_ringsz + 5567f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan sizeof(struct alx_rrd) * alx->rx_ringsz); 5577f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rxq.rfd_dma = alx->descmem.dma + 5587f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan sizeof(struct alx_txd) * alx->tx_ringsz + 5597f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan sizeof(struct alx_rrd) * alx->rx_ringsz; 5603ac8c70f74ca67111c570f4ba828cc4b6fc229f4Dave Olson 5613ac8c70f74ca67111c570f4ba828cc4b6fc229f4Dave Olson return 0; 5623ac8c70f74ca67111c570f4ba828cc4b6fc229f4Dave Olsonout_free: 5637f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan kfree(alx->txq.bufs); 56440d97692fbfe52ef68fa771d8121394b2210fd67Pavel Emelyanov kfree(alx->rxq.bufs); 565f716cdfe57f217966f41a7add190d6f5b9fd0769Joan Eslinger return -ENOMEM; 566f716cdfe57f217966f41a7add190d6f5b9fd0769Joan Eslinger} 5677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5681fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivanstatic int alx_alloc_rings(struct alx_priv *alx) 5691fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan{ 5701fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan int err; 5713ac8c70f74ca67111c570f4ba828cc4b6fc229f4Dave Olson 5727f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = alx_alloc_descriptors(alx); 5737f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (err) 5747f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return err; 5757f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5767f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->int_mask &= ~ALX_ISR_ALL_QUEUES; 5777f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0; 5787f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->tx_ringsz = alx->tx_ringsz; 5797f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5807f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netif_napi_add(alx->dev, &alx->napi, alx_poll, 64); 5817f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5827f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_reinit_rings(alx); 5837f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return 0; 5847f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 5857f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5867f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_free_rings(struct alx_priv *alx) 5877f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 5887f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netif_napi_del(&alx->napi); 5897f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_free_buffers(alx); 5907f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5917f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan kfree(alx->txq.bufs); 5927f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan kfree(alx->rxq.bufs); 5937f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 5947f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_free_coherent(&alx->hw.pdev->dev, 5957f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->descmem.size, 5967f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->descmem.virt, 5977f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->descmem.dma); 5987f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 5997f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6007f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_config_vector_mapping(struct alx_priv *alx) 6017f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 6027f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 6037f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6047f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_MSI_MAP_TBL1, 0); 6057f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_MSI_MAP_TBL2, 0); 6067f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_MSI_ID_MAP, 0); 6077f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 6087f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 60927b678dd04a636f2c351816f4b3042c8815d4e9dBryan O'Sullivanstatic void alx_irq_enable(struct alx_priv *alx) 6107f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 6117f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 6127f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6137f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* level-1 interrupt switch */ 6147f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_ISR, 0); 6157f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_IMR, alx->int_mask); 6167f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_post_write(hw); 6177f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 6187f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6197f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_irq_disable(struct alx_priv *alx) 6207f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 6217f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 6227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6237f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS); 6247f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_IMR, 0); 6257f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_post_write(hw); 6267f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6277f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan synchronize_irq(alx->hw.pdev->irq); 6287f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 6297f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6307f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_request_irq(struct alx_priv *alx) 6317f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 6327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct pci_dev *pdev = alx->hw.pdev; 6337f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 6347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int err; 6357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan u32 msi_ctrl; 6367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan msi_ctrl = (hw->imt >> 1) << ALX_MSI_RETRANS_TM_SHIFT; 6387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6397f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!pci_enable_msi(alx->hw.pdev)) { 6407f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->msi = true; 6417f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, 6437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan msi_ctrl | ALX_MSI_MASK_SEL_LINE); 6447f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = request_irq(pdev->irq, alx_intr_msi, 0, 6457f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->dev->name, alx); 6467f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!err) 6477f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan goto out; 6487f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* fall back to legacy interrupt */ 6497f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan pci_disable_msi(alx->hw.pdev); 6507f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 6517f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6527f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, 0); 6537f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = request_irq(pdev->irq, alx_intr_legacy, IRQF_SHARED, 6547f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->dev->name, alx); 6557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanout: 6567f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!err) 6577f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_config_vector_mapping(alx); 6587f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return err; 6597f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 6607f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6617f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_free_irq(struct alx_priv *alx) 6627f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 6637f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct pci_dev *pdev = alx->hw.pdev; 6647f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6657f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan free_irq(pdev->irq, alx); 6667f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (alx->msi) { 6687f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan pci_disable_msi(alx->hw.pdev); 6697f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->msi = false; 6707f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 6717f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 6727f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6737f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_identify_hw(struct alx_priv *alx) 6747f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 6757f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 6767f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int rev = alx_hw_revision(hw); 6777f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6787f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (rev > ALX_REV_C0) 6797f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return -EINVAL; 6807f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6817f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->max_dma_chnl = rev >= ALX_REV_B0 ? 4 : 2; 6827f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6837f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return 0; 6847f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 6857f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6867f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_init_sw(struct alx_priv *alx) 6877f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 6887f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct pci_dev *pdev = alx->hw.pdev; 6897f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 6907f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int err; 6917f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6927f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = alx_identify_hw(alx); 6937f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (err) { 6947f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dev_err(&pdev->dev, "unrecognized chip, aborting\n"); 6957f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return err; 6967f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 6977f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 6987f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->hw.lnk_patch = 6997f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan pdev->device == ALX_DEV_ID_AR8161 && 7007f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan pdev->subsystem_vendor == PCI_VENDOR_ID_ATTANSIC && 7017f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan pdev->subsystem_device == 0x0091 && 7027f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan pdev->revision == 0; 7037f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7047f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->smb_timer = 400; 7057f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->mtu = alx->dev->mtu; 7067f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rxbuf_size = ALIGN(ALX_RAW_MTU(hw->mtu), 8); 7077f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->tx_ringsz = 256; 7087f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rx_ringsz = 512; 7097f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->imt = 200; 7107f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->int_mask = ALX_ISR_MISC; 7117f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->dma_chnl = hw->max_dma_chnl; 7127f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->ith_tpd = alx->tx_ringsz / 3; 7137f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->link_speed = SPEED_UNKNOWN; 7147f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->duplex = DUPLEX_UNKNOWN; 7157f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->adv_cfg = ADVERTISED_Autoneg | 7167f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ADVERTISED_10baseT_Half | 7177f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ADVERTISED_10baseT_Full | 7187f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ADVERTISED_100baseT_Full | 7197f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ADVERTISED_100baseT_Half | 7207f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ADVERTISED_1000baseT_Full; 7217f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->flowctrl = ALX_FC_ANEG | ALX_FC_RX | ALX_FC_TX; 7227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7237f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->rx_ctrl = ALX_MAC_CTRL_WOLSPED_SWEN | 7247f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ALX_MAC_CTRL_MHASH_ALG_HI5B | 7257f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ALX_MAC_CTRL_BRD_EN | 7267f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ALX_MAC_CTRL_PCRCE | 7277f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ALX_MAC_CTRL_CRCE | 7287f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ALX_MAC_CTRL_RXFC_EN | 7297f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ALX_MAC_CTRL_TXFC_EN | 7307f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7 << ALX_MAC_CTRL_PRMBLEN_SHIFT; 7317f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return err; 7339929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan} 7347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic netdev_features_t alx_fix_features(struct net_device *netdev, 7377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netdev_features_t features) 7387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 7397f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (netdev->mtu > ALX_MAX_TSO_PKT_SIZE) 7409929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan features &= ~(NETIF_F_TSO | NETIF_F_TSO6); 7419929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 7427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return features; 7437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 7447f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7459929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanstatic void alx_netif_stop(struct alx_priv *alx) 7467f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 7479929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx->dev->trans_start = jiffies; 7489929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (netif_carrier_ok(alx->dev)) { 7499929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan netif_carrier_off(alx->dev); 7507f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netif_tx_disable(alx->dev); 7517f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan napi_disable(&alx->napi); 7527f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 7537f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 7547f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_halt(struct alx_priv *alx) 7567f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 7577f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 7587f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7597f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_netif_stop(alx); 7607f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->link_speed = SPEED_UNKNOWN; 7617f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->duplex = DUPLEX_UNKNOWN; 7627f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7637f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_reset_mac(hw); 764c59a80aca0bfc491d90534ed5606d5493eca24a3Ralph Campbell 765c59a80aca0bfc491d90534ed5606d5493eca24a3Ralph Campbell /* disable l0s/l1 */ 766d8274869d742c3d8082e1428de47e54d12104928Dave Olson alx_enable_aspm(hw, false, false); 7677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_irq_disable(alx); 7687f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_free_buffers(alx); 769d8274869d742c3d8082e1428de47e54d12104928Dave Olson} 7707f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7717f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_configure(struct alx_priv *alx) 7727f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 7737f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 77444f8e3f3f7d8e61b4aafced278403955fe18ad88Roland Dreier 7757f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_configure_basic(hw); 7767f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_disable_rss(hw); 7777f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan __alx_set_rx_mode(alx->dev); 7787f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7797f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); 7807f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 7817f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7827f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_activate(struct alx_priv *alx) 78344f8e3f3f7d8e61b4aafced278403955fe18ad88Roland Dreier{ 7847f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* hardware setting lost, restore it */ 7857f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_reinit_rings(alx); 7869929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_configure(alx); 7877f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7887f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* clear old interrupts */ 7897f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS); 7907f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7917f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_irq_enable(alx); 7927f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7937f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_schedule_link_check(alx); 7947f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 7957f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 7967f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_reinit(struct alx_priv *alx) 7977f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 7987f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ASSERT_RTNL(); 7997f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8007f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_halt(alx); 8017f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_activate(alx); 8027f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 8037f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8047f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_change_mtu(struct net_device *netdev, int mtu) 8057f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 8067f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_priv *alx = netdev_priv(netdev); 8077f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int max_frame = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; 8087f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8097f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if ((max_frame < ALX_MIN_FRAME_SIZE) || 8107f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan (max_frame > ALX_MAX_FRAME_SIZE)) 8117f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return -EINVAL; 8127f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8137f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (netdev->mtu == mtu) 8147f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return 0; 8157f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8167f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netdev->mtu = mtu; 8177f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->hw.mtu = mtu; 8187f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx->rxbuf_size = mtu > ALX_DEF_RXBUF_SIZE ? 8197f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan ALIGN(max_frame, 8) : ALX_DEF_RXBUF_SIZE; 8207f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netdev_update_features(netdev); 8217f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (netif_running(netdev)) 8227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_reinit(alx); 8237f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return 0; 8247f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 8257f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8267f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_netif_start(struct alx_priv *alx) 8277f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 8287f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netif_tx_wake_all_queues(alx->dev); 8297f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan napi_enable(&alx->napi); 8307f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netif_carrier_on(alx->dev); 8317f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 8327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8337f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int __alx_open(struct alx_priv *alx, bool resume) 8347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 8357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int err; 8367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!resume) 8387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netif_carrier_off(alx->dev); 8397f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8407f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = alx_alloc_rings(alx); 8417f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (err) 8427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return err; 8437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8449929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_configure(alx); 8459929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 8469929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan err = alx_request_irq(alx); 8479929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (err) 8489929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan goto out_free_rings; 8499929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 8509929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan /* clear old interrupts */ 8519929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS); 8529929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 8539929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_irq_enable(alx); 8549929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 8559929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (!resume) 8569929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan netif_tx_start_all_queues(alx->dev); 8579929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 8589929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_schedule_link_check(alx); 8599929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan return 0; 8609929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 8619929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanout_free_rings: 8629929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_free_rings(alx); 8639929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan return err; 8649929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan} 8659929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 8669929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanstatic void __alx_stop(struct alx_priv *alx) 8679929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan{ 8689929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_halt(alx); 8699929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_free_irq(alx); 8709929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_free_rings(alx); 8719929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan} 8729929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 8739929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanstatic const char *alx_speed_desc(struct alx_hw *hw) 8747f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 8757f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan switch (alx_speed_to_ethadv(hw->link_speed, hw->duplex)) { 8767f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan case ADVERTISED_1000baseT_Full: 8777f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return "1 Gbps Full"; 8787f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan case ADVERTISED_100baseT_Full: 8797f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return "100 Mbps Full"; 8807f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan case ADVERTISED_100baseT_Half: 8817f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return "100 Mbps Half"; 8827f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan case ADVERTISED_10baseT_Full: 8837f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return "10 Mbps Full"; 8847f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan case ADVERTISED_10baseT_Half: 8857f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return "10 Mbps Half"; 8867f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan default: 8877f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return "Unknown speed"; 8887f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 8899929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan} 8907f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 8917f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_check_link(struct alx_priv *alx) 8920ed9a4a0b6df0548f9ccadb62add2c0155d5262cBryan O'Sullivan{ 8930ed9a4a0b6df0548f9ccadb62add2c0155d5262cBryan O'Sullivan struct alx_hw *hw = &alx->hw; 8940ed9a4a0b6df0548f9ccadb62add2c0155d5262cBryan O'Sullivan unsigned long flags; 8950ed9a4a0b6df0548f9ccadb62add2c0155d5262cBryan O'Sullivan int old_speed; 8960ed9a4a0b6df0548f9ccadb62add2c0155d5262cBryan O'Sullivan u8 old_duplex; 8970ed9a4a0b6df0548f9ccadb62add2c0155d5262cBryan O'Sullivan int err; 8980ed9a4a0b6df0548f9ccadb62add2c0155d5262cBryan O'Sullivan 8990ed9a4a0b6df0548f9ccadb62add2c0155d5262cBryan O'Sullivan /* clear PHY internal interrupt status, otherwise the main 9000ed9a4a0b6df0548f9ccadb62add2c0155d5262cBryan O'Sullivan * interrupt status will be asserted forever 9017f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan */ 9027f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_clear_phy_intr(hw); 9037f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 90460948a415859cb859e24f0dfe739069d66577466Ralph Campbell old_speed = hw->link_speed; 9057f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan old_duplex = hw->duplex; 9067f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = alx_read_phy_link(hw); 9077f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (err < 0) 9087f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan goto reset; 9099929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 9109929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan spin_lock_irqsave(&alx->irq_lock, flags); 9119929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx->int_mask |= ALX_ISR_PHY; 9129929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_write_mem32(hw, ALX_IMR, alx->int_mask); 9139929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan spin_unlock_irqrestore(&alx->irq_lock, flags); 9147f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 9157f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (old_speed == hw->link_speed) 9167f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return; 9177f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 9187f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (hw->link_speed != SPEED_UNKNOWN) { 9199929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan netif_info(alx, link, alx->dev, 9209929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan "NIC Up: %s\n", alx_speed_desc(hw)); 9217f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_post_phy_link(hw); 9227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_enable_aspm(hw, true, true); 9237f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_start_mac(hw); 9247f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 9257f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (old_speed == SPEED_UNKNOWN) 9267f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_netif_start(alx); 9277f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } else { 9287f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* link is now down */ 9297f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_netif_stop(alx); 9307f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netif_info(alx, link, alx->dev, "Link Down\n"); 9317f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = alx_reset_mac(hw); 9327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (err) 9337f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan goto reset; 9347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_irq_disable(alx); 9357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 9367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* MAC reset causes all HW settings to be lost, restore all */ 9377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = alx_reinit_rings(alx); 9387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (err) 9397f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan goto reset; 9407f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_configure(alx); 9417f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_enable_aspm(hw, false, true); 9427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_post_phy_link(hw); 9437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_irq_enable(alx); 9447f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 9457f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 9467f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return; 9477f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 948f716cdfe57f217966f41a7add190d6f5b9fd0769Joan Eslingerreset: 949f716cdfe57f217966f41a7add190d6f5b9fd0769Joan Eslinger alx_schedule_reset(alx); 9507f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 9517f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 9527f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_open(struct net_device *netdev) 9537f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 9547f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return __alx_open(netdev_priv(netdev), false); 9557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 9567f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 9577f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_stop(struct net_device *netdev) 9587f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 9597f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan __alx_stop(netdev_priv(netdev)); 960f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan return 0; 9617f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 9627f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 9637f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_link_check(struct work_struct *work) 9647f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 965f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan struct alx_priv *alx; 9669929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 9677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx = container_of(work, struct alx_priv, link_check_wk); 9687f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 9699929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan rtnl_lock(); 9707f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_check_link(alx); 9717f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan rtnl_unlock(); 9727f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 9737f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 9747f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_reset(struct work_struct *work) 975f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan{ 976f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan struct alx_priv *alx = container_of(work, struct alx_priv, reset_wk); 977f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 9781fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan rtnl_lock(); 9791fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan alx_reinit(alx); 980f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan rtnl_unlock(); 981f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan} 9821fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan 983f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivanstatic int alx_tx_csum(struct sk_buff *skb, struct alx_txd *first) 984f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan{ 985f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan u8 cso, css; 986f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 987f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan if (skb->ip_summed != CHECKSUM_PARTIAL) 988f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan return 0; 989f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 990f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan cso = skb_checksum_start_offset(skb); 991f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan if (cso & 1) 992f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan return -EINVAL; 993f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 994f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan css = cso + skb->csum_offset; 995f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan first->word1 |= cpu_to_le32((cso >> 1) << TPD_CXSUMSTART_SHIFT); 996f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan first->word1 |= cpu_to_le32((css >> 1) << TPD_CXSUMOFFSET_SHIFT); 997f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan first->word1 |= cpu_to_le32(1 << TPD_CXSUM_EN_SHIFT); 998f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 999f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan return 0; 1000f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan} 1001f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 1002f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivanstatic int alx_map_tx_skb(struct alx_priv *alx, struct sk_buff *skb) 1003f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan{ 1004f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan struct alx_tx_queue *txq = &alx->txq; 10051fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan struct alx_txd *tpd, *first_tpd; 1006f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan dma_addr_t dma; 1007f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan int maplen, f, first_idx = txq->write_idx; 1008f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 10091fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan first_tpd = &txq->tpd[txq->write_idx]; 10101fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan tpd = first_tpd; 10111fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan 1012f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan maplen = skb_headlen(skb); 10131fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan dma = dma_map_single(&alx->hw.pdev->dev, skb->data, maplen, 10141fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan DMA_TO_DEVICE); 10151fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan if (dma_mapping_error(&alx->hw.pdev->dev, dma)) 1016f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan goto err_dma; 1017f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 1018f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen); 1019f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma); 10207f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10217f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan tpd->adrl.addr = cpu_to_le64(dma); 10227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan tpd->len = cpu_to_le16(maplen); 10237f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10247f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { 10257f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct skb_frag_struct *frag; 1026f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 1027f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan frag = &skb_shinfo(skb)->frags[f]; 1028f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 1029f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan if (++txq->write_idx == alx->tx_ringsz) 1030f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan txq->write_idx = 0; 10317f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan tpd = &txq->tpd[txq->write_idx]; 10327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10337f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan tpd->word1 = first_tpd->word1; 10347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan maplen = skb_frag_size(frag); 10367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma = skb_frag_dma_map(&alx->hw.pdev->dev, frag, 0, 10377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan maplen, DMA_TO_DEVICE); 10387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (dma_mapping_error(&alx->hw.pdev->dev, dma)) 10397f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan goto err_dma; 10407f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen); 10417f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma); 10427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan tpd->adrl.addr = cpu_to_le64(dma); 10447f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan tpd->len = cpu_to_le16(maplen); 10457f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 10467f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10477f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* last TPD, set EOP flag and store skb */ 10487f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan tpd->word1 |= cpu_to_le32(1 << TPD_EOP_SHIFT); 10497f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan txq->bufs[txq->write_idx].skb = skb; 10509929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 10519929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (++txq->write_idx == alx->tx_ringsz) 10527f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan txq->write_idx = 0; 10537f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10547f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return 0; 10557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10567f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanerr_dma: 1057f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan f = first_idx; 1058f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan while (f != txq->write_idx) { 1059f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan alx_free_txbuf(alx, f); 1060f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan if (++f == alx->tx_ringsz) 10617f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan f = 0; 10629929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } 10637f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return -ENOMEM; 10647f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 10657f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10669929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanstatic netdev_tx_t alx_start_xmit(struct sk_buff *skb, 10677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct net_device *netdev) 10687f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 10697f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_priv *alx = netdev_priv(netdev); 10709929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct alx_tx_queue *txq = &alx->txq; 1071f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan struct alx_txd *first; 1072eb9dc6f48dc7537ce53163109625bd992150e0cfBryan O'Sullivan int tpdreq = skb_shinfo(skb)->nr_frags + 1; 1073eb9dc6f48dc7537ce53163109625bd992150e0cfBryan O'Sullivan 1074eb9dc6f48dc7537ce53163109625bd992150e0cfBryan O'Sullivan if (alx_tpd_avail(alx) < tpdreq) { 1075eb9dc6f48dc7537ce53163109625bd992150e0cfBryan O'Sullivan netif_stop_queue(alx->dev); 1076eb9dc6f48dc7537ce53163109625bd992150e0cfBryan O'Sullivan goto drop; 1077eb9dc6f48dc7537ce53163109625bd992150e0cfBryan O'Sullivan } 1078eb9dc6f48dc7537ce53163109625bd992150e0cfBryan O'Sullivan 1079367fe711c5dc85dbc3265cf01e34d4d6fbd55f06Bryan O'Sullivan first = &txq->tpd[txq->write_idx]; 1080367fe711c5dc85dbc3265cf01e34d4d6fbd55f06Bryan O'Sullivan memset(first, 0, sizeof(*first)); 1081367fe711c5dc85dbc3265cf01e34d4d6fbd55f06Bryan O'Sullivan 1082367fe711c5dc85dbc3265cf01e34d4d6fbd55f06Bryan O'Sullivan if (alx_tx_csum(skb, first)) 1083f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan goto drop; 10847f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10857f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (alx_map_tx_skb(alx, skb) < 0) 10867f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan goto drop; 10877f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10887f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netdev_sent_queue(alx->dev, skb->len); 10897f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10907f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* flush updates before updating hardware */ 10917f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan wmb(); 10927f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_write_mem16(&alx->hw, ALX_TPD_PRI0_PIDX, txq->write_idx); 10937f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10947f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (alx_tpd_avail(alx) < alx->tx_ringsz/8) 10957f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netif_stop_queue(alx->dev); 10967f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10977f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return NETDEV_TX_OK; 10987f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 10991fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivandrop: 11007f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dev_kfree_skb(skb); 11017f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return NETDEV_TX_OK; 11027f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 11037f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 11047f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_tx_timeout(struct net_device *dev) 11057f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 11067f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_priv *alx = netdev_priv(dev); 11077f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 11087f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan alx_schedule_reset(alx); 11099929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan} 11107f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 11117f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_mdio_read(struct net_device *netdev, 11127f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int prtad, int devad, u16 addr) 11137f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 11147f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_priv *alx = netdev_priv(netdev); 11157f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 11167f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan u16 val; 11177f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int err; 11187f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 1119f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan if (prtad != hw->mdio.prtad) 1120f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan return -EINVAL; 11217f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 11227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (devad == MDIO_DEVAD_NONE) 11237f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = alx_read_phy_reg(hw, addr, &val); 11247f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan else 11251fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan err = alx_read_phy_ext(hw, devad, addr, &val); 11261fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan 11271fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan if (err) 11287f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return err; 11297f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return val; 11307f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan} 11317f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 11327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_mdio_write(struct net_device *netdev, 11337f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int prtad, int devad, u16 addr, u16 val) 11347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 11357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_priv *alx = netdev_priv(netdev); 11367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw = &alx->hw; 11379929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 11383c8450860ba9d6279dbc969633eacf99161860d9Nick Piggin if (prtad != hw->mdio.prtad) 11399929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan return -EINVAL; 11403c8450860ba9d6279dbc969633eacf99161860d9Nick Piggin 11413c8450860ba9d6279dbc969633eacf99161860d9Nick Piggin if (devad == MDIO_DEVAD_NONE) 11429929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan return alx_write_phy_reg(hw, addr, val); 11433c8450860ba9d6279dbc969633eacf99161860d9Nick Piggin 11449929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan return alx_write_phy_ext(hw, devad, addr, val); 11453c8450860ba9d6279dbc969633eacf99161860d9Nick Piggin} 11469929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 11473c8450860ba9d6279dbc969633eacf99161860d9Nick Pigginstatic int alx_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) 11489929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan{ 11493c8450860ba9d6279dbc969633eacf99161860d9Nick Piggin struct alx_priv *alx = netdev_priv(netdev); 11503c8450860ba9d6279dbc969633eacf99161860d9Nick Piggin 11513c8450860ba9d6279dbc969633eacf99161860d9Nick Piggin if (!netif_running(netdev)) 11529929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan return -EAGAIN; 11539929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 11549929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan return mdio_mii_ioctl(&alx->hw.mdio, if_mii(ifr), cmd); 11553c8450860ba9d6279dbc969633eacf99161860d9Nick Piggin} 11569929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 11579929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan#ifdef CONFIG_NET_POLL_CONTROLLER 11589929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanstatic void alx_poll_controller(struct net_device *netdev) 11599929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan{ 11609929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct alx_priv *alx = netdev_priv(netdev); 11619929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 11629929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (alx->msi) 11639929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_intr_msi(0, alx); 11649929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan else 11650a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell alx_intr_legacy(0, alx); 11669929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan} 11679929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan#endif 11680a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell 11699929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanstatic struct rtnl_link_stats64 *alx_get_stats64(struct net_device *dev, 11709929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct rtnl_link_stats64 *net_stats) 11719929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan{ 11729929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct alx_priv *alx = netdev_priv(dev); 11739929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct alx_hw_stats *hw_stats = &alx->hw.stats; 11749929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1175c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage spin_lock(&alx->stats_lock); 1176c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 1177c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage alx_update_hw_stats(&alx->hw); 11789929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1179c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->tx_bytes = hw_stats->tx_byte_cnt; 1180c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->rx_bytes = hw_stats->rx_byte_cnt; 1181c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->multicast = hw_stats->rx_mcast; 1182c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->collisions = hw_stats->tx_single_col + 1183c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->tx_multi_col + 1184c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->tx_late_col + 1185c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->tx_abort_col; 1186c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 1187c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->rx_errors = hw_stats->rx_frag + 1188c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->rx_fcs_err + 1189c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->rx_len_err + 1190c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->rx_ov_sz + 1191c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->rx_ov_rrd + 1192c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->rx_align_err + 1193c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->rx_ov_rxf; 1194c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 1195c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->rx_fifo_errors = hw_stats->rx_ov_rxf; 1196c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->rx_length_errors = hw_stats->rx_len_err; 1197c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->rx_crc_errors = hw_stats->rx_fcs_err; 1198c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->rx_frame_errors = hw_stats->rx_align_err; 1199c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->rx_dropped = hw_stats->rx_ov_rrd; 1200c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 1201c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->tx_errors = hw_stats->tx_late_col + 1202c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->tx_abort_col + 1203c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->tx_underrun + 1204c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage hw_stats->tx_trunc; 1205c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 1206c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->tx_aborted_errors = hw_stats->tx_abort_col; 1207c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->tx_fifo_errors = hw_stats->tx_underrun; 1208c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->tx_window_errors = hw_stats->tx_late_col; 1209c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 1210c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors; 1211c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors; 1212c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 1213c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage spin_unlock(&alx->stats_lock); 12149929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1215c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage return net_stats; 12169929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan} 12179929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 12189929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanstatic const struct net_device_ops alx_netdev_ops = { 12199929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_open = alx_open, 12209929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_stop = alx_stop, 12219929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_start_xmit = alx_start_xmit, 12229929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_get_stats64 = alx_get_stats64, 12239929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_set_rx_mode = alx_set_rx_mode, 12249929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_validate_addr = eth_validate_addr, 12259929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_set_mac_address = alx_set_mac_address, 12260a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell .ndo_change_mtu = alx_change_mtu, 12279929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_do_ioctl = alx_ioctl, 12289929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_tx_timeout = alx_tx_timeout, 12299929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_fix_features = alx_fix_features, 12309929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan#ifdef CONFIG_NET_POLL_CONTROLLER 12319929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .ndo_poll_controller = alx_poll_controller, 12327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#endif 12337f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan}; 12347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 12357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 12367f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan{ 12377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct net_device *netdev; 12387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_priv *alx; 12397f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan struct alx_hw *hw; 12407f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan bool phy_configured; 12417f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan int bars, err; 12427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 12437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = pci_enable_device_mem(pdev); 12447f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (err) 12457f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return err; 12467f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 12479929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan /* The alx chip can DMA to 64-bit addresses, but it uses a single 12487f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * shared register for the high 32 bits, so only a single, aligned, 12497f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan * 4 GB physical address range can be used for descriptors. 12507f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan */ 12519929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) && 12529929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) { 12539929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n"); 12549929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } else { 12557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 1256f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan if (err) { 12577f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = dma_set_coherent_mask(&pdev->dev, 12587f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan DMA_BIT_MASK(32)); 12597f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (err) { 12609929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan dev_err(&pdev->dev, 12619929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan "No usable DMA config, aborting\n"); 12629929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan goto out_pci_disable; 12639929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } 12647f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 12657f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 12667f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 12677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan bars = pci_select_bars(pdev, IORESOURCE_MEM); 12689929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan err = pci_request_selected_regions(pdev, bars, alx_drv_name); 12699929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (err) { 12707f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dev_err(&pdev->dev, 12719929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan "pci_request_selected_regions failed(bars:%d)\n", bars); 12729929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan goto out_pci_disable; 12739929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } 1274f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 12757f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan pci_enable_pcie_error_reporting(pdev); 12769929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan pci_set_master(pdev); 12777f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 12789929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (!pdev->pm_cap) { 12799929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan dev_err(&pdev->dev, 12807f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan "Can't find power management capability, aborting\n"); 12819929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan err = -EIO; 12829929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan goto out_pci_release; 12839929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } 12849929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 12859929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan netdev = alloc_etherdev(sizeof(*alx)); 12860a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell if (!netdev) { 12870a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell err = -ENOMEM; 12880a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell goto out_pci_release; 12890a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell } 12909929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 12919929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan SET_NETDEV_DEV(netdev, &pdev->dev); 12929929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx = netdev_priv(netdev); 1293a18e26ae442001de62f6b84a923e8613347dc35fRalph Campbell spin_lock_init(&alx->hw.mdio_lock); 12949929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan spin_lock_init(&alx->irq_lock); 12959929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan spin_lock_init(&alx->stats_lock); 1296e2ab41cae418108f376ad1634d7507f56379f7a2Dave Olson alx->dev = netdev; 12979929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx->hw.pdev = pdev; 12989929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP | 12999929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR | NETIF_MSG_WOL; 1300e2ab41cae418108f376ad1634d7507f56379f7a2Dave Olson hw = &alx->hw; 1301e2ab41cae418108f376ad1634d7507f56379f7a2Dave Olson pci_set_drvdata(pdev, alx); 13029929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1303e2ab41cae418108f376ad1634d7507f56379f7a2Dave Olson hw->hw_addr = pci_ioremap_bar(pdev, 0); 13049929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (!hw->hw_addr) { 13059929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan dev_err(&pdev->dev, "cannot map device registers\n"); 13069929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan err = -EIO; 13079929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan goto out_free_netdev; 1308e2ab41cae418108f376ad1634d7507f56379f7a2Dave Olson } 13099929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1310f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan netdev->netdev_ops = &alx_netdev_ops; 13119929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan SET_ETHTOOL_OPS(netdev, &alx_ethtool_ops); 13129929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan netdev->irq = pdev->irq; 13137f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netdev->watchdog_timeo = ALX_WATCHDOG_TIME; 13149929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 13159929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (ent->driver_data & ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG) 13169929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan pdev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; 13179929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 13189929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan err = alx_init_sw(alx); 13191fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan if (err) { 13209929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan dev_err(&pdev->dev, "net device private data init failed\n"); 13219929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan goto out_unmap; 13227f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan } 13239929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1324f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan alx_reset_pcie(hw); 1325525d0ca1d452ed336c1d907fb20c104467a8a47bBryan O'Sullivan 1326f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan phy_configured = alx_phy_configured(hw); 1327f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 1328f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan if (!phy_configured) 13299929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan alx_reset_phy(hw); 13301fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan 1331f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan err = alx_reset_mac(hw); 13329929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (err) { 1333f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan dev_err(&pdev->dev, "MAC Reset failed, error = %d\n", err); 1334f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan goto out_unmap; 13351fd3b40fde3bfacdf742cadfe99cfd47ffd05219Bryan O'Sullivan } 1336f37bda92461313ad3bbfbf5660adc849c69718bfBryan O'Sullivan 13377f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan /* setup link to put it in a known good starting state */ 13387f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!phy_configured) { 13397f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl); 13407f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (err) { 13417f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dev_err(&pdev->dev, 13427f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan "failed to configure PHY speed/duplex (err=%d)\n", 13437f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err); 13449929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan goto out_unmap; 13459929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } 13469929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } 13479929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 13487f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; 13497f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 13507f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (alx_get_perm_macaddr(hw, hw->perm_addr)) { 135170c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones dev_warn(&pdev->dev, 135270c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones "Invalid permanent address programmed, using random one\n"); 135370c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones eth_hw_addr_random(netdev); 135470c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones memcpy(hw->perm_addr, netdev->dev_addr, netdev->addr_len); 135570c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones } 135670c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones 135770c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones memcpy(hw->mac_addr, hw->perm_addr, ETH_ALEN); 135870c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones memcpy(netdev->dev_addr, hw->mac_addr, ETH_ALEN); 135970c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones memcpy(netdev->perm_addr, hw->perm_addr, ETH_ALEN); 136070c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones 136170c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones hw->mdio.prtad = 0; 136270c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones hw->mdio.mmds = 0; 136370c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones hw->mdio.dev = netdev; 1364f2d042313e420002b06715675963cfab48ed2597Robert Walsh hw->mdio.mode_support = MDIO_SUPPORTS_C45 | 1365f2d042313e420002b06715675963cfab48ed2597Robert Walsh MDIO_SUPPORTS_C22 | 1366f2d042313e420002b06715675963cfab48ed2597Robert Walsh MDIO_EMULATE_C22; 13677f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan hw->mdio.mdio_read = alx_mdio_read; 1368e35d710d0c5b74bc9833d6a3791706bd577a3724Bryan O'Sullivan hw->mdio.mdio_write = alx_mdio_write; 13697f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 13707f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (!alx_get_phy_info(hw)) { 13717f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan dev_err(&pdev->dev, "failed to identify PHY\n"); 13727f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan err = -EIO; 137370c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones goto out_unmap; 137470c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones } 137570c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones 13767f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan INIT_WORK(&alx->link_check_wk, alx_link_check); 137770c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones INIT_WORK(&alx->reset_wk, alx_reset); 1378f2d042313e420002b06715675963cfab48ed2597Robert Walsh netif_carrier_off(netdev); 137970c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones 1380f2d042313e420002b06715675963cfab48ed2597Robert Walsh err = register_netdev(netdev); 13817f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan if (err) { 1382f2d042313e420002b06715675963cfab48ed2597Robert Walsh dev_err(&pdev->dev, "register netdevice failed\n"); 138370c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones goto out_unmap; 1384f2d042313e420002b06715675963cfab48ed2597Robert Walsh } 138570c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones 138670c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones netdev_info(netdev, 1387f2d042313e420002b06715675963cfab48ed2597Robert Walsh "Qualcomm Atheros AR816x/AR817x Ethernet [%pM]\n", 1388f2d042313e420002b06715675963cfab48ed2597Robert Walsh netdev->dev_addr); 1389f2d042313e420002b06715675963cfab48ed2597Robert Walsh 1390f2d042313e420002b06715675963cfab48ed2597Robert Walsh return 0; 1391f2d042313e420002b06715675963cfab48ed2597Robert Walsh 1392f2d042313e420002b06715675963cfab48ed2597Robert Walshout_unmap: 1393f2d042313e420002b06715675963cfab48ed2597Robert Walsh iounmap(hw->hw_addr); 1394f2d042313e420002b06715675963cfab48ed2597Robert Walshout_free_netdev: 1395f2d042313e420002b06715675963cfab48ed2597Robert Walsh free_netdev(netdev); 1396f2d042313e420002b06715675963cfab48ed2597Robert Walshout_pci_release: 139770c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones pci_release_selected_regions(pdev, bars); 139870c51da2c4f84317bb13a2b564600afdcebd686fArthur Jonesout_pci_disable: 1399f2d042313e420002b06715675963cfab48ed2597Robert Walsh pci_disable_device(pdev); 1400f2d042313e420002b06715675963cfab48ed2597Robert Walsh return err; 1401f2d042313e420002b06715675963cfab48ed2597Robert Walsh} 1402f2d042313e420002b06715675963cfab48ed2597Robert Walsh 14037f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic void alx_remove(struct pci_dev *pdev) 140470c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones{ 140570c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones struct alx_priv *alx = pci_get_drvdata(pdev); 140670c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones struct alx_hw *hw = &alx->hw; 140770c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones 14087f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan cancel_work_sync(&alx->link_check_wk); 1409c59a80aca0bfc491d90534ed5606d5493eca24a3Ralph Campbell cancel_work_sync(&alx->reset_wk); 1410c59a80aca0bfc491d90534ed5606d5493eca24a3Ralph Campbell 1411c59a80aca0bfc491d90534ed5606d5493eca24a3Ralph Campbell /* restore permanent mac address */ 1412c59a80aca0bfc491d90534ed5606d5493eca24a3Ralph Campbell alx_set_macaddr(hw, hw->perm_addr); 1413f2d042313e420002b06715675963cfab48ed2597Robert Walsh 141470c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones unregister_netdev(alx->dev); 1415f2d042313e420002b06715675963cfab48ed2597Robert Walsh iounmap(hw->hw_addr); 141670c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones pci_release_selected_regions(pdev, 141770c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones pci_select_bars(pdev, IORESOURCE_MEM)); 14187f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan 141970c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones pci_disable_pcie_error_reporting(pdev); 142070c51da2c4f84317bb13a2b564600afdcebd686fArthur Jones pci_disable_device(pdev); 1421f2d042313e420002b06715675963cfab48ed2597Robert Walsh 1422d8274869d742c3d8082e1428de47e54d12104928Dave Olson free_netdev(alx->dev); 1423f2d042313e420002b06715675963cfab48ed2597Robert Walsh} 1424f2d042313e420002b06715675963cfab48ed2597Robert Walsh 1425f2d042313e420002b06715675963cfab48ed2597Robert Walsh#ifdef CONFIG_PM_SLEEP 1426f2d042313e420002b06715675963cfab48ed2597Robert Walshstatic int alx_suspend(struct device *dev) 1427f2d042313e420002b06715675963cfab48ed2597Robert Walsh{ 14289929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct pci_dev *pdev = to_pci_dev(dev); 1429f2d042313e420002b06715675963cfab48ed2597Robert Walsh struct alx_priv *alx = pci_get_drvdata(pdev); 1430f2d042313e420002b06715675963cfab48ed2597Robert Walsh 1431f2d042313e420002b06715675963cfab48ed2597Robert Walsh if (!netif_running(alx->dev)) 14327f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return 0; 1433f2d042313e420002b06715675963cfab48ed2597Robert Walsh netif_device_detach(alx->dev); 14347f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan __alx_stop(alx); 14357f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan return 0; 1436f2d042313e420002b06715675963cfab48ed2597Robert Walsh} 1437f2d042313e420002b06715675963cfab48ed2597Robert Walsh 1438f2d042313e420002b06715675963cfab48ed2597Robert Walshstatic int alx_resume(struct device *dev) 1439f2d042313e420002b06715675963cfab48ed2597Robert Walsh{ 1440f2d042313e420002b06715675963cfab48ed2597Robert Walsh struct pci_dev *pdev = to_pci_dev(dev); 1441f2d042313e420002b06715675963cfab48ed2597Robert Walsh struct alx_priv *alx = pci_get_drvdata(pdev); 1442f2d042313e420002b06715675963cfab48ed2597Robert Walsh struct alx_hw *hw = &alx->hw; 1443f2d042313e420002b06715675963cfab48ed2597Robert Walsh 1444f2d042313e420002b06715675963cfab48ed2597Robert Walsh alx_reset_phy(hw); 1445f2d042313e420002b06715675963cfab48ed2597Robert Walsh 1446f2d042313e420002b06715675963cfab48ed2597Robert Walsh if (!netif_running(alx->dev)) 1447f2d042313e420002b06715675963cfab48ed2597Robert Walsh return 0; 1448f2d042313e420002b06715675963cfab48ed2597Robert Walsh netif_device_attach(alx->dev); 1449f2d042313e420002b06715675963cfab48ed2597Robert Walsh return __alx_open(alx, true); 1450f2d042313e420002b06715675963cfab48ed2597Robert Walsh} 1451f2d042313e420002b06715675963cfab48ed2597Robert Walsh 14527f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivanstatic SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume); 1453e35d710d0c5b74bc9833d6a3791706bd577a3724Bryan O'Sullivan#define ALX_PM_OPS (&alx_pm_ops) 14547f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#else 14557f510b46e4771cfb89af134b3aa827d46125a2ceBryan O'Sullivan#define ALX_PM_OPS NULL 14560df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage#endif 14570df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 14580df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 14590df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbagestatic pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev, 14600df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage pci_channel_state_t state) 14610df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage{ 14620df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage struct alx_priv *alx = pci_get_drvdata(pdev); 14630df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage struct net_device *netdev = alx->dev; 14640df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage pci_ers_result_t rc = PCI_ERS_RESULT_NEED_RESET; 14650df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 14660df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage dev_info(&pdev->dev, "pci error detected\n"); 14670df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 14680df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage rtnl_lock(); 14690df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 14700df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage if (netif_running(netdev)) { 14710df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage netif_device_detach(netdev); 14720df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage alx_halt(alx); 14730df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage } 14740df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 14750df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage if (state == pci_channel_io_perm_failure) 14760df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage rc = PCI_ERS_RESULT_DISCONNECT; 14770df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage else 14780df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage pci_disable_device(pdev); 14790df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 14800df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage rtnl_unlock(); 14810df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 14820df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage return rc; 14830df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage} 14840df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 14850df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbagestatic pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev) 14860df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage{ 14870df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage struct alx_priv *alx = pci_get_drvdata(pdev); 14889929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan struct alx_hw *hw = &alx->hw; 14899929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; 14909929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 14919929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan dev_info(&pdev->dev, "pci error slot reset\n"); 14929929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1493c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage rtnl_lock(); 14949929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 14959929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan if (pci_enable_device(pdev)) { 14969929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan dev_err(&pdev->dev, "Failed to re-enable PCI device after reset\n"); 1497bacf4013530e7fc230a8aa0c6ea3c17fc2f47665Mark Debbage goto out; 14989929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan } 14999929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1500bacf4013530e7fc230a8aa0c6ea3c17fc2f47665Mark Debbage pci_set_master(pdev); 15019929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1502c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage alx_reset_pcie(hw); 15030df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage if (!alx_reset_mac(hw)) 15040df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage rc = PCI_ERS_RESULT_RECOVERED; 15050df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbageout: 15060df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage pci_cleanup_aer_uncorrect_error_status(pdev); 1507c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 15080df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage rtnl_unlock(); 15090df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 15100df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage return rc; 15110df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage} 15120df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 15130df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbagestatic void alx_pci_error_resume(struct pci_dev *pdev) 15140df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage{ 15150df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage struct alx_priv *alx = pci_get_drvdata(pdev); 15160df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage struct net_device *netdev = alx->dev; 15170df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage 1518c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage dev_info(&pdev->dev, "pci error resume\n"); 1519c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 15200df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage rtnl_lock(); 1521c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage 15220df6291c8af2778d05f278d5738eef2c8fafa2ddMark Debbage if (netif_running(netdev)) { 1523c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage alx_activate(alx); 1524c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage netif_device_attach(netdev); 1525c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage } 15260a5a83cffc03592c2102ad07b7532b596a16f8cdRalph Campbell 15279929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan rtnl_unlock(); 15289929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan} 15299929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 15309929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanstatic const struct pci_error_handlers alx_err_handlers = { 1531c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage .error_detected = alx_pci_error_detected, 1532c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage .slot_reset = alx_pci_error_slot_reset, 15339929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .resume = alx_pci_error_resume, 15349929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan}; 15359929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 15369929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivanstatic DEFINE_PCI_DEVICE_TABLE(alx_pci_tbl) = { 15379929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8161), 15389929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, 1539c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200), 15409929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, 15419929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162), 15429929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG }, 15439929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) }, 15449929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8172) }, 15459929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan {} 15469929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan}; 15479929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1548c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbagestatic struct pci_driver alx_driver = { 15499929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .name = alx_drv_name, 15509929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .id_table = alx_pci_tbl, 15519929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .probe = alx_probe, 15529929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .remove = alx_remove, 15539929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .err_handler = &alx_err_handlers, 15549929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan .driver.pm = ALX_PM_OPS, 15559929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan}; 15569929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan 1557947d7617a1d876c2c93f73017a734e070c64d43bRalph Campbellmodule_pci_driver(alx_driver); 1558c7e29ff11f23ec78b3caf691789c2b791bb596bfMark DebbageMODULE_DEVICE_TABLE(pci, alx_pci_tbl); 1559c7e29ff11f23ec78b3caf691789c2b791bb596bfMark DebbageMODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); 1560c7e29ff11f23ec78b3caf691789c2b791bb596bfMark DebbageMODULE_AUTHOR("Qualcomm Corporation, <nic-devel@qualcomm.com>"); 1561c7e29ff11f23ec78b3caf691789c2b791bb596bfMark DebbageMODULE_DESCRIPTION( 1562c7e29ff11f23ec78b3caf691789c2b791bb596bfMark Debbage "Qualcomm Atheros(R) AR816x/AR817x PCI-E Ethernet Network Driver"); 15639929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'SullivanMODULE_LICENSE("GPL"); 15649929b0fb0f35f54371e9364bab809bcd753f9d3aBryan O'Sullivan