.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * IUCV base infrastructure. |
---|
3 | 4 | * |
---|
.. | .. |
---|
17 | 18 | * Documentation used: |
---|
18 | 19 | * The original source |
---|
19 | 20 | * CP Programming Service, IBM document # SC24-5760 |
---|
20 | | - * |
---|
21 | | - * This program is free software; you can redistribute it and/or modify |
---|
22 | | - * it under the terms of the GNU General Public License as published by |
---|
23 | | - * the Free Software Foundation; either version 2, or (at your option) |
---|
24 | | - * any later version. |
---|
25 | | - * |
---|
26 | | - * This program is distributed in the hope that it will be useful, |
---|
27 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
28 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
29 | | - * GNU General Public License for more details. |
---|
30 | | - * |
---|
31 | | - * You should have received a copy of the GNU General Public License |
---|
32 | | - * along with this program; if not, write to the Free Software |
---|
33 | | - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
34 | 21 | */ |
---|
35 | 22 | |
---|
36 | 23 | #define KMSG_COMPONENT "iucv" |
---|
.. | .. |
---|
80 | 67 | return 0; |
---|
81 | 68 | } |
---|
82 | 69 | |
---|
83 | | -enum iucv_pm_states { |
---|
84 | | - IUCV_PM_INITIAL = 0, |
---|
85 | | - IUCV_PM_FREEZING = 1, |
---|
86 | | - IUCV_PM_THAWING = 2, |
---|
87 | | - IUCV_PM_RESTORING = 3, |
---|
88 | | -}; |
---|
89 | | -static enum iucv_pm_states iucv_pm_state; |
---|
90 | | - |
---|
91 | | -static int iucv_pm_prepare(struct device *); |
---|
92 | | -static void iucv_pm_complete(struct device *); |
---|
93 | | -static int iucv_pm_freeze(struct device *); |
---|
94 | | -static int iucv_pm_thaw(struct device *); |
---|
95 | | -static int iucv_pm_restore(struct device *); |
---|
96 | | - |
---|
97 | | -static const struct dev_pm_ops iucv_pm_ops = { |
---|
98 | | - .prepare = iucv_pm_prepare, |
---|
99 | | - .complete = iucv_pm_complete, |
---|
100 | | - .freeze = iucv_pm_freeze, |
---|
101 | | - .thaw = iucv_pm_thaw, |
---|
102 | | - .restore = iucv_pm_restore, |
---|
103 | | -}; |
---|
104 | | - |
---|
105 | 70 | struct bus_type iucv_bus = { |
---|
106 | 71 | .name = "iucv", |
---|
107 | 72 | .match = iucv_bus_match, |
---|
108 | | - .pm = &iucv_pm_ops, |
---|
109 | 73 | }; |
---|
110 | 74 | EXPORT_SYMBOL(iucv_bus); |
---|
111 | 75 | |
---|
.. | .. |
---|
119 | 83 | u16 ippathid; |
---|
120 | 84 | u8 ipflags1; |
---|
121 | 85 | u8 iptype; |
---|
122 | | - u32 res2[8]; |
---|
| 86 | + u32 res2[9]; |
---|
123 | 87 | }; |
---|
124 | 88 | |
---|
125 | 89 | struct iucv_irq_list { |
---|
.. | .. |
---|
141 | 105 | * The tasklet for fast delivery of iucv interrupts. |
---|
142 | 106 | */ |
---|
143 | 107 | static void iucv_tasklet_fn(unsigned long); |
---|
144 | | -static DECLARE_TASKLET(iucv_tasklet, iucv_tasklet_fn,0); |
---|
| 108 | +static DECLARE_TASKLET_OLD(iucv_tasklet, iucv_tasklet_fn); |
---|
145 | 109 | |
---|
146 | 110 | /* |
---|
147 | 111 | * Queue of interrupt buffers for delivery via a work queue |
---|
.. | .. |
---|
442 | 406 | parm = iucv_param_irq[cpu]; |
---|
443 | 407 | memset(parm, 0, sizeof(union iucv_param)); |
---|
444 | 408 | iucv_call_b2f0(IUCV_SETMASK, parm); |
---|
445 | | - |
---|
446 | | - /* Clear indication that iucv interrupts are allowed for this cpu. */ |
---|
447 | | - cpumask_clear_cpu(cpu, &iucv_irq_cpumask); |
---|
448 | | -} |
---|
449 | | - |
---|
450 | | -/** |
---|
451 | | - * iucv_block_cpu_almost |
---|
452 | | - * @data: unused |
---|
453 | | - * |
---|
454 | | - * Allow connection-severed interrupts only on this cpu. |
---|
455 | | - */ |
---|
456 | | -static void iucv_block_cpu_almost(void *data) |
---|
457 | | -{ |
---|
458 | | - int cpu = smp_processor_id(); |
---|
459 | | - union iucv_param *parm; |
---|
460 | | - |
---|
461 | | - /* Allow iucv control interrupts only */ |
---|
462 | | - parm = iucv_param_irq[cpu]; |
---|
463 | | - memset(parm, 0, sizeof(union iucv_param)); |
---|
464 | | - parm->set_mask.ipmask = 0x08; |
---|
465 | | - iucv_call_b2f0(IUCV_SETMASK, parm); |
---|
466 | | - /* Allow iucv-severed interrupt only */ |
---|
467 | | - memset(parm, 0, sizeof(union iucv_param)); |
---|
468 | | - parm->set_mask.ipmask = 0x20; |
---|
469 | | - iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); |
---|
470 | 409 | |
---|
471 | 410 | /* Clear indication that iucv interrupts are allowed for this cpu. */ |
---|
472 | 411 | cpumask_clear_cpu(cpu, &iucv_irq_cpumask); |
---|
.. | .. |
---|
1177 | 1116 | if (msg->flags & IUCV_IPRMDATA) |
---|
1178 | 1117 | return iucv_message_receive_iprmdata(path, msg, flags, |
---|
1179 | 1118 | buffer, size, residual); |
---|
1180 | | - if (cpumask_empty(&iucv_buffer_cpumask)) { |
---|
1181 | | - rc = -EIO; |
---|
1182 | | - goto out; |
---|
1183 | | - } |
---|
| 1119 | + if (cpumask_empty(&iucv_buffer_cpumask)) |
---|
| 1120 | + return -EIO; |
---|
| 1121 | + |
---|
1184 | 1122 | parm = iucv_param[smp_processor_id()]; |
---|
1185 | 1123 | memset(parm, 0, sizeof(union iucv_param)); |
---|
1186 | 1124 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; |
---|
.. | .. |
---|
1196 | 1134 | if (residual) |
---|
1197 | 1135 | *residual = parm->db.ipbfln1f; |
---|
1198 | 1136 | } |
---|
1199 | | -out: |
---|
1200 | 1137 | return rc; |
---|
1201 | 1138 | } |
---|
1202 | 1139 | EXPORT_SYMBOL(__iucv_message_receive); |
---|
.. | .. |
---|
1845 | 1782 | tasklet_schedule(&iucv_tasklet); |
---|
1846 | 1783 | } |
---|
1847 | 1784 | spin_unlock(&iucv_queue_lock); |
---|
1848 | | -} |
---|
1849 | | - |
---|
1850 | | -static int iucv_pm_prepare(struct device *dev) |
---|
1851 | | -{ |
---|
1852 | | - int rc = 0; |
---|
1853 | | - |
---|
1854 | | -#ifdef CONFIG_PM_DEBUG |
---|
1855 | | - printk(KERN_INFO "iucv_pm_prepare\n"); |
---|
1856 | | -#endif |
---|
1857 | | - if (dev->driver && dev->driver->pm && dev->driver->pm->prepare) |
---|
1858 | | - rc = dev->driver->pm->prepare(dev); |
---|
1859 | | - return rc; |
---|
1860 | | -} |
---|
1861 | | - |
---|
1862 | | -static void iucv_pm_complete(struct device *dev) |
---|
1863 | | -{ |
---|
1864 | | -#ifdef CONFIG_PM_DEBUG |
---|
1865 | | - printk(KERN_INFO "iucv_pm_complete\n"); |
---|
1866 | | -#endif |
---|
1867 | | - if (dev->driver && dev->driver->pm && dev->driver->pm->complete) |
---|
1868 | | - dev->driver->pm->complete(dev); |
---|
1869 | | -} |
---|
1870 | | - |
---|
1871 | | -/** |
---|
1872 | | - * iucv_path_table_empty() - determine if iucv path table is empty |
---|
1873 | | - * |
---|
1874 | | - * Returns 0 if there are still iucv pathes defined |
---|
1875 | | - * 1 if there are no iucv pathes defined |
---|
1876 | | - */ |
---|
1877 | | -static int iucv_path_table_empty(void) |
---|
1878 | | -{ |
---|
1879 | | - int i; |
---|
1880 | | - |
---|
1881 | | - for (i = 0; i < iucv_max_pathid; i++) { |
---|
1882 | | - if (iucv_path_table[i]) |
---|
1883 | | - return 0; |
---|
1884 | | - } |
---|
1885 | | - return 1; |
---|
1886 | | -} |
---|
1887 | | - |
---|
1888 | | -/** |
---|
1889 | | - * iucv_pm_freeze() - Freeze PM callback |
---|
1890 | | - * @dev: iucv-based device |
---|
1891 | | - * |
---|
1892 | | - * disable iucv interrupts |
---|
1893 | | - * invoke callback function of the iucv-based driver |
---|
1894 | | - * shut down iucv, if no iucv-pathes are established anymore |
---|
1895 | | - */ |
---|
1896 | | -static int iucv_pm_freeze(struct device *dev) |
---|
1897 | | -{ |
---|
1898 | | - int cpu; |
---|
1899 | | - struct iucv_irq_list *p, *n; |
---|
1900 | | - int rc = 0; |
---|
1901 | | - |
---|
1902 | | -#ifdef CONFIG_PM_DEBUG |
---|
1903 | | - printk(KERN_WARNING "iucv_pm_freeze\n"); |
---|
1904 | | -#endif |
---|
1905 | | - if (iucv_pm_state != IUCV_PM_FREEZING) { |
---|
1906 | | - for_each_cpu(cpu, &iucv_irq_cpumask) |
---|
1907 | | - smp_call_function_single(cpu, iucv_block_cpu_almost, |
---|
1908 | | - NULL, 1); |
---|
1909 | | - cancel_work_sync(&iucv_work); |
---|
1910 | | - list_for_each_entry_safe(p, n, &iucv_work_queue, list) { |
---|
1911 | | - list_del_init(&p->list); |
---|
1912 | | - iucv_sever_pathid(p->data.ippathid, |
---|
1913 | | - iucv_error_no_listener); |
---|
1914 | | - kfree(p); |
---|
1915 | | - } |
---|
1916 | | - } |
---|
1917 | | - iucv_pm_state = IUCV_PM_FREEZING; |
---|
1918 | | - if (dev->driver && dev->driver->pm && dev->driver->pm->freeze) |
---|
1919 | | - rc = dev->driver->pm->freeze(dev); |
---|
1920 | | - if (iucv_path_table_empty()) |
---|
1921 | | - iucv_disable(); |
---|
1922 | | - return rc; |
---|
1923 | | -} |
---|
1924 | | - |
---|
1925 | | -/** |
---|
1926 | | - * iucv_pm_thaw() - Thaw PM callback |
---|
1927 | | - * @dev: iucv-based device |
---|
1928 | | - * |
---|
1929 | | - * make iucv ready for use again: allocate path table, declare interrupt buffers |
---|
1930 | | - * and enable iucv interrupts |
---|
1931 | | - * invoke callback function of the iucv-based driver |
---|
1932 | | - */ |
---|
1933 | | -static int iucv_pm_thaw(struct device *dev) |
---|
1934 | | -{ |
---|
1935 | | - int rc = 0; |
---|
1936 | | - |
---|
1937 | | -#ifdef CONFIG_PM_DEBUG |
---|
1938 | | - printk(KERN_WARNING "iucv_pm_thaw\n"); |
---|
1939 | | -#endif |
---|
1940 | | - iucv_pm_state = IUCV_PM_THAWING; |
---|
1941 | | - if (!iucv_path_table) { |
---|
1942 | | - rc = iucv_enable(); |
---|
1943 | | - if (rc) |
---|
1944 | | - goto out; |
---|
1945 | | - } |
---|
1946 | | - if (cpumask_empty(&iucv_irq_cpumask)) { |
---|
1947 | | - if (iucv_nonsmp_handler) |
---|
1948 | | - /* enable interrupts on one cpu */ |
---|
1949 | | - iucv_allow_cpu(NULL); |
---|
1950 | | - else |
---|
1951 | | - /* enable interrupts on all cpus */ |
---|
1952 | | - iucv_setmask_mp(); |
---|
1953 | | - } |
---|
1954 | | - if (dev->driver && dev->driver->pm && dev->driver->pm->thaw) |
---|
1955 | | - rc = dev->driver->pm->thaw(dev); |
---|
1956 | | -out: |
---|
1957 | | - return rc; |
---|
1958 | | -} |
---|
1959 | | - |
---|
1960 | | -/** |
---|
1961 | | - * iucv_pm_restore() - Restore PM callback |
---|
1962 | | - * @dev: iucv-based device |
---|
1963 | | - * |
---|
1964 | | - * make iucv ready for use again: allocate path table, declare interrupt buffers |
---|
1965 | | - * and enable iucv interrupts |
---|
1966 | | - * invoke callback function of the iucv-based driver |
---|
1967 | | - */ |
---|
1968 | | -static int iucv_pm_restore(struct device *dev) |
---|
1969 | | -{ |
---|
1970 | | - int rc = 0; |
---|
1971 | | - |
---|
1972 | | -#ifdef CONFIG_PM_DEBUG |
---|
1973 | | - printk(KERN_WARNING "iucv_pm_restore %p\n", iucv_path_table); |
---|
1974 | | -#endif |
---|
1975 | | - if ((iucv_pm_state != IUCV_PM_RESTORING) && iucv_path_table) |
---|
1976 | | - pr_warn("Suspending Linux did not completely close all IUCV connections\n"); |
---|
1977 | | - iucv_pm_state = IUCV_PM_RESTORING; |
---|
1978 | | - if (cpumask_empty(&iucv_irq_cpumask)) { |
---|
1979 | | - rc = iucv_query_maxconn(); |
---|
1980 | | - rc = iucv_enable(); |
---|
1981 | | - if (rc) |
---|
1982 | | - goto out; |
---|
1983 | | - } |
---|
1984 | | - if (dev->driver && dev->driver->pm && dev->driver->pm->restore) |
---|
1985 | | - rc = dev->driver->pm->restore(dev); |
---|
1986 | | -out: |
---|
1987 | | - return rc; |
---|
1988 | 1785 | } |
---|
1989 | 1786 | |
---|
1990 | 1787 | struct iucv_interface iucv_if = { |
---|