diff options
-rw-r--r-- | include/linux/ethtool.h | 31 | ||||
-rw-r--r-- | net/core/ethtool.c | 90 |
2 files changed, 121 insertions, 0 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index bd0b50b85f06..c6a850ab2ec5 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h | |||
@@ -601,6 +601,26 @@ struct ethtool_flash { | |||
601 | char data[ETHTOOL_FLASH_MAX_FILENAME]; | 601 | char data[ETHTOOL_FLASH_MAX_FILENAME]; |
602 | }; | 602 | }; |
603 | 603 | ||
604 | /** | ||
605 | * struct ethtool_dump - used for retrieving, setting device dump | ||
606 | * @cmd: Command number - %ETHTOOL_GET_DUMP_FLAG, %ETHTOOL_GET_DUMP_DATA, or | ||
607 | * %ETHTOOL_SET_DUMP | ||
608 | * @version: FW version of the dump, filled in by driver | ||
609 | * @flag: driver dependent flag for dump setting, filled in by driver during | ||
610 | * get and filled in by ethtool for set operation | ||
611 | * @len: length of dump data, used as the length of the user buffer on entry to | ||
612 | * %ETHTOOL_GET_DUMP_DATA and this is returned as dump length by driver | ||
613 | * for %ETHTOOL_GET_DUMP_FLAG command | ||
614 | * @data: data collected for get dump data operation | ||
615 | */ | ||
616 | struct ethtool_dump { | ||
617 | __u32 cmd; | ||
618 | __u32 version; | ||
619 | __u32 flag; | ||
620 | __u32 len; | ||
621 | __u8 data[0]; | ||
622 | }; | ||
623 | |||
604 | /* for returning and changing feature sets */ | 624 | /* for returning and changing feature sets */ |
605 | 625 | ||
606 | /** | 626 | /** |
@@ -853,6 +873,10 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported); | |||
853 | * @get_channels: Get number of channels. | 873 | * @get_channels: Get number of channels. |
854 | * @set_channels: Set number of channels. Returns a negative error code or | 874 | * @set_channels: Set number of channels. Returns a negative error code or |
855 | * zero. | 875 | * zero. |
876 | * @get_dump_flag: Get dump flag indicating current dump length, version, | ||
877 | * and flag of the device. | ||
878 | * @get_dump_data: Get dump data. | ||
879 | * @set_dump: Set dump specific flags to the device. | ||
856 | * | 880 | * |
857 | * All operations are optional (i.e. the function pointer may be set | 881 | * All operations are optional (i.e. the function pointer may be set |
858 | * to %NULL) and callers must take this into account. Callers must | 882 | * to %NULL) and callers must take this into account. Callers must |
@@ -927,6 +951,10 @@ struct ethtool_ops { | |||
927 | const struct ethtool_rxfh_indir *); | 951 | const struct ethtool_rxfh_indir *); |
928 | void (*get_channels)(struct net_device *, struct ethtool_channels *); | 952 | void (*get_channels)(struct net_device *, struct ethtool_channels *); |
929 | int (*set_channels)(struct net_device *, struct ethtool_channels *); | 953 | int (*set_channels)(struct net_device *, struct ethtool_channels *); |
954 | int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); | ||
955 | int (*get_dump_data)(struct net_device *, | ||
956 | struct ethtool_dump *, void *); | ||
957 | int (*set_dump)(struct net_device *, struct ethtool_dump *); | ||
930 | 958 | ||
931 | }; | 959 | }; |
932 | #endif /* __KERNEL__ */ | 960 | #endif /* __KERNEL__ */ |
@@ -998,6 +1026,9 @@ struct ethtool_ops { | |||
998 | #define ETHTOOL_SFEATURES 0x0000003b /* Change device offload settings */ | 1026 | #define ETHTOOL_SFEATURES 0x0000003b /* Change device offload settings */ |
999 | #define ETHTOOL_GCHANNELS 0x0000003c /* Get no of channels */ | 1027 | #define ETHTOOL_GCHANNELS 0x0000003c /* Get no of channels */ |
1000 | #define ETHTOOL_SCHANNELS 0x0000003d /* Set no of channels */ | 1028 | #define ETHTOOL_SCHANNELS 0x0000003d /* Set no of channels */ |
1029 | #define ETHTOOL_SET_DUMP 0x0000003e /* Set dump settings */ | ||
1030 | #define ETHTOOL_GET_DUMP_FLAG 0x0000003f /* Get dump settings */ | ||
1031 | #define ETHTOOL_GET_DUMP_DATA 0x00000040 /* Get dump data */ | ||
1001 | 1032 | ||
1002 | /* compatibility with older code */ | 1033 | /* compatibility with older code */ |
1003 | #define SPARC_ETH_GSET ETHTOOL_GSET | 1034 | #define SPARC_ETH_GSET ETHTOOL_GSET |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index b8c2b10f397a..b8c2bcfee6af 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -1823,6 +1823,87 @@ static noinline_for_stack int ethtool_flash_device(struct net_device *dev, | |||
1823 | return dev->ethtool_ops->flash_device(dev, &efl); | 1823 | return dev->ethtool_ops->flash_device(dev, &efl); |
1824 | } | 1824 | } |
1825 | 1825 | ||
1826 | static int ethtool_set_dump(struct net_device *dev, | ||
1827 | void __user *useraddr) | ||
1828 | { | ||
1829 | struct ethtool_dump dump; | ||
1830 | |||
1831 | if (!dev->ethtool_ops->set_dump) | ||
1832 | return -EOPNOTSUPP; | ||
1833 | |||
1834 | if (copy_from_user(&dump, useraddr, sizeof(dump))) | ||
1835 | return -EFAULT; | ||
1836 | |||
1837 | return dev->ethtool_ops->set_dump(dev, &dump); | ||
1838 | } | ||
1839 | |||
1840 | static int ethtool_get_dump_flag(struct net_device *dev, | ||
1841 | void __user *useraddr) | ||
1842 | { | ||
1843 | int ret; | ||
1844 | struct ethtool_dump dump; | ||
1845 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
1846 | |||
1847 | if (!dev->ethtool_ops->get_dump_flag) | ||
1848 | return -EOPNOTSUPP; | ||
1849 | |||
1850 | if (copy_from_user(&dump, useraddr, sizeof(dump))) | ||
1851 | return -EFAULT; | ||
1852 | |||
1853 | ret = ops->get_dump_flag(dev, &dump); | ||
1854 | if (ret) | ||
1855 | return ret; | ||
1856 | |||
1857 | if (copy_to_user(useraddr, &dump, sizeof(dump))) | ||
1858 | return -EFAULT; | ||
1859 | return 0; | ||
1860 | } | ||
1861 | |||
1862 | static int ethtool_get_dump_data(struct net_device *dev, | ||
1863 | void __user *useraddr) | ||
1864 | { | ||
1865 | int ret; | ||
1866 | __u32 len; | ||
1867 | struct ethtool_dump dump, tmp; | ||
1868 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
1869 | void *data = NULL; | ||
1870 | |||
1871 | if (!dev->ethtool_ops->get_dump_data || | ||
1872 | !dev->ethtool_ops->get_dump_flag) | ||
1873 | return -EOPNOTSUPP; | ||
1874 | |||
1875 | if (copy_from_user(&dump, useraddr, sizeof(dump))) | ||
1876 | return -EFAULT; | ||
1877 | |||
1878 | memset(&tmp, 0, sizeof(tmp)); | ||
1879 | tmp.cmd = ETHTOOL_GET_DUMP_FLAG; | ||
1880 | ret = ops->get_dump_flag(dev, &tmp); | ||
1881 | if (ret) | ||
1882 | return ret; | ||
1883 | |||
1884 | len = (tmp.len > dump.len) ? dump.len : tmp.len; | ||
1885 | if (!len) | ||
1886 | return -EFAULT; | ||
1887 | |||
1888 | data = vzalloc(tmp.len); | ||
1889 | if (!data) | ||
1890 | return -ENOMEM; | ||
1891 | ret = ops->get_dump_data(dev, &dump, data); | ||
1892 | if (ret) | ||
1893 | goto out; | ||
1894 | |||
1895 | if (copy_to_user(useraddr, &dump, sizeof(dump))) { | ||
1896 | ret = -EFAULT; | ||
1897 | goto out; | ||
1898 | } | ||
1899 | useraddr += offsetof(struct ethtool_dump, data); | ||
1900 | if (copy_to_user(useraddr, data, len)) | ||
1901 | ret = -EFAULT; | ||
1902 | out: | ||
1903 | vfree(data); | ||
1904 | return ret; | ||
1905 | } | ||
1906 | |||
1826 | /* The main entry point in this file. Called from net/core/dev.c */ | 1907 | /* The main entry point in this file. Called from net/core/dev.c */ |
1827 | 1908 | ||
1828 | int dev_ethtool(struct net *net, struct ifreq *ifr) | 1909 | int dev_ethtool(struct net *net, struct ifreq *ifr) |
@@ -2039,6 +2120,15 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
2039 | case ETHTOOL_SCHANNELS: | 2120 | case ETHTOOL_SCHANNELS: |
2040 | rc = ethtool_set_channels(dev, useraddr); | 2121 | rc = ethtool_set_channels(dev, useraddr); |
2041 | break; | 2122 | break; |
2123 | case ETHTOOL_SET_DUMP: | ||
2124 | rc = ethtool_set_dump(dev, useraddr); | ||
2125 | break; | ||
2126 | case ETHTOOL_GET_DUMP_FLAG: | ||
2127 | rc = ethtool_get_dump_flag(dev, useraddr); | ||
2128 | break; | ||
2129 | case ETHTOOL_GET_DUMP_DATA: | ||
2130 | rc = ethtool_get_dump_data(dev, useraddr); | ||
2131 | break; | ||
2042 | default: | 2132 | default: |
2043 | rc = -EOPNOTSUPP; | 2133 | rc = -EOPNOTSUPP; |
2044 | } | 2134 | } |