Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * PCI I/O adapter configuration related functions.
0004  *
0005  * Copyright IBM Corp. 2016
0006  */
0007 #define KMSG_COMPONENT "sclp_cmd"
0008 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0009 
0010 #include <linux/completion.h>
0011 #include <linux/export.h>
0012 #include <linux/mutex.h>
0013 #include <linux/errno.h>
0014 #include <linux/slab.h>
0015 #include <linux/init.h>
0016 #include <linux/err.h>
0017 
0018 #include <asm/sclp.h>
0019 
0020 #include "sclp.h"
0021 
0022 #define SCLP_CMDW_CONFIGURE_PCI         0x001a0001
0023 #define SCLP_CMDW_DECONFIGURE_PCI       0x001b0001
0024 
0025 #define SCLP_ATYPE_PCI              2
0026 
0027 #define SCLP_ERRNOTIFY_AQ_RESET         0
0028 #define SCLP_ERRNOTIFY_AQ_REPAIR        1
0029 #define SCLP_ERRNOTIFY_AQ_INFO_LOG      2
0030 
0031 static DEFINE_MUTEX(sclp_pci_mutex);
0032 static struct sclp_register sclp_pci_event = {
0033     .send_mask = EVTYP_ERRNOTIFY_MASK,
0034 };
0035 
0036 struct err_notify_evbuf {
0037     struct evbuf_header header;
0038     u8 action;
0039     u8 atype;
0040     u32 fh;
0041     u32 fid;
0042     u8 data[];
0043 } __packed;
0044 
0045 struct err_notify_sccb {
0046     struct sccb_header header;
0047     struct err_notify_evbuf evbuf;
0048 } __packed;
0049 
0050 struct pci_cfg_sccb {
0051     struct sccb_header header;
0052     u8 atype;       /* adapter type */
0053     u8 reserved1;
0054     u16 reserved2;
0055     u32 aid;        /* adapter identifier */
0056 } __packed;
0057 
0058 static int do_pci_configure(sclp_cmdw_t cmd, u32 fid)
0059 {
0060     struct pci_cfg_sccb *sccb;
0061     int rc;
0062 
0063     if (!SCLP_HAS_PCI_RECONFIG)
0064         return -EOPNOTSUPP;
0065 
0066     sccb = (struct pci_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
0067     if (!sccb)
0068         return -ENOMEM;
0069 
0070     sccb->header.length = PAGE_SIZE;
0071     sccb->atype = SCLP_ATYPE_PCI;
0072     sccb->aid = fid;
0073     rc = sclp_sync_request(cmd, sccb);
0074     if (rc)
0075         goto out;
0076     switch (sccb->header.response_code) {
0077     case 0x0020:
0078     case 0x0120:
0079         break;
0080     default:
0081         pr_warn("configure PCI I/O adapter failed: cmd=0x%08x  response=0x%04x\n",
0082             cmd, sccb->header.response_code);
0083         rc = -EIO;
0084         break;
0085     }
0086 out:
0087     free_page((unsigned long) sccb);
0088     return rc;
0089 }
0090 
0091 int sclp_pci_configure(u32 fid)
0092 {
0093     return do_pci_configure(SCLP_CMDW_CONFIGURE_PCI, fid);
0094 }
0095 EXPORT_SYMBOL(sclp_pci_configure);
0096 
0097 int sclp_pci_deconfigure(u32 fid)
0098 {
0099     return do_pci_configure(SCLP_CMDW_DECONFIGURE_PCI, fid);
0100 }
0101 EXPORT_SYMBOL(sclp_pci_deconfigure);
0102 
0103 static void sclp_pci_callback(struct sclp_req *req, void *data)
0104 {
0105     struct completion *completion = data;
0106 
0107     complete(completion);
0108 }
0109 
0110 static int sclp_pci_check_report(struct zpci_report_error_header *report)
0111 {
0112     if (report->version != 1)
0113         return -EINVAL;
0114 
0115     switch (report->action) {
0116     case SCLP_ERRNOTIFY_AQ_RESET:
0117     case SCLP_ERRNOTIFY_AQ_REPAIR:
0118     case SCLP_ERRNOTIFY_AQ_INFO_LOG:
0119         break;
0120     default:
0121         return -EINVAL;
0122     }
0123 
0124     if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb)))
0125         return -EINVAL;
0126 
0127     return 0;
0128 }
0129 
0130 int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid)
0131 {
0132     DECLARE_COMPLETION_ONSTACK(completion);
0133     struct err_notify_sccb *sccb;
0134     struct sclp_req req;
0135     int ret;
0136 
0137     ret = sclp_pci_check_report(report);
0138     if (ret)
0139         return ret;
0140 
0141     mutex_lock(&sclp_pci_mutex);
0142     ret = sclp_register(&sclp_pci_event);
0143     if (ret)
0144         goto out_unlock;
0145 
0146     if (!(sclp_pci_event.sclp_receive_mask & EVTYP_ERRNOTIFY_MASK)) {
0147         ret = -EOPNOTSUPP;
0148         goto out_unregister;
0149     }
0150 
0151     sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
0152     if (!sccb) {
0153         ret = -ENOMEM;
0154         goto out_unregister;
0155     }
0156 
0157     memset(&req, 0, sizeof(req));
0158     req.callback_data = &completion;
0159     req.callback = sclp_pci_callback;
0160     req.command = SCLP_CMDW_WRITE_EVENT_DATA;
0161     req.status = SCLP_REQ_FILLED;
0162     req.sccb = sccb;
0163 
0164     sccb->evbuf.header.length = sizeof(sccb->evbuf) + report->length;
0165     sccb->evbuf.header.type = EVTYP_ERRNOTIFY;
0166     sccb->header.length = sizeof(sccb->header) + sccb->evbuf.header.length;
0167 
0168     sccb->evbuf.action = report->action;
0169     sccb->evbuf.atype = SCLP_ATYPE_PCI;
0170     sccb->evbuf.fh = fh;
0171     sccb->evbuf.fid = fid;
0172 
0173     memcpy(sccb->evbuf.data, report->data, report->length);
0174 
0175     ret = sclp_add_request(&req);
0176     if (ret)
0177         goto out_free_req;
0178 
0179     wait_for_completion(&completion);
0180     if (req.status != SCLP_REQ_DONE) {
0181         pr_warn("request failed (status=0x%02x)\n",
0182             req.status);
0183         ret = -EIO;
0184         goto out_free_req;
0185     }
0186 
0187     if (sccb->header.response_code != 0x0020) {
0188         pr_warn("request failed with response code 0x%x\n",
0189             sccb->header.response_code);
0190         ret = -EIO;
0191     }
0192 
0193 out_free_req:
0194     free_page((unsigned long) sccb);
0195 out_unregister:
0196     sclp_unregister(&sclp_pci_event);
0197 out_unlock:
0198     mutex_unlock(&sclp_pci_mutex);
0199     return ret;
0200 }