linux网卡的fec功能,网络控制器驱动程序学习记录fec(1)

linux网卡的fec功能,网络控制器驱动程序学习记录fec(1)1,首先从模块加载函数module_init(fec_enet_module_init);staticint__initfec_enet_module_init(void){structnet_device*dev;inti,j,err;DECLARE_MAC_BUF(mac);printk(“FECENETVersion0.2\n”);for(i=0;(i<…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

35833eaa271097e3ebabfcf86da98039.png

1,首先从模块加载函数module_init(fec_enet_module_init);

static int __init fec_enet_module_init(void)

{

struct net_device *dev;

int i, j, err;

DECLARE_MAC_BUF(mac);

printk(“FEC ENET Version 0.2\n”);

for (i = 0; (i < FEC_MAX_PORTS); i++) {

dev = alloc_etherdev(sizeof(struct fec_enet_private));//申请一个网络设备其格式是fec_enet_private

if (!dev)

return -ENOMEM;

err = fec_enet_init(dev);

if (err) {

free_netdev(dev);

continue;

}

/

net_dev_array[i]=dev;

/

if (register_netdev(dev) != 0) {

/* XXX: missing cleanup here */

free_netdev(dev);

return -EIO;

}

printk(“%s: ethernet %s\n”,

dev->name, print_mac(mac, dev->dev_addr));

}

return 0;

}

2,关键结构体fec_enet_private定义了网络设备所用到的所有私有资源

struct fec_enet_private {

/* Hardware registers of the FEC device */

volatile fec_t*hwp;

struct net_device *netdev;

/* The saved address of a sent-in-place packet/buffer, for skfree(). */

unsigned char *tx_bounce[TX_RING_SIZE];

structsk_buff* tx_skbuff[TX_RING_SIZE];

ushortskb_cur;

ushortskb_dirty;

/* CPM dual port RAM relative addresses.

*/

cbd_t*rx_bd_base;/* Address of Rx and Tx buffers. */

cbd_t*tx_bd_base;

cbd_t*cur_rx, *cur_tx;/* The next free ring entry */

cbd_t*dirty_tx;/* The ring entries to be free()ed. */

uinttx_full;

spinlock_t lock;

uintphy_id;

uintphy_id_done;

uintphy_status;

uintphy_speed;

phy_info_t const*phy;

struct work_struct phy_task;

volatile fec_t*phy_hwp;

uintsequence_done;

uintmii_phy_task_queued;

uintphy_addr;

intindex;

intopened;

intlink;

intold_link;

intfull_duplex;

#ifdef CONFIG_M5445X

intspeed_10;

struct timer_list phy_timer;

unsigned long sTime;

unsigned long rxCount;

unsigned long bktCount;

unsigned long mTime;

unsigned long pktCount;

unsigned long bpkt_state;//for broadcast packet reject state machine

unsigned long bpkt_flag;//flag for reject broadcast packet

unsigned long pTime;

unsigned long bpkt_msk;

unsigned long tLimit;

unsigned long tCount;

unsigned long pkt_acount;//the all packet count in current slot

unsigned long bpkt_rcount;//the boradcast packet count in current slot

unsigned long bpkt_rlimit;//the broadcast packet receive limit

unsigned long pCount;//the total packet count

unsigned long bCount;//the total broadcast packet count

unsigned long flux_aCount;//byte count for all packet

unsigned long flux_aCount_st; //sticky of byte count for all packet

unsigned long flux_bCount;//byte count for broadcast packet

unsigned long flux_bCount_st; //sticky of byte count for broadcast packet

unsigned long flux_dCount[32];

unsigned long flux_rTime[32];

unsigned long flux_index;

unsigned long flux_wCount;

unsigned long aflux;//flux for total packet

unsigned long bflux;//flux for broadcast packet

#endif

};

//其中重要的是两个自旋锁,其中一个是发送用的,一个网络设备net_device,两个sk_buff指针一个发送一个接收,还有两个地址发送接收的buffer地址,一个计时器等等。。

socket缓冲描述结构体,包含控制状态信息以及数据长度,缓冲地址。

typedef struct bufdesc {

unsigned shortcbd_sc;/* Control and status info */

unsigned shortcbd_datlen;/* Data length */

unsigned longcbd_bufaddr;/* Buffer address */

} cbd_t;

Fec结构体定义了faste thernet control有用的寄存器具体看各成员列表:

typedef struct fec {

unsigned longfec_reserved0;

unsigned longfec_ievent;/* Interrupt event reg */

unsigned longfec_imask;/* Interrupt mask reg */

unsigned longfec_reserved1;

unsigned longfec_r_des_active;/* Receive descriptor reg */

unsigned longfec_x_des_active;/* Transmit descriptor reg */

unsigned longfec_reserved2[3];

unsigned longfec_ecntrl;/* Ethernet control reg */

unsigned longfec_reserved3[6];

unsigned longfec_mii_data;/* MII manage frame reg */

unsigned longfec_mii_speed;/* MII speed control reg */

unsigned longfec_reserved4[7];

unsigned longfec_mib_ctrlstat;/* MIB control/status reg */

unsigned longfec_reserved5[7];

unsigned longfec_r_cntrl;/* Receive control reg */

unsigned longfec_reserved6[15];

unsigned longfec_x_cntrl;/* Transmit Control reg */

unsigned longfec_reserved7[7];

unsigned longfec_addr_low;/* Low 32bits MAC address */

unsigned longfec_addr_high;/* High 16bits MAC address */

unsigned longfec_opd;/* Opcode + Pause duration */

unsigned longfec_reserved8[10];

unsigned longfec_hash_table_high;/* High 32bits hash table */

unsigned longfec_hash_table_low;/* Low 32bits hash table */

unsigned longfec_grp_hash_table_high;/* High 32bits hash table */

unsigned longfec_grp_hash_table_low;/* Low 32bits hash table */

unsigned longfec_reserved9[7];

unsigned longfec_x_wmrk;/* FIFO transmit water mark */

unsigned longfec_reserved10;

unsigned longfec_r_bound;/* FIFO receive bound reg */

unsigned longfec_r_fstart;/* FIFO receive start reg */

unsigned longfec_reserved11[11];

unsigned longfec_r_des_start;/* Receive descriptor ring */

unsigned longfec_x_des_start;/* Transmit descriptor ring */

unsigned longfec_r_buff_size;/* Maximum receive buff size */

unsigned longfec_reserved12[29]; //

unsigned longfec_mib_ram[64];//for fec mib message buffer

} fec_t;

3网络设备初始化,各个步骤:

1b56f206896decb9b1ef2e3a4340bcd7.png

具体实现代码如下:

/* Initialize the FEC Ethernet.

*/

/*

* XXX:We need to clean up on failure exits here.

*/

int __init fec_enet_init(struct net_device *dev)

{

struct fec_enet_private *fep = netdev_priv(dev);

unsigned longmem_addr;

volatile cbd_t*bdp;

cbd_t*cbd_base;

volatile fec_t*fecp;

int i, j;

static intindex = 0;

/* Only allow us to be probed once. */

if (index >= FEC_MAX_PORTS)

return -ENXIO;

/* Allocate memory for buffer descriptors.

*/

mem_addr = __get_free_page(GFP_DMA);//申请一个页内存,通过方式DMA

if (mem_addr == 0) {

printk(“FEC: allocate descriptor memory failed?\n”);

return -ENOMEM;

}

/* Create an Ethernet device instance.

*/

fecp = (volatile fec_t *) fec_hw[index];//FEC设备的基地址灰色为添加的便于观看,实际这里没有,这里看地址应该是0xfc034000 MCF_MBAR=0

/*

* Define the fixed address of the FEC hardware.

*/

static unsigned int fec_hw[] = {

#if defined(CONFIG_M5272)

(MCF_MBAR + 0x840),

#elif defined(CONFIG_M527x)

(MCF_MBAR + 0x1000),

(MCF_MBAR + 0x1800),

#elif defined(CONFIG_M523x) || defined(CONFIG_M528x)

(MCF_MBAR + 0x1000),

#elif defined(CONFIG_M520x)

(MCF_MBAR+0x30000),

#elif defined(CONFIG_M532x)

(MCF_MBAR+0xfc030000),

#elif defined(CONFIG_M5445X)

(MCF_MBAR+0xfc030000),

#if defined(CONFIG_FEC2)

(MCF_MBAR+0xfc034000),

#endif

fep->index = index;

fep->hwp = fecp;

fep->netdev = dev;

#ifdef CONFIG_FEC_SHARED_PHY

fep->phy_hwp = (volatile fec_t *) fec_hw[index & ~1];

#else

fep->phy_hwp = fecp;

#endif

/* Whack a reset.We should wait for this.

*/

fecp->fec_ecntrl = 1;//复位网络设备

udelay(10);

//

fecp->fec_mib_ctrlstat|=FEC_MIB_EN_MSK;clear mib counter

for(i=0;i<64;i++)

{

fecp->fec_mib_ram[i]=0;

}

/

/* Set the Ethernet address.If using multiple Enets on the 8xx,

* this needs some work to get unique addresses.

*

* This is our default MAC address unless the user changes

* it via eth_mac_addr (our dev->set_mac_addr handler).

*/

fec_get_mac(dev);

cbd_base = (cbd_t *)mem_addr;

/* XXX: missing check for allocation failure */

fec_uncache(mem_addr);

/* Set receive and transmit descriptor base.

*/

fep->rx_bd_base = cbd_base;

fep->tx_bd_base = cbd_base + RX_RING_SIZE;

fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;

fep->cur_rx = fep->rx_bd_base;

fep->skb_cur = fep->skb_dirty = 0;

/* Initialize the receive buffer descriptors.

*/

bdp = fep->rx_bd_base;

for (i=0; i

/* Allocate a page.

*/

mem_addr = __get_free_page(GFP_DMA);//再次申请内存

/* XXX: missing check for allocation failure */

fec_uncache(mem_addr);

/* Initialize the BD for every fragment in the page.

*/

for (j=0; j

bdp->cbd_sc = BD_ENET_RX_EMPTY;

bdp->cbd_bufaddr = __pa(mem_addr);//虚拟地址到物理地址的转换

mem_addr += FEC_ENET_RX_FRSIZE;

bdp++;

}

}

/* Set the last buffer to wrap.

*/

bdp–;

bdp->cbd_sc |= BD_SC_WRAP;

/* …and the same for transmmit.

*/

bdp = fep->tx_bd_base;

for (i=0, j=FEC_ENET_TX_FRPPG; i

if (j >= FEC_ENET_TX_FRPPG) {

mem_addr = __get_free_page(GFP_DMA);

j = 1;

} else {

mem_addr += FEC_ENET_TX_FRSIZE;

j++;

}

fep->tx_bounce[i] = (unsigned char *) mem_addr;

/* Initialize the BD for every fragment in the page.

*/

bdp->cbd_sc = 0;

bdp->cbd_bufaddr = 0;

bdp++;

}

/* Set the last buffer to wrap.

*/

bdp–;

bdp->cbd_sc |= BD_SC_WRAP;

/* Set receive and transmit descriptor base.

*/

fecp->fec_r_des_start = __pa((uint)(fep->rx_bd_base));

fecp->fec_x_des_start = __pa((uint)(fep->tx_bd_base));

/* Install our interrupt handlers. This varies depending on

* the architecture.

*/

fec_request_intrs(dev);//注册设备中断

fecp->fec_grp_hash_table_high = 0;

fecp->fec_grp_hash_table_low = 0;

fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;

fecp->fec_ecntrl = 2;

fecp->fec_r_des_active = 0;

#ifndef CONFIG_M5272

fecp->fec_hash_table_high = 0;

fecp->fec_hash_table_low = 0;

#endif//设置一些寄存器

dev->base_addr = (unsigned long)fecp;将寄存器地址赋值给网络设备基地址

/* The FEC Ethernet specific entries in the device structure. */

dev->open = fec_enet_open;

dev->hard_start_xmit = fec_enet_start_xmit;//该函数特殊,是上层协议调用的函数

dev->tx_timeout = fec_timeout;

dev->watchdog_timeo = TX_TIMEOUT;

dev->stop = fec_enet_close;

dev->set_multicast_list = set_multicast_list;

for (i=0; i

mii_cmds[i].mii_next = &mii_cmds[i+1];

mii_free = mii_cmds;

/* setup MII interface */

fec_set_mii(dev, fep);//设置为mii方式

/* Clear and enable interrupts */

fecp->fec_ievent = 0xffc00000;

fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |

FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);

/* Queue up command to detect the PHY and initialize the

* remainder of the interface.

*/

fep->phy_id_done = 0;

#ifndef CONFIG_FEC_SHARED_PHY

fep->phy_addr = 0;

#else

fep->phy_addr = fep->index;

#endif

mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy);

index++;

/

fecp->fec_mib_ctrlstat&=~FEC_MIB_EN_MSK;//enable fec mib counter,add by pjy on 2012-2-27

/***************************************************************************************************************/

return 0;

}

4申请中断函数实现

static void __inline__ fec_request_intrs(struct net_device *dev)

{

struct fec_enet_private *fep;

int b;

static const struct idesc {

char *name;

unsigned short irq;

} *idp, id[] = {

{ “fec(TXF)”, 36 },

{ “fec(TXB)”, 37 },

{ “fec(TXFIFO)”, 38 },

{ “fec(TXCR)”, 39 },

{ “fec(RXF)”, 40 },

{ “fec(RXB)”, 41 },

{ “fec(MII)”, 42 },

{ “fec(LC)”, 43 },

{ “fec(HBERR)”, 44 },

{ “fec(GRA)”, 45 },

{ “fec(EBERR)”, 46 },

{ “fec(BABT)”, 47 },

{ “fec(BABR)”, 48 },

{ NULL },

};//中断名及中断号

fep = netdev_priv(dev);

b = (fep->index) ? 77 : 64;

/* Setup interrupt handlers. */

for (idp = id; idp->name; idp++) {

if (request_irq(b+idp->irq,fec_enet_interrupt, IRQF_DISABLED,//申请中断,中断处理函数为fec_enet_interrupt

idp->name, dev) != 0)

printk(KERN_ERR “FEC: Could not alloc %s IRQ(%d)!\n”,

idp->name, b+idp->irq);

}

#if 1 //,we use MII

if (fep->index) {/* Configure FEC1 to MII */

MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC &

MCF_GPIO_PAR_FEC_FEC1_MASK) |MCF_GPIO_PAR_FEC_FEC1_MII;}

else {/* Configure FEC0 to MII */

MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC &

MCF_GPIO_PAR_FEC_FEC0_MASK) |MCF_GPIO_PAR_FEC_FEC0_MII;}

#else // we use MII

if (fep->index) {

/* Configure RMII */

MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC &

MCF_GPIO_PAR_FEC_FEC1_MASK) |

MCF_GPIO_PAR_FEC_FEC1_RMII_GPIO;

} else {

/* Configure RMII */

MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC &

MCF_GPIO_PAR_FEC_FEC0_MASK) |

MCF_GPIO_PAR_FEC_FEC0_RMII_GPIO;

}

#endif

/* Set up gpio outputs for MII lines on FEC0 */

MCF_GPIO_PAR_FECI2C |= (0 |

MCF_GPIO_PAR_FECI2C_MDIO0_MDIO0 |

MCF_GPIO_PAR_FECI2C_MDC0_MDC0);

}

中断处理函数实现:

static irqreturn_t

fec_enet_interrupt(int irq, void * dev_id)

{

structnet_device *dev = dev_id;

//structnet_device *pdev;

volatile fec_t*fecp;

uintint_events;

int handled = 0;

int i;

/

fecp = (volatile fec_t*)dev->base_addr;

/* Get the interrupt events that caused us to be here.

*/

//fecp->fec_imask &= ~FEC_ENET_RXF; //disable rx int

while ((int_events = fecp->fec_ievent) != 0) {

//fecp->fec_ievent = int_events;//

/* Handle receive event in its own function.

*/

if (int_events & FEC_ENET_RXF) {

handled = 1;

fec_enet_rx(dev);//接收处理

}

fecp->fec_ievent = int_events;//

//fecp->fec_imask |=FEC_ENET_RXF; //enable rx int

/* Transmit OK, or non-fatal error. Update the buffer

descriptors. FEC handles all errors, we just discover

them as part of the transmit process.

*/

if (int_events & FEC_ENET_TXF) {

handled = 1;

fec_enet_tx(dev);//发送处理

}

if (int_events & FEC_ENET_MII) {

handled = 1;

fec_enet_mii(dev);//mii处理

}

}

return IRQ_RETVAL(handled);

}

5上层接口函数含义:open stop等:

dev->open = fec_enet_open;//打开网络设备函数

dev->hard_start_xmit = fec_enet_start_xmit;//该函数特殊,是上层协议调用的函数

dev->tx_timeout = fec_timeout;发送超时函数处理

dev->watchdog_timeo = TX_TIMEOUT;超时时间设置

dev->stop = fec_enet_close;//关闭网络设备

dev->set_multicast_list = set_multicast_list;

6发送函数:

7接收函数:

待续。。。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/169615.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Decorator 单一职责模式[通俗易懂]

    Decorator 单一职责模式[通俗易懂]单一职责模式动机模式定义案例结构要点总结笔记动机在某些情况下我们可能会“过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多的子类的膨胀如何使“对象功能的扩展”能够根据需要来动态实现?同时避免”扩展功能的增多“带来的子类膨胀问题?从而使得任何任何”功能扩展变化“所导致的影响将为最低?模式定义动态(组合)地给一个对象增加一些额外的职责。就增加功能而言Decorator模式比生成子类

  • MQTT服务器搭建–Mosquitto[通俗易懂]

    MQTT服务器搭建–Mosquitto[通俗易懂]MQTT服务器搭建–Mosquitto1.Mosquitto简介MQTT(MQTelemetryTransport),消息队列遥测传输协议,轻量级的发布/订阅协议, 适用于一些条件比较苛刻的环境,进行低带宽、不可靠或间歇性的通信。目前已经是物联网消息通信事实上的标准协议了。值得一提的是mqtt提供三种不同质量的消息服务:l “至多一次”:消息发布完全依赖底层 TCP/IP 网络。

  • startService bindService 区别「建议收藏」

    startService bindService 区别「建议收藏」Android执行Service有两种方法,一种是startService,一种是bindService。下面让我们一起来聊一聊这两种执行Service方法的区别。 1、生命周期上的区别执行startService时,Service会经历onCreate-&gt;onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Se…

  • WinExec、ShellExecute和CreateProcess

    WinExec、ShellExecute和CreateProcess有三个API函数可以运行可执行文件WinExec、ShellExecute和CreateProcess。CreateProcess因为使用复杂,比较少用。    WinExec主要运行EXE文件。  ⑴ 函数原型: UINT Win Exec(LPCSTR lpCmdLine, UINT uCmdShow);   ⑵ 参数:   lpCmdLine:指向一个空结束的字符串,串中包含将要执行的应用程…

  • sql server之pivot函数「建议收藏」

    PIVOT用于将列值旋转为列名(即行转列)今天整理以前的笔记时,发现以前在PPD实习的时候遇到一个场景,感觉很实用所以想记录一下,说不定以后能用到,话不多说,直接上案例:–表table1问题编号时间节点listing_sizeTotalAmount1.120140-1k623.9001.12014…

  • windows CMD生成文件夹树状图(tree)命令(以图形显示驱动器或路径的文件夹结构)(tree命令、tree指令)(tree /f /a)「建议收藏」

    windows CMD生成文件夹树状图(tree)命令(以图形显示驱动器或路径的文件夹结构)(tree命令、tree指令)(tree /f /a)「建议收藏」如:也可以用相对路径:省略.\也可以:可以看到,上面只显示文件夹未能显示文件。我们继续看下面:(用加上后,显示效果明显好不少)能够将文件夹树状图生成到当前文件夹的tree.txt文件中:参考文章1:Windows中CMD命令之Tree生成目录参考文章2:treer:命令行生成目录结构的实用小工具……

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号