下面在重点分析几个dm9000收发包以及中断函数。
/*
* Hardware start transmission.
* Send a packet to media from the upper layer.
*/
static int
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned long flags;
board_info_t *db = netdev_priv(dev);
dm9000_dbg(db, 3, "%s:n", __func__);
if (db->tx_pkt_cnt > 1)
return NETDEV_TX_BUSY;
spin_lock_irqsave(&db->lock, flags);
/* Move data to DM9000 TX RAM */
writeb(DM9000_MWCMD, db->io_addr);
(db->outblk)(db->io_data, skb->data, skb->len);
dev->stats.tx_bytes += skb->len;
db->tx_pkt_cnt++;
/* TX control: First packet immediately send, second packet queue */
if (db->tx_pkt_cnt == 1) {
dm9000_send_packet(dev, skb->ip_summed, skb->len);
} else {
/* Second packet */
db->queue_pkt_len = skb->len;
db->queue_ip_summed = skb->ip_summed;
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&db->lock, flags);
/* free this SKB */
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
首先将数据包内容用writeb写入网卡的发送buffer。如果tx_pkt_cnt =1,那么调用dm9000_send_packet直接发送。如果tx_pkt_cnt = 2,那么就要通过netif_stop_queue通知上层停止发送。然后等待第一个包发送完毕,在中断函数中发送第二包。
static void dm9000_send_packet(struct net_device *dev,
int ip_summed,
u16 pkt_len)
{
board_info_t *dm = to_dm9000_board(dev);
/* The DM9000 is not smart enough to leave fragmented packets alone. */
if (dm->ip_summed != ip_summed) {
if (ip_summed == CHECKSUM_NONE)
iow(dm, DM9000_TCCR, 0);
else
iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
dm->ip_summed = ip_summed;
}
/* Set TX length to DM9000 */
iow(dm, DM9000_TXPLL, pkt_len);
iow(dm, DM9000_TXPLH, pkt_len >> 8);
/* Issue TX polling command */
iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
}
上面的代码主要是 CPU向dm9000传递了发送这个命令。通过看数据手册,我们知道,发送时是先向dm9000写入包的长度,然后操作TCR寄存器,dm9000就开始发包。
下面是dm9000发送完毕后,被中断函数调用的一个发送完毕后的处理函数
/*
* DM9000 interrupt handler
* receive the packet to upper layer, free the transmitted packet
*/
static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
{
int tx_status = ior(db, DM9000_NSR); /* Got TX status */
if (tx_status & (NSR_TX2END | NSR_TX1END)) {
/* One packet sent complete */
db->tx_pkt_cnt--;
dev->stats.tx_packets++;
if (netif_msg_tx_done(db))
dev_dbg(db->dev, "tx done, NSR %02xn", tx_status);
/* Queue packet check & send */
if (db->tx_pkt_cnt > 0)
dm9000_send_packet(dev, db->queue_ip_summed,
db->queue_pkt_len);
netif_wake_queue(dev);
}
}
这里我们可以看到如果db->tx_pkt_cnt > 0,那么dm9000就会继续发送网卡里面的另一个包。
下面是收包函数,这个rx函数是在interrupt函数中调用的,它不属于struct net_device_ops dm9000_netdev_ops中的成员。
/*
* Received a packet and pass to upper layer
*/
static void
dm9000_rx(struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
struct dm9000_rxhdr rxhdr;
struct sk_buff *skb;
u8 rxbyte, *rdptr;
bool GoodPacket;
int RxLen;
/* Check packet ready or not */
do {
ior(db, DM9000_MRCMDX); /* Dummy read */
/* Get most updated data */
rxbyte = readb(db->io_data);
/* Status check: this byte must be 0 or 1 */
if (rxbyte & DM9000_PKT_ERR) {
dev_warn(db->dev, "status check fail: %dn", rxbyte);
iow(db, DM9000_RCR, 0x00); /* Stop Device */
iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
return;
}
if (!(rxbyte & DM9000_PKT_RDY))
return;
/* A packet ready now & Get status/length */
GoodPacket = true;
writeb(DM9000_MRCMD, db->io_addr);
(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));
RxLen = le16_to_cpu(rxhdr.RxLen);
if (netif_msg_rx_status(db))
dev_dbg(db->dev, "RX: status %02x, length %04xn",
rxhdr.RxStatus, RxLen);
/* Packet Status check */
if (RxLen < 0x40) {
GoodPacket = false;
if (netif_msg_rx_err(db))
dev_dbg(db->dev, "RX: Bad Packet (runt)n");
}
if (RxLen > DM9000_PKT_MAX) {
dev_dbg(db->dev, "RST: RX Len:%xn", RxLen);
}
/* rxhdr.RxStatus is identical to RSR register. */
if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
RSR_PLE | RSR_RWTO |
RSR_LCS | RSR_RF)) {
GoodPacket = false;
if (rxhdr.RxStatus & RSR_FOE) {
if (netif_msg_rx_err(db))
dev_dbg(db->dev, "fifo errorn");
dev->stats.rx_fifo_errors++;
}
if (rxhdr.RxStatus & RSR_CE) {
if (netif_msg_rx_err(db))
dev_dbg(db->dev, "crc errorn");
dev->stats.rx_crc_errors++;
}
if (rxhdr.RxStatus & RSR_RF) {
if (netif_msg_rx_err(db))
dev_dbg(db->dev, "length errorn");
dev->stats.rx_length_errors++;
}
}
/* Move data from DM9000 */
if (GoodPacket
&& ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {
skb_reserve(skb, 2);
rdptr = (u8 *) skb_put(skb, RxLen - 4);
/* Read received packet from RX SRAM */
(db->inblk)(db->io_data, rdptr, RxLen);
dev->stats.rx_bytes += RxLen;
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb, dev);
if (db->rx_csum) {
if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;
}
netif_rx(skb);
dev->stats.rx_packets++;
} else {
/* need to dump the packet's data */
(db->dumpblk)(db->io_data, RxLen);
}
} while (rxbyte & DM9000_PKT_RDY);
}
收报时,数据包是分批从dm9000中读入的,先读入第一个byte,rxdata 看是否接收出错,然后在读入rxhdr,判断头部是否合格。这些都满足后,再读入完整的数据包。否则就调用dumpblk函数,让dm9000把错误的包丢弃。通过函数netif_rx 通知上层,对收到的包进行处理。在tx_done函数中,并不会直接通知上层发送完毕,只是调用了wakeup_queue函数,使上层可以继续发包。
网卡的学习和分析就到这里,
最后,网卡的carrier相关的部分,还有phy相关的部分,是我不明白的。。。希望以后有机会可以懂。
上一篇:mini2440裸机编程-----IIC—读写AT24C08
下一篇:s3c2440上MMC/SD卡驱动的分析(一)
推荐阅读最新更新时间:2024-11-13 19:17
设计资源 培训 开发板 精华推荐
- DER-879 - 10 W 隔离式反激电源,使用 LinkSwitch-TNZ 无损生成交流过零信号和 X 电容器放电
- LT5506 的典型应用 - 具有 VGA 的 40MHz 至 500MHz 正交解调器
- DC901A、LTC3444EDD 演示板、用于 CDMA/HSDPA 的微功率同步降压-升压转换器
- 使用 MaxLinear, Inc 的 SPX385AM1-1.2 的参考设计
- LT3973HMSE-5 2.5V 降压转换器的典型应用
- LTC3406ES5-1.5 微型 3.3V/600mA 降压稳压器的典型应用电路
- 【训练营】涂鸦智能物联网
- AM3G-0505SZ 5V 3 瓦 DC-DC 转换器的典型应用
- 一把带rgb的Alice键盘
- FEBFL77904-L82H08A-GEVB:8 W 交流 LED 驱动器