Exemple #1
0
/**
 * 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;
}
Exemple #2
0
/**
 * 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;
}
Exemple #3
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);
}
Exemple #4
0
/**
 * 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;
}