File Index
Files and directories
Sign in
FILE

ipmi_si_pci.c

File preview with syntax highlighting.

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