File Index
Files and directories
Sign in
FILE

sclp_pci.c

File preview with syntax highlighting.

linux-6.19.14/drivers/s390/char/sclp_pci.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * PCI I/O adapter configuration related functions.
  4 *
  5 * Copyright IBM Corp. 2016
  6 */
  7#define pr_fmt(fmt) "sclp_cmd: " fmt
  8
  9#include <linux/completion.h>
 10#include <linux/export.h>
 11#include <linux/mutex.h>
 12#include <linux/errno.h>
 13#include <linux/slab.h>
 14#include <linux/init.h>
 15#include <linux/err.h>
 16
 17#include <asm/sclp.h>
 18
 19#include "sclp.h"
 20
 21#define SCLP_CMDW_CONFIGURE_PCI			0x001a0001
 22#define SCLP_CMDW_DECONFIGURE_PCI		0x001b0001
 23
 24#define SCLP_ATYPE_PCI				2
 25
 26static DEFINE_MUTEX(sclp_pci_mutex);
 27static struct sclp_register sclp_pci_event = {
 28	.send_mask = EVTYP_ERRNOTIFY_MASK,
 29};
 30
 31struct pci_cfg_sccb {
 32	struct sccb_header header;
 33	u8 atype;		/* adapter type */
 34	u8 reserved1;
 35	u16 reserved2;
 36	u32 aid;		/* adapter identifier */
 37} __packed;
 38
 39static int do_pci_configure(sclp_cmdw_t cmd, u32 fid)
 40{
 41	struct pci_cfg_sccb *sccb;
 42	int rc;
 43
 44	if (!SCLP_HAS_PCI_RECONFIG)
 45		return -EOPNOTSUPP;
 46
 47	sccb = (struct pci_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
 48	if (!sccb)
 49		return -ENOMEM;
 50
 51	sccb->header.length = PAGE_SIZE;
 52	sccb->atype = SCLP_ATYPE_PCI;
 53	sccb->aid = fid;
 54	rc = sclp_sync_request(cmd, sccb);
 55	if (rc)
 56		goto out;
 57	switch (sccb->header.response_code) {
 58	case 0x0020:
 59	case 0x0120:
 60		break;
 61	default:
 62		pr_warn("configure PCI I/O adapter failed: cmd=0x%08x  response=0x%04x\n",
 63			cmd, sccb->header.response_code);
 64		rc = -EIO;
 65		break;
 66	}
 67out:
 68	free_page((unsigned long) sccb);
 69	return rc;
 70}
 71
 72int sclp_pci_configure(u32 fid)
 73{
 74	return do_pci_configure(SCLP_CMDW_CONFIGURE_PCI, fid);
 75}
 76EXPORT_SYMBOL(sclp_pci_configure);
 77
 78int sclp_pci_deconfigure(u32 fid)
 79{
 80	return do_pci_configure(SCLP_CMDW_DECONFIGURE_PCI, fid);
 81}
 82EXPORT_SYMBOL(sclp_pci_deconfigure);
 83
 84static void sclp_pci_callback(struct sclp_req *req, void *data)
 85{
 86	struct completion *completion = data;
 87
 88	complete(completion);
 89}
 90
 91static int sclp_pci_check_report(struct zpci_report_error_header *report)
 92{
 93	if (report->version != 1)
 94		return -EINVAL;
 95
 96	switch (report->action) {
 97	case SCLP_ERRNOTIFY_AQ_RESET:
 98	case SCLP_ERRNOTIFY_AQ_REPAIR:
 99	case SCLP_ERRNOTIFY_AQ_INFO_LOG:
100	case SCLP_ERRNOTIFY_AQ_OPTICS_DATA:
101		break;
102	default:
103		return -EINVAL;
104	}
105
106	if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb)))
107		return -EINVAL;
108
109	return 0;
110}
111
112int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid)
113{
114	DECLARE_COMPLETION_ONSTACK(completion);
115	struct err_notify_sccb *sccb;
116	struct sclp_req req;
117	int ret;
118
119	ret = sclp_pci_check_report(report);
120	if (ret)
121		return ret;
122
123	mutex_lock(&sclp_pci_mutex);
124	ret = sclp_register(&sclp_pci_event);
125	if (ret)
126		goto out_unlock;
127
128	if (!(sclp_pci_event.sclp_receive_mask & EVTYP_ERRNOTIFY_MASK)) {
129		ret = -EOPNOTSUPP;
130		goto out_unregister;
131	}
132
133	sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
134	if (!sccb) {
135		ret = -ENOMEM;
136		goto out_unregister;
137	}
138
139	memset(&req, 0, sizeof(req));
140	req.callback_data = &completion;
141	req.callback = sclp_pci_callback;
142	req.command = SCLP_CMDW_WRITE_EVENT_DATA;
143	req.status = SCLP_REQ_FILLED;
144	req.sccb = sccb;
145
146	sccb->evbuf.header.length = sizeof(sccb->evbuf) + report->length;
147	sccb->evbuf.header.type = EVTYP_ERRNOTIFY;
148	sccb->header.length = sizeof(sccb->header) + sccb->evbuf.header.length;
149
150	sccb->evbuf.action = report->action;
151	sccb->evbuf.atype = SCLP_ATYPE_PCI;
152	sccb->evbuf.fh = fh;
153	sccb->evbuf.fid = fid;
154
155	memcpy(sccb->evbuf.data, report->data, report->length);
156
157	ret = sclp_add_request(&req);
158	if (ret)
159		goto out_free_req;
160
161	wait_for_completion(&completion);
162	if (req.status != SCLP_REQ_DONE) {
163		pr_warn("request failed (status=0x%02x)\n",
164			req.status);
165		ret = -EIO;
166		goto out_free_req;
167	}
168
169	if (sccb->header.response_code != 0x0020) {
170		pr_warn("request failed with response code 0x%x\n",
171			sccb->header.response_code);
172		ret = -EIO;
173	}
174
175out_free_req:
176	free_page((unsigned long) sccb);
177out_unregister:
178	sclp_unregister(&sclp_pci_event);
179out_unlock:
180	mutex_unlock(&sclp_pci_mutex);
181	return ret;
182}
~/ Read-only file preview.