📄 athrs26_phy.c
字号:
#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 *)®_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 + -