大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
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网络设备初始化,各个步骤:
具体实现代码如下:
/* 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账号...