aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2017-09-12 23:28:49 -0400
committerCorey Minyard <cminyard@mvista.com>2017-09-27 17:03:45 -0400
commit44814ec982d2905d50fe4d0cdaf693b76afe7f64 (patch)
treeb7ce3392fde9e9ff2efcdaaa2b2fc529d93df132
parentbb398a4cb09a0ed96cf0fc2e90012cf6bf13a824 (diff)
ipmi_si: Move the hotmod handling to another file.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
-rw-r--r--drivers/char/ipmi/Makefile3
-rw-r--r--drivers/char/ipmi/ipmi_si.h2
-rw-r--r--drivers/char/ipmi/ipmi_si_hotmod.c242
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c261
4 files changed, 264 insertions, 244 deletions
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
index eefb0b301e83..61c7d5d32f4a 100644
--- a/drivers/char/ipmi/Makefile
+++ b/drivers/char/ipmi/Makefile
@@ -2,7 +2,8 @@
2# Makefile for the ipmi drivers. 2# Makefile for the ipmi drivers.
3# 3#
4 4
5ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o 5ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \
6 ipmi_si_hotmod.o
6 7
7obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o 8obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
8obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o 9obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h
index 9573b35d73af..4ceb5ac3ad98 100644
--- a/drivers/char/ipmi/ipmi_si.h
+++ b/drivers/char/ipmi/ipmi_si.h
@@ -20,3 +20,5 @@ void ipmi_irq_start_cleanup(struct si_sm_io *io);
20int ipmi_std_irq_setup(struct si_sm_io *io); 20int ipmi_std_irq_setup(struct si_sm_io *io);
21void ipmi_irq_finish_setup(struct si_sm_io *io); 21void ipmi_irq_finish_setup(struct si_sm_io *io);
22int ipmi_si_remove_by_dev(struct device *dev); 22int ipmi_si_remove_by_dev(struct device *dev);
23void ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
24 unsigned long addr);
diff --git a/drivers/char/ipmi/ipmi_si_hotmod.c b/drivers/char/ipmi/ipmi_si_hotmod.c
new file mode 100644
index 000000000000..da5716159974
--- /dev/null
+++ b/drivers/char/ipmi/ipmi_si_hotmod.c
@@ -0,0 +1,242 @@
1/*
2 * ipmi_si_hotmod.c
3 *
4 * Handling for dynamically adding/removing IPMI devices through
5 * a module parameter (and thus sysfs).
6 */
7#include <linux/moduleparam.h>
8#include <linux/ipmi.h>
9#include "ipmi_si.h"
10
11#define PFX "ipmi_hotmod: "
12
13static int hotmod_handler(const char *val, struct kernel_param *kp);
14
15module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200);
16MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See"
17 " Documentation/IPMI.txt in the kernel sources for the"
18 " gory details.");
19
20/*
21 * Parms come in as <op1>[:op2[:op3...]]. ops are:
22 * add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
23 * Options are:
24 * rsp=<regspacing>
25 * rsi=<regsize>
26 * rsh=<regshift>
27 * irq=<irq>
28 * ipmb=<ipmb addr>
29 */
30enum hotmod_op { HM_ADD, HM_REMOVE };
31struct hotmod_vals {
32 const char *name;
33 const int val;
34};
35
36static const struct hotmod_vals hotmod_ops[] = {
37 { "add", HM_ADD },
38 { "remove", HM_REMOVE },
39 { NULL }
40};
41
42static const struct hotmod_vals hotmod_si[] = {
43 { "kcs", SI_KCS },
44 { "smic", SI_SMIC },
45 { "bt", SI_BT },
46 { NULL }
47};
48
49static const struct hotmod_vals hotmod_as[] = {
50 { "mem", IPMI_MEM_ADDR_SPACE },
51 { "i/o", IPMI_IO_ADDR_SPACE },
52 { NULL }
53};
54
55static int parse_str(const struct hotmod_vals *v, int *val, char *name,
56 char **curr)
57{
58 char *s;
59 int i;
60
61 s = strchr(*curr, ',');
62 if (!s) {
63 pr_warn(PFX "No hotmod %s given.\n", name);
64 return -EINVAL;
65 }
66 *s = '\0';
67 s++;
68 for (i = 0; v[i].name; i++) {
69 if (strcmp(*curr, v[i].name) == 0) {
70 *val = v[i].val;
71 *curr = s;
72 return 0;
73 }
74 }
75
76 pr_warn(PFX "Invalid hotmod %s '%s'\n", name, *curr);
77 return -EINVAL;
78}
79
80static int check_hotmod_int_op(const char *curr, const char *option,
81 const char *name, int *val)
82{
83 char *n;
84
85 if (strcmp(curr, name) == 0) {
86 if (!option) {
87 pr_warn(PFX "No option given for '%s'\n", curr);
88 return -EINVAL;
89 }
90 *val = simple_strtoul(option, &n, 0);
91 if ((*n != '\0') || (*option == '\0')) {
92 pr_warn(PFX "Bad option given for '%s'\n", curr);
93 return -EINVAL;
94 }
95 return 1;
96 }
97 return 0;
98}
99
100static int hotmod_handler(const char *val, struct kernel_param *kp)
101{
102 char *str = kstrdup(val, GFP_KERNEL);
103 int rv;
104 char *next, *curr, *s, *n, *o;
105 enum hotmod_op op;
106 enum si_type si_type;
107 int addr_space;
108 unsigned long addr;
109 int regspacing;
110 int regsize;
111 int regshift;
112 int irq;
113 int ipmb;
114 int ival;
115 int len;
116
117 if (!str)
118 return -ENOMEM;
119
120 /* Kill any trailing spaces, as we can get a "\n" from echo. */
121 len = strlen(str);
122 ival = len - 1;
123 while ((ival >= 0) && isspace(str[ival])) {
124 str[ival] = '\0';
125 ival--;
126 }
127
128 for (curr = str; curr; curr = next) {
129 regspacing = 1;
130 regsize = 1;
131 regshift = 0;
132 irq = 0;
133 ipmb = 0; /* Choose the default if not specified */
134
135 next = strchr(curr, ':');
136 if (next) {
137 *next = '\0';
138 next++;
139 }
140
141 rv = parse_str(hotmod_ops, &ival, "operation", &curr);
142 if (rv)
143 break;
144 op = ival;
145
146 rv = parse_str(hotmod_si, &ival, "interface type", &curr);
147 if (rv)
148 break;
149 si_type = ival;
150
151 rv = parse_str(hotmod_as, &addr_space, "address space", &curr);
152 if (rv)
153 break;
154
155 s = strchr(curr, ',');
156 if (s) {
157 *s = '\0';
158 s++;
159 }
160 addr = simple_strtoul(curr, &n, 0);
161 if ((*n != '\0') || (*curr == '\0')) {
162 pr_warn(PFX "Invalid hotmod address '%s'\n", curr);
163 break;
164 }
165
166 while (s) {
167 curr = s;
168 s = strchr(curr, ',');
169 if (s) {
170 *s = '\0';
171 s++;
172 }
173 o = strchr(curr, '=');
174 if (o) {
175 *o = '\0';
176 o++;
177 }
178 rv = check_hotmod_int_op(curr, o, "rsp", &regspacing);
179 if (rv < 0)
180 goto out;
181 else if (rv)
182 continue;
183 rv = check_hotmod_int_op(curr, o, "rsi", &regsize);
184 if (rv < 0)
185 goto out;
186 else if (rv)
187 continue;
188 rv = check_hotmod_int_op(curr, o, "rsh", &regshift);
189 if (rv < 0)
190 goto out;
191 else if (rv)
192 continue;
193 rv = check_hotmod_int_op(curr, o, "irq", &irq);
194 if (rv < 0)
195 goto out;
196 else if (rv)
197 continue;
198 rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb);
199 if (rv < 0)
200 goto out;
201 else if (rv)
202 continue;
203
204 rv = -EINVAL;
205 pr_warn(PFX "Invalid hotmod option '%s'\n", curr);
206 goto out;
207 }
208
209 if (op == HM_ADD) {
210 struct si_sm_io io;
211
212 memset(&io, 0, sizeof(io));
213 io.addr_source = SI_HOTMOD;
214 io.si_type = si_type;
215 io.addr_data = addr;
216 io.addr_type = addr_space;
217
218 io.addr = NULL;
219 io.regspacing = regspacing;
220 if (!io.regspacing)
221 io.regspacing = DEFAULT_REGSPACING;
222 io.regsize = regsize;
223 if (!io.regsize)
224 io.regsize = DEFAULT_REGSIZE;
225 io.regshift = regshift;
226 io.irq = irq;
227 if (io.irq)
228 io.irq_setup = ipmi_std_irq_setup;
229 io.slave_addr = ipmb;
230
231 rv = ipmi_si_add_smi(&io);
232 if (rv)
233 goto out;
234 } else {
235 ipmi_si_remove_by_data(addr_space, si_type, addr);
236 }
237 }
238 rv = len;
239out:
240 kfree(str);
241 return rv;
242}
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 6c2e14af8321..02e263b2152a 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1310,13 +1310,6 @@ static unsigned int num_slave_addrs;
1310 1310
1311static const char * const addr_space_to_str[] = { "i/o", "mem" }; 1311static const char * const addr_space_to_str[] = { "i/o", "mem" };
1312 1312
1313static int hotmod_handler(const char *val, struct kernel_param *kp);
1314
1315module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200);
1316MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See"
1317 " Documentation/IPMI.txt in the kernel sources for the"
1318 " gory details.");
1319
1320#ifdef CONFIG_ACPI 1313#ifdef CONFIG_ACPI
1321module_param_named(tryacpi, si_tryacpi, bool, 0); 1314module_param_named(tryacpi, si_tryacpi, bool, 0);
1322MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the" 1315MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the"
@@ -1689,86 +1682,6 @@ static int mem_setup(struct si_sm_io *io)
1689 return 0; 1682 return 0;
1690} 1683}
1691 1684
1692/*
1693 * Parms come in as <op1>[:op2[:op3...]]. ops are:
1694 * add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
1695 * Options are:
1696 * rsp=<regspacing>
1697 * rsi=<regsize>
1698 * rsh=<regshift>
1699 * irq=<irq>
1700 * ipmb=<ipmb addr>
1701 */
1702enum hotmod_op { HM_ADD, HM_REMOVE };
1703struct hotmod_vals {
1704 const char *name;
1705 const int val;
1706};
1707
1708static const struct hotmod_vals hotmod_ops[] = {
1709 { "add", HM_ADD },
1710 { "remove", HM_REMOVE },
1711 { NULL }
1712};
1713
1714static const struct hotmod_vals hotmod_si[] = {
1715 { "kcs", SI_KCS },
1716 { "smic", SI_SMIC },
1717 { "bt", SI_BT },
1718 { NULL }
1719};
1720
1721static const struct hotmod_vals hotmod_as[] = {
1722 { "mem", IPMI_MEM_ADDR_SPACE },
1723 { "i/o", IPMI_IO_ADDR_SPACE },
1724 { NULL }
1725};
1726
1727static int parse_str(const struct hotmod_vals *v, int *val, char *name,
1728 char **curr)
1729{
1730 char *s;
1731 int i;
1732
1733 s = strchr(*curr, ',');
1734 if (!s) {
1735 pr_warn(PFX "No hotmod %s given.\n", name);
1736 return -EINVAL;
1737 }
1738 *s = '\0';
1739 s++;
1740 for (i = 0; v[i].name; i++) {
1741 if (strcmp(*curr, v[i].name) == 0) {
1742 *val = v[i].val;
1743 *curr = s;
1744 return 0;
1745 }
1746 }
1747
1748 pr_warn(PFX "Invalid hotmod %s '%s'\n", name, *curr);
1749 return -EINVAL;
1750}
1751
1752static int check_hotmod_int_op(const char *curr, const char *option,
1753 const char *name, int *val)
1754{
1755 char *n;
1756
1757 if (strcmp(curr, name) == 0) {
1758 if (!option) {
1759 pr_warn(PFX "No option given for '%s'\n", curr);
1760 return -EINVAL;
1761 }
1762 *val = simple_strtoul(option, &n, 0);
1763 if ((*n != '\0') || (*option == '\0')) {
1764 pr_warn(PFX "Bad option given for '%s'\n", curr);
1765 return -EINVAL;
1766 }
1767 return 1;
1768 }
1769 return 0;
1770}
1771
1772static struct smi_info *smi_info_alloc(void) 1685static struct smi_info *smi_info_alloc(void)
1773{ 1686{
1774 struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL); 1687 struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -1778,162 +1691,6 @@ static struct smi_info *smi_info_alloc(void)
1778 return info; 1691 return info;
1779} 1692}
1780 1693
1781static int hotmod_handler(const char *val, struct kernel_param *kp)
1782{
1783 char *str = kstrdup(val, GFP_KERNEL);
1784 int rv;
1785 char *next, *curr, *s, *n, *o;
1786 enum hotmod_op op;
1787 enum si_type si_type;
1788 int addr_space;
1789 unsigned long addr;
1790 int regspacing;
1791 int regsize;
1792 int regshift;
1793 int irq;
1794 int ipmb;
1795 int ival;
1796 int len;
1797
1798 if (!str)
1799 return -ENOMEM;
1800
1801 /* Kill any trailing spaces, as we can get a "\n" from echo. */
1802 len = strlen(str);
1803 ival = len - 1;
1804 while ((ival >= 0) && isspace(str[ival])) {
1805 str[ival] = '\0';
1806 ival--;
1807 }
1808
1809 for (curr = str; curr; curr = next) {
1810 regspacing = 1;
1811 regsize = 1;
1812 regshift = 0;
1813 irq = 0;
1814 ipmb = 0; /* Choose the default if not specified */
1815
1816 next = strchr(curr, ':');
1817 if (next) {
1818 *next = '\0';
1819 next++;
1820 }
1821
1822 rv = parse_str(hotmod_ops, &ival, "operation", &curr);
1823 if (rv)
1824 break;
1825 op = ival;
1826
1827 rv = parse_str(hotmod_si, &ival, "interface type", &curr);
1828 if (rv)
1829 break;
1830 si_type = ival;
1831
1832 rv = parse_str(hotmod_as, &addr_space, "address space", &curr);
1833 if (rv)
1834 break;
1835
1836 s = strchr(curr, ',');
1837 if (s) {
1838 *s = '\0';
1839 s++;
1840 }
1841 addr = simple_strtoul(curr, &n, 0);
1842 if ((*n != '\0') || (*curr == '\0')) {
1843 pr_warn(PFX "Invalid hotmod address '%s'\n", curr);
1844 break;
1845 }
1846
1847 while (s) {
1848 curr = s;
1849 s = strchr(curr, ',');
1850 if (s) {
1851 *s = '\0';
1852 s++;
1853 }
1854 o = strchr(curr, '=');
1855 if (o) {
1856 *o = '\0';
1857 o++;
1858 }
1859 rv = check_hotmod_int_op(curr, o, "rsp", &regspacing);
1860 if (rv < 0)
1861 goto out;
1862 else if (rv)
1863 continue;
1864 rv = check_hotmod_int_op(curr, o, "rsi", &regsize);
1865 if (rv < 0)
1866 goto out;
1867 else if (rv)
1868 continue;
1869 rv = check_hotmod_int_op(curr, o, "rsh", &regshift);
1870 if (rv < 0)
1871 goto out;
1872 else if (rv)
1873 continue;
1874 rv = check_hotmod_int_op(curr, o, "irq", &irq);
1875 if (rv < 0)
1876 goto out;
1877 else if (rv)
1878 continue;
1879 rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb);
1880 if (rv < 0)
1881 goto out;
1882 else if (rv)
1883 continue;
1884
1885 rv = -EINVAL;
1886 pr_warn(PFX "Invalid hotmod option '%s'\n", curr);
1887 goto out;
1888 }
1889
1890 if (op == HM_ADD) {
1891 struct si_sm_io io;
1892
1893 memset(&io, 0, sizeof(io));
1894 io.addr_source = SI_HOTMOD;
1895 io.si_type = si_type;
1896 io.addr_data = addr;
1897 io.addr_type = addr_space;
1898
1899 io.addr = NULL;
1900 io.regspacing = regspacing;
1901 if (!io.regspacing)
1902 io.regspacing = DEFAULT_REGSPACING;
1903 io.regsize = regsize;
1904 if (!io.regsize)
1905 io.regsize = DEFAULT_REGSIZE;
1906 io.regshift = regshift;
1907 io.irq = irq;
1908 if (io.irq)
1909 io.irq_setup = ipmi_std_irq_setup;
1910 io.slave_addr = ipmb;
1911
1912 rv = ipmi_si_add_smi(&io);
1913 if (rv)
1914 goto out;
1915 } else {
1916 /* remove */
1917 struct smi_info *e, *tmp_e;
1918
1919 mutex_lock(&smi_infos_lock);
1920 list_for_each_entry_safe(e, tmp_e, &smi_infos, link) {
1921 if (e->io.addr_type != addr_space)
1922 continue;
1923 if (e->io.si_type != si_type)
1924 continue;
1925 if (e->io.addr_data == addr)
1926 cleanup_one_si(e);
1927 }
1928 mutex_unlock(&smi_infos_lock);
1929 }
1930 }
1931 rv = len;
1932out:
1933 kfree(str);
1934 return rv;
1935}
1936
1937static int hardcode_find_bmc(void) 1694static int hardcode_find_bmc(void)
1938{ 1695{
1939 int ret = -ENODEV; 1696 int ret = -ENODEV;
@@ -3779,6 +3536,24 @@ int ipmi_si_remove_by_dev(struct device *dev)
3779 return rv; 3536 return rv;
3780} 3537}
3781 3538
3539void ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
3540 unsigned long addr)
3541{
3542 /* remove */
3543 struct smi_info *e, *tmp_e;
3544
3545 mutex_lock(&smi_infos_lock);
3546 list_for_each_entry_safe(e, tmp_e, &smi_infos, link) {
3547 if (e->io.addr_type != addr_space)
3548 continue;
3549 if (e->io.si_type != si_type)
3550 continue;
3551 if (e->io.addr_data == addr)
3552 cleanup_one_si(e);
3553 }
3554 mutex_unlock(&smi_infos_lock);
3555}
3556
3782static void cleanup_ipmi_si(void) 3557static void cleanup_ipmi_si(void)
3783{ 3558{
3784 struct smi_info *e, *tmp_e; 3559 struct smi_info *e, *tmp_e;