diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/sky2.c | 97 |
1 files changed, 55 insertions, 42 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index e24b25ca1c69..4e3e2a37c3d1 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -3732,27 +3732,63 @@ static int sky2_get_eeprom_len(struct net_device *dev) | |||
3732 | return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8); | 3732 | return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8); |
3733 | } | 3733 | } |
3734 | 3734 | ||
3735 | static u32 sky2_vpd_read(struct sky2_hw *hw, int cap, u16 offset) | 3735 | static int sky2_vpd_wait(const struct sky2_hw *hw, int cap, u16 busy) |
3736 | { | 3736 | { |
3737 | u32 val; | 3737 | unsigned long start = jiffies; |
3738 | 3738 | ||
3739 | sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset); | 3739 | while ( (sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F) == busy) { |
3740 | /* Can take up to 10.6 ms for write */ | ||
3741 | if (time_after(jiffies, start + HZ/4)) { | ||
3742 | dev_err(&hw->pdev->dev, PFX "VPD cycle timed out"); | ||
3743 | return -ETIMEDOUT; | ||
3744 | } | ||
3745 | mdelay(1); | ||
3746 | } | ||
3740 | 3747 | ||
3741 | do { | 3748 | return 0; |
3742 | offset = sky2_pci_read16(hw, cap + PCI_VPD_ADDR); | 3749 | } |
3743 | } while (!(offset & PCI_VPD_ADDR_F)); | ||
3744 | 3750 | ||
3745 | val = sky2_pci_read32(hw, cap + PCI_VPD_DATA); | 3751 | static int sky2_vpd_read(struct sky2_hw *hw, int cap, void *data, |
3746 | return val; | 3752 | u16 offset, size_t length) |
3753 | { | ||
3754 | int rc = 0; | ||
3755 | |||
3756 | while (length > 0) { | ||
3757 | u32 val; | ||
3758 | |||
3759 | sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset); | ||
3760 | rc = sky2_vpd_wait(hw, cap, 0); | ||
3761 | if (rc) | ||
3762 | break; | ||
3763 | |||
3764 | val = sky2_pci_read32(hw, cap + PCI_VPD_DATA); | ||
3765 | |||
3766 | memcpy(data, &val, min(sizeof(val), length)); | ||
3767 | offset += sizeof(u32); | ||
3768 | data += sizeof(u32); | ||
3769 | length -= sizeof(u32); | ||
3770 | } | ||
3771 | |||
3772 | return rc; | ||
3747 | } | 3773 | } |
3748 | 3774 | ||
3749 | static void sky2_vpd_write(struct sky2_hw *hw, int cap, u16 offset, u32 val) | 3775 | static int sky2_vpd_write(struct sky2_hw *hw, int cap, const void *data, |
3776 | u16 offset, unsigned int length) | ||
3750 | { | 3777 | { |
3751 | sky2_pci_write16(hw, cap + PCI_VPD_DATA, val); | 3778 | unsigned int i; |
3752 | sky2_pci_write32(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F); | 3779 | int rc = 0; |
3753 | do { | 3780 | |
3754 | offset = sky2_pci_read16(hw, cap + PCI_VPD_ADDR); | 3781 | for (i = 0; i < length; i += sizeof(u32)) { |
3755 | } while (offset & PCI_VPD_ADDR_F); | 3782 | u32 val = *(u32 *)(data + i); |
3783 | |||
3784 | sky2_pci_write32(hw, cap + PCI_VPD_DATA, val); | ||
3785 | sky2_pci_write32(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F); | ||
3786 | |||
3787 | rc = sky2_vpd_wait(hw, cap, PCI_VPD_ADDR_F); | ||
3788 | if (rc) | ||
3789 | break; | ||
3790 | } | ||
3791 | return rc; | ||
3756 | } | 3792 | } |
3757 | 3793 | ||
3758 | static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | 3794 | static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, |
@@ -3760,24 +3796,13 @@ static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom | |||
3760 | { | 3796 | { |
3761 | struct sky2_port *sky2 = netdev_priv(dev); | 3797 | struct sky2_port *sky2 = netdev_priv(dev); |
3762 | int cap = pci_find_capability(sky2->hw->pdev, PCI_CAP_ID_VPD); | 3798 | int cap = pci_find_capability(sky2->hw->pdev, PCI_CAP_ID_VPD); |
3763 | int length = eeprom->len; | ||
3764 | u16 offset = eeprom->offset; | ||
3765 | 3799 | ||
3766 | if (!cap) | 3800 | if (!cap) |
3767 | return -EINVAL; | 3801 | return -EINVAL; |
3768 | 3802 | ||
3769 | eeprom->magic = SKY2_EEPROM_MAGIC; | 3803 | eeprom->magic = SKY2_EEPROM_MAGIC; |
3770 | 3804 | ||
3771 | while (length > 0) { | 3805 | return sky2_vpd_read(sky2->hw, cap, data, eeprom->offset, eeprom->len); |
3772 | u32 val = sky2_vpd_read(sky2->hw, cap, offset); | ||
3773 | int n = min_t(int, length, sizeof(val)); | ||
3774 | |||
3775 | memcpy(data, &val, n); | ||
3776 | length -= n; | ||
3777 | data += n; | ||
3778 | offset += n; | ||
3779 | } | ||
3780 | return 0; | ||
3781 | } | 3806 | } |
3782 | 3807 | ||
3783 | static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | 3808 | static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, |
@@ -3785,8 +3810,6 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom | |||
3785 | { | 3810 | { |
3786 | struct sky2_port *sky2 = netdev_priv(dev); | 3811 | struct sky2_port *sky2 = netdev_priv(dev); |
3787 | int cap = pci_find_capability(sky2->hw->pdev, PCI_CAP_ID_VPD); | 3812 | int cap = pci_find_capability(sky2->hw->pdev, PCI_CAP_ID_VPD); |
3788 | int length = eeprom->len; | ||
3789 | u16 offset = eeprom->offset; | ||
3790 | 3813 | ||
3791 | if (!cap) | 3814 | if (!cap) |
3792 | return -EINVAL; | 3815 | return -EINVAL; |
@@ -3794,21 +3817,11 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom | |||
3794 | if (eeprom->magic != SKY2_EEPROM_MAGIC) | 3817 | if (eeprom->magic != SKY2_EEPROM_MAGIC) |
3795 | return -EINVAL; | 3818 | return -EINVAL; |
3796 | 3819 | ||
3797 | while (length > 0) { | 3820 | /* Partial writes not supported */ |
3798 | u32 val; | 3821 | if ((eeprom->offset & 3) || (eeprom->len & 3)) |
3799 | int n = min_t(int, length, sizeof(val)); | 3822 | return -EINVAL; |
3800 | |||
3801 | if (n < sizeof(val)) | ||
3802 | val = sky2_vpd_read(sky2->hw, cap, offset); | ||
3803 | memcpy(&val, data, n); | ||
3804 | |||
3805 | sky2_vpd_write(sky2->hw, cap, offset, val); | ||
3806 | 3823 | ||
3807 | length -= n; | 3824 | return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len); |
3808 | data += n; | ||
3809 | offset += n; | ||
3810 | } | ||
3811 | return 0; | ||
3812 | } | 3825 | } |
3813 | 3826 | ||
3814 | 3827 | ||