| .. | .. |
|---|
| 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 | |
|---|
| .. | .. |
|---|
| 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 = { |
|---|