Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *  Copyright IBM Corp. 2012
  4 *
  5 *  Author(s):
  6 *    Jan Glauber <jang@linux.vnet.ibm.com>
  7 */
  8
  9#define KMSG_COMPONENT "zpci"
 10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 11
 12#include <linux/kernel.h>
 13#include <linux/pci.h>
 14#include <asm/pci_debug.h>
 15#include <asm/sclp.h>
 16
 17/* Content Code Description for PCI Function Error */
 18struct zpci_ccdf_err {
 19	u32 reserved1;
 20	u32 fh;				/* function handle */
 21	u32 fid;			/* function id */
 22	u32 ett		:  4;		/* expected table type */
 23	u32 mvn		: 12;		/* MSI vector number */
 24	u32 dmaas	:  8;		/* DMA address space */
 25	u32		:  6;
 26	u32 q		:  1;		/* event qualifier */
 27	u32 rw		:  1;		/* read/write */
 28	u64 faddr;			/* failing address */
 29	u32 reserved3;
 30	u16 reserved4;
 31	u16 pec;			/* PCI event code */
 32} __packed;
 33
 34/* Content Code Description for PCI Function Availability */
 35struct zpci_ccdf_avail {
 36	u32 reserved1;
 37	u32 fh;				/* function handle */
 38	u32 fid;			/* function id */
 39	u32 reserved2;
 40	u32 reserved3;
 41	u32 reserved4;
 42	u32 reserved5;
 43	u16 reserved6;
 44	u16 pec;			/* PCI event code */
 45} __packed;
 46
 47static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
 48{
 49	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
 50	struct pci_dev *pdev = NULL;
 51
 52	zpci_err("error CCDF:\n");
 53	zpci_err_hex(ccdf, sizeof(*ccdf));
 54
 55	if (zdev)
 56		pdev = pci_get_slot(zdev->bus, ZPCI_DEVFN);
 57
 58	pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n",
 59	       pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid);
 60
 61	if (!pdev)
 62		return;
 63
 64	pdev->error_state = pci_channel_io_perm_failure;
 65	pci_dev_put(pdev);
 66}
 67
 68void zpci_event_error(void *data)
 69{
 70	if (zpci_is_enabled())
 71		__zpci_event_error(data);
 72}
 73
 74static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
 75{
 76	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
 77	struct pci_dev *pdev = NULL;
 78	enum zpci_state state;
 79	int ret;
 80
 81	if (zdev)
 82		pdev = pci_get_slot(zdev->bus, ZPCI_DEVFN);
 83
 84	pr_info("%s: Event 0x%x reconfigured PCI function 0x%x\n",
 85		pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid);
 86	zpci_err("avail CCDF:\n");
 87	zpci_err_hex(ccdf, sizeof(*ccdf));
 88
 89	switch (ccdf->pec) {
 90	case 0x0301: /* Reserved|Standby -> Configured */
 91		if (!zdev) {
 92			ret = clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
 93			if (ret)
 94				break;
 95			zdev = get_zdev_by_fid(ccdf->fid);
 96		}
 97		if (!zdev || zdev->state != ZPCI_FN_STATE_STANDBY)
 98			break;
 99		zdev->state = ZPCI_FN_STATE_CONFIGURED;
100		zdev->fh = ccdf->fh;
101		ret = zpci_enable_device(zdev);
102		if (ret)
103			break;
104		pci_lock_rescan_remove();
105		pci_rescan_bus(zdev->bus);
106		pci_unlock_rescan_remove();
107		break;
108	case 0x0302: /* Reserved -> Standby */
109		if (!zdev)
110			clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
111		break;
112	case 0x0303: /* Deconfiguration requested */
113		if (!zdev)
114			break;
115		if (pdev)
116			pci_stop_and_remove_bus_device_locked(pdev);
117
118		ret = zpci_disable_device(zdev);
119		if (ret)
120			break;
121
122		ret = sclp_pci_deconfigure(zdev->fid);
123		zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret);
124		if (!ret)
125			zdev->state = ZPCI_FN_STATE_STANDBY;
126
127		break;
128	case 0x0304: /* Configured -> Standby|Reserved */
129		if (!zdev)
130			break;
131		if (pdev) {
132			/* Give the driver a hint that the function is
133			 * already unusable. */
134			pdev->error_state = pci_channel_io_perm_failure;
135			pci_stop_and_remove_bus_device_locked(pdev);
136		}
137
138		zdev->fh = ccdf->fh;
139		zpci_disable_device(zdev);
140		zdev->state = ZPCI_FN_STATE_STANDBY;
141		if (!clp_get_state(ccdf->fid, &state) &&
142		    state == ZPCI_FN_STATE_RESERVED) {
143			zpci_remove_device(zdev);
144		}
145		break;
146	case 0x0306: /* 0x308 or 0x302 for multiple devices */
147		clp_rescan_pci_devices();
148		break;
149	case 0x0308: /* Standby -> Reserved */
150		if (!zdev)
151			break;
152		zpci_remove_device(zdev);
153		break;
154	default:
155		break;
156	}
157	pci_dev_put(pdev);
158}
159
160void zpci_event_availability(void *data)
161{
162	if (zpci_is_enabled())
163		__zpci_event_availability(data);
164}