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