Chinaunix首页 | 论坛 | 博客
  • 博客访问: 680023
  • 博文数量: 30
  • 博客积分: 10035
  • 博客等级: 上将
  • 技术积分: 1545
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-03 06:50
文章分类

全部博文(30)

文章存档

2012年(30)

我的朋友

分类:

2012-05-31 16:01:35

 

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];

         struct       sk_buff* tx_skbuff[TX_RING_SIZE];

         ushort      skb_cur;

         ushort      skb_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. */

         uint  tx_full;

         spinlock_t lock;

 

         uint  phy_id;

         uint  phy_id_done;

         uint  phy_status;

         uint  phy_speed;

         phy_info_t const      *phy;

         struct work_struct phy_task;

         volatile fec_t    *phy_hwp;

 

         uint  sequence_done;

         uint  mii_phy_task_queued;

 

         uint  phy_addr;

 

         int    index;

         int    opened;

         int    link;

         int    old_link;

         int    full_duplex;

#ifdef CONFIG_M5445X

         int    speed_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 short         cbd_sc;                       /* Control and status info */

         unsigned short         cbd_datlen;               /* Data length */

         unsigned long  cbd_bufaddr;            /* Buffer address */

} cbd_t;

 

 

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

typedef struct fec {

         unsigned long  fec_reserved0;

         unsigned long  fec_ievent;                /* Interrupt event reg */

         unsigned long  fec_imask;                 /* Interrupt mask reg */

         unsigned long  fec_reserved1;

         unsigned long  fec_r_des_active;    /* Receive descriptor reg */

         unsigned long  fec_x_des_active;   /* Transmit descriptor reg */

         unsigned long  fec_reserved2[3];

         unsigned long  fec_ecntrl;                 /* Ethernet control reg */

         unsigned long  fec_reserved3[6];

         unsigned long  fec_mii_data;           /* MII manage frame reg */

         unsigned long  fec_mii_speed;                  /* MII speed control reg */

         unsigned long  fec_reserved4[7];

         unsigned long  fec_mib_ctrlstat;     /* MIB control/status reg */

         unsigned long  fec_reserved5[7];

         unsigned long  fec_r_cntrl;               /* Receive control reg */

         unsigned long  fec_reserved6[15];

         unsigned long  fec_x_cntrl;               /* Transmit Control reg */

         unsigned long  fec_reserved7[7];

         unsigned long  fec_addr_low;          /* Low 32bits MAC address */

         unsigned long  fec_addr_high;                  /* High 16bits MAC address */

         unsigned long  fec_opd;            /* Opcode + Pause duration */

         unsigned long  fec_reserved8[10];

         unsigned long  fec_hash_table_high;      /* High 32bits hash table */

         unsigned long  fec_hash_table_low;       /* Low 32bits hash table */

         unsigned long  fec_grp_hash_table_high;/* High 32bits hash table */

         unsigned long  fec_grp_hash_table_low;        /* Low 32bits hash table */

         unsigned long  fec_reserved9[7];

         unsigned long  fec_x_wmrk;             /* FIFO transmit water mark */

         unsigned long  fec_reserved10;

         unsigned long  fec_r_bound;            /* FIFO receive bound reg */

         unsigned long  fec_r_fstart;             /* FIFO receive start reg */

         unsigned long  fec_reserved11[11];

         unsigned long  fec_r_des_start;      /* Receive descriptor ring */

         unsigned long  fec_x_des_start;     /* Transmit descriptor ring */

         unsigned long  fec_r_buff_size;       /* Maximum receive buff size */

   unsigned long  fec_reserved12[29]; //

   unsigned long  fec_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 long  mem_addr;

         volatile cbd_t   *bdp;

         cbd_t                 *cbd_base;

         volatile fec_t    *fecp;

         int            i, j;

         static int  index = 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)

{

         struct       net_device *dev = dev_id;

   //struct      net_device *pdev;

         volatile fec_t    *fecp;

         uint  int_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 接收函数:

 

待续。。。

阅读(566) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~