1. mii 的实现
初始化函数:fec_enet_init里初始化一个mii命令队列,mii_free指向空闲队列的头,mii_head和mii_tail在队列中加入第一项时初始化,指示待处理命令队列。mii_queue往队列中放入一个待处理命令,若列表为空,则直接改变mii寄存器的值。
fec_enet_mii处理mii中断,即在mii操作完成后执行回调函数func。
mk_mii_read(REG) 用于组装读PHY寄存器的命令;
mk_mii_write(REG)用于组装写PHY寄存器的命令;
1) 原型声明
typedef struct mii_list {
uint mii_regval;
void (*mii_func)(uint val, struct net_device *dev);
struct mii_list *mii_next;
} mii_list_t;
#define NMII 20
static mii_list_t mii_cmds[NMII];
static mii_list_t *mii_free;
static mii_list_t *mii_head;
static mii_list_t *mii_tail;
static int mii_queue(struct net_device *dev, int request,
void (*func)(uint, struct net_device *));
/* Make MII read/write commands for the FEC.
*/
#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))
#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | /
(VAL & 0xffff))
#define mk_mii_end 0
2) 相关函数
创建mii命令队列:
nt __init fec_enet_init(struct net_device *dev)
{
…
/*初始化一个空的mii命令列表*/
for (i=0; i<NMII-1; i++)
mii_cmds[i].mii_next = &mii_cmds[i+1];
/*mii_free指向可用节点*/
mii_free = mii_cmds;
...
}
mii中断:
fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
{
…
/*响应中断调用fec_enet_mii*/
if (int_events & FEC_ENET_MII)
fec_enet_mii(dev);
…
}
mii中断处理程序:
/* called from interrupt context */
static void
fec_enet_mii(struct net_device *dev)
{
struct fec_enet_private *fep;
volatile fec_t *ep;
mii_list_t *mip;
uint mii_reg;
fep = netdev_priv(dev);
spin_lock_irq(&fep->mii_lock);
ep = fep->hwp;
/* 指向fec映射地址 */
mii_reg = ep->fec_mii_data;
if ((mip = mii_head) == NULL) {
printk("MII and no head!/n");
goto unlock;
}
if (mip->mii_func != NULL)
(*(mip->mii_func))(mii_reg, dev);
/* 通过mii获得的数据供用户使用 */
mii_head = mip->mii_next;
mip->mii_next = mii_free;
mii_free = mip;
if ((mip = mii_head) != NULL)
ep->fec_mii_data = mip->mii_regval;
unlock:
spin_unlock_irq(&fep->mii_lock);
}
配置fec接口模式为mii
static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
{
u32 rate;
struct clk *clk;
volatile fec_t *fecp;
fecp = fep->hwp;
fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
fecp->fec_x_cntrl = 0x00;
/*
* Set MII speed to 2.5 MHz
*/
clk = clk_get(NULL, "fec_clk");
rate = clk_get_rate(clk);
clk_put(clk);
fep->phy_speed =
((((rate / 2 + 4999999) / 2500000) / 2) & 0x3F) << 1;
fecp->fec_mii_speed = fep->phy_speed;
fec_restart(dev, 0);
}