⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 athrs26_phy.c

📁 linux下atheros的ag7100驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
#endif    }    /*     * All PHYs have had adequate time to autonegotiate.     * Now initialize software status.     *     * It's possible that some ports may take a bit longer     * to autonegotiate; but we can't wait forever.  They'll     * get noticed by mv_phyCheckStatusChange during regular     * polling activities.     */    for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {        if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {            continue;        }        if (athrs26_phy_is_link_alive(phyUnit)) {            liveLinks++;            ATHR_IS_PHY_ALIVE(phyUnit) = TRUE;        } else {            ATHR_IS_PHY_ALIVE(phyUnit) = FALSE;        }        DRV_PRINT(DRV_DEBUG_PHYSETUP,            ("eth%d: Phy Specific Status=%4.4x\n",            ethUnit,             phy_reg_read(ATHR_PHYBASE(phyUnit),                         ATHR_PHYADDR(phyUnit),                         ATHR_PHY_SPEC_STATUS)));    }    return (liveLinks > 0);}/******************************************************************************** athrs26_phy_is_fdx - Determines whether the phy ports associated with the* specified device are FULL or HALF duplex.** RETURNS:*    1 --> FULL*    0 --> HALF*/intathrs26_phy_is_fdx(int ethUnit){    int       phyUnit;    uint32_t  phyBase;    uint32_t  phyAddr;    uint16_t  phyHwStatus;    int       ii = 200;    if (ethUnit == ENET_UNIT_LAN)        return TRUE;    for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {        if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {            continue;        }        if (athrs26_phy_is_link_alive(phyUnit)) {            phyBase = ATHR_PHYBASE(phyUnit);            phyAddr = ATHR_PHYADDR(phyUnit);            do {                phyHwStatus = ag7100_mii_read (phyBase, phyAddr,                                                ATHR_PHY_SPEC_STATUS);                mdelay(10);            } while((!(phyHwStatus & ATHR_STATUS_RESOVLED)) && --ii);                        if (phyHwStatus & ATHER_STATUS_FULL_DEPLEX)                return TRUE;        }    }    return FALSE;}/******************************************************************************** athrs26_phy_speed - Determines the speed of phy ports associated with the* specified device.** RETURNS:*               AG7100_PHY_SPEED_10T, AG7100_PHY_SPEED_100TX;*               AG7100_PHY_SPEED_1000T;*/intathrs26_phy_speed(int ethUnit){    int       phyUnit;    uint16_t  phyHwStatus;    uint32_t  phyBase;    uint32_t  phyAddr;    int       ii = 200;    if (ethUnit == ENET_UNIT_LAN)        return AG7100_PHY_SPEED_100TX;    for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {        if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {            continue;        }        if (athrs26_phy_is_link_alive(phyUnit)) {            phyBase = ATHR_PHYBASE(phyUnit);            phyAddr = ATHR_PHYADDR(phyUnit);            do {                phyHwStatus = ag7100_mii_read(phyBase, phyAddr,                                               ATHR_PHY_SPEC_STATUS);                mdelay(10);            }while((!(phyHwStatus & ATHR_STATUS_RESOVLED)) && --ii);                        phyHwStatus = ((phyHwStatus & ATHER_STATUS_LINK_MASK) >>                           ATHER_STATUS_LINK_SHIFT);            switch(phyHwStatus) {            case 0:                return AG7100_PHY_SPEED_10T;            case 1:                return AG7100_PHY_SPEED_100TX;            case 2:                return AG7100_PHY_SPEED_1000T;            default:                printk("Unkown speed read!\n");            }        }    }    return AG7100_PHY_SPEED_10T;}/******************************************************************************* athr_phy_is_up -- checks for significant changes in PHY state.** A "significant change" is:*     dropped link (e.g. ethernet cable unplugged) OR*     autonegotiation completed + link (e.g. ethernet cable plugged in)** When a PHY is plugged in, phyLinkGained is called.* When a PHY is unplugged, phyLinkLost is called.*/intathrs26_phy_is_up(int ethUnit){    int           phyUnit;    uint16_t      phyHwStatus, phyHwControl;    athrPhyInfo_t *lastStatus;    int           linkCount   = 0;    int           lostLinks   = 0;    int           gainedLinks = 0;    uint32_t      phyBase;    uint32_t      phyAddr;#ifdef HEADER_REG_CONF    /* if using header to config s26, the link of MAC0 should always be up */    if (ethUnit == ENET_UNIT_LAN)        return 1;#endif    for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {        if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {            continue;        }        phyBase = ATHR_PHYBASE(phyUnit);        phyAddr = ATHR_PHYADDR(phyUnit);        lastStatus = &athrPhyInfo[phyUnit];        if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */            phyHwStatus = phy_reg_read(phyBase, phyAddr, ATHR_PHY_SPEC_STATUS);            /* See if we've lost link */            if (phyHwStatus & ATHR_STATUS_LINK_PASS) {                linkCount++;            } else {                lostLinks++;                DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d down\n",                                               ethUnit, phyUnit));                lastStatus->isPhyAlive = FALSE;            }        } else { /* last known link status was DEAD */            /* Check for reset complete */            phyHwStatus = phy_reg_read(phyBase, phyAddr, ATHR_PHY_STATUS);            if (!ATHR_RESET_DONE(phyHwStatus))                continue;            phyHwControl = phy_reg_read(phyBase, phyAddr, ATHR_PHY_CONTROL);            /* Check for AutoNegotiation complete */                        if ((!(phyHwControl & ATHR_CTRL_AUTONEGOTIATION_ENABLE))                  || ATHR_AUTONEG_DONE(phyHwStatus)) {                phyHwStatus = phy_reg_read(phyBase, phyAddr,                                            ATHR_PHY_SPEC_STATUS);                if (phyHwStatus & ATHR_STATUS_LINK_PASS) {                gainedLinks++;                linkCount++;                DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d up\n",                                               ethUnit, phyUnit));                lastStatus->isPhyAlive = TRUE;                }            }        }    }    return (linkCount);#if 0    if (linkCount == 0) {        if (lostLinks) {            /* We just lost the last link for this MAC */            phyLinkLost(ethUnit);        }    } else {        if (gainedLinks == linkCount) {            /* We just gained our first link(s) for this MAC */            phyLinkGained(ethUnit);        }    }#endif}static intathrs26_header_config_reg (struct net_device *dev, uint8_t wr_flag,                            uint32_t reg_addr, uint16_t cmd_len,                           uint8_t *val) {    struct sk_buff *skb;    at_header_t at_header;    reg_cmd_t reg_cmd;	    /*allocate skb*/            skb = dev_alloc_skb(64);    if (!skb) {        printk("allocate skb fail\n");        return -1;    }    skb_put(skb, 60);             /*fill at_header*/    at_header.reserved0 = 0x10;  //default     at_header.priority = 0;    at_header.type = 0x5;    at_header.broadcast = 0;      at_header.from_cpu = 1;    at_header.reserved1 = 0x01; //default       at_header.port_num = 0;    skb->data[0] = at_header.port_num;    skb->data[0] |= at_header.reserved1 << 4;    skb->data[0] |= at_header.from_cpu << 6;    skb->data[0] |= at_header.broadcast << 7;        skb->data[1] = at_header.type;      skb->data[1] |= at_header.priority << 4;        skb->data[1] |= at_header.reserved0 << 6;              /*fill reg cmd*/    if(cmd_len > 4)         cmd_len = 4;//only support 32bits register r/w          reg_cmd.reg_addr = reg_addr&0x3FFFC;    reg_cmd.cmd_len = cmd_len;    reg_cmd.cmd = wr_flag;    reg_cmd.reserved2 = 0x5; //default    reg_cmd.seq_num = atomic_read(&seqcnt);       skb->data[2] = reg_cmd.reg_addr & 0xff;    skb->data[3] = (reg_cmd.reg_addr & 0xff00) >> 8;    skb->data[4] = (reg_cmd.reg_addr & 0x30000) >> 16;    skb->data[4] |= reg_cmd.cmd_len << 4;    skb->data[5] = reg_cmd.cmd << 4;    skb->data[5] |= reg_cmd.reserved2 << 5;    skb->data[6] = (reg_cmd.seq_num & 0x7f) << 1;    skb->data[7] = (reg_cmd.seq_num & 0x7f80) >> 7;    skb->data[8] = (reg_cmd.seq_num & 0x7f8000) >> 15;    skb->data[9] = (reg_cmd.seq_num & 0x7f800000) >> 23;	    if(!wr_flag)//write        memcpy(skb->data + 10, val, cmd_len);        skb->dev = dev;    /* add identify for header */    skb->cb[0] = 0x7f;    skb->cb[1] = 0x5d;        /*start xmit*/            header_xmit(skb, dev);    return 0;}intathrs26_header_write_reg(uint32_t reg_addr, uint16_t cmd_len, uint8_t *reg_data){    long timeout;    int i = 2;    uint8_t reg_tmp[4];	    /*fill reg data*/    reg_tmp[0] = (uint8_t)(0x00ff & (*((uint32_t *)reg_data)));     reg_tmp[1] = (uint8_t)((0xff00 & (*((uint32_t *)reg_data))) >> 8);          reg_tmp[2] = (uint8_t)((0xff0000 & (*((uint32_t *)reg_data))) >> 16);    reg_tmp[3] = (uint8_t)((0xff000000 & (*((uint32_t *)reg_data))) >> 24);	    atomic_inc(&seqcnt);	    do {        wait_flag = 0;        athrs26_header_config_reg(ag7100_macs[0]->mac_dev, 0, reg_addr, cmd_len, reg_tmp);        timeout = HZ;             if (!in_interrupt()) {            timeout = wait_event_interruptible_timeout (hd_conf_wait,                                                         wait_flag != 0, timeout);        }        if (timeout || ((reg_addr == 0)&&(reg_tmp[3]&0x80)))  //ignore reset write echo             break;        else            printk("write time out\n");    } while (i--);    if(i==0) {        return -1;    }        return 0;   }intathrs26_header_read_reg(uint32_t reg_addr, uint16_t cmd_len, uint8_t *reg_data){    long timeout;    int i = 2;    if (in_interrupt())        return -1;            atomic_inc(&seqcnt);    do {        wait_flag = 0;                  athrs26_header_config_reg(ag7100_macs[0]->mac_dev, 1, reg_addr, cmd_len, reg_data);        timeout = HZ;          timeout = wait_event_interruptible_timeout (hd_conf_wait,                                                     wait_flag != 0, timeout);         if (timeout)             break;        else             printk("read time out\n");    } while(i--);           if ((i==0) || (atomic_read(&seqcnt) != cmd_resp.seq) || (cmd_len != cmd_resp.len)) {        return -1;    }	    (*((uint32_t *)reg_data)) = cmd_resp.data[0] | (cmd_resp.data[1] << 8)		                         | (cmd_resp.data[2] << 16)| (cmd_resp.data[3] << 24);    return 0;   }int header_receive_skb(struct sk_buff *skb){    wait_flag = 1;    cmd_resp.len = skb->data[4] >> 4;    if (cmd_resp.len > 10)        goto out;        cmd_resp.seq = skb->data[6] >> 1;    cmd_resp.seq |= skb->data[7] << 7;    cmd_resp.seq |= skb->data[8] << 15;    cmd_resp.seq |= skb->data[9] << 23;    if (cmd_resp.seq < atomic_read(&seqcnt))        goto out;              memcpy (cmd_resp.data, (skb->data + 10), cmd_resp.len);    wake_up_interruptible(&hd_conf_wait);    out:        kfree_skb(skb);	}void athrs26_reg_dev(ag7100_mac_t **mac){    ag7100_macs[0] = mac[0];    ag7100_macs[0]->mac_speed = 0xff;    ag7100_macs[1] = mac[1];    ag7100_macs[1]->mac_speed = 0xff;}static uint32_tathrs26_reg_read(uint32_t reg_addr){#ifndef HEADER_REG_CONF	    uint32_t reg_word_addr;    uint32_t phy_addr, tmp_val, reg_val;    uint16_t phy_val;    uint8_t phy_reg;    /* change reg_addr to 16-bit word address, 32-bit aligned */    reg_word_addr = (reg_addr & 0xfffffffc) >> 1;    /* configure register high address */    phy_addr = 0x18;    phy_reg = 0x0;    phy_val = (uint16_t) ((reg_word_addr >> 8) & 0x1ff);  /* bit16-8 of reg address */    phy_reg_write(0, phy_addr, phy_reg, phy_val);    /* For some registers such as MIBs, since it is read/clear, we should */    /* read the lower 16-bit register then the higher one */    /* read register in lower address */    phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */    phy_reg = (uint8_t) (reg_word_addr & 0x1f);   /* bit4-0 of reg address */    reg_val = (uint32_t) phy_reg_read(0, phy_addr, phy_reg);    /* read register in higher address */    reg_word_addr++;    phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */    phy_reg = (uint8_t) (reg_word_addr & 0x1f);   /* bit4-0 of reg address */    tmp_val = (uint32_t) phy_reg_read(0, phy_addr, phy_reg);    reg_val |= (tmp_val << 16);    return reg_val;#else    uint8_t reg_data[4];        memset (reg_data, 0, 4);    athrs26_header_read_reg(reg_addr, 4, reg_data);    return *((uint32_t *)reg_data);#endif    }static voidathrs26_reg_write(uint32_t reg_addr, uint32_t reg_val){#ifndef HEADER_REG_CONF    uint32_t reg_word_addr;    uint32_t phy_addr;    uint16_t phy_val;    uint8_t phy_reg;    /* change reg_addr to 16-bit word address, 32-bit aligned */    reg_word_addr = (reg_addr & 0xfffffffc) >> 1;    /* configure register high address */    phy_addr = 0x18;    phy_reg = 0x0;    phy_val = (uint16_t) ((reg_word_addr >> 8) & 0x1ff);  /* bit16-8 of reg address */    phy_reg_write(0, phy_addr, phy_reg, phy_val);    /* For some registers such as ARL and VLAN, since they include BUSY bit */    /* in lower address, we should write the higher 16-bit register then the */    /* lower one */    /* read register in higher address */    reg_word_addr++;    phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */    phy_reg = (uint8_t) (reg_word_addr & 0x1f);   /* bit4-0 of reg address */    phy_val = (uint16_t) ((reg_val >> 16) & 0xffff);    phy_reg_write(0, phy_addr, phy_reg, phy_val);    /* write register in lower address */    reg_word_addr--;    phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */    phy_reg = (uint8_t) (reg_word_addr & 0x1f);   /* bit4-0 of reg address */    phy_val = (uint16_t) (reg_val & 0xffff);    phy_reg_write(0, phy_addr, phy_reg, phy_val); #else    athrs26_header_write_reg (reg_addr, 4, (uint8_t *)&reg_val);#endif}intathr_ioctl(uint32_t *args, int cmd){#ifdef FULL_FEATURE    if (sw_ioctl(args, cmd))        return -EOPNOTSUPP;    return 0;#else	printk("EOPNOTSUPP\n");    return -EOPNOTSUPP;#endif}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -