/** * gcu_release_adapter * * gcu_release_adapter is used by the functions exported in gcu_if.c to get * release the adapter spinlock and the handle to the adapter **/ void gcu_release_adapter(const struct gcu_adapter **adapter) { GCU_DBG("%s\n", __func__); if(adapter == NULL) { GCU_ERR("global gcu_adapter handle is invalid\n"); } else { *adapter = 0; } spin_unlock_irqrestore(&global_adapter_spinlock, g_intflags); return; }
/** * gcu_read_eth_phy * @phy_num: phy we want to write to, either 0, 1, or 2 * @reg_addr: address in PHY's register space to write to * @phy_data: data to be written * * interface function for other modules to access the GCU **/ int32_t gcu_read_eth_phy(uint32_t phy_num, uint32_t reg_addr, uint16_t *phy_data) { const struct gcu_adapter *adapter; uint32_t data = 0; uint32_t timeoutCounter = 0; const uint32_t timeoutCounterMax = GCU_MAX_ATTEMPTS; uint32_t complete = 0; #if defined(CONFIG_UTM2000) || defined(CONFIG_UTM3000) static int once = 0; if (once++ == 0) { vt_enable_port(1); mvl_enable_ports(2); mvl_enable_ports(4); //mii_dump(); } #endif /* CONFIG_UTM2000 || CONFIG_UTM3000 */ GCU_DBG("%s\n", __func__); #if defined(CONFIG_UTM2000) || defined(CONFIG_UTM3000) /* * For the Marvell 88E6161, we use an indirect addressing mode * to get at all the registers. We map PHY addresses over 32 to * these devices. ie. Device has phy address 2: to access, use a * virtual phy address range of 64 to 96, which will be mapped into * the switch. */ if (phy_num >= MVL_PHYS_PHY_MAX) { int32_t mphy, phyid, result; adapter = gcu_get_adapter(); if(!adapter) { GCU_ERR("gcu_adapter not available, cannot access MMIO\n"); return -1; } mphy = phy_num / MVL_PHYS_PHY_MAX; phyid = phy_num % MVL_PHYS_PHY_MAX; if (phyid < 6) result = mvl_mii_phy_read(adapter, mphy, phyid, reg_addr, phy_data); else result = mvl_mii_read(adapter, mphy, phyid, reg_addr, phy_data); gcu_release_adapter(&adapter); if (result == -1) { GCU_ERR("Error reading from Marvell phy register\n"); return result; } return 0; } #endif /* CONFIG_UTM2000 || CONFIG_UTM3000 */ if(phy_num > MDIO_COMMAND_PHY_ADDR_MAX) { GCU_ERR("phy_num = %d, which is greater than " "MDIO_COMMAND_PHY_ADDR_MAX\n", phy_num); return -1; } if(reg_addr > MDIO_COMMAND_PHY_REG_MAX) { GCU_ERR("reg_addr = %d, which is greater than " "MDIO_COMMAND_PHY_REG_MAX\n", phy_num); return -1; } /* format the data to be written to MDIO_COMMAND_REG */ data |= (reg_addr << MDIO_COMMAND_PHY_REG_OFFSET); data |= (phy_num << MDIO_COMMAND_PHY_ADDR_OFFSET); data |= MDIO_COMMAND_GO_MASK; /* * this call contains a spinlock, so this may pause for a bit */ adapter = gcu_get_adapter(); if(!adapter) { GCU_ERR("gcu_adapter not available, cannot access MMIO\n"); return -1; } /* * We write to MDIO_COMMAND_REG initially, then read that * same register until its MDIO_GO bit is cleared. When cleared, * the transaction is complete */ iowrite32(data, adapter->hw_addr + MDIO_COMMAND_REG); do { timeoutCounter++; udelay(0x32); /* 50 microsecond delay */ data = ioread32(adapter->hw_addr + MDIO_COMMAND_REG); complete = (data & MDIO_COMMAND_GO_MASK) >> MDIO_COMMAND_GO_OFFSET; } while(complete && timeoutCounter < timeoutCounterMax); /* KAD !complete to complete */ if(timeoutCounter == timeoutCounterMax && !complete) { GCU_ERR("Reached maximum number of retries" " accessing MDIO_COMMAND_REG\n"); gcu_release_adapter(&adapter); return -1; } /* we retrieve the data from the MDIO_STATUS_REGISTER */ data = ioread32(adapter->hw_addr + MDIO_STATUS_REG); if((data & MDIO_STATUS_STATUS_MASK) != 0) { GCU_ERR("Unable to retrieve data from MDIO_STATUS_REG\n"); gcu_release_adapter(&adapter); return -1; } *phy_data = (uint16_t) (data & MDIO_STATUS_READ_DATA_MASK); gcu_release_adapter(&adapter); return 0; }
/** * gcu_write_verify * @phy_num: phy we want to write to, either 0, 1, or 2 * @reg_addr: address in PHY's register space to write to * @phy_data: data to be checked * @adapter: pointer to global adapter struct * * This f(n) assumes that the spinlock acquired for adapter is * still in force. **/ int32_t gcu_write_verify(uint32_t phy_num, uint32_t reg_addr, uint16_t written_data, const struct gcu_adapter *adapter) { uint32_t data = 0; uint32_t timeoutCounter = 0; const uint32_t timeoutCounterMax = GCU_MAX_ATTEMPTS; uint32_t complete = 0; GCU_DBG("%s\n", __func__); if(!adapter) { GCU_ERR("Invalid adapter pointer\n"); return 0; } if(phy_num > MDIO_COMMAND_PHY_ADDR_MAX) { GCU_ERR("phy_num = %d, which is greater than " "MDIO_COMMAND_PHY_ADDR_MAX\n", phy_num); return 0; } if(reg_addr > MDIO_COMMAND_PHY_REG_MAX) { GCU_ERR("reg_addr = %d, which is greater than " "MDIO_COMMAND_PHY_REG_MAX\n", phy_num); return 0; } /* format the data to be written to MDIO_COMMAND_REG */ data |= (reg_addr << MDIO_COMMAND_PHY_REG_OFFSET); data |= (phy_num << MDIO_COMMAND_PHY_ADDR_OFFSET); data |= MDIO_COMMAND_GO_MASK; /* * We write to MDIO_COMMAND_REG initially, then read that * same register until its MDIO_GO bit is cleared. When cleared, * the transaction is complete */ iowrite32(data, adapter->hw_addr + MDIO_COMMAND_REG); do { timeoutCounter++; udelay(0x32); /* 50 microsecond delay */ data = ioread32(adapter->hw_addr + MDIO_COMMAND_REG); complete = (data & MDIO_COMMAND_GO_MASK) >> MDIO_COMMAND_GO_OFFSET; } while(complete && timeoutCounter < timeoutCounterMax); if(timeoutCounter == timeoutCounterMax && !complete) { GCU_ERR("Reached maximum number of retries" " accessing MDIO_COMMAND_REG\n"); return 0; } /* we retrieve the data from the MDIO_STATUS_REGISTER */ data = ioread32(adapter->hw_addr + MDIO_STATUS_REG); if((data & MDIO_STATUS_STATUS_MASK) != 0) { GCU_ERR("Unable to retrieve data from MDIO_STATUS_REG\n"); return 0; } return written_data == (uint16_t) (data & MDIO_STATUS_READ_DATA_MASK); }
/** * gcu_write_eth_phy * @phy_num: phy we want to write to, either 0, 1, or 2 * @reg_addr: address in PHY's register space to write to * @phy_data: data to be written * * interface function for other modules to access the GCU **/ int32_t gcu_write_eth_phy(uint32_t phy_num, uint32_t reg_addr, uint16_t phy_data) { const struct gcu_adapter *adapter; uint32_t data = 0; uint32_t timeoutCounter = 0; const uint32_t timeoutCounterMax = GCU_MAX_ATTEMPTS; uint32_t complete; GCU_DBG("%s\n", __func__); #if defined(CONFIG_UTM2000) || defined(CONFIG_UTM3000) /* * For the Marvell 88E6161, we use an indirect addressing mode * to get at all the registers. We map PHY addresses over 32 to * these devices. ie. Device has phy address 2: to access, use a * virtual phy address range of 64 to 96, which will be mapped into * the switch. */ if (phy_num >= MVL_PHYS_PHY_MAX) { int32_t mphy, phyid, result; adapter = gcu_get_adapter(); if(!adapter) { GCU_ERR("gcu_adapter not available, cannot access MMIO\n"); return -1; } mphy = phy_num / MVL_PHYS_PHY_MAX; phyid = phy_num % MVL_PHYS_PHY_MAX; if (phyid < 6) result = mvl_mii_phy_write(adapter, mphy, phyid, reg_addr, phy_data); else result = mvl_mii_write(adapter, mphy, phyid, reg_addr, phy_data); gcu_release_adapter(&adapter); if (result == -1) { GCU_ERR("Error writing to Marvell phy register\n"); return result; } return 0; } #endif /* CONFIG_UTM2000 || CONFIG_UTM3000 */ if(phy_num > MDIO_COMMAND_PHY_ADDR_MAX) { GCU_ERR("phy_num = %d, which is greater than " "MDIO_COMMAND_PHY_ADDR_MAX\n", phy_num); return -1; } if(reg_addr > MDIO_COMMAND_PHY_REG_MAX) { GCU_ERR("reg_addr = %d, which is greater than " "MDIO_COMMAND_PHY_REG_MAX\n", phy_num); return -1; } /* format the data to be written to the MDIO_COMMAND_REG */ data = phy_data; data |= (reg_addr << MDIO_COMMAND_PHY_REG_OFFSET); data |= (phy_num << MDIO_COMMAND_PHY_ADDR_OFFSET); data |= MDIO_COMMAND_OPER_MASK | MDIO_COMMAND_GO_MASK; /* * get_gcu_adapter contains a spinlock, this may pause for a bit */ adapter = gcu_get_adapter(); if(!adapter) { GCU_ERR("gcu_adapter not available, cannot access MMIO\n"); return -1; } /* * We write to MDIO_COMMAND_REG initially, then read that * same register until its MDIO_GO bit is cleared. When cleared, * the transaction is complete */ iowrite32(data, adapter->hw_addr + MDIO_COMMAND_REG); do { timeoutCounter++; udelay(0x32); /* 50 microsecond delay */ data = ioread32(adapter->hw_addr + MDIO_COMMAND_REG); complete = (data & MDIO_COMMAND_GO_MASK) >> MDIO_COMMAND_GO_OFFSET; } while(complete && timeoutCounter < timeoutCounterMax); /* KAD !complete to complete */ if(timeoutCounter == timeoutCounterMax && !complete) { GCU_ERR("Reached maximum number of retries" " accessing MDIO_COMMAND_REG\n"); gcu_release_adapter(&adapter); return -1; } /* validate the write during debug */ #ifdef DBG if(!gcu_write_verify(phy_num, reg_addr, phy_data, adapter)) { GCU_ERR("Write verification failed for PHY=%d and addr=%d\n", phy_num, reg_addr); gcu_release_adapter(&adapter); return -1; } #endif gcu_release_adapter(&adapter); return 0; }