priv->spi_transfer_buf[0] = op | (addr & ADDR_MASK);
priv->spi_transfer_buf[1] = val;
ret = spi_write(priv->spi, priv->spi_transfer_buf, 2); if (ret && netif_msg_drv(priv))
dev_printk(KERN_DEBUG, dev, "%s() failed: ret = %d\n",
__func__, ret); return ret;
}
staticvoid enc28j60_soft_reset(struct enc28j60_net *priv)
{
spi_write_op(priv, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); /* Errata workaround #1, CLKRDY check is unreliable,
* delay at least 1 ms instead */
udelay(2000);
}
/* * select the current register bank if necessary
*/ staticvoid enc28j60_set_bank(struct enc28j60_net *priv, u8 addr)
{
u8 b = (addr & BANK_MASK) >> 5;
/* These registers (EIE, EIR, ESTAT, ECON2, ECON1) * are present in all banks, no need to switch bank.
*/ if (addr >= EIE && addr <= ECON1) return;
/* Clear or set each bank selection bit as needed */ if ((b & ECON1_BSEL0) != (priv->bank & ECON1_BSEL0)) { if (b & ECON1_BSEL0)
spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1,
ECON1_BSEL0); else
spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1,
ECON1_BSEL0);
} if ((b & ECON1_BSEL1) != (priv->bank & ECON1_BSEL1)) { if (b & ECON1_BSEL1)
spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1,
ECON1_BSEL1); else
spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1,
ECON1_BSEL1);
}
priv->bank = b;
}
/* * Register access routines through the SPI bus. * Every register access comes in two flavours: * - nolock_xxx: caller needs to invoke mutex_lock, usually to access * atomically more than one register * - locked_xxx: caller doesn't need to invoke mutex_lock, single access * * Some registers can be accessed through the bit field clear and * bit field set to avoid a read modify write cycle.
*/
/* * Register bit field Set
*/ staticvoid nolock_reg_bfset(struct enc28j60_net *priv, u8 addr, u8 mask)
{
enc28j60_set_bank(priv, addr);
spi_write_op(priv, ENC28J60_BIT_FIELD_SET, addr, mask);
}
mutex_lock(&priv->lock); /* Set the write pointer to start of transmit buffer area */
nolock_regw_write(priv, EWRPTL, TXSTART_INIT); #ifdef CONFIG_ENC28J60_WRITEVERIFY if (netif_msg_drv(priv)) {
u16 reg;
reg = nolock_regw_read(priv, EWRPTL); if (reg != TXSTART_INIT)
dev_printk(KERN_DEBUG, dev, "%s() ERWPT:0x%04x != 0x%04x\n",
__func__, reg, TXSTART_INIT);
} #endif /* Set the TXND pointer to correspond to the packet size given */
nolock_regw_write(priv, ETXNDL, TXSTART_INIT + len); /* write per-packet control byte */
spi_write_op(priv, ENC28J60_WRITE_BUF_MEM, 0, 0x00); if (netif_msg_hw(priv))
dev_printk(KERN_DEBUG, dev, "%s() after control byte ERWPT:0x%04x\n",
__func__, nolock_regw_read(priv, EWRPTL)); /* copy the packet into the transmit buffer */
spi_write_buf(priv, len, data); if (netif_msg_hw(priv))
dev_printk(KERN_DEBUG, dev, "%s() after write packet ERWPT:0x%04x, len=%d\n",
__func__, nolock_regw_read(priv, EWRPTL), len);
mutex_unlock(&priv->lock);
}
mutex_lock(&priv->lock); /* set the PHY register address */
nolock_regb_write(priv, MIREGADR, address); /* write the PHY data */
nolock_regw_write(priv, MIWRL, data); /* wait until the PHY write completes and return */
ret = wait_phy_ready(priv);
mutex_unlock(&priv->lock);
return ret;
}
/* * Program the hardware MAC address from dev->dev_addr.
*/ staticint enc28j60_set_hw_macaddr(struct net_device *ndev)
{ int ret; struct enc28j60_net *priv = netdev_priv(ndev); struct device *dev = &priv->spi->dev;
mutex_lock(&priv->lock); if (!priv->hw_enable) { if (netif_msg_drv(priv))
dev_info(dev, "%s: Setting MAC address to %pM\n",
ndev->name, ndev->dev_addr); /* NOTE: MAC address in ENC28J60 is byte-backward */
nolock_regb_write(priv, MAADR5, ndev->dev_addr[0]);
nolock_regb_write(priv, MAADR4, ndev->dev_addr[1]);
nolock_regb_write(priv, MAADR3, ndev->dev_addr[2]);
nolock_regb_write(priv, MAADR2, ndev->dev_addr[3]);
nolock_regb_write(priv, MAADR1, ndev->dev_addr[4]);
nolock_regb_write(priv, MAADR0, ndev->dev_addr[5]);
ret = 0;
} else { if (netif_msg_drv(priv))
dev_printk(KERN_DEBUG, dev, "%s() Hardware must be disabled to set Mac address\n",
__func__);
ret = -EBUSY;
}
mutex_unlock(&priv->lock); return ret;
}
/* * Store the new hardware address in dev->dev_addr, and update the MAC.
*/ staticint enc28j60_set_mac_address(struct net_device *dev, void *addr)
{ struct sockaddr *address = addr;
if (netif_running(dev)) return -EBUSY; if (!is_valid_ether_addr(address->sa_data)) return -EADDRNOTAVAIL;
/* * ERXRDPT need to be set always at odd addresses, refer to errata datasheet
*/ static u16 erxrdpt_workaround(u16 next_packet_ptr, u16 start, u16 end)
{
u16 erxrdpt;
if (start > 0x1FFF || end > 0x1FFF || start > end) { if (netif_msg_drv(priv))
dev_err(dev, "%s(%d, %d) TXFIFO bad parameters!\n",
__func__, start, end); return;
} /* set transmit buffer start + end */
nolock_regw_write(priv, ETXSTL, start);
nolock_regw_write(priv, ETXNDL, end);
}
/* * Low power mode shrinks power consumption about 100x, so we'd like * the chip to be in that mode whenever it's inactive. (However, we * can't stay in low power mode during suspend with WOL active.)
*/ staticvoid enc28j60_lowpower(struct enc28j60_net *priv, bool is_low)
{ struct device *dev = &priv->spi->dev;
if (netif_msg_drv(priv))
dev_dbg(dev, "%s power...\n", is_low ? "low" : "high");
staticint
enc28j60_setlink(struct net_device *ndev, u8 autoneg, u16 speed, u8 duplex)
{ struct enc28j60_net *priv = netdev_priv(ndev); int ret = 0;
if (!priv->hw_enable) { /* link is in low power mode now; duplex setting * will take effect on next enc28j60_hw_init().
*/ if (autoneg == AUTONEG_DISABLE && speed == SPEED_10)
priv->full_duplex = (duplex == DUPLEX_FULL); else { if (netif_msg_link(priv))
netdev_warn(ndev, "unsupported link setting\n");
ret = -EOPNOTSUPP;
}
} else { if (netif_msg_link(priv))
netdev_warn(ndev, "Warning: hw must be disabled to set link mode\n");
ret = -EBUSY;
} return ret;
}
/* * Read the Transmit Status Vector
*/ staticvoid enc28j60_read_tsv(struct enc28j60_net *priv, u8 tsv[TSV_SIZE])
{ struct device *dev = &priv->spi->dev; int endptr;
if (netif_msg_rx_status(priv))
enc28j60_dump_rsv(priv, __func__, next_packet, len, rxstat);
if (!RSV_GETBIT(rxstat, RSV_RXOK) || len > MAX_FRAMELEN) { if (netif_msg_rx_err(priv))
netdev_err(ndev, "Rx Error (%04x)\n", rxstat);
ndev->stats.rx_errors++; if (RSV_GETBIT(rxstat, RSV_CRCERROR))
ndev->stats.rx_crc_errors++; if (RSV_GETBIT(rxstat, RSV_LENCHECKERR))
ndev->stats.rx_frame_errors++; if (len > MAX_FRAMELEN)
ndev->stats.rx_over_errors++;
} else {
skb = netdev_alloc_skb(ndev, len + NET_IP_ALIGN); if (!skb) { if (netif_msg_rx_err(priv))
netdev_err(ndev, "out of memory for Rx'd frame\n");
ndev->stats.rx_dropped++;
} else {
skb_reserve(skb, NET_IP_ALIGN); /* copy the packet from the receive buffer */
enc28j60_mem_read(priv,
rx_packet_start(priv->next_pk_ptr),
len, skb_put(skb, len)); if (netif_msg_pktdata(priv))
dump_packet(__func__, skb->len, skb->data);
skb->protocol = eth_type_trans(skb, ndev); /* update statistics */
ndev->stats.rx_packets++;
ndev->stats.rx_bytes += len;
netif_rx(skb);
}
} /* * Move the RX read pointer to the start of the next * received packet. * This frees the memory we just read out.
*/
erxrdpt = erxrdpt_workaround(next_packet, RXSTART_INIT, RXEND_INIT); if (netif_msg_hw(priv))
dev_printk(KERN_DEBUG, dev, "%s() ERXRDPT:0x%04x\n",
__func__, erxrdpt);
mutex_lock(&priv->lock);
nolock_regw_write(priv, ERXRDPTL, erxrdpt); #ifdef CONFIG_ENC28J60_WRITEVERIFY if (netif_msg_drv(priv)) {
u16 reg;
reg = nolock_regw_read(priv, ERXRDPTL); if (reg != erxrdpt)
dev_printk(KERN_DEBUG, dev, "%s() ERXRDPT verify error (0x%04x - 0x%04x)\n",
__func__, reg, erxrdpt);
} #endif
priv->next_pk_ptr = next_packet; /* we are done with this packet, decrement the packet counter */
nolock_reg_bfset(priv, ECON2, ECON2_PKTDEC);
mutex_unlock(&priv->lock);
}
/* * Calculate free space in RxFIFO
*/ staticint enc28j60_get_free_rxfifo(struct enc28j60_net *priv)
{ struct net_device *ndev = priv->netdev; int epkcnt, erxst, erxnd, erxwr, erxrd; int free_space;
if (err)
ndev->stats.tx_errors++; else
ndev->stats.tx_packets++;
if (priv->tx_skb) { if (!err)
ndev->stats.tx_bytes += priv->tx_skb->len;
dev_kfree_skb(priv->tx_skb);
priv->tx_skb = NULL;
}
locked_reg_bfclr(priv, ECON1, ECON1_TXRTS);
netif_wake_queue(ndev);
}
/* * RX handler * Ignore PKTIF because is unreliable! (Look at the errata datasheet) * Check EPKTCNT is the suggested workaround. * We don't need to clear interrupt flag, automatically done when * enc28j60_hw_rx() decrements the packet counter. * Returns how many packet processed.
*/ staticint enc28j60_rx_interrupt(struct net_device *ndev)
{ struct enc28j60_net *priv = netdev_priv(ndev); int pk_counter, ret;
pk_counter = locked_regb_read(priv, EPKTCNT); if (pk_counter && netif_msg_intr(priv))
netdev_printk(KERN_DEBUG, ndev, "intRX, pk_cnt: %d\n",
pk_counter); if (pk_counter > priv->max_pk_counter) { /* update statistics */
priv->max_pk_counter = pk_counter; if (netif_msg_rx_status(priv) && priv->max_pk_counter > 1)
netdev_printk(KERN_DEBUG, ndev, "RX max_pk_cnt: %d\n",
priv->max_pk_counter);
}
ret = pk_counter; while (pk_counter-- > 0)
enc28j60_hw_rx(ndev);
/* * Hardware transmit function. * Fill the buffer memory and send the contents of the transmit buffer * onto the network
*/ staticvoid enc28j60_hw_tx(struct enc28j60_net *priv)
{ struct net_device *ndev = priv->netdev;
BUG_ON(!priv->tx_skb);
if (netif_msg_tx_queued(priv))
netdev_printk(KERN_DEBUG, ndev, "Tx Packet Len:%d\n",
priv->tx_skb->len);
if (netif_msg_pktdata(priv))
dump_packet(__func__,
priv->tx_skb->len, priv->tx_skb->data);
enc28j60_packet_write(priv, priv->tx_skb->len, priv->tx_skb->data);
#ifdef CONFIG_ENC28J60_WRITEVERIFY /* readback and verify written data */ if (netif_msg_drv(priv)) { struct device *dev = &priv->spi->dev; int test_len, k;
u8 test_buf[64]; /* limit the test to the first 64 bytes */ int okflag;
test_len = priv->tx_skb->len; if (test_len > sizeof(test_buf))
test_len = sizeof(test_buf);
/* + 1 to skip control byte */
enc28j60_mem_read(priv, TXSTART_INIT + 1, test_len, test_buf);
okflag = 1; for (k = 0; k < test_len; k++) { if (priv->tx_skb->data[k] != test_buf[k]) {
dev_printk(KERN_DEBUG, dev, "Error, %d location differ: 0x%02x-0x%02x\n",
k, priv->tx_skb->data[k], test_buf[k]);
okflag = 0;
}
} if (!okflag)
dev_printk(KERN_DEBUG, dev, "Tx write buffer, verify ERROR!\n");
} #endif /* set TX request flag */
locked_reg_bfset(priv, ECON1, ECON1_TXRTS);
}
/* If some error occurs while trying to transmit this * packet, you should return '1' from this function. * In such a case you _may not_ do anything to the * SKB, it is still owned by the network queueing * layer when an error is returned. This means you * may not modify any SKB fields, you may not free * the SKB, etc.
*/
netif_stop_queue(dev);
/* Remember the skb for deferred processing */
priv->tx_skb = skb;
schedule_work(&priv->tx_work);
if (netif_msg_timer(priv))
netdev_err(ndev, "tx timeout\n");
ndev->stats.tx_errors++; /* can't restart safely under softirq */
schedule_work(&priv->restart_work);
}
/* * Open/initialize the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. * * This routine should set everything up anew at each open, even * registers that "should" only need to be set once at boot, so that * there is non-reboot way to recover if something goes wrong.
*/ staticint enc28j60_net_open(struct net_device *dev)
{ struct enc28j60_net *priv = netdev_priv(dev);
if (!is_valid_ether_addr(dev->dev_addr)) { if (netif_msg_ifup(priv))
netdev_err(dev, "invalid MAC address %pM\n", dev->dev_addr); return -EADDRNOTAVAIL;
} /* Reset the hardware here (and take it out of low power mode) */
enc28j60_lowpower(priv, false);
enc28j60_hw_disable(priv); if (!enc28j60_hw_init(priv)) { if (netif_msg_ifup(priv))
netdev_err(dev, "hw_reset() failed\n"); return -EINVAL;
} /* Update the MAC address (in case user has changed it) */
enc28j60_set_hw_macaddr(dev); /* Enable interrupts */
enc28j60_hw_enable(priv); /* check link status */
enc28j60_check_link_status(dev); /* We are now ready to accept transmit requests from * the queueing layer of the networking.
*/
netif_start_queue(dev);
return 0;
}
/* The inverse routine to net_open(). */ staticint enc28j60_net_close(struct net_device *dev)
{ struct enc28j60_net *priv = netdev_priv(dev);
/* * Set or clear the multicast filter for this adapter * num_addrs == -1 Promiscuous mode, receive all packets * num_addrs == 0 Normal mode, filter out multicast packets * num_addrs > 0 Multicast mode, receive normal and MC packets
*/ staticvoid enc28j60_set_multicast_list(struct net_device *dev)
{ struct enc28j60_net *priv = netdev_priv(dev); int oldfilter = priv->rxfilter;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.