brintos

brintos / linux-shallow public Read only

0
0
Text · 3.6 KiB · b83d556 Raw
164 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * ipmi_si_pci.c4 *5 * Handling for IPMI devices on the PCI bus.6 */7 8#define pr_fmt(fmt) "ipmi_pci: " fmt9 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 0x121A23 24static int ipmi_pci_probe_regspacing(struct si_sm_io *io)25{26	if (io->si_type == SI_KCS) {27		unsigned char	status;28		int		regspacing;29 30		io->regsize = DEFAULT_REGSIZE;31		io->regshift = 0;32 33		/* detect 1, 4, 16byte spacing */34		for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) {35			io->regspacing = regspacing;36			if (io->io_setup(io)) {37				dev_err(io->dev, "Could not setup I/O space\n");38				return DEFAULT_REGSPACING;39			}40			/* write invalid cmd */41			io->outputb(io, 1, 0x10);42			/* read status back */43			status = io->inputb(io, 1);44			io->io_cleanup(io);45			if (status)46				return regspacing;47			regspacing *= 4;48		}49	}50	return DEFAULT_REGSPACING;51}52 53static struct pci_device_id ipmi_pci_blacklist[] = {54	/*55	 * This is a "Virtual IPMI device", whatever that is.  It appears56	 * as a KCS device by the class, but it is not one.57	 */58	{ PCI_VDEVICE(REALTEK, 0x816c) },59	{ 0, }60};61 62static int ipmi_pci_probe(struct pci_dev *pdev,63				    const struct pci_device_id *ent)64{65	int rv;66	struct si_sm_io io;67 68	if (pci_match_id(ipmi_pci_blacklist, pdev))69		return -ENODEV;70 71	memset(&io, 0, sizeof(io));72	io.addr_source = SI_PCI;73	dev_info(&pdev->dev, "probing via PCI");74 75	switch (pdev->class) {76	case PCI_CLASS_SERIAL_IPMI_SMIC:77		io.si_type = SI_SMIC;78		break;79 80	case PCI_CLASS_SERIAL_IPMI_KCS:81		io.si_type = SI_KCS;82		break;83 84	case PCI_CLASS_SERIAL_IPMI_BT:85		io.si_type = SI_BT;86		break;87 88	default:89		dev_info(&pdev->dev, "Unknown IPMI class: %x\n", pdev->class);90		return -ENOMEM;91	}92 93	rv = pcim_enable_device(pdev);94	if (rv) {95		dev_err(&pdev->dev, "couldn't enable PCI device\n");96		return rv;97	}98 99	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {100		if (!IS_ENABLED(CONFIG_HAS_IOPORT))101			return -ENXIO;102 103		io.addr_space = IPMI_IO_ADDR_SPACE;104		io.io_setup = ipmi_si_port_setup;105	} else {106		io.addr_space = IPMI_MEM_ADDR_SPACE;107		io.io_setup = ipmi_si_mem_setup;108	}109	io.addr_data = pci_resource_start(pdev, 0);110 111	io.dev = &pdev->dev;112 113	io.regspacing = ipmi_pci_probe_regspacing(&io);114	io.regsize = DEFAULT_REGSIZE;115	io.regshift = 0;116 117	io.irq = pdev->irq;118	if (io.irq)119		io.irq_setup = ipmi_std_irq_setup;120 121	dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n",122		 &pdev->resource[0], io.regsize, io.regspacing, io.irq);123 124	return ipmi_si_add_smi(&io);125}126 127static void ipmi_pci_remove(struct pci_dev *pdev)128{129	ipmi_si_remove_by_dev(&pdev->dev);130}131 132static const struct pci_device_id ipmi_pci_devices[] = {133	{ PCI_VDEVICE(HP, PCI_DEVICE_ID_HP_MMC) },134	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_SMIC, ~0) },135	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_KCS, ~0) },136	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_BT, ~0) },137	{ 0, }138};139MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);140 141static struct pci_driver ipmi_pci_driver = {142	.name =         SI_DEVICE_NAME,143	.id_table =     ipmi_pci_devices,144	.probe =        ipmi_pci_probe,145	.remove =       ipmi_pci_remove,146};147 148void ipmi_si_pci_init(void)149{150	if (si_trypci) {151		int rv = pci_register_driver(&ipmi_pci_driver);152		if (rv)153			pr_err("Unable to register PCI driver: %d\n", rv);154		else155			pci_registered = true;156	}157}158 159void ipmi_si_pci_shutdown(void)160{161	if (pci_registered)162		pci_unregister_driver(&ipmi_pci_driver);163}164