您的位置:首页 > 理论基础 > 计算机网络

linux网络设备应用与驱动编程学习4——模板与实例(B)——打开和释放方法

2011-09-27 10:31 991 查看
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()停止传输包,重启以太网模块,改变设备连接状态,停止时钟。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐