RK3288 GMAC整理

摘要:
网卡设备是通用数据结构,私有数据则为各个MAC控制器的数据结构。检测要添加的设备,检查HW能力并设置驱动程序的特性。2)收到数据产生中断,进入该函数进行数据接收和处理。GMAC根据寄存器配置,获取可用接收描述子,然后从RxFIFO中读取从PHY接收的Ethernet报文,如果报文符合接收条件,将该报文写入接收描述子指向的数据缓冲区,并回写接收描述子。

一、源文件

源码路径:drivers etethernet ockchipgmac

源码阅读顺序:

RK3288 GMAC整理第1张

二、重要探针函数stmmac_dvr_probe

1. alloc_etherdev

申请网卡设备和私有数据。

struct net_device *ndev = NULL;

struct stmmac_priv *priv;

ndev = alloc_etherdev(sizeof(struct stmmac_priv));

priv = netdev_priv(ndev);

网卡设备和私有数据紧紧的挨在一起:网卡设备+私用数据结构,通过netdev_priv获取私有数据。网卡设备是通用数据结构,私有数据则为各个MAC控制器的数据结构。

2. stmmac_hw_init

初始化MAC设备。检测要添加的设备(GMAC/MAC10-100),检查HW能力并设置驱动程序的特性。

3. netif_napi_add

初始化一个NAPI上下文,轮询接收数据包接口。

netif_napi_add(ndev, &priv->napi, stmmac_poll, 64);

stmmac_poll是轮询接口

该接口完成两个事情:

1)当数据发送完成时产生中断,进入该函数进行资源回收。

2)收到数据产生中断,进入该函数进行数据接收和处理。

static int stmmac_poll(struct napi_struct *napi, intbudget)
{
......
  stmmac_tx_clean(priv);  //传输完成后回收资源
  work_done = stmmac_rx(priv, budget); //数据包接收处理
  stmmac_enable_dma_irq(priv); //使能dma终端
......
}

stmmac_rx函数解析

作用:再次填充并使用skb预先分配的缓存,由NAPI轮询方法调用,可以获得环内所有帧。

函数:static int stmmac_rx(struct stmmac_priv *priv, int limit)

函数内定义:

1priv->hw->desc->get_rx_owner(p)

判断当前描述子的归属:描述子数据结构中OWN位,

0: 当前描述子应该由CPU操作,

1: 前描述子应该由GMAC操作。

对于接收,初始化dma描述子队列时设置为1

GMAC根据寄存器配置,获取可用接收描述子,然后从RxFIFO中读取从PHY接收的Ethernet报文,如果报文符合接收条件,将该报文写入接收描述子指向的数据缓冲区,并回写接收描述子。这个回写就会将OWN位设置为0

2)next_entry = (++priv->cur_rx) % rxsize;

获取下一帧描述符,

p_next =priv->dma_rx + next_entry;

priv->cur_rx:已经传递给协议层的index

3)status =(priv->hw->desc->rx_status(&priv->dev->stats, &priv->xstats,p));

获取收到帧状态,如果是丢弃帧,则什么都不处理;否则上传到上层网络。

4frame_len = priv->hw->desc->get_rx_frame_len(p, coe); 获取帧长度

5skb = priv->rx_skbuff[entry];

priv->rx_skbuff[entry] = NULL;

注意:skb将有上层网络处理完后进行释放。

6skb_put(skb, frame_len);

dma_unmap_single(priv->device,priv->rx_skbuff_dma[entry],priv->dma_buf_sz, DMA_FROM_DEVICE); 设置skb数据长度和解除流式DMA映射

7)获取skb的协议类型

skb->protocol = eth_type_trans(skb,priv->dev);

skb->dev = priv->dev;

8)napi_gro_receive(&priv->napi,skb);

skb通过NAPI接口上传上层网络协议处理。

9)stmmac_rx_refill(priv); 重新填充接收队列

三、打开网卡设备接口stmmac_open

网卡刚起来时是关闭的,要用命令去打开,ifconfig eth0 up 时调用net_device_ops.ndo_open,这里为stmmac_open

  1. netdev_priv 获得网络设备私有数据
  2. stmmac_check_ether_addr 检测MAC地址是否有效,若无效,随机产生一个
  3. stmmac_mdio_register注册MII总线

mdiobus_register()

a.注册总线设备device_register(&bus->dev);

b.复位总线bus->reset(bus);

c.扫描总线上的PHY设备,最大支持32

4. stmmac_init_phy初始化PHY设备,并将PHYMAC绑定

5. request_irq 申请中断

ret = request_irq(dev->irq,stmmac_interrupt,

IRQF_SHARED, dev->name, dev);

注册中断请求线IRQ,中断处理函数stmmac_interrupt用于接收DMA数据,配NAPI处理。

static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
{
  ......
  /*To handle DMA interrupts */stmmac_dma_interrupt(priv);  
}

static void stmmac_dma_interrupt(struct stmmac_priv *priv)
{
  ......
  status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
  if (likely((status & handle_rx)) || (status &handle_tx)) {
    if (likely(napi_schedule_prep(&priv->napi))) {
      stmmac_disable_dma_irq(priv);
      __napi_schedule(&priv->napi); //加入poll流程}
  }
  ......
}

四、发送数据接口stmmac_xmit

该接口实现了Scatter/Gather I/O功能,通过skb_shinfo宏来判断数据包是由一个数据片段组成,还是由大量数据片段组成。

1entry= priv->cur_tx % txsize;

desc= priv->dma_tx + entry; 获取可用发送描述子

first= desc; 保存第一个数据片段

2priv->tx_skbuff[entry]= skb;

priv->tx_page[entry]= NULL; skb放到发送队列

3unsignedint nopaged_len = skb_headlen(skb);

desc->des2=dma_map_single(priv->device,skb->data,nopaged_len, DMA_TO_DEVICE);

priv->hw->desc->prepare_tx_desc(desc,1, nopaged_len, csum_insertion);

发送单个或第一个数据包,当只有一个数据片段时,skb->data将发送所有数据;当有多个数据片段时,skb->data则指向第一个数据片段,数据长度skb->len skb->data_len,其他数据存放在共享数据结构frags数组中。(skb->len:数据包中全部数据的长度,skb->data_len分隔存储数据片段长度)

4

for (i = 0; i < nfrags; i++) {
  const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
  int len =skb_frag_size(frag);
  entry = (++priv->cur_tx) %txsize;
  if (priv->extend_desc)
    desc = (struct dma_desc *)(priv->dma_etx +entry);
  elsedesc = priv->dma_tx +entry;
  TX_DBG("[entry %d] segment len: %d
", entry, len);
  desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len, DMA_TO_DEVICE);
  priv->tx_skbuff_dma[entry] = desc->des2;
  priv->tx_skbuff[entry] =NULL;
  priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion,
  priv->mode);
  wmb();
  priv->hw->desc->set_tx_owner(desc);
  wmb();
}

发送剩余数据片段。

对于多个数据片段时,还要进行数据片段的发送,采用页处理。直接处理页结构,而不是内核虚拟地址。

5priv->hw->desc->set_tx_owner(first);

priv->cur_tx ++;

将第一个数据片段描述子交给GMAC,记录当前发送index

6priv->hw->dma->enable_dma_transmission(priv->dma_ioaddr,

priv->dma_channel);

写任何值唤醒处于挂起的RxDMA

免责声明:文章转载自《RK3288 GMAC整理》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SqlServer中的数据类型UniqueIdentifierQt多国语言QT_TR_NOOP和QT_TRANSLATE_NOOP下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

STM32CubeMx——串口使用DMA收发数据

用到的是DMA发送数据,DMA接收,在中断回调里发送出去。 一.代码生成 1.按以前的方法设置好时钟和调试方式,这里就不多说了。 2.设置串口1。 3.在DMASetting里点击Add添加USART1_TX,Mode有两种模式,一种是普通模式,使用一次发送语句就发一次,另一种是循环模式,使用一次发送会一直发送。这里发送我选择普通模式,接收选择循环模式...

RT Thread的SPI设备驱动框架的使用以及内部机制分析

注释:这是19年初的博客,写得很一般,理解不到位也不全面。19年末得空时又重新看了RTThread的SPI和GPIO,这次理解得比较深刻。有时间时再整理上传。 --------------------------------------------------------------------------------------------------...

双轴按键摇杆控制器控制TFTLCD(使用ADC1双通道DMA传输)

实验使用如下所示的双轴按键摇杆控制器,来控制TFTLCD上显示的直线。首先介绍一下双轴按键摇杆控制器。原理:十字摇杆为一个双向的10K电阻器,随着摇杆方向不同,抽头的阻值随着变化。本模块使用5V供电(在本实验中使用3.3V),原始状态下X,Y读出电压为2.5V左右(本实验为1.65V),当随箭头方向按下,读出电压值随着增加,最大到5V(本实验最大为3.3V...

记STM32F030多通道ADC DMA读取乱序问题

问题描述通过 uint16_t ConvData[8]保存DMA搬运的ADC转换数值,但是这个数组数值的顺序总是和ADC不是顺序对应的。比如用7个通道的ADC,当设置ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Backward,是对应顺序是:0->0,1->7,2->6...

scatter gather 使用

先来点概念: http://blog.csdn.net/fudan_abc/archive/2007/07/28/1713976.aspx 无聊的it玩家们创建了有一个词,叫做scatter/gather,她是一种用于高性能IO的标准技术.她通常意味着一种DMA传输方式,对于一个给定的数据块,她老人家可能在内存中存在于一些离散的缓冲区,换言之,就是说一些不...

STM32 ADC基础与多通道采样

12位ADC是一种逐次逼近型模拟数字数字转换器。它有多达18个通道,可测量16个外部和2个内部信号源。ADC的输入时钟不得超过14MHZ,它是由PCLK2经分频产生。如果被ADC转换的模拟电压低于低阀值或高于高阀值,AWD模拟看门狗状态位被设置。 ADC通常要与DMA一起使用 这里只是简单的用库配置ADC 不断扫描来实现ADC的应用。 配置DMA: voi...