diff options
-rw-r--r-- | arch/s390/include/asm/pci.h | 11 | ||||
-rw-r--r-- | arch/s390/include/asm/sclp.h | 2 | ||||
-rw-r--r-- | arch/s390/pci/pci.c | 9 | ||||
-rw-r--r-- | drivers/pci/hotplug/Kconfig | 11 | ||||
-rw-r--r-- | drivers/pci/hotplug/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/s390_pci_hpc.c | 252 | ||||
-rw-r--r-- | drivers/s390/char/sclp.h | 3 | ||||
-rw-r--r-- | drivers/s390/char/sclp_cmd.c | 64 |
8 files changed, 351 insertions, 2 deletions
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index d3597dcfec3..48ce434d6fd 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h | |||
@@ -95,6 +95,11 @@ struct zpci_dev { | |||
95 | enum pci_bus_speed max_bus_speed; | 95 | enum pci_bus_speed max_bus_speed; |
96 | }; | 96 | }; |
97 | 97 | ||
98 | struct pci_hp_callback_ops { | ||
99 | int (*create_slot) (struct zpci_dev *zdev); | ||
100 | void (*remove_slot) (struct zpci_dev *zdev); | ||
101 | }; | ||
102 | |||
98 | static inline bool zdev_enabled(struct zpci_dev *zdev) | 103 | static inline bool zdev_enabled(struct zpci_dev *zdev) |
99 | { | 104 | { |
100 | return (zdev->fh & (1UL << 31)) ? true : false; | 105 | return (zdev->fh & (1UL << 31)) ? true : false; |
@@ -140,4 +145,10 @@ bool zpci_fid_present(u32); | |||
140 | int zpci_dma_init(void); | 145 | int zpci_dma_init(void); |
141 | void zpci_dma_exit(void); | 146 | void zpci_dma_exit(void); |
142 | 147 | ||
148 | /* Hotplug */ | ||
149 | extern struct mutex zpci_list_lock; | ||
150 | extern struct list_head zpci_list; | ||
151 | extern struct pci_hp_callback_ops hotplug_ops; | ||
152 | extern unsigned int pci_probe; | ||
153 | |||
143 | #endif | 154 | #endif |
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index e62a555557e..833788693f0 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h | |||
@@ -55,5 +55,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info); | |||
55 | void sclp_get_ipl_info(struct sclp_ipl_info *info); | 55 | void sclp_get_ipl_info(struct sclp_ipl_info *info); |
56 | bool sclp_has_linemode(void); | 56 | bool sclp_has_linemode(void); |
57 | bool sclp_has_vt220(void); | 57 | bool sclp_has_vt220(void); |
58 | int sclp_pci_configure(u32 fid); | ||
59 | int sclp_pci_deconfigure(u32 fid); | ||
58 | 60 | ||
59 | #endif /* _ASM_S390_SCLP_H */ | 61 | #endif /* _ASM_S390_SCLP_H */ |
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 5a2ef9e75c9..c523594a6d4 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
@@ -47,7 +47,12 @@ | |||
47 | 47 | ||
48 | /* list of all detected zpci devices */ | 48 | /* list of all detected zpci devices */ |
49 | LIST_HEAD(zpci_list); | 49 | LIST_HEAD(zpci_list); |
50 | EXPORT_SYMBOL_GPL(zpci_list); | ||
50 | DEFINE_MUTEX(zpci_list_lock); | 51 | DEFINE_MUTEX(zpci_list_lock); |
52 | EXPORT_SYMBOL_GPL(zpci_list_lock); | ||
53 | |||
54 | struct pci_hp_callback_ops hotplug_ops; | ||
55 | EXPORT_SYMBOL_GPL(hotplug_ops); | ||
51 | 56 | ||
52 | static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES); | 57 | static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES); |
53 | static DEFINE_SPINLOCK(zpci_domain_lock); | 58 | static DEFINE_SPINLOCK(zpci_domain_lock); |
@@ -935,6 +940,8 @@ int zpci_create_device(struct zpci_dev *zdev) | |||
935 | 940 | ||
936 | mutex_lock(&zpci_list_lock); | 941 | mutex_lock(&zpci_list_lock); |
937 | list_add_tail(&zdev->entry, &zpci_list); | 942 | list_add_tail(&zdev->entry, &zpci_list); |
943 | if (hotplug_ops.create_slot) | ||
944 | hotplug_ops.create_slot(zdev); | ||
938 | mutex_unlock(&zpci_list_lock); | 945 | mutex_unlock(&zpci_list_lock); |
939 | 946 | ||
940 | if (zdev->state == ZPCI_FN_STATE_STANDBY) | 947 | if (zdev->state == ZPCI_FN_STATE_STANDBY) |
@@ -948,6 +955,8 @@ int zpci_create_device(struct zpci_dev *zdev) | |||
948 | out_start: | 955 | out_start: |
949 | mutex_lock(&zpci_list_lock); | 956 | mutex_lock(&zpci_list_lock); |
950 | list_del(&zdev->entry); | 957 | list_del(&zdev->entry); |
958 | if (hotplug_ops.remove_slot) | ||
959 | hotplug_ops.remove_slot(zdev); | ||
951 | mutex_unlock(&zpci_list_lock); | 960 | mutex_unlock(&zpci_list_lock); |
952 | out_bus: | 961 | out_bus: |
953 | zpci_free_domain(zdev); | 962 | zpci_free_domain(zdev); |
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index b0e46dede1a..13e9e63a726 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig | |||
@@ -151,4 +151,15 @@ config HOTPLUG_PCI_SGI | |||
151 | 151 | ||
152 | When in doubt, say N. | 152 | When in doubt, say N. |
153 | 153 | ||
154 | config HOTPLUG_PCI_S390 | ||
155 | tristate "System z PCI Hotplug Support" | ||
156 | depends on S390 && 64BIT | ||
157 | help | ||
158 | Say Y here if you want to use the System z PCI Hotplug | ||
159 | driver for PCI devices. Without this driver it is not | ||
160 | possible to access stand-by PCI functions nor to deconfigure | ||
161 | PCI functions. | ||
162 | |||
163 | When in doubt, say Y. | ||
164 | |||
154 | endif # HOTPLUG_PCI | 165 | endif # HOTPLUG_PCI |
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index c459cd4e39c..47ec8c80e16 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o | |||
18 | obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o | 18 | obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o |
19 | obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o | 19 | obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o |
20 | obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o | 20 | obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o |
21 | obj-$(CONFIG_HOTPLUG_PCI_S390) += s390_pci_hpc.o | ||
21 | 22 | ||
22 | # acpiphp_ibm extends acpiphp, so should be linked afterwards. | 23 | # acpiphp_ibm extends acpiphp, so should be linked afterwards. |
23 | 24 | ||
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c new file mode 100644 index 00000000000..dee68e0698e --- /dev/null +++ b/drivers/pci/hotplug/s390_pci_hpc.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * PCI Hot Plug Controller Driver for System z | ||
3 | * | ||
4 | * Copyright 2012 IBM Corp. | ||
5 | * | ||
6 | * Author(s): | ||
7 | * Jan Glauber <jang@linux.vnet.ibm.com> | ||
8 | */ | ||
9 | |||
10 | #define COMPONENT "zPCI hpc" | ||
11 | #define pr_fmt(fmt) COMPONENT ": " fmt | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/pci_hotplug.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <asm/sclp.h> | ||
20 | |||
21 | #define SLOT_NAME_SIZE 10 | ||
22 | static LIST_HEAD(s390_hotplug_slot_list); | ||
23 | |||
24 | MODULE_AUTHOR("Jan Glauber <jang@linux.vnet.ibm.com"); | ||
25 | MODULE_DESCRIPTION("Hot Plug PCI Controller for System z"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | |||
28 | static int zpci_fn_configured(enum zpci_state state) | ||
29 | { | ||
30 | return state == ZPCI_FN_STATE_CONFIGURED || | ||
31 | state == ZPCI_FN_STATE_ONLINE; | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * struct slot - slot information for each *physical* slot | ||
36 | */ | ||
37 | struct slot { | ||
38 | struct list_head slot_list; | ||
39 | struct hotplug_slot *hotplug_slot; | ||
40 | struct zpci_dev *zdev; | ||
41 | }; | ||
42 | |||
43 | static int enable_slot(struct hotplug_slot *hotplug_slot) | ||
44 | { | ||
45 | struct slot *slot = hotplug_slot->private; | ||
46 | int rc; | ||
47 | |||
48 | if (slot->zdev->state != ZPCI_FN_STATE_STANDBY) | ||
49 | return -EIO; | ||
50 | |||
51 | rc = sclp_pci_configure(slot->zdev->fid); | ||
52 | if (!rc) { | ||
53 | slot->zdev->state = ZPCI_FN_STATE_CONFIGURED; | ||
54 | /* automatically scan the device after is was configured */ | ||
55 | zpci_enable_device(slot->zdev); | ||
56 | zpci_scan_device(slot->zdev); | ||
57 | } | ||
58 | return rc; | ||
59 | } | ||
60 | |||
61 | static int disable_slot(struct hotplug_slot *hotplug_slot) | ||
62 | { | ||
63 | struct slot *slot = hotplug_slot->private; | ||
64 | int rc; | ||
65 | |||
66 | if (!zpci_fn_configured(slot->zdev->state)) | ||
67 | return -EIO; | ||
68 | |||
69 | /* TODO: we rely on the user to unbind/remove the device, is that plausible | ||
70 | * or do we need to trigger that here? | ||
71 | */ | ||
72 | rc = sclp_pci_deconfigure(slot->zdev->fid); | ||
73 | if (!rc) { | ||
74 | /* Fixme: better call List-PCI to find the disabled FH | ||
75 | for the FID since the FH should be opaque... */ | ||
76 | slot->zdev->fh &= 0x7fffffff; | ||
77 | slot->zdev->state = ZPCI_FN_STATE_STANDBY; | ||
78 | } | ||
79 | return rc; | ||
80 | } | ||
81 | |||
82 | static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) | ||
83 | { | ||
84 | struct slot *slot = hotplug_slot->private; | ||
85 | |||
86 | switch (slot->zdev->state) { | ||
87 | case ZPCI_FN_STATE_STANDBY: | ||
88 | *value = 0; | ||
89 | break; | ||
90 | default: | ||
91 | *value = 1; | ||
92 | break; | ||
93 | } | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) | ||
98 | { | ||
99 | /* if the slot exits it always contains a function */ | ||
100 | *value = 1; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static void release_slot(struct hotplug_slot *hotplug_slot) | ||
105 | { | ||
106 | struct slot *slot = hotplug_slot->private; | ||
107 | |||
108 | pr_debug("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot)); | ||
109 | kfree(slot->hotplug_slot->info); | ||
110 | kfree(slot->hotplug_slot); | ||
111 | kfree(slot); | ||
112 | } | ||
113 | |||
114 | static struct hotplug_slot_ops s390_hotplug_slot_ops = { | ||
115 | .enable_slot = enable_slot, | ||
116 | .disable_slot = disable_slot, | ||
117 | .get_power_status = get_power_status, | ||
118 | .get_adapter_status = get_adapter_status, | ||
119 | }; | ||
120 | |||
121 | static int init_pci_slot(struct zpci_dev *zdev) | ||
122 | { | ||
123 | struct hotplug_slot *hotplug_slot; | ||
124 | struct hotplug_slot_info *info; | ||
125 | char name[SLOT_NAME_SIZE]; | ||
126 | struct slot *slot; | ||
127 | int rc; | ||
128 | |||
129 | if (!zdev) | ||
130 | return 0; | ||
131 | |||
132 | slot = kzalloc(sizeof(*slot), GFP_KERNEL); | ||
133 | if (!slot) | ||
134 | goto error; | ||
135 | |||
136 | hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); | ||
137 | if (!hotplug_slot) | ||
138 | goto error_hp; | ||
139 | hotplug_slot->private = slot; | ||
140 | |||
141 | slot->hotplug_slot = hotplug_slot; | ||
142 | slot->zdev = zdev; | ||
143 | |||
144 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
145 | if (!info) | ||
146 | goto error_info; | ||
147 | hotplug_slot->info = info; | ||
148 | |||
149 | hotplug_slot->ops = &s390_hotplug_slot_ops; | ||
150 | hotplug_slot->release = &release_slot; | ||
151 | |||
152 | get_power_status(hotplug_slot, &info->power_status); | ||
153 | get_adapter_status(hotplug_slot, &info->adapter_status); | ||
154 | |||
155 | snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid); | ||
156 | rc = pci_hp_register(slot->hotplug_slot, zdev->bus, | ||
157 | ZPCI_DEVFN, name); | ||
158 | if (rc) { | ||
159 | pr_err("pci_hp_register failed with error %d\n", rc); | ||
160 | goto error_reg; | ||
161 | } | ||
162 | list_add(&slot->slot_list, &s390_hotplug_slot_list); | ||
163 | return 0; | ||
164 | |||
165 | error_reg: | ||
166 | kfree(info); | ||
167 | error_info: | ||
168 | kfree(hotplug_slot); | ||
169 | error_hp: | ||
170 | kfree(slot); | ||
171 | error: | ||
172 | return -ENOMEM; | ||
173 | } | ||
174 | |||
175 | static int __init init_pci_slots(void) | ||
176 | { | ||
177 | struct zpci_dev *zdev; | ||
178 | int device = 0; | ||
179 | |||
180 | /* | ||
181 | * Create a structure for each slot, and register that slot | ||
182 | * with the pci_hotplug subsystem. | ||
183 | */ | ||
184 | mutex_lock(&zpci_list_lock); | ||
185 | list_for_each_entry(zdev, &zpci_list, entry) { | ||
186 | init_pci_slot(zdev); | ||
187 | device++; | ||
188 | } | ||
189 | |||
190 | mutex_unlock(&zpci_list_lock); | ||
191 | return (device) ? 0 : -ENODEV; | ||
192 | } | ||
193 | |||
194 | static void exit_pci_slot(struct zpci_dev *zdev) | ||
195 | { | ||
196 | struct list_head *tmp, *n; | ||
197 | struct slot *slot; | ||
198 | |||
199 | list_for_each_safe(tmp, n, &s390_hotplug_slot_list) { | ||
200 | slot = list_entry(tmp, struct slot, slot_list); | ||
201 | if (slot->zdev != zdev) | ||
202 | continue; | ||
203 | list_del(&slot->slot_list); | ||
204 | pci_hp_deregister(slot->hotplug_slot); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static void __exit exit_pci_slots(void) | ||
209 | { | ||
210 | struct list_head *tmp, *n; | ||
211 | struct slot *slot; | ||
212 | |||
213 | /* | ||
214 | * Unregister all of our slots with the pci_hotplug subsystem. | ||
215 | * Memory will be freed in release_slot() callback after slot's | ||
216 | * lifespan is finished. | ||
217 | */ | ||
218 | list_for_each_safe(tmp, n, &s390_hotplug_slot_list) { | ||
219 | slot = list_entry(tmp, struct slot, slot_list); | ||
220 | list_del(&slot->slot_list); | ||
221 | pci_hp_deregister(slot->hotplug_slot); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static int __init pci_hotplug_s390_init(void) | ||
226 | { | ||
227 | /* | ||
228 | * Do specific initialization stuff for your driver here | ||
229 | * like initializing your controller hardware (if any) and | ||
230 | * determining the number of slots you have in the system | ||
231 | * right now. | ||
232 | */ | ||
233 | |||
234 | if (!pci_probe) | ||
235 | return -EOPNOTSUPP; | ||
236 | |||
237 | /* register callbacks for slot handling from arch code */ | ||
238 | mutex_lock(&zpci_list_lock); | ||
239 | hotplug_ops.create_slot = init_pci_slot; | ||
240 | hotplug_ops.remove_slot = exit_pci_slot; | ||
241 | mutex_unlock(&zpci_list_lock); | ||
242 | pr_info("registered hotplug slot callbacks\n"); | ||
243 | return init_pci_slots(); | ||
244 | } | ||
245 | |||
246 | static void __exit pci_hotplug_s390_exit(void) | ||
247 | { | ||
248 | exit_pci_slots(); | ||
249 | } | ||
250 | |||
251 | module_init(pci_hotplug_s390_init); | ||
252 | module_exit(pci_hotplug_s390_exit); | ||
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index d7e97ae9ef6..25bcd4c0ed8 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright IBM Corp. 1999, 2009 | 2 | * Copyright IBM Corp. 1999,2012 |
3 | * | 3 | * |
4 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | 4 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
5 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 5 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
@@ -103,6 +103,7 @@ extern u64 sclp_facilities; | |||
103 | #define SCLP_HAS_CHP_RECONFIG (sclp_facilities & 0x2000000000000000ULL) | 103 | #define SCLP_HAS_CHP_RECONFIG (sclp_facilities & 0x2000000000000000ULL) |
104 | #define SCLP_HAS_CPU_INFO (sclp_facilities & 0x0800000000000000ULL) | 104 | #define SCLP_HAS_CPU_INFO (sclp_facilities & 0x0800000000000000ULL) |
105 | #define SCLP_HAS_CPU_RECONFIG (sclp_facilities & 0x0400000000000000ULL) | 105 | #define SCLP_HAS_CPU_RECONFIG (sclp_facilities & 0x0400000000000000ULL) |
106 | #define SCLP_HAS_PCI_RECONFIG (sclp_facilities & 0x0000000040000000ULL) | ||
106 | 107 | ||
107 | 108 | ||
108 | struct gds_subvector { | 109 | struct gds_subvector { |
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 0dfa88a3011..c44d13f607b 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright IBM Corp. 2007, 2009 | 2 | * Copyright IBM Corp. 2007,2012 |
3 | * | 3 | * |
4 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, | 4 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, |
5 | * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 5 | * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> |
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/export.h> | ||
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
16 | #include <linux/string.h> | 17 | #include <linux/string.h> |
17 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
@@ -701,6 +702,67 @@ __initcall(sclp_detect_standby_memory); | |||
701 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 702 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
702 | 703 | ||
703 | /* | 704 | /* |
705 | * PCI I/O adapter configuration related functions. | ||
706 | */ | ||
707 | #define SCLP_CMDW_CONFIGURE_PCI 0x001a0001 | ||
708 | #define SCLP_CMDW_DECONFIGURE_PCI 0x001b0001 | ||
709 | |||
710 | #define SCLP_RECONFIG_PCI_ATPYE 2 | ||
711 | |||
712 | struct pci_cfg_sccb { | ||
713 | struct sccb_header header; | ||
714 | u8 atype; /* adapter type */ | ||
715 | u8 reserved1; | ||
716 | u16 reserved2; | ||
717 | u32 aid; /* adapter identifier */ | ||
718 | } __packed; | ||
719 | |||
720 | static int do_pci_configure(sclp_cmdw_t cmd, u32 fid) | ||
721 | { | ||
722 | struct pci_cfg_sccb *sccb; | ||
723 | int rc; | ||
724 | |||
725 | if (!SCLP_HAS_PCI_RECONFIG) | ||
726 | return -EOPNOTSUPP; | ||
727 | |||
728 | sccb = (struct pci_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
729 | if (!sccb) | ||
730 | return -ENOMEM; | ||
731 | |||
732 | sccb->header.length = PAGE_SIZE; | ||
733 | sccb->atype = SCLP_RECONFIG_PCI_ATPYE; | ||
734 | sccb->aid = fid; | ||
735 | rc = do_sync_request(cmd, sccb); | ||
736 | if (rc) | ||
737 | goto out; | ||
738 | switch (sccb->header.response_code) { | ||
739 | case 0x0020: | ||
740 | case 0x0120: | ||
741 | break; | ||
742 | default: | ||
743 | pr_warn("configure PCI I/O adapter failed: cmd=0x%08x response=0x%04x\n", | ||
744 | cmd, sccb->header.response_code); | ||
745 | rc = -EIO; | ||
746 | break; | ||
747 | } | ||
748 | out: | ||
749 | free_page((unsigned long) sccb); | ||
750 | return rc; | ||
751 | } | ||
752 | |||
753 | int sclp_pci_configure(u32 fid) | ||
754 | { | ||
755 | return do_pci_configure(SCLP_CMDW_CONFIGURE_PCI, fid); | ||
756 | } | ||
757 | EXPORT_SYMBOL(sclp_pci_configure); | ||
758 | |||
759 | int sclp_pci_deconfigure(u32 fid) | ||
760 | { | ||
761 | return do_pci_configure(SCLP_CMDW_DECONFIGURE_PCI, fid); | ||
762 | } | ||
763 | EXPORT_SYMBOL(sclp_pci_deconfigure); | ||
764 | |||
765 | /* | ||
704 | * Channel path configuration related functions. | 766 | * Channel path configuration related functions. |
705 | */ | 767 | */ |
706 | 768 | ||