Commit 29dd54b72ba8c5ad0dd6dd33584449b5953f700b

Authored by Anirban Chakraborty
Committed by David S. Miller
1 parent bdc220da32

ethtool: Added support for FW dump

Added code to take FW dump via ethtool. Dump level can be controlled via setting the
dump flag. A get function is provided to query the current setting of the dump flag.
Dump data is obtained from the driver via a separate get function.

Changes from v3:
Fixed buffer length issue in ethtool_get_dump_data function.
Updated kernel doc for ethtool_dump struct and get_dump_flag function.

Changes from v2:
Provided separate commands for get flag and data.
Check for minimum of the two buffer length obtained via ethtool and driver and
use that for dump buffer
Pass up the driver return error codes up to the caller.
Added kernel doc comments.

Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Reviewed-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 2 changed files with 121 additions and 0 deletions Side-by-side Diff

include/linux/ethtool.h
... ... @@ -601,6 +601,26 @@
601 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 624 /* for returning and changing feature sets */
605 625  
606 626 /**
... ... @@ -853,6 +873,10 @@
853 873 * @get_channels: Get number of channels.
854 874 * @set_channels: Set number of channels. Returns a negative error code or
855 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 881 * All operations are optional (i.e. the function pointer may be set
858 882 * to %NULL) and callers must take this into account. Callers must
... ... @@ -927,6 +951,10 @@
927 951 const struct ethtool_rxfh_indir *);
928 952 void (*get_channels)(struct net_device *, struct ethtool_channels *);
929 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 960 #endif /* __KERNEL__ */
... ... @@ -998,6 +1026,9 @@
998 1026 #define ETHTOOL_SFEATURES 0x0000003b /* Change device offload settings */
999 1027 #define ETHTOOL_GCHANNELS 0x0000003c /* Get no of channels */
1000 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 1033 /* compatibility with older code */
1003 1034 #define SPARC_ETH_GSET ETHTOOL_GSET
... ... @@ -1823,6 +1823,87 @@
1823 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 1907 /* The main entry point in this file. Called from net/core/dev.c */
1827 1908  
1828 1909 int dev_ethtool(struct net *net, struct ifreq *ifr)
... ... @@ -2038,6 +2119,15 @@
2038 2119 break;
2039 2120 case ETHTOOL_SCHANNELS:
2040 2121 rc = ethtool_set_channels(dev, useraddr);
  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);
2041 2131 break;
2042 2132 default:
2043 2133 rc = -EOPNOTSUPP;