`
wodamazi
  • 浏览: 1417539 次
文章分类
社区版块
存档分类
最新评论

Linux2.6.39下dm9k驱动源码分析(二)

阅读更多

2.3、网卡打开操作

问题:open函数在什么时候调用?

答:网卡打开的时候,命令#ifconfig eth0 up,此时网卡被打开,在网卡open函数中应该完成以下操作:

注册中断;设置寄存器,启动设备;启动发送队列,初始化dm9000,复位芯片,检查MII接口。
static int dm9000_open(struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

if (netif_msg_ifup(db))
dev_dbg(db->dev, "enabling %s\n", dev->name);

/* If there is no IRQ type specified, default to something that
* may work, and tell the user that this is a problem */

if (irqflags == IRQF_TRIGGER_NONE)
dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
//注册中断
irqflags |= IRQF_SHARED;

if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
return -EAGAIN;

/* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
mdelay(1); /* delay needs by DM9000B */

/* Initialize DM9000 board */
dm9000_reset(db);//复位芯片
dm9000_init_dm9000(dev);//初始化dm9K,初始化芯片的寄存器

/* Init driver variable */
db->dbug_cnt = 0;

//检查MII接口
mii_check_media(&db->mii, netif_msg_link(db), 1);
/**开启网络接口发送数据队列*/
netif_start_queue(dev);
/*之前在probe函数中已经使用 INIT_DELAYED_WORK来初始化一个延迟工作队列并关联了一个操作函数dm9000_poll_work(), 此时运行schedule来调用这个函数*/
dm9000_schedule_poll(db);

return 0;
}

/* dm9k复位操作往network ctl 控制寄存器写数据*/

static void dm9000_reset(board_info_t * db)
{
dev_dbg(db->dev, "resetting device\n");

/* RESET device */
//写地址 00h
writeb(DM9000_NCR, db->io_addr);
udelay(200);
//写1
writeb(NCR_RST, db->io_data);
udelay(200);
}

/*
*初始化dm9k硬件信息
*/
static void dm9000_init_dm9000(struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
unsigned int imr;
unsigned int ncr;

dm9000_dbg(db, 1, "entering %s\n", __func__);

/* I/O mode */
//读中断状态寄存器
db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */

/* Checksum mode */
dm9000_set_rx_csum_unlocked(dev, db->rx_csum);//校验模式

iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */

ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;

/* if wol is needed, then always set NCR_WAKEEN otherwise we end
* up dumping the wake events if we disable this. There is already
* a wake-mask in DM9000_WCR */
if (db->wake_supported)
ncr |= NCR_WAKEEN;

iow(db, DM9000_NCR, ncr);

/* Program operating register */
iow(db, DM9000_TCR, 0); /* TX Polling clear */
iow(db, DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */
iow(db, DM9000_FCR, 0xff); /* Flow Control */
iow(db, DM9000_SMCR, 0); /* Special Mode */
/* clear TX status */
iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */

/* Set address filter table */
dm9000_hash_table_unlocked(dev);

imr = IMR_PAR | IMR_PTM | IMR_PRM;
if (db->type != TYPE_DM9000E)
imr |= IMR_LNKCHNG;

db->imr_all = imr;

/* Enable TX/RX interrupt mask */
iow(db, DM9000_IMR, imr);

/* Init Driver variable */
db->tx_pkt_cnt = 0;
db->queue_pkt_len = 0;
dev->trans_start = jiffies;
}

2.4、数据发送

问题:数据发送函数在什么时候调用

答:当网卡有数据要发送的时候,该函数被调用

/*
* 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);//获取net_device私有数据

dm9000_dbg(db, 3, "%s:\n", __func__);

if (db->tx_pkt_cnt > 1)
return NETDEV_TX_BUSY;
//屏蔽自旋锁并将目前的的状态写入flags中
spin_lock_irqsave(&db->lock, flags);
// 将skb中的data部分写入DM9000的TX RAM,
/* 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;
}

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;
}
//配置TX长度
/* Set TX length to DM9000 */
iow(dm, DM9000_TXPLL, pkt_len);
iow(dm, DM9000_TXPLH, pkt_len >> 8);
//发送数据将TX控制寄存器的0位配置1
/* Issue TX polling command */
iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
}

2.4、中断处理函数

问题:网卡有几种类型的中断

答:网卡有三种中断:新报文到达中断,报文发送完成中断,出错中断,当数据包发送完后会出发该中断函数

static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
board_info_t *db = netdev_priv(dev);
int int_status;
unsigned long flags;
u8 reg_save;

dm9000_dbg(db, 3, "entering %s\n", __func__);

/* A real interrupt coming */

/* holders of db->lock must always block IRQs */
spin_lock_irqsave(&db->lock, flags);
//保存之前的IO地址
/* Save previous register address */
reg_save = readb(db->io_addr);
//关闭所有的中断
/* Disable all interrupts */
iow(db, DM9000_IMR, IMR_PAR);
//读取中断状态寄存器
/* Got DM9000 interrupt status */
int_status = ior(db, DM9000_ISR); /* Got ISR */
//清中断
iow(db, DM9000_ISR, int_status); /* Clear ISR status */

if (netif_msg_intr(db))
dev_dbg(db->dev, "interrupt status %02x\n", int_status);
//新报文达到中断
/* Received the coming packet */
if (int_status & ISR_PRS)
dm9000_rx(dev);
//报文发送完成中断
/* Trnasmit Interrupt check */
if (int_status & ISR_PTS)
dm9000_tx_done(dev, db);//包发送完

if (db->type != TYPE_DM9000E) {
if (int_status & ISR_LNKCHNG) {
/* fire a link-change request */
schedule_delayed_work(&db->phy_poll, 1);
}
}
//重新使能中断
/* Re-enable interrupt mask */
iow(db, DM9000_IMR, db->imr_all);
//恢复之前的IO地址
/* Restore previous register address */
writeb(reg_save, db->io_addr);

spin_unlock_irqrestore(&db->lock, flags);

return IRQ_HANDLED;
}

2.5、包接收

当网卡接收到数据时,产生中断,在中断处理函数中通过中断状态寄存器判断出是否接收中断,接着使用函数dm9000_rx处理接收到的数据

/*
* 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: %d\n", 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 %04x\n",
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:%x\n", 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 error\n");
dev->stats.rx_fifo_errors++;
}
if (rxhdr.RxStatus & RSR_CE) {
if (netif_msg_rx_err(db))
dev_dbg(db->dev, "crc error\n");
dev->stats.rx_crc_errors++;
}
if (rxhdr.RxStatus & RSR_RF) {
if (netif_msg_rx_err(db))
dev_dbg(db->dev, "length error\n");
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_checksum_none_assert(skb);
}
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);
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics