12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2010 ASIX Electronics Corporation
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
- *
- * ASIX AX88796C SPI Fast Ethernet Linux driver
- */
- #define pr_fmt(fmt) "ax88796c: " fmt
- #include "ax88796c_main.h"
- #include "ax88796c_ioctl.h"
- #include <linux/bitmap.h>
- #include <linux/etherdevice.h>
- #include <linux/iopoll.h>
- #include <linux/lockdep.h>
- #include <linux/mdio.h>
- #include <linux/minmax.h>
- #include <linux/module.h>
- #include <linux/netdevice.h>
- #include <linux/of.h>
- #include <linux/phy.h>
- #include <linux/skbuff.h>
- #include <linux/spi/spi.h>
- static int comp = IS_ENABLED(CONFIG_SPI_AX88796C_COMPRESSION);
- static int msg_enable = NETIF_MSG_PROBE |
- NETIF_MSG_LINK |
- NETIF_MSG_RX_ERR |
- NETIF_MSG_TX_ERR;
- static const char *no_regs_list = "80018001,e1918001,8001a001,fc0d0000";
- unsigned long ax88796c_no_regs_mask[AX88796C_REGDUMP_LEN / (sizeof(unsigned long) * 8)];
- module_param(msg_enable, int, 0444);
- MODULE_PARM_DESC(msg_enable, "Message mask (see linux/netdevice.h for bitmap)");
- static int ax88796c_soft_reset(struct ax88796c_device *ax_local)
- {
- u16 temp;
- int ret;
- lockdep_assert_held(&ax_local->spi_lock);
- AX_WRITE(&ax_local->ax_spi, PSR_RESET, P0_PSR);
- AX_WRITE(&ax_local->ax_spi, PSR_RESET_CLR, P0_PSR);
- ret = read_poll_timeout(AX_READ, ret,
- (ret & PSR_DEV_READY),
- 0, jiffies_to_usecs(160 * HZ / 1000), false,
- &ax_local->ax_spi, P0_PSR);
- if (ret)
- return ret;
- temp = AX_READ(&ax_local->ax_spi, P4_SPICR);
- if (ax_local->priv_flags & AX_CAP_COMP) {
- AX_WRITE(&ax_local->ax_spi,
- (temp | SPICR_RCEN | SPICR_QCEN), P4_SPICR);
- ax_local->ax_spi.comp = 1;
- } else {
- AX_WRITE(&ax_local->ax_spi,
- (temp & ~(SPICR_RCEN | SPICR_QCEN)), P4_SPICR);
- ax_local->ax_spi.comp = 0;
- }
- return 0;
- }
- static int ax88796c_reload_eeprom(struct ax88796c_device *ax_local)
- {
- int ret;
- lockdep_assert_held(&ax_local->spi_lock);
- AX_WRITE(&ax_local->ax_spi, EECR_RELOAD, P3_EECR);
- ret = read_poll_timeout(AX_READ, ret,
- (ret & PSR_DEV_READY),
- 0, jiffies_to_usecs(2 * HZ / 1000), false,
- &ax_local->ax_spi, P0_PSR);
- if (ret) {
- dev_err(&ax_local->spi->dev,
- "timeout waiting for reload eeprom\n");
- return ret;
- }
- return 0;
- }
- static void ax88796c_set_hw_multicast(struct net_device *ndev)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- int mc_count = netdev_mc_count(ndev);
- u16 rx_ctl = RXCR_AB;
- lockdep_assert_held(&ax_local->spi_lock);
- memset(ax_local->multi_filter, 0, AX_MCAST_FILTER_SIZE);
- if (ndev->flags & IFF_PROMISC) {
- rx_ctl |= RXCR_PRO;
- } else if (ndev->flags & IFF_ALLMULTI || mc_count > AX_MAX_MCAST) {
- rx_ctl |= RXCR_AMALL;
- } else if (mc_count == 0) {
- /* just broadcast and directed */
- } else {
- u32 crc_bits;
- int i;
- struct netdev_hw_addr *ha;
- netdev_for_each_mc_addr(ha, ndev) {
- crc_bits = ether_crc(ETH_ALEN, ha->addr);
- ax_local->multi_filter[crc_bits >> 29] |=
- (1 << ((crc_bits >> 26) & 7));
- }
- for (i = 0; i < 4; i++) {
- AX_WRITE(&ax_local->ax_spi,
- ((ax_local->multi_filter[i * 2 + 1] << 8) |
- ax_local->multi_filter[i * 2]), P3_MFAR(i));
- }
- }
- AX_WRITE(&ax_local->ax_spi, rx_ctl, P2_RXCR);
- }
- static void ax88796c_set_mac_addr(struct net_device *ndev)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- lockdep_assert_held(&ax_local->spi_lock);
- AX_WRITE(&ax_local->ax_spi, ((u16)(ndev->dev_addr[4] << 8) |
- (u16)ndev->dev_addr[5]), P3_MACASR0);
- AX_WRITE(&ax_local->ax_spi, ((u16)(ndev->dev_addr[2] << 8) |
- (u16)ndev->dev_addr[3]), P3_MACASR1);
- AX_WRITE(&ax_local->ax_spi, ((u16)(ndev->dev_addr[0] << 8) |
- (u16)ndev->dev_addr[1]), P3_MACASR2);
- }
- static void ax88796c_load_mac_addr(struct net_device *ndev)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- u8 addr[ETH_ALEN];
- u16 temp;
- lockdep_assert_held(&ax_local->spi_lock);
- /* Try the device tree first */
- if (!platform_get_ethdev_address(&ax_local->spi->dev, ndev) &&
- is_valid_ether_addr(ndev->dev_addr)) {
- if (netif_msg_probe(ax_local))
- dev_info(&ax_local->spi->dev,
- "MAC address read from device tree\n");
- return;
- }
- /* Read the MAC address from AX88796C */
- temp = AX_READ(&ax_local->ax_spi, P3_MACASR0);
- addr[5] = (u8)temp;
- addr[4] = (u8)(temp >> 8);
- temp = AX_READ(&ax_local->ax_spi, P3_MACASR1);
- addr[3] = (u8)temp;
- addr[2] = (u8)(temp >> 8);
- temp = AX_READ(&ax_local->ax_spi, P3_MACASR2);
- addr[1] = (u8)temp;
- addr[0] = (u8)(temp >> 8);
- if (is_valid_ether_addr(addr)) {
- eth_hw_addr_set(ndev, addr);
- if (netif_msg_probe(ax_local))
- dev_info(&ax_local->spi->dev,
- "MAC address read from ASIX chip\n");
- return;
- }
- /* Use random address if none found */
- if (netif_msg_probe(ax_local))
- dev_info(&ax_local->spi->dev, "Use random MAC address\n");
- eth_hw_addr_random(ndev);
- }
- static void ax88796c_proc_tx_hdr(struct tx_pkt_info *info, u8 ip_summed)
- {
- u16 pkt_len_bar = (~info->pkt_len & TX_HDR_SOP_PKTLENBAR);
- /* Prepare SOP header */
- info->sop.flags_len = info->pkt_len |
- ((ip_summed == CHECKSUM_NONE) ||
- (ip_summed == CHECKSUM_UNNECESSARY) ? TX_HDR_SOP_DICF : 0);
- info->sop.seq_lenbar = ((info->seq_num << 11) & TX_HDR_SOP_SEQNUM)
- | pkt_len_bar;
- cpu_to_be16s(&info->sop.flags_len);
- cpu_to_be16s(&info->sop.seq_lenbar);
- /* Prepare Segment header */
- info->seg.flags_seqnum_seglen = TX_HDR_SEG_FS | TX_HDR_SEG_LS
- | info->pkt_len;
- info->seg.eo_so_seglenbar = pkt_len_bar;
- cpu_to_be16s(&info->seg.flags_seqnum_seglen);
- cpu_to_be16s(&info->seg.eo_so_seglenbar);
- /* Prepare EOP header */
- info->eop.seq_len = ((info->seq_num << 11) &
- TX_HDR_EOP_SEQNUM) | info->pkt_len;
- info->eop.seqbar_lenbar = ((~info->seq_num << 11) &
- TX_HDR_EOP_SEQNUMBAR) | pkt_len_bar;
- cpu_to_be16s(&info->eop.seq_len);
- cpu_to_be16s(&info->eop.seqbar_lenbar);
- }
- static int
- ax88796c_check_free_pages(struct ax88796c_device *ax_local, u8 need_pages)
- {
- u8 free_pages;
- u16 tmp;
- lockdep_assert_held(&ax_local->spi_lock);
- free_pages = AX_READ(&ax_local->ax_spi, P0_TFBFCR) & TX_FREEBUF_MASK;
- if (free_pages < need_pages) {
- /* schedule free page interrupt */
- tmp = AX_READ(&ax_local->ax_spi, P0_TFBFCR)
- & TFBFCR_SCHE_FREE_PAGE;
- AX_WRITE(&ax_local->ax_spi, tmp | TFBFCR_TX_PAGE_SET |
- TFBFCR_SET_FREE_PAGE(need_pages),
- P0_TFBFCR);
- return -ENOMEM;
- }
- return 0;
- }
- static struct sk_buff *
- ax88796c_tx_fixup(struct net_device *ndev, struct sk_buff_head *q)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- u8 spi_len = ax_local->ax_spi.comp ? 1 : 4;
- struct sk_buff *skb;
- struct tx_pkt_info info;
- struct skb_data *entry;
- u16 pkt_len;
- u8 padlen, seq_num;
- u8 need_pages;
- int headroom;
- int tailroom;
- if (skb_queue_empty(q))
- return NULL;
- skb = skb_peek(q);
- pkt_len = skb->len;
- need_pages = (pkt_len + TX_OVERHEAD + 127) >> 7;
- if (ax88796c_check_free_pages(ax_local, need_pages) != 0)
- return NULL;
- headroom = skb_headroom(skb);
- tailroom = skb_tailroom(skb);
- padlen = round_up(pkt_len, 4) - pkt_len;
- seq_num = ++ax_local->seq_num & 0x1F;
- info.pkt_len = pkt_len;
- if (skb_cloned(skb) ||
- (headroom < (TX_OVERHEAD + spi_len)) ||
- (tailroom < (padlen + TX_EOP_SIZE))) {
- size_t h = max((TX_OVERHEAD + spi_len) - headroom, 0);
- size_t t = max((padlen + TX_EOP_SIZE) - tailroom, 0);
- if (pskb_expand_head(skb, h, t, GFP_KERNEL))
- return NULL;
- }
- info.seq_num = seq_num;
- ax88796c_proc_tx_hdr(&info, skb->ip_summed);
- /* SOP and SEG header */
- memcpy(skb_push(skb, TX_OVERHEAD), &info.sop, TX_OVERHEAD);
- /* Write SPI TXQ header */
- memcpy(skb_push(skb, spi_len), ax88796c_tx_cmd_buf, spi_len);
- /* Make 32-bit alignment */
- skb_put(skb, padlen);
- /* EOP header */
- skb_put_data(skb, &info.eop, TX_EOP_SIZE);
- skb_unlink(skb, q);
- entry = (struct skb_data *)skb->cb;
- memset(entry, 0, sizeof(*entry));
- entry->len = pkt_len;
- if (netif_msg_pktdata(ax_local)) {
- char pfx[IFNAMSIZ + 7];
- snprintf(pfx, sizeof(pfx), "%s: ", ndev->name);
- netdev_info(ndev, "TX packet len %d, total len %d, seq %d\n",
- pkt_len, skb->len, seq_num);
- netdev_info(ndev, " SPI Header:\n");
- print_hex_dump(KERN_INFO, pfx, DUMP_PREFIX_OFFSET, 16, 1,
- skb->data, 4, 0);
- netdev_info(ndev, " TX SOP:\n");
- print_hex_dump(KERN_INFO, pfx, DUMP_PREFIX_OFFSET, 16, 1,
- skb->data + 4, TX_OVERHEAD, 0);
- netdev_info(ndev, " TX packet:\n");
- print_hex_dump(KERN_INFO, pfx, DUMP_PREFIX_OFFSET, 16, 1,
- skb->data + 4 + TX_OVERHEAD,
- skb->len - TX_EOP_SIZE - 4 - TX_OVERHEAD, 0);
- netdev_info(ndev, " TX EOP:\n");
- print_hex_dump(KERN_INFO, pfx, DUMP_PREFIX_OFFSET, 16, 1,
- skb->data + skb->len - 4, 4, 0);
- }
- return skb;
- }
- static int ax88796c_hard_xmit(struct ax88796c_device *ax_local)
- {
- struct ax88796c_pcpu_stats *stats;
- struct sk_buff *tx_skb;
- struct skb_data *entry;
- unsigned long flags;
- lockdep_assert_held(&ax_local->spi_lock);
- stats = this_cpu_ptr(ax_local->stats);
- tx_skb = ax88796c_tx_fixup(ax_local->ndev, &ax_local->tx_wait_q);
- if (!tx_skb) {
- this_cpu_inc(ax_local->stats->tx_dropped);
- return 0;
- }
- entry = (struct skb_data *)tx_skb->cb;
- AX_WRITE(&ax_local->ax_spi,
- (TSNR_TXB_START | TSNR_PKT_CNT(1)), P0_TSNR);
- axspi_write_txq(&ax_local->ax_spi, tx_skb->data, tx_skb->len);
- if (((AX_READ(&ax_local->ax_spi, P0_TSNR) & TXNR_TXB_IDLE) == 0) ||
- ((ISR_TXERR & AX_READ(&ax_local->ax_spi, P0_ISR)) != 0)) {
- /* Ack tx error int */
- AX_WRITE(&ax_local->ax_spi, ISR_TXERR, P0_ISR);
- this_cpu_inc(ax_local->stats->tx_dropped);
- if (net_ratelimit())
- netif_err(ax_local, tx_err, ax_local->ndev,
- "TX FIFO error, re-initialize the TX bridge\n");
- /* Reinitial tx bridge */
- AX_WRITE(&ax_local->ax_spi, TXNR_TXB_REINIT |
- AX_READ(&ax_local->ax_spi, P0_TSNR), P0_TSNR);
- ax_local->seq_num = 0;
- } else {
- flags = u64_stats_update_begin_irqsave(&stats->syncp);
- u64_stats_inc(&stats->tx_packets);
- u64_stats_add(&stats->tx_bytes, entry->len);
- u64_stats_update_end_irqrestore(&stats->syncp, flags);
- }
- entry->state = tx_done;
- dev_kfree_skb(tx_skb);
- return 1;
- }
- static netdev_tx_t
- ax88796c_start_xmit(struct sk_buff *skb, struct net_device *ndev)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- skb_queue_tail(&ax_local->tx_wait_q, skb);
- if (skb_queue_len(&ax_local->tx_wait_q) > TX_QUEUE_HIGH_WATER)
- netif_stop_queue(ndev);
- set_bit(EVENT_TX, &ax_local->flags);
- schedule_work(&ax_local->ax_work);
- return NETDEV_TX_OK;
- }
- static void
- ax88796c_skb_return(struct ax88796c_device *ax_local,
- struct sk_buff *skb, struct rx_header *rxhdr)
- {
- struct net_device *ndev = ax_local->ndev;
- struct ax88796c_pcpu_stats *stats;
- unsigned long flags;
- int status;
- stats = this_cpu_ptr(ax_local->stats);
- do {
- if (!(ndev->features & NETIF_F_RXCSUM))
- break;
- /* checksum error bit is set */
- if ((rxhdr->flags & RX_HDR3_L3_ERR) ||
- (rxhdr->flags & RX_HDR3_L4_ERR))
- break;
- /* Other types may be indicated by more than one bit. */
- if ((rxhdr->flags & RX_HDR3_L4_TYPE_TCP) ||
- (rxhdr->flags & RX_HDR3_L4_TYPE_UDP))
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- } while (0);
- flags = u64_stats_update_begin_irqsave(&stats->syncp);
- u64_stats_inc(&stats->rx_packets);
- u64_stats_add(&stats->rx_bytes, skb->len);
- u64_stats_update_end_irqrestore(&stats->syncp, flags);
- skb->dev = ndev;
- skb->protocol = eth_type_trans(skb, ax_local->ndev);
- netif_info(ax_local, rx_status, ndev, "< rx, len %zu, type 0x%x\n",
- skb->len + sizeof(struct ethhdr), skb->protocol);
- status = netif_rx(skb);
- if (status != NET_RX_SUCCESS && net_ratelimit())
- netif_info(ax_local, rx_err, ndev,
- "netif_rx status %d\n", status);
- }
- static void
- ax88796c_rx_fixup(struct ax88796c_device *ax_local, struct sk_buff *rx_skb)
- {
- struct rx_header *rxhdr = (struct rx_header *)rx_skb->data;
- struct net_device *ndev = ax_local->ndev;
- u16 len;
- be16_to_cpus(&rxhdr->flags_len);
- be16_to_cpus(&rxhdr->seq_lenbar);
- be16_to_cpus(&rxhdr->flags);
- if ((rxhdr->flags_len & RX_HDR1_PKT_LEN) !=
- (~rxhdr->seq_lenbar & 0x7FF)) {
- netif_err(ax_local, rx_err, ndev, "Header error\n");
- this_cpu_inc(ax_local->stats->rx_frame_errors);
- kfree_skb(rx_skb);
- return;
- }
- if ((rxhdr->flags_len & RX_HDR1_MII_ERR) ||
- (rxhdr->flags_len & RX_HDR1_CRC_ERR)) {
- netif_err(ax_local, rx_err, ndev, "CRC or MII error\n");
- this_cpu_inc(ax_local->stats->rx_crc_errors);
- kfree_skb(rx_skb);
- return;
- }
- len = rxhdr->flags_len & RX_HDR1_PKT_LEN;
- if (netif_msg_pktdata(ax_local)) {
- char pfx[IFNAMSIZ + 7];
- snprintf(pfx, sizeof(pfx), "%s: ", ndev->name);
- netdev_info(ndev, "RX data, total len %d, packet len %d\n",
- rx_skb->len, len);
- netdev_info(ndev, " Dump RX packet header:");
- print_hex_dump(KERN_INFO, pfx, DUMP_PREFIX_OFFSET, 16, 1,
- rx_skb->data, sizeof(*rxhdr), 0);
- netdev_info(ndev, " Dump RX packet:");
- print_hex_dump(KERN_INFO, pfx, DUMP_PREFIX_OFFSET, 16, 1,
- rx_skb->data + sizeof(*rxhdr), len, 0);
- }
- skb_pull(rx_skb, sizeof(*rxhdr));
- pskb_trim(rx_skb, len);
- ax88796c_skb_return(ax_local, rx_skb, rxhdr);
- }
- static int ax88796c_receive(struct net_device *ndev)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- struct skb_data *entry;
- u16 w_count, pkt_len;
- struct sk_buff *skb;
- u8 pkt_cnt;
- lockdep_assert_held(&ax_local->spi_lock);
- /* check rx packet and total word count */
- AX_WRITE(&ax_local->ax_spi, AX_READ(&ax_local->ax_spi, P0_RTWCR)
- | RTWCR_RX_LATCH, P0_RTWCR);
- pkt_cnt = AX_READ(&ax_local->ax_spi, P0_RXBCR2) & RXBCR2_PKT_MASK;
- if (!pkt_cnt)
- return 0;
- pkt_len = AX_READ(&ax_local->ax_spi, P0_RCPHR) & 0x7FF;
- w_count = round_up(pkt_len + 6, 4) >> 1;
- skb = netdev_alloc_skb(ndev, w_count * 2);
- if (!skb) {
- AX_WRITE(&ax_local->ax_spi, RXBCR1_RXB_DISCARD, P0_RXBCR1);
- this_cpu_inc(ax_local->stats->rx_dropped);
- return 0;
- }
- entry = (struct skb_data *)skb->cb;
- AX_WRITE(&ax_local->ax_spi, RXBCR1_RXB_START | w_count, P0_RXBCR1);
- axspi_read_rxq(&ax_local->ax_spi,
- skb_put(skb, w_count * 2), skb->len);
- /* Check if rx bridge is idle */
- if ((AX_READ(&ax_local->ax_spi, P0_RXBCR2) & RXBCR2_RXB_IDLE) == 0) {
- if (net_ratelimit())
- netif_err(ax_local, rx_err, ndev,
- "Rx Bridge is not idle\n");
- AX_WRITE(&ax_local->ax_spi, RXBCR2_RXB_REINIT, P0_RXBCR2);
- entry->state = rx_err;
- } else {
- entry->state = rx_done;
- }
- AX_WRITE(&ax_local->ax_spi, ISR_RXPKT, P0_ISR);
- ax88796c_rx_fixup(ax_local, skb);
- return 1;
- }
- static int ax88796c_process_isr(struct ax88796c_device *ax_local)
- {
- struct net_device *ndev = ax_local->ndev;
- int todo = 0;
- u16 isr;
- lockdep_assert_held(&ax_local->spi_lock);
- isr = AX_READ(&ax_local->ax_spi, P0_ISR);
- AX_WRITE(&ax_local->ax_spi, isr, P0_ISR);
- netif_dbg(ax_local, intr, ndev, " ISR 0x%04x\n", isr);
- if (isr & ISR_TXERR) {
- netif_dbg(ax_local, intr, ndev, " TXERR interrupt\n");
- AX_WRITE(&ax_local->ax_spi, TXNR_TXB_REINIT, P0_TSNR);
- ax_local->seq_num = 0x1f;
- }
- if (isr & ISR_TXPAGES) {
- netif_dbg(ax_local, intr, ndev, " TXPAGES interrupt\n");
- set_bit(EVENT_TX, &ax_local->flags);
- }
- if (isr & ISR_LINK) {
- netif_dbg(ax_local, intr, ndev, " Link change interrupt\n");
- phy_mac_interrupt(ax_local->ndev->phydev);
- }
- if (isr & ISR_RXPKT) {
- netif_dbg(ax_local, intr, ndev, " RX interrupt\n");
- todo = ax88796c_receive(ax_local->ndev);
- }
- return todo;
- }
- static irqreturn_t ax88796c_interrupt(int irq, void *dev_instance)
- {
- struct ax88796c_device *ax_local;
- struct net_device *ndev;
- ndev = dev_instance;
- if (!ndev) {
- pr_err("irq %d for unknown device.\n", irq);
- return IRQ_RETVAL(0);
- }
- ax_local = to_ax88796c_device(ndev);
- disable_irq_nosync(irq);
- netif_dbg(ax_local, intr, ndev, "Interrupt occurred\n");
- set_bit(EVENT_INTR, &ax_local->flags);
- schedule_work(&ax_local->ax_work);
- return IRQ_HANDLED;
- }
- static void ax88796c_work(struct work_struct *work)
- {
- struct ax88796c_device *ax_local =
- container_of(work, struct ax88796c_device, ax_work);
- mutex_lock(&ax_local->spi_lock);
- if (test_bit(EVENT_SET_MULTI, &ax_local->flags)) {
- ax88796c_set_hw_multicast(ax_local->ndev);
- clear_bit(EVENT_SET_MULTI, &ax_local->flags);
- }
- if (test_bit(EVENT_INTR, &ax_local->flags)) {
- AX_WRITE(&ax_local->ax_spi, IMR_MASKALL, P0_IMR);
- while (ax88796c_process_isr(ax_local))
- /* nothing */;
- clear_bit(EVENT_INTR, &ax_local->flags);
- AX_WRITE(&ax_local->ax_spi, IMR_DEFAULT, P0_IMR);
- enable_irq(ax_local->ndev->irq);
- }
- if (test_bit(EVENT_TX, &ax_local->flags)) {
- while (skb_queue_len(&ax_local->tx_wait_q)) {
- if (!ax88796c_hard_xmit(ax_local))
- break;
- }
- clear_bit(EVENT_TX, &ax_local->flags);
- if (netif_queue_stopped(ax_local->ndev) &&
- (skb_queue_len(&ax_local->tx_wait_q) < TX_QUEUE_LOW_WATER))
- netif_wake_queue(ax_local->ndev);
- }
- mutex_unlock(&ax_local->spi_lock);
- }
- static void ax88796c_get_stats64(struct net_device *ndev,
- struct rtnl_link_stats64 *stats)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- u32 rx_frame_errors = 0, rx_crc_errors = 0;
- u32 rx_dropped = 0, tx_dropped = 0;
- unsigned int start;
- int cpu;
- for_each_possible_cpu(cpu) {
- struct ax88796c_pcpu_stats *s;
- u64 rx_packets, rx_bytes;
- u64 tx_packets, tx_bytes;
- s = per_cpu_ptr(ax_local->stats, cpu);
- do {
- start = u64_stats_fetch_begin_irq(&s->syncp);
- rx_packets = u64_stats_read(&s->rx_packets);
- rx_bytes = u64_stats_read(&s->rx_bytes);
- tx_packets = u64_stats_read(&s->tx_packets);
- tx_bytes = u64_stats_read(&s->tx_bytes);
- } while (u64_stats_fetch_retry_irq(&s->syncp, start));
- stats->rx_packets += rx_packets;
- stats->rx_bytes += rx_bytes;
- stats->tx_packets += tx_packets;
- stats->tx_bytes += tx_bytes;
- rx_dropped += s->rx_dropped;
- tx_dropped += s->tx_dropped;
- rx_frame_errors += s->rx_frame_errors;
- rx_crc_errors += s->rx_crc_errors;
- }
- stats->rx_dropped = rx_dropped;
- stats->tx_dropped = tx_dropped;
- stats->rx_frame_errors = rx_frame_errors;
- stats->rx_crc_errors = rx_crc_errors;
- }
- static void ax88796c_set_mac(struct ax88796c_device *ax_local)
- {
- u16 maccr;
- maccr = (ax_local->link) ? MACCR_RXEN : 0;
- switch (ax_local->speed) {
- case SPEED_100:
- maccr |= MACCR_SPEED_100;
- break;
- case SPEED_10:
- case SPEED_UNKNOWN:
- break;
- default:
- return;
- }
- switch (ax_local->duplex) {
- case DUPLEX_FULL:
- maccr |= MACCR_SPEED_100;
- break;
- case DUPLEX_HALF:
- case DUPLEX_UNKNOWN:
- break;
- default:
- return;
- }
- if (ax_local->flowctrl & AX_FC_ANEG &&
- ax_local->phydev->autoneg) {
- maccr |= ax_local->pause ? MACCR_RXFC_ENABLE : 0;
- maccr |= !ax_local->pause != !ax_local->asym_pause ?
- MACCR_TXFC_ENABLE : 0;
- } else {
- maccr |= (ax_local->flowctrl & AX_FC_RX) ? MACCR_RXFC_ENABLE : 0;
- maccr |= (ax_local->flowctrl & AX_FC_TX) ? MACCR_TXFC_ENABLE : 0;
- }
- mutex_lock(&ax_local->spi_lock);
- maccr |= AX_READ(&ax_local->ax_spi, P0_MACCR) &
- ~(MACCR_DUPLEX_FULL | MACCR_SPEED_100 |
- MACCR_TXFC_ENABLE | MACCR_RXFC_ENABLE);
- AX_WRITE(&ax_local->ax_spi, maccr, P0_MACCR);
- mutex_unlock(&ax_local->spi_lock);
- }
- static void ax88796c_handle_link_change(struct net_device *ndev)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- struct phy_device *phydev = ndev->phydev;
- bool update = false;
- if (phydev->link && (ax_local->speed != phydev->speed ||
- ax_local->duplex != phydev->duplex ||
- ax_local->pause != phydev->pause ||
- ax_local->asym_pause != phydev->asym_pause)) {
- ax_local->speed = phydev->speed;
- ax_local->duplex = phydev->duplex;
- ax_local->pause = phydev->pause;
- ax_local->asym_pause = phydev->asym_pause;
- update = true;
- }
- if (phydev->link != ax_local->link) {
- if (!phydev->link) {
- ax_local->speed = SPEED_UNKNOWN;
- ax_local->duplex = DUPLEX_UNKNOWN;
- }
- ax_local->link = phydev->link;
- update = true;
- }
- if (update)
- ax88796c_set_mac(ax_local);
- if (net_ratelimit())
- phy_print_status(ndev->phydev);
- }
- static void ax88796c_set_csums(struct ax88796c_device *ax_local)
- {
- struct net_device *ndev = ax_local->ndev;
- lockdep_assert_held(&ax_local->spi_lock);
- if (ndev->features & NETIF_F_RXCSUM) {
- AX_WRITE(&ax_local->ax_spi, COERCR0_DEFAULT, P4_COERCR0);
- AX_WRITE(&ax_local->ax_spi, COERCR1_DEFAULT, P4_COERCR1);
- } else {
- AX_WRITE(&ax_local->ax_spi, 0, P4_COERCR0);
- AX_WRITE(&ax_local->ax_spi, 0, P4_COERCR1);
- }
- if (ndev->features & NETIF_F_HW_CSUM) {
- AX_WRITE(&ax_local->ax_spi, COETCR0_DEFAULT, P4_COETCR0);
- AX_WRITE(&ax_local->ax_spi, COETCR1_TXPPPE, P4_COETCR1);
- } else {
- AX_WRITE(&ax_local->ax_spi, 0, P4_COETCR0);
- AX_WRITE(&ax_local->ax_spi, 0, P4_COETCR1);
- }
- }
- static int
- ax88796c_open(struct net_device *ndev)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- unsigned long irq_flag = 0;
- int fc = AX_FC_NONE;
- int ret;
- u16 t;
- ret = request_irq(ndev->irq, ax88796c_interrupt,
- irq_flag, ndev->name, ndev);
- if (ret) {
- netdev_err(ndev, "unable to get IRQ %d (errno=%d).\n",
- ndev->irq, ret);
- return ret;
- }
- mutex_lock(&ax_local->spi_lock);
- ret = ax88796c_soft_reset(ax_local);
- if (ret < 0) {
- free_irq(ndev->irq, ndev);
- mutex_unlock(&ax_local->spi_lock);
- return ret;
- }
- ax_local->seq_num = 0x1f;
- ax88796c_set_mac_addr(ndev);
- ax88796c_set_csums(ax_local);
- /* Disable stuffing packet */
- t = AX_READ(&ax_local->ax_spi, P1_RXBSPCR);
- t &= ~RXBSPCR_STUF_ENABLE;
- AX_WRITE(&ax_local->ax_spi, t, P1_RXBSPCR);
- /* Enable RX packet process */
- AX_WRITE(&ax_local->ax_spi, RPPER_RXEN, P1_RPPER);
- t = AX_READ(&ax_local->ax_spi, P0_FER);
- t |= FER_RXEN | FER_TXEN | FER_BSWAP | FER_IRQ_PULL;
- AX_WRITE(&ax_local->ax_spi, t, P0_FER);
- /* Setup LED mode */
- AX_WRITE(&ax_local->ax_spi,
- (LCR_LED0_EN | LCR_LED0_DUPLEX | LCR_LED1_EN |
- LCR_LED1_100MODE), P2_LCR0);
- AX_WRITE(&ax_local->ax_spi,
- (AX_READ(&ax_local->ax_spi, P2_LCR1) & LCR_LED2_MASK) |
- LCR_LED2_EN | LCR_LED2_LINK, P2_LCR1);
- /* Disable PHY auto-polling */
- AX_WRITE(&ax_local->ax_spi, PCR_PHYID(AX88796C_PHY_ID), P2_PCR);
- /* Enable MAC interrupts */
- AX_WRITE(&ax_local->ax_spi, IMR_DEFAULT, P0_IMR);
- mutex_unlock(&ax_local->spi_lock);
- /* Setup flow-control configuration */
- phy_support_asym_pause(ax_local->phydev);
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
- ax_local->phydev->advertising) ||
- linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
- ax_local->phydev->advertising))
- fc |= AX_FC_ANEG;
- fc |= linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
- ax_local->phydev->advertising) ? AX_FC_RX : 0;
- fc |= (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
- ax_local->phydev->advertising) !=
- linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
- ax_local->phydev->advertising)) ? AX_FC_TX : 0;
- ax_local->flowctrl = fc;
- phy_start(ax_local->ndev->phydev);
- netif_start_queue(ndev);
- spi_message_init(&ax_local->ax_spi.rx_msg);
- return 0;
- }
- static int
- ax88796c_close(struct net_device *ndev)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- phy_stop(ndev->phydev);
- /* We lock the mutex early not only to protect the device
- * against concurrent access, but also avoid waking up the
- * queue in ax88796c_work(). phy_stop() needs to be called
- * before because it locks the mutex to access SPI.
- */
- mutex_lock(&ax_local->spi_lock);
- netif_stop_queue(ndev);
- /* No more work can be scheduled now. Make any pending work,
- * including one already waiting for the mutex to be unlocked,
- * NOP.
- */
- netif_dbg(ax_local, ifdown, ndev, "clearing bits\n");
- clear_bit(EVENT_SET_MULTI, &ax_local->flags);
- clear_bit(EVENT_INTR, &ax_local->flags);
- clear_bit(EVENT_TX, &ax_local->flags);
- /* Disable MAC interrupts */
- AX_WRITE(&ax_local->ax_spi, IMR_MASKALL, P0_IMR);
- __skb_queue_purge(&ax_local->tx_wait_q);
- ax88796c_soft_reset(ax_local);
- mutex_unlock(&ax_local->spi_lock);
- cancel_work_sync(&ax_local->ax_work);
- free_irq(ndev->irq, ndev);
- return 0;
- }
- static int
- ax88796c_set_features(struct net_device *ndev, netdev_features_t features)
- {
- struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
- netdev_features_t changed = features ^ ndev->features;
- if (!(changed & (NETIF_F_RXCSUM | NETIF_F_HW_CSUM)))
- return 0;
- ndev->features = features;
- if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_CSUM))
- ax88796c_set_csums(ax_local);
- return 0;
- }
- static const struct net_device_ops ax88796c_netdev_ops = {
- .ndo_open = ax88796c_open,
- .ndo_stop = ax88796c_close,
- .ndo_start_xmit = ax88796c_start_xmit,
- .ndo_get_stats64 = ax88796c_get_stats64,
- .ndo_eth_ioctl = ax88796c_ioctl,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_set_features = ax88796c_set_features,
- };
- static int ax88796c_hard_reset(struct ax88796c_device *ax_local)
- {
- struct device *dev = (struct device *)&ax_local->spi->dev;
- struct gpio_desc *reset_gpio;
- /* reset info */
- reset_gpio = gpiod_get(dev, "reset", 0);
- if (IS_ERR(reset_gpio)) {
- dev_err(dev, "Could not get 'reset' GPIO: %ld", PTR_ERR(reset_gpio));
- return PTR_ERR(reset_gpio);
- }
- /* set reset */
- gpiod_direction_output(reset_gpio, 1);
- msleep(100);
- gpiod_direction_output(reset_gpio, 0);
- gpiod_put(reset_gpio);
- msleep(20);
- return 0;
- }
- static int ax88796c_probe(struct spi_device *spi)
- {
- char phy_id[MII_BUS_ID_SIZE + 3];
- struct ax88796c_device *ax_local;
- struct net_device *ndev;
- u16 temp;
- int ret;
- ndev = devm_alloc_etherdev(&spi->dev, sizeof(*ax_local));
- if (!ndev)
- return -ENOMEM;
- SET_NETDEV_DEV(ndev, &spi->dev);
- ax_local = to_ax88796c_device(ndev);
- dev_set_drvdata(&spi->dev, ax_local);
- ax_local->spi = spi;
- ax_local->ax_spi.spi = spi;
- ax_local->stats =
- devm_netdev_alloc_pcpu_stats(&spi->dev,
- struct ax88796c_pcpu_stats);
- if (!ax_local->stats)
- return -ENOMEM;
- ax_local->ndev = ndev;
- ax_local->priv_flags |= comp ? AX_CAP_COMP : 0;
- ax_local->msg_enable = msg_enable;
- mutex_init(&ax_local->spi_lock);
- ax_local->mdiobus = devm_mdiobus_alloc(&spi->dev);
- if (!ax_local->mdiobus)
- return -ENOMEM;
- ax_local->mdiobus->priv = ax_local;
- ax_local->mdiobus->read = ax88796c_mdio_read;
- ax_local->mdiobus->write = ax88796c_mdio_write;
- ax_local->mdiobus->name = "ax88976c-mdiobus";
- ax_local->mdiobus->phy_mask = (u32)~BIT(AX88796C_PHY_ID);
- ax_local->mdiobus->parent = &spi->dev;
- snprintf(ax_local->mdiobus->id, MII_BUS_ID_SIZE,
- "ax88796c-%s.%u", dev_name(&spi->dev), spi->chip_select);
- ret = devm_mdiobus_register(&spi->dev, ax_local->mdiobus);
- if (ret < 0) {
- dev_err(&spi->dev, "Could not register MDIO bus\n");
- return ret;
- }
- if (netif_msg_probe(ax_local)) {
- dev_info(&spi->dev, "AX88796C-SPI Configuration:\n");
- dev_info(&spi->dev, " Compression : %s\n",
- ax_local->priv_flags & AX_CAP_COMP ? "ON" : "OFF");
- }
- ndev->irq = spi->irq;
- ndev->netdev_ops = &ax88796c_netdev_ops;
- ndev->ethtool_ops = &ax88796c_ethtool_ops;
- ndev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
- ndev->features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
- ndev->needed_headroom = TX_OVERHEAD;
- ndev->needed_tailroom = TX_EOP_SIZE;
- mutex_lock(&ax_local->spi_lock);
- /* ax88796c gpio reset */
- ax88796c_hard_reset(ax_local);
- /* Reset AX88796C */
- ret = ax88796c_soft_reset(ax_local);
- if (ret < 0) {
- ret = -ENODEV;
- mutex_unlock(&ax_local->spi_lock);
- goto err;
- }
- /* Check board revision */
- temp = AX_READ(&ax_local->ax_spi, P2_CRIR);
- if ((temp & 0xF) != 0x0) {
- dev_err(&spi->dev, "spi read failed: %d\n", temp);
- ret = -ENODEV;
- mutex_unlock(&ax_local->spi_lock);
- goto err;
- }
- /*Reload EEPROM*/
- ax88796c_reload_eeprom(ax_local);
- ax88796c_load_mac_addr(ndev);
- if (netif_msg_probe(ax_local))
- dev_info(&spi->dev,
- "irq %d, MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
- ndev->irq,
- ndev->dev_addr[0], ndev->dev_addr[1],
- ndev->dev_addr[2], ndev->dev_addr[3],
- ndev->dev_addr[4], ndev->dev_addr[5]);
- /* Disable power saving */
- AX_WRITE(&ax_local->ax_spi, (AX_READ(&ax_local->ax_spi, P0_PSCR)
- & PSCR_PS_MASK) | PSCR_PS_D0, P0_PSCR);
- mutex_unlock(&ax_local->spi_lock);
- INIT_WORK(&ax_local->ax_work, ax88796c_work);
- skb_queue_head_init(&ax_local->tx_wait_q);
- snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
- ax_local->mdiobus->id, AX88796C_PHY_ID);
- ax_local->phydev = phy_connect(ax_local->ndev, phy_id,
- ax88796c_handle_link_change,
- PHY_INTERFACE_MODE_MII);
- if (IS_ERR(ax_local->phydev)) {
- ret = PTR_ERR(ax_local->phydev);
- goto err;
- }
- ax_local->phydev->irq = PHY_POLL;
- ret = devm_register_netdev(&spi->dev, ndev);
- if (ret) {
- dev_err(&spi->dev, "failed to register a network device\n");
- goto err_phy_dis;
- }
- netif_info(ax_local, probe, ndev, "%s %s registered\n",
- dev_driver_string(&spi->dev),
- dev_name(&spi->dev));
- phy_attached_info(ax_local->phydev);
- return 0;
- err_phy_dis:
- phy_disconnect(ax_local->phydev);
- err:
- return ret;
- }
- static void ax88796c_remove(struct spi_device *spi)
- {
- struct ax88796c_device *ax_local = dev_get_drvdata(&spi->dev);
- struct net_device *ndev = ax_local->ndev;
- phy_disconnect(ndev->phydev);
- netif_info(ax_local, probe, ndev, "removing network device %s %s\n",
- dev_driver_string(&spi->dev),
- dev_name(&spi->dev));
- }
- #ifdef CONFIG_OF
- static const struct of_device_id ax88796c_dt_ids[] = {
- { .compatible = "asix,ax88796c" },
- {},
- };
- MODULE_DEVICE_TABLE(of, ax88796c_dt_ids);
- #endif
- static const struct spi_device_id asix_id[] = {
- { "ax88796c", 0 },
- { }
- };
- MODULE_DEVICE_TABLE(spi, asix_id);
- static struct spi_driver ax88796c_spi_driver = {
- .driver = {
- .name = DRV_NAME,
- .of_match_table = of_match_ptr(ax88796c_dt_ids),
- },
- .probe = ax88796c_probe,
- .remove = ax88796c_remove,
- .id_table = asix_id,
- };
- static __init int ax88796c_spi_init(void)
- {
- int ret;
- bitmap_zero(ax88796c_no_regs_mask, AX88796C_REGDUMP_LEN);
- ret = bitmap_parse(no_regs_list, 35,
- ax88796c_no_regs_mask, AX88796C_REGDUMP_LEN);
- if (ret) {
- bitmap_fill(ax88796c_no_regs_mask, AX88796C_REGDUMP_LEN);
- pr_err("Invalid bitmap description, masking all registers\n");
- }
- return spi_register_driver(&ax88796c_spi_driver);
- }
- static __exit void ax88796c_spi_exit(void)
- {
- spi_unregister_driver(&ax88796c_spi_driver);
- }
- module_init(ax88796c_spi_init);
- module_exit(ax88796c_spi_exit);
- MODULE_AUTHOR("Łukasz Stelmach <[email protected]>");
- MODULE_DESCRIPTION("ASIX AX88796C SPI Ethernet driver");
- MODULE_LICENSE("GPL");
|