l open方法
static int lpc32xx_net_open(struct net_device *ndev)
{
struct netdata_local *pldat = netdev_priv(ndev);
/* if the phy is not yet registered, retry later*/
if (!pldat->phy_dev)
{
return -EAGAIN;
}
if (netif_msg_ifup(pldat))
{
dev_dbg(&pldat->pdev->dev, "enabling %s\n", ndev->name);
}
if (!is_valid_ether_addr(ndev->dev_addr))
{
return -EADDRNOTAVAIL;
}
__lpc32xx_net_clock_enable(pldat, 1);
/* Reset and initialize */
__lpc32xx_eth_reset(pldat);
__lpc32xx_eth_init(pldat);
/* schedule a link state check */
phy_start(pldat->phy_dev);
// 更换PHY状态,启动PHY
netif_start_queue(ndev);
//激活发送队列
return 0;
}
总结:open中最重要的两个函数是__lpc32xx_eth_init()和netif_start()一个做数据处理前的准备工作,另一个激活发送队列
追踪__lpc32xx_eth_init
static void __lpc32xx_eth_init(struct netdata_local *pldat)
{
u32 tmp;
/* Disable controller and reset */
tmp = __raw_readl(ENET_COMMAND(pldat->net_base));
tmp &= ~COMMAND_RXENABLE | COMMAND_TXENABLE;
__raw_writel(tmp, ENET_COMMAND(pldat->net_base));
tmp = __raw_readl(ENET_MAC1(pldat->net_base));
tmp &= ~MAC1_RECV_ENABLE;
__raw_writel(tmp, ENET_MAC1(pldat->net_base));
/*在命令寄存器中禁能接收和发送,然后又在MAC1中禁止接收帧*/
/* Initial MAC setup */
__raw_writel(MAC1_PASS_ALL_RX_FRAMES, ENET_MAC1(pldat->net_base));
__raw_writel((MAC2_PAD_CRC_ENABLE | MAC2_CRC_ENABLE),
ENET_MAC2(pldat->net_base));
__raw_writel(ENET_MAXF_SIZE, ENET_MAXF(pldat->net_base));
/*在MAC初始化配置:传递所有帧,每帧上添加CRC,MAC填充所有短帧,最大帧长度为1536个字节*/
/* Collision window, gap */
__raw_writel((CLRT_LOAD_RETRY_MAX(0xF) |
CLRT_LOAD_COLLISION_WINDOW(0x37)), ENET_CLRT(pldat->net_base));
__raw_writel(IPGR_LOAD_PART2(0x12), ENET_IPGR(pldat->net_base));
/*冲突窗口/重试寄存器,冲突之后重复发送次数15次,冲突窗口(导言区和SFD)之后有56个字节窗口;非背对背的内部包间隔寄存器:包间隔为18*/
#if defined (MAC_LPC32XX_MII_SUPPORT)
__raw_writel(COMMAND_PASSRUNTFRAME, ENET_COMMAND(pldat->net_base));
//MII模式,小于64字节的短帧传递到寄存器
#else
__raw_writel((COMMAND_PASSRUNTFRAME | COMMAND_RMII),
ENET_COMMAND(pldat->net_base));
__raw_writel(SUPP_RESET_RMII, ENET_SUPP(pldat->net_base));
#endif
/*RMII模式,100Mbps模式*/
__lpc32xx_params_setup(pldat);
/* Setup TX and RX descriptors */
__lpc32xx_txrx_desc_setup(pldat);
//建立描述符,这是接收和发送过程的第一步
/* Setup packet filtering */
__raw_writel((RXFLTRW_ACCEPTUBROADCAST | RXFLTRW_ACCEPTPERFECT),
ENET_RXFILTER_CTRL(pldat->net_base));
/* Clear and enable interrupts */
__raw_writel(0xFFFF, ENET_INTCLEAR(pldat->net_base));
__raw_writel((MACINT_RXDONEINTEN | MACINT_TXDONEINTEN),
ENET_INTENABLE(pldat->net_base));
//设置过滤寄存器和使能中断
/* Get the next TX buffer output index */
pldat->num_used_tx_buffs = 0;
pldat->last_tx_idx =
__raw_readl(ENET_TXCONSUMEINDEX(pldat->net_base));
/* Enable controller */
tmp = __raw_readl(ENET_COMMAND(pldat->net_base));
tmp |= COMMAND_RXENABLE | COMMAND_TXENABLE;
__raw_writel(tmp, ENET_COMMAND(pldat->net_base));
tmp = __raw_readl(ENET_MAC1(pldat->net_base));
tmp |= MAC1_RECV_ENABLE;
__raw_writel(tmp, ENET_MAC1(pldat->net_base));
}
/*使能发送和接收通道。接收时还要使能MAC。这是接收和发送过程的第二步*/
总结:__lpc32xx_eth_init()函数完成了以太网模块工作方式的初始化:工作模式,速度,帧格式,建立描述符,使能接收和发送通道。这些都是接收数据前的准备工作。
追踪__lpc32xx_params_setup(pldat);
static void __lpc32xx_params_setup(struct netdata_local *pldat)
{
u32 tmp;
if (pldat->duplex == DUPLEX_FULL)
{
tmp = __raw_readl(ENET_MAC2(pldat->net_base));
tmp |= MAC2_FULL_DUPLEX;
__raw_writel(tmp, ENET_MAC2(pldat->net_base));
//配置为全双工模式
tmp = __raw_readl(ENET_COMMAND(pldat->net_base));
tmp |= COMMAND_FULLDUPLEX;
__raw_writel(tmp, ENET_COMMAND(pldat->net_base));
//全双工模式下操作
__raw_writel(IPGT_LOAD(0x15), ENET_IPGT(pldat->net_base));
//包结尾与包开始的时间间隔
}
else
{
tmp = __raw_readl(ENET_MAC2(pldat->net_base));
tmp &= ~MAC2_FULL_DUPLEX;
__raw_writel(tmp, ENET_MAC2(pldat->net_base));
tmp = __raw_readl(ENET_COMMAND(pldat->net_base));
tmp &= ~COMMAND_FULLDUPLEX;
__raw_writel(tmp, ENET_COMMAND(pldat->net_base));
__raw_writel(IPGT_LOAD(0x12), ENET_IPGT(pldat->net_base));
}
//或者设置成半双工模式
if (pldat->speed == SPEED_100)
{
__raw_writel(SUPP_SPEED, ENET_SUPP(pldat->net_base));
}
else
{
__raw_writel(0, ENET_SUPP(pldat->net_base));
}
}
//RMII的附加设置,设置速度为10Mbps或100Mbps
追踪__lpc32xx_txrx_desc_setup(pldat);
static void __lpc32xx_txrx_desc_setup(struct netdata_local *pldat)
{
u32 tbuff, *ptxstat;
int i;
struct txrx_desc_t *ptxrxdesc;
struct rx_status_t *prxstat;
// txrx_desc_t结构用来描述帧片断描述符的,rx_status_t结构用来描述描述符态的
tbuff = __ptr_align(pldat->dma_buff_base_v);
//16字节对齐tbuff
/* Setup TX descriptors, status, and buffers */
for (i = 0; i < ENET_TX_DESC; i++)
{
pldat->tx_desc_v [i] = tbuff;
tbuff += sizeof(struct txrx_desc_t);
}
for (i = 0; i < ENET_TX_DESC; i++)
{
pldat->tx_stat_v [i] = tbuff;
tbuff += sizeof(u32);
}
tbuff = __ptr_align(tbuff);
for (i = 0; i < ENET_TX_DESC; i++)
{
pldat->tx_buff_v [i] = tbuff;
tbuff += ENET_MAXF_SIZE;
}
/* Setup RX descriptors, status, and buffers */
for (i = 0; i < ENET_RX_DESC; i++)
{
pldat->rx_desc_v [i] = tbuff;
tbuff += sizeof(struct txrx_desc_t);
}
tbuff = __ptr_align(tbuff);
for (i = 0; i < ENET_RX_DESC; i++)
{
pldat->rx_stat_v [i] = tbuff;
tbuff += sizeof(struct rx_status_t);
}
tbuff = __ptr_align(tbuff);
for (i = 0; i < ENET_RX_DESC; i++)
{
pldat->rx_buff_v [i] = tbuff;
tbuff += ENET_MAXF_SIZE;
}
/*以上内容分别给发送和接收描述符,状态,相关数据区做了空间分配*/
/* Map the TX descriptors to the TX buffers in hardware */
for (i = 0; i < ENET_TX_DESC; i++)
{
ptxstat = (u32 *) pldat->tx_stat_v [i];
ptxrxdesc = (struct txrx_desc_t *) pldat->tx_desc_v [i];
ptxrxdesc->packet = __va_to_pa(pldat->tx_buff_v [i], pldat);
ptxrxdesc->control = 0;
*ptxstat = 0;
}
/* Map the RX descriptors to the RX buffers in hardware */
for (i = 0; i < ENET_RX_DESC; i++)
{
prxstat = (struct rx_status_t *) pldat->rx_stat_v [i];
ptxrxdesc = (struct txrx_desc_t *) pldat->rx_desc_v [i];
ptxrxdesc->packet = __va_to_pa(pldat->rx_buff_v [i], pldat);
ptxrxdesc->control = 0x80000000 | (ENET_MAXF_SIZE - 1);
prxstat->statusinfo = 0;
prxstat->statushashcrc = 0;
}
/* Setup base addresses in hardware to point to buffers and descriptors */
__raw_writel((ENET_TX_DESC - 1), ENET_TXDESCRIPTORNUMBER(pldat->net_base));
__raw_writel(__va_to_pa(pldat->tx_desc_v [0], pldat), ENET_TXDESCRIPTOR(pldat->net_base));
__raw_writel(__va_to_pa(pldat->tx_stat_v [0], pldat), ENET_TXSTATUS(pldat->net_base));
__raw_writel((ENET_RX_DESC - 1), ENET_RXDESCRIPTORNUMBER(pldat->net_base));
__raw_writel(__va_to_pa(pldat->rx_desc_v [0], pldat), ENET_RXDESCRIPTOR(pldat->net_base));
__raw_writel(__va_to_pa(pldat->rx_stat_v [0], pldat), ENET_RXSTATUS(pldat->net_base));
}
/*初始化了描述符和状态寄存器的数值,然后写入相应寄存器,packet指向的是一个物理地址*/
总结:正如函数的名字__lpc32xx_txrx_desc_setup,它的作用就是建立描述符,和相关状态初始化。
static int lpc32xx_net_close(struct net_device *ndev)
{
unsigned long flags;
struct netdata_local *pldat = netdev_priv(ndev);
if (netif_msg_ifdown(pldat))
{
dev_dbg(&pldat->pdev->dev, "shutting down %s\n", ndev->name);
}
netif_stop_queue(ndev);
if (pldat->phy_dev)
{
phy_stop(pldat->phy_dev);
}
spin_lock_irqsave(&pldat->lock, flags);
__lpc32xx_eth_reset(pldat);
netif_carrier_off(ndev);
__raw_writel(0, ENET_MAC1(pldat->net_base));
__raw_writel(0, ENET_MAC2(pldat->net_base));
spin_unlock_irqrestore(&pldat->lock, flags);
__lpc32xx_net_clock_enable(pldat, 0);
return 0;
}
和open方法相反,调用netif_stop_queue()停止传输包,重启以太网模块,改变设备连接状态,停止时钟。