linux/arch/s390/pci/pci_event.c
<<
>>
Prefs
   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/pci_dma.h>
  16#include <asm/sclp.h>
  17
  18#include "pci_bus.h"
  19
  20/* Content Code Description for PCI Function Error */
  21struct zpci_ccdf_err {
  22        u32 reserved1;
  23        u32 fh;                         /* function handle */
  24        u32 fid;                        /* function id */
  25        u32 ett         :  4;           /* expected table type */
  26        u32 mvn         : 12;           /* MSI vector number */
  27        u32 dmaas       :  8;           /* DMA address space */
  28        u32             :  6;
  29        u32 q           :  1;           /* event qualifier */
  30        u32 rw          :  1;           /* read/write */
  31        u64 faddr;                      /* failing address */
  32        u32 reserved3;
  33        u16 reserved4;
  34        u16 pec;                        /* PCI event code */
  35} __packed;
  36
  37/* Content Code Description for PCI Function Availability */
  38struct zpci_ccdf_avail {
  39        u32 reserved1;
  40        u32 fh;                         /* function handle */
  41        u32 fid;                        /* function id */
  42        u32 reserved2;
  43        u32 reserved3;
  44        u32 reserved4;
  45        u32 reserved5;
  46        u16 reserved6;
  47        u16 pec;                        /* PCI event code */
  48} __packed;
  49
  50static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
  51{
  52        struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
  53        struct pci_dev *pdev = NULL;
  54
  55        zpci_err("error CCDF:\n");
  56        zpci_err_hex(ccdf, sizeof(*ccdf));
  57
  58        if (zdev)
  59                pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
  60
  61        pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n",
  62               pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid);
  63
  64        if (!pdev)
  65                return;
  66
  67        pdev->error_state = pci_channel_io_perm_failure;
  68        pci_dev_put(pdev);
  69}
  70
  71void zpci_event_error(void *data)
  72{
  73        if (zpci_is_enabled())
  74                __zpci_event_error(data);
  75}
  76
  77static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh)
  78{
  79        zdev->fh = fh;
  80        /* Give the driver a hint that the function is
  81         * already unusable.
  82         */
  83        zpci_bus_remove_device(zdev, true);
  84        /* Even though the device is already gone we still
  85         * need to free zPCI resources as part of the disable.
  86         */
  87        if (zdev->dma_table)
  88                zpci_dma_exit_device(zdev);
  89        if (zdev_enabled(zdev))
  90                zpci_disable_device(zdev);
  91        zdev->state = ZPCI_FN_STATE_STANDBY;
  92}
  93
  94static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
  95{
  96        struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
  97        enum zpci_state state;
  98
  99        zpci_err("avail CCDF:\n");
 100        zpci_err_hex(ccdf, sizeof(*ccdf));
 101
 102        switch (ccdf->pec) {
 103        case 0x0301: /* Reserved|Standby -> Configured */
 104                if (!zdev) {
 105                        zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_CONFIGURED);
 106                        if (IS_ERR(zdev))
 107                                break;
 108                } else {
 109                        /* the configuration request may be stale */
 110                        if (zdev->state != ZPCI_FN_STATE_STANDBY)
 111                                break;
 112                        zdev->state = ZPCI_FN_STATE_CONFIGURED;
 113                }
 114                zpci_scan_configured_device(zdev, ccdf->fh);
 115                break;
 116        case 0x0302: /* Reserved -> Standby */
 117                if (!zdev)
 118                        zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_STANDBY);
 119                else
 120                        zdev->fh = ccdf->fh;
 121                break;
 122        case 0x0303: /* Deconfiguration requested */
 123                if (zdev) {
 124                        /* The event may have been queued before we confirgured
 125                         * the device.
 126                         */
 127                        if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
 128                                break;
 129                        zdev->fh = ccdf->fh;
 130                        zpci_deconfigure_device(zdev);
 131                }
 132                break;
 133        case 0x0304: /* Configured -> Standby|Reserved */
 134                if (zdev) {
 135                        /* The event may have been queued before we confirgured
 136                         * the device.:
 137                         */
 138                        if (zdev->state == ZPCI_FN_STATE_CONFIGURED)
 139                                zpci_event_hard_deconfigured(zdev, ccdf->fh);
 140                        /* The 0x0304 event may immediately reserve the device */
 141                        if (!clp_get_state(zdev->fid, &state) &&
 142                            state == ZPCI_FN_STATE_RESERVED) {
 143                                zpci_device_reserved(zdev);
 144                        }
 145                }
 146                break;
 147        case 0x0306: /* 0x308 or 0x302 for multiple devices */
 148                zpci_remove_reserved_devices();
 149                clp_scan_pci_devices();
 150                break;
 151        case 0x0308: /* Standby -> Reserved */
 152                if (!zdev)
 153                        break;
 154                zpci_device_reserved(zdev);
 155                break;
 156        default:
 157                break;
 158        }
 159}
 160
 161void zpci_event_availability(void *data)
 162{
 163        if (zpci_is_enabled())
 164                __zpci_event_availability(data);
 165}
 166