diff options
Diffstat (limited to 'drivers/net/skge.c')
-rw-r--r-- | drivers/net/skge.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index a439d4304458..953f8023f24c 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c | |||
@@ -59,6 +59,9 @@ | |||
59 | #define BLINK_MS 250 | 59 | #define BLINK_MS 250 |
60 | #define LINK_HZ HZ | 60 | #define LINK_HZ HZ |
61 | 61 | ||
62 | #define SKGE_EEPROM_MAGIC 0x9933aabb | ||
63 | |||
64 | |||
62 | MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); | 65 | MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); |
63 | MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); | 66 | MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); |
64 | MODULE_LICENSE("GPL"); | 67 | MODULE_LICENSE("GPL"); |
@@ -798,6 +801,98 @@ static int skge_phys_id(struct net_device *dev, u32 data) | |||
798 | return 0; | 801 | return 0; |
799 | } | 802 | } |
800 | 803 | ||
804 | static int skge_get_eeprom_len(struct net_device *dev) | ||
805 | { | ||
806 | struct skge_port *skge = netdev_priv(dev); | ||
807 | u32 reg2; | ||
808 | |||
809 | pci_read_config_dword(skge->hw->pdev, PCI_DEV_REG2, ®2); | ||
810 | return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8); | ||
811 | } | ||
812 | |||
813 | static u32 skge_vpd_read(struct pci_dev *pdev, int cap, u16 offset) | ||
814 | { | ||
815 | u32 val; | ||
816 | |||
817 | pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset); | ||
818 | |||
819 | do { | ||
820 | pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); | ||
821 | } while (!(offset & PCI_VPD_ADDR_F)); | ||
822 | |||
823 | pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val); | ||
824 | return val; | ||
825 | } | ||
826 | |||
827 | static void skge_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val) | ||
828 | { | ||
829 | pci_write_config_dword(pdev, cap + PCI_VPD_DATA, val); | ||
830 | pci_write_config_word(pdev, cap + PCI_VPD_ADDR, | ||
831 | offset | PCI_VPD_ADDR_F); | ||
832 | |||
833 | do { | ||
834 | pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); | ||
835 | } while (offset & PCI_VPD_ADDR_F); | ||
836 | } | ||
837 | |||
838 | static int skge_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | ||
839 | u8 *data) | ||
840 | { | ||
841 | struct skge_port *skge = netdev_priv(dev); | ||
842 | struct pci_dev *pdev = skge->hw->pdev; | ||
843 | int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); | ||
844 | int length = eeprom->len; | ||
845 | u16 offset = eeprom->offset; | ||
846 | |||
847 | if (!cap) | ||
848 | return -EINVAL; | ||
849 | |||
850 | eeprom->magic = SKGE_EEPROM_MAGIC; | ||
851 | |||
852 | while (length > 0) { | ||
853 | u32 val = skge_vpd_read(pdev, cap, offset); | ||
854 | int n = min_t(int, length, sizeof(val)); | ||
855 | |||
856 | memcpy(data, &val, n); | ||
857 | length -= n; | ||
858 | data += n; | ||
859 | offset += n; | ||
860 | } | ||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | static int skge_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | ||
865 | u8 *data) | ||
866 | { | ||
867 | struct skge_port *skge = netdev_priv(dev); | ||
868 | struct pci_dev *pdev = skge->hw->pdev; | ||
869 | int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); | ||
870 | int length = eeprom->len; | ||
871 | u16 offset = eeprom->offset; | ||
872 | |||
873 | if (!cap) | ||
874 | return -EINVAL; | ||
875 | |||
876 | if (eeprom->magic != SKGE_EEPROM_MAGIC) | ||
877 | return -EINVAL; | ||
878 | |||
879 | while (length > 0) { | ||
880 | u32 val; | ||
881 | int n = min_t(int, length, sizeof(val)); | ||
882 | |||
883 | if (n < sizeof(val)) | ||
884 | val = skge_vpd_read(pdev, cap, offset); | ||
885 | memcpy(&val, data, n); | ||
886 | |||
887 | skge_vpd_write(pdev, cap, offset, val); | ||
888 | |||
889 | length -= n; | ||
890 | data += n; | ||
891 | offset += n; | ||
892 | } | ||
893 | return 0; | ||
894 | } | ||
895 | |||
801 | static const struct ethtool_ops skge_ethtool_ops = { | 896 | static const struct ethtool_ops skge_ethtool_ops = { |
802 | .get_settings = skge_get_settings, | 897 | .get_settings = skge_get_settings, |
803 | .set_settings = skge_set_settings, | 898 | .set_settings = skge_set_settings, |
@@ -810,6 +905,9 @@ static const struct ethtool_ops skge_ethtool_ops = { | |||
810 | .set_msglevel = skge_set_msglevel, | 905 | .set_msglevel = skge_set_msglevel, |
811 | .nway_reset = skge_nway_reset, | 906 | .nway_reset = skge_nway_reset, |
812 | .get_link = ethtool_op_get_link, | 907 | .get_link = ethtool_op_get_link, |
908 | .get_eeprom_len = skge_get_eeprom_len, | ||
909 | .get_eeprom = skge_get_eeprom, | ||
910 | .set_eeprom = skge_set_eeprom, | ||
813 | .get_ringparam = skge_get_ring_param, | 911 | .get_ringparam = skge_get_ring_param, |
814 | .set_ringparam = skge_set_ring_param, | 912 | .set_ringparam = skge_set_ring_param, |
815 | .get_pauseparam = skge_get_pauseparam, | 913 | .get_pauseparam = skge_get_pauseparam, |