linux/drivers/char/ipmi/ipmi_si_pci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * ipmi_si_pci.c
   4 *
   5 * Handling for IPMI devices on the PCI bus.
   6 */
   7#include <linux/module.h>
   8#include <linux/pci.h>
   9#include "ipmi_si.h"
  10
  11#define PFX "ipmi_pci: "
  12
  13static bool pci_registered;
  14
  15static bool si_trypci = true;
  16
  17module_param_named(trypci, si_trypci, bool, 0);
  18MODULE_PARM_DESC(trypci, "Setting this to zero will disable the"
  19                 " default scan of the interfaces identified via pci");
  20
  21#define PCI_CLASS_SERIAL_IPMI           0x0c07
  22#define PCI_CLASS_SERIAL_IPMI_SMIC      0x0c0700
  23#define PCI_CLASS_SERIAL_IPMI_KCS       0x0c0701
  24#define PCI_CLASS_SERIAL_IPMI_BT        0x0c0702
  25
  26#define PCI_DEVICE_ID_HP_MMC 0x121A
  27
  28static void ipmi_pci_cleanup(struct si_sm_io *io)
  29{
  30        struct pci_dev *pdev = io->addr_source_data;
  31
  32        pci_disable_device(pdev);
  33}
  34
  35static int ipmi_pci_probe_regspacing(struct si_sm_io *io)
  36{
  37        if (io->si_type == SI_KCS) {
  38                unsigned char   status;
  39                int             regspacing;
  40
  41                io->regsize = DEFAULT_REGSIZE;
  42                io->regshift = 0;
  43
  44                /* detect 1, 4, 16byte spacing */
  45                for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) {
  46                        io->regspacing = regspacing;
  47                        if (io->io_setup(io)) {
  48                                dev_err(io->dev,
  49                                        "Could not setup I/O space\n");
  50                                return DEFAULT_REGSPACING;
  51                        }
  52                        /* write invalid cmd */
  53                        io->outputb(io, 1, 0x10);
  54                        /* read status back */
  55                        status = io->inputb(io, 1);
  56                        io->io_cleanup(io);
  57                        if (status)
  58                                return regspacing;
  59                        regspacing *= 4;
  60                }
  61        }
  62        return DEFAULT_REGSPACING;
  63}
  64
  65static struct pci_device_id ipmi_pci_blacklist[] = {
  66        /*
  67         * This is a "Virtual IPMI device", whatever that is.  It appears
  68         * as a KCS device by the class, but it is not one.
  69         */
  70        { PCI_VDEVICE(REALTEK, 0x816c) },
  71        { 0, }
  72};
  73
  74static int ipmi_pci_probe(struct pci_dev *pdev,
  75                                    const struct pci_device_id *ent)
  76{
  77        int rv;
  78        struct si_sm_io io;
  79
  80        if (pci_match_id(ipmi_pci_blacklist, pdev))
  81                return -ENODEV;
  82
  83        memset(&io, 0, sizeof(io));
  84        io.addr_source = SI_PCI;
  85        dev_info(&pdev->dev, "probing via PCI");
  86
  87        switch (pdev->class) {
  88        case PCI_CLASS_SERIAL_IPMI_SMIC:
  89                io.si_type = SI_SMIC;
  90                break;
  91
  92        case PCI_CLASS_SERIAL_IPMI_KCS:
  93                io.si_type = SI_KCS;
  94                break;
  95
  96        case PCI_CLASS_SERIAL_IPMI_BT:
  97                io.si_type = SI_BT;
  98                break;
  99
 100        default:
 101                dev_info(&pdev->dev, "Unknown IPMI class: %x\n", pdev->class);
 102                return -ENOMEM;
 103        }
 104
 105        rv = pci_enable_device(pdev);
 106        if (rv) {
 107                dev_err(&pdev->dev, "couldn't enable PCI device\n");
 108                return rv;
 109        }
 110
 111        io.addr_source_cleanup = ipmi_pci_cleanup;
 112        io.addr_source_data = pdev;
 113
 114        if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
 115                io.addr_type = IPMI_IO_ADDR_SPACE;
 116                io.io_setup = ipmi_si_port_setup;
 117        } else {
 118                io.addr_type = IPMI_MEM_ADDR_SPACE;
 119                io.io_setup = ipmi_si_mem_setup;
 120        }
 121        io.addr_data = pci_resource_start(pdev, 0);
 122
 123        io.regspacing = ipmi_pci_probe_regspacing(&io);
 124        io.regsize = DEFAULT_REGSIZE;
 125        io.regshift = 0;
 126
 127        io.irq = pdev->irq;
 128        if (io.irq)
 129                io.irq_setup = ipmi_std_irq_setup;
 130
 131        io.dev = &pdev->dev;
 132
 133        dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n",
 134                &pdev->resource[0], io.regsize, io.regspacing, io.irq);
 135
 136        rv = ipmi_si_add_smi(&io);
 137        if (rv)
 138                pci_disable_device(pdev);
 139
 140        return rv;
 141}
 142
 143static void ipmi_pci_remove(struct pci_dev *pdev)
 144{
 145        ipmi_si_remove_by_dev(&pdev->dev);
 146}
 147
 148static const struct pci_device_id ipmi_pci_devices[] = {
 149        { PCI_VDEVICE(HP, PCI_DEVICE_ID_HP_MMC) },
 150        { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_SMIC, ~0) },
 151        { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_KCS, ~0) },
 152        { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_BT, ~0) },
 153        { 0, }
 154};
 155MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
 156
 157static struct pci_driver ipmi_pci_driver = {
 158        .name =         DEVICE_NAME,
 159        .id_table =     ipmi_pci_devices,
 160        .probe =        ipmi_pci_probe,
 161        .remove =       ipmi_pci_remove,
 162};
 163
 164void ipmi_si_pci_init(void)
 165{
 166        if (si_trypci) {
 167                int rv = pci_register_driver(&ipmi_pci_driver);
 168                if (rv)
 169                        pr_err(PFX "Unable to register PCI driver: %d\n", rv);
 170                else
 171                        pci_registered = true;
 172        }
 173}
 174
 175void ipmi_si_pci_shutdown(void)
 176{
 177        if (pci_registered)
 178                pci_unregister_driver(&ipmi_pci_driver);
 179}
 180