ipmi_si_pci.c 3.9 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0+
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * ipmi_si_pci.c
 *
 * Handling for IPMI devices on the PCI bus.
 */
#include <linux/module.h>
#include <linux/pci.h>
#include "ipmi_si.h"

#define PFX "ipmi_pci: "

static bool pci_registered;

static bool si_trypci = true;

module_param_named(trypci, si_trypci, bool, 0);
MODULE_PARM_DESC(trypci, "Setting this to zero will disable the"
		 " default scan of the interfaces identified via pci");

21 22 23 24
#define PCI_CLASS_SERIAL_IPMI		0x0c07
#define PCI_CLASS_SERIAL_IPMI_SMIC	0x0c0700
#define PCI_CLASS_SERIAL_IPMI_KCS	0x0c0701
#define PCI_CLASS_SERIAL_IPMI_BT	0x0c0702
25

26
#define PCI_DEVICE_ID_HP_MMC 0x121A
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

static void ipmi_pci_cleanup(struct si_sm_io *io)
{
	struct pci_dev *pdev = io->addr_source_data;

	pci_disable_device(pdev);
}

static int ipmi_pci_probe_regspacing(struct si_sm_io *io)
{
	if (io->si_type == SI_KCS) {
		unsigned char	status;
		int		regspacing;

		io->regsize = DEFAULT_REGSIZE;
		io->regshift = 0;

		/* detect 1, 4, 16byte spacing */
		for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) {
			io->regspacing = regspacing;
			if (io->io_setup(io)) {
				dev_err(io->dev,
					"Could not setup I/O space\n");
				return DEFAULT_REGSPACING;
			}
			/* write invalid cmd */
			io->outputb(io, 1, 0x10);
			/* read status back */
			status = io->inputb(io, 1);
			io->io_cleanup(io);
			if (status)
				return regspacing;
			regspacing *= 4;
		}
	}
	return DEFAULT_REGSPACING;
}

65 66 67 68 69 70 71 72 73
static struct pci_device_id ipmi_pci_blacklist[] = {
	/*
	 * This is a "Virtual IPMI device", whatever that is.  It appears
	 * as a KCS device by the class, but it is not one.
	 */
	{ PCI_VDEVICE(REALTEK, 0x816c) },
	{ 0, }
};

74 75 76 77 78 79
static int ipmi_pci_probe(struct pci_dev *pdev,
				    const struct pci_device_id *ent)
{
	int rv;
	struct si_sm_io io;

80 81 82
	if (pci_match_id(ipmi_pci_blacklist, pdev))
		return -ENODEV;

83 84 85 86
	memset(&io, 0, sizeof(io));
	io.addr_source = SI_PCI;
	dev_info(&pdev->dev, "probing via PCI");

87 88
	switch (pdev->class) {
	case PCI_CLASS_SERIAL_IPMI_SMIC:
89 90 91
		io.si_type = SI_SMIC;
		break;

92
	case PCI_CLASS_SERIAL_IPMI_KCS:
93 94 95
		io.si_type = SI_KCS;
		break;

96
	case PCI_CLASS_SERIAL_IPMI_BT:
97 98 99 100
		io.si_type = SI_BT;
		break;

	default:
101
		dev_info(&pdev->dev, "Unknown IPMI class: %x\n", pdev->class);
102 103 104 105 106 107 108 109 110 111 112 113
		return -ENOMEM;
	}

	rv = pci_enable_device(pdev);
	if (rv) {
		dev_err(&pdev->dev, "couldn't enable PCI device\n");
		return rv;
	}

	io.addr_source_cleanup = ipmi_pci_cleanup;
	io.addr_source_data = pdev;

C
Corey Minyard 已提交
114
	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
115
		io.addr_type = IPMI_IO_ADDR_SPACE;
C
Corey Minyard 已提交
116 117
		io.io_setup = ipmi_si_port_setup;
	} else {
118
		io.addr_type = IPMI_MEM_ADDR_SPACE;
C
Corey Minyard 已提交
119 120
		io.io_setup = ipmi_si_mem_setup;
	}
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
	io.addr_data = pci_resource_start(pdev, 0);

	io.regspacing = ipmi_pci_probe_regspacing(&io);
	io.regsize = DEFAULT_REGSIZE;
	io.regshift = 0;

	io.irq = pdev->irq;
	if (io.irq)
		io.irq_setup = ipmi_std_irq_setup;

	io.dev = &pdev->dev;

	dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n",
		&pdev->resource[0], io.regsize, io.regspacing, io.irq);

	rv = ipmi_si_add_smi(&io);
	if (rv)
		pci_disable_device(pdev);

	return rv;
}

static void ipmi_pci_remove(struct pci_dev *pdev)
{
	ipmi_si_remove_by_dev(&pdev->dev);
}

static const struct pci_device_id ipmi_pci_devices[] = {
149 150 151 152
	{ PCI_VDEVICE(HP, PCI_DEVICE_ID_HP_MMC) },
	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_SMIC, ~0) },
	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_KCS, ~0) },
	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_BT, ~0) },
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
	{ 0, }
};
MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);

static struct pci_driver ipmi_pci_driver = {
	.name =         DEVICE_NAME,
	.id_table =     ipmi_pci_devices,
	.probe =        ipmi_pci_probe,
	.remove =       ipmi_pci_remove,
};

void ipmi_si_pci_init(void)
{
	if (si_trypci) {
		int rv = pci_register_driver(&ipmi_pci_driver);
		if (rv)
			pr_err(PFX "Unable to register PCI driver: %d\n", rv);
		else
			pci_registered = true;
	}
}

void ipmi_si_pci_shutdown(void)
{
	if (pci_registered)
		pci_unregister_driver(&ipmi_pci_driver);
}