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

时间:2022-01-30 19:03:48
 

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()停止传输包,重启以太网模块,改变设备连接状态,停止时钟。