xref: /openbmc/linux/drivers/char/ipmi/ipmi_si_pci.c (revision 07cbd87b)
1243ac210SCorey Minyard // SPDX-License-Identifier: GPL-2.0+
213d0b35cSCorey Minyard /*
313d0b35cSCorey Minyard  * ipmi_si_pci.c
413d0b35cSCorey Minyard  *
513d0b35cSCorey Minyard  * Handling for IPMI devices on the PCI bus.
613d0b35cSCorey Minyard  */
725880f7dSJoe Perches 
825880f7dSJoe Perches #define pr_fmt(fmt) "ipmi_pci: " fmt
925880f7dSJoe Perches 
1013d0b35cSCorey Minyard #include <linux/module.h>
1113d0b35cSCorey Minyard #include <linux/pci.h>
1213d0b35cSCorey Minyard #include "ipmi_si.h"
1313d0b35cSCorey Minyard 
1413d0b35cSCorey Minyard static bool pci_registered;
1513d0b35cSCorey Minyard 
1613d0b35cSCorey Minyard static bool si_trypci = true;
1713d0b35cSCorey Minyard 
1813d0b35cSCorey Minyard module_param_named(trypci, si_trypci, bool, 0);
19*07cbd87bSAndy Shevchenko MODULE_PARM_DESC(trypci,
20*07cbd87bSAndy Shevchenko 		 "Setting this to zero will disable the default scan of the interfaces identified via pci");
2113d0b35cSCorey Minyard 
22ad2575f8SCorey Minyard #define PCI_DEVICE_ID_HP_MMC 0x121A
2313d0b35cSCorey Minyard 
ipmi_pci_probe_regspacing(struct si_sm_io * io)2413d0b35cSCorey Minyard static int ipmi_pci_probe_regspacing(struct si_sm_io *io)
2513d0b35cSCorey Minyard {
2613d0b35cSCorey Minyard 	if (io->si_type == SI_KCS) {
2713d0b35cSCorey Minyard 		unsigned char	status;
2813d0b35cSCorey Minyard 		int		regspacing;
2913d0b35cSCorey Minyard 
3013d0b35cSCorey Minyard 		io->regsize = DEFAULT_REGSIZE;
3113d0b35cSCorey Minyard 		io->regshift = 0;
3213d0b35cSCorey Minyard 
3313d0b35cSCorey Minyard 		/* detect 1, 4, 16byte spacing */
3413d0b35cSCorey Minyard 		for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) {
3513d0b35cSCorey Minyard 			io->regspacing = regspacing;
3613d0b35cSCorey Minyard 			if (io->io_setup(io)) {
3725880f7dSJoe Perches 				dev_err(io->dev, "Could not setup I/O space\n");
3813d0b35cSCorey Minyard 				return DEFAULT_REGSPACING;
3913d0b35cSCorey Minyard 			}
4013d0b35cSCorey Minyard 			/* write invalid cmd */
4113d0b35cSCorey Minyard 			io->outputb(io, 1, 0x10);
4213d0b35cSCorey Minyard 			/* read status back */
4313d0b35cSCorey Minyard 			status = io->inputb(io, 1);
4413d0b35cSCorey Minyard 			io->io_cleanup(io);
4513d0b35cSCorey Minyard 			if (status)
4613d0b35cSCorey Minyard 				return regspacing;
4713d0b35cSCorey Minyard 			regspacing *= 4;
4813d0b35cSCorey Minyard 		}
4913d0b35cSCorey Minyard 	}
5013d0b35cSCorey Minyard 	return DEFAULT_REGSPACING;
5113d0b35cSCorey Minyard }
5213d0b35cSCorey Minyard 
53bc48fa1bSCorey Minyard static struct pci_device_id ipmi_pci_blacklist[] = {
54bc48fa1bSCorey Minyard 	/*
55bc48fa1bSCorey Minyard 	 * This is a "Virtual IPMI device", whatever that is.  It appears
56bc48fa1bSCorey Minyard 	 * as a KCS device by the class, but it is not one.
57bc48fa1bSCorey Minyard 	 */
58bc48fa1bSCorey Minyard 	{ PCI_VDEVICE(REALTEK, 0x816c) },
59bc48fa1bSCorey Minyard 	{ 0, }
60bc48fa1bSCorey Minyard };
61bc48fa1bSCorey Minyard 
ipmi_pci_probe(struct pci_dev * pdev,const struct pci_device_id * ent)6213d0b35cSCorey Minyard static int ipmi_pci_probe(struct pci_dev *pdev,
6313d0b35cSCorey Minyard 				    const struct pci_device_id *ent)
6413d0b35cSCorey Minyard {
6513d0b35cSCorey Minyard 	int rv;
6613d0b35cSCorey Minyard 	struct si_sm_io io;
6713d0b35cSCorey Minyard 
68bc48fa1bSCorey Minyard 	if (pci_match_id(ipmi_pci_blacklist, pdev))
69bc48fa1bSCorey Minyard 		return -ENODEV;
70bc48fa1bSCorey Minyard 
7113d0b35cSCorey Minyard 	memset(&io, 0, sizeof(io));
7213d0b35cSCorey Minyard 	io.addr_source = SI_PCI;
7313d0b35cSCorey Minyard 	dev_info(&pdev->dev, "probing via PCI");
7413d0b35cSCorey Minyard 
75ad2575f8SCorey Minyard 	switch (pdev->class) {
76ad2575f8SCorey Minyard 	case PCI_CLASS_SERIAL_IPMI_SMIC:
7713d0b35cSCorey Minyard 		io.si_type = SI_SMIC;
7813d0b35cSCorey Minyard 		break;
7913d0b35cSCorey Minyard 
80ad2575f8SCorey Minyard 	case PCI_CLASS_SERIAL_IPMI_KCS:
8113d0b35cSCorey Minyard 		io.si_type = SI_KCS;
8213d0b35cSCorey Minyard 		break;
8313d0b35cSCorey Minyard 
84ad2575f8SCorey Minyard 	case PCI_CLASS_SERIAL_IPMI_BT:
8513d0b35cSCorey Minyard 		io.si_type = SI_BT;
8613d0b35cSCorey Minyard 		break;
8713d0b35cSCorey Minyard 
8813d0b35cSCorey Minyard 	default:
89ad2575f8SCorey Minyard 		dev_info(&pdev->dev, "Unknown IPMI class: %x\n", pdev->class);
9013d0b35cSCorey Minyard 		return -ENOMEM;
9113d0b35cSCorey Minyard 	}
9213d0b35cSCorey Minyard 
932dafddb8SAndy Shevchenko 	rv = pcim_enable_device(pdev);
9413d0b35cSCorey Minyard 	if (rv) {
9513d0b35cSCorey Minyard 		dev_err(&pdev->dev, "couldn't enable PCI device\n");
9613d0b35cSCorey Minyard 		return rv;
9713d0b35cSCorey Minyard 	}
9813d0b35cSCorey Minyard 
991ac8aa8dSCorey Minyard 	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
100f6296bdcSCorey Minyard 		io.addr_space = IPMI_IO_ADDR_SPACE;
1011ac8aa8dSCorey Minyard 		io.io_setup = ipmi_si_port_setup;
1021ac8aa8dSCorey Minyard 	} else {
103f6296bdcSCorey Minyard 		io.addr_space = IPMI_MEM_ADDR_SPACE;
1041ac8aa8dSCorey Minyard 		io.io_setup = ipmi_si_mem_setup;
1051ac8aa8dSCorey Minyard 	}
10613d0b35cSCorey Minyard 	io.addr_data = pci_resource_start(pdev, 0);
10713d0b35cSCorey Minyard 
10801508d9eSMeelis Roos 	io.dev = &pdev->dev;
10901508d9eSMeelis Roos 
11013d0b35cSCorey Minyard 	io.regspacing = ipmi_pci_probe_regspacing(&io);
11113d0b35cSCorey Minyard 	io.regsize = DEFAULT_REGSIZE;
11213d0b35cSCorey Minyard 	io.regshift = 0;
11313d0b35cSCorey Minyard 
11413d0b35cSCorey Minyard 	io.irq = pdev->irq;
11513d0b35cSCorey Minyard 	if (io.irq)
11613d0b35cSCorey Minyard 		io.irq_setup = ipmi_std_irq_setup;
11713d0b35cSCorey Minyard 
11813d0b35cSCorey Minyard 	dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n",
11913d0b35cSCorey Minyard 		 &pdev->resource[0], io.regsize, io.regspacing, io.irq);
12013d0b35cSCorey Minyard 
1212dafddb8SAndy Shevchenko 	return ipmi_si_add_smi(&io);
12213d0b35cSCorey Minyard }
12313d0b35cSCorey Minyard 
ipmi_pci_remove(struct pci_dev * pdev)12413d0b35cSCorey Minyard static void ipmi_pci_remove(struct pci_dev *pdev)
12513d0b35cSCorey Minyard {
12613d0b35cSCorey Minyard 	ipmi_si_remove_by_dev(&pdev->dev);
12713d0b35cSCorey Minyard }
12813d0b35cSCorey Minyard 
12913d0b35cSCorey Minyard static const struct pci_device_id ipmi_pci_devices[] = {
130ad2575f8SCorey Minyard 	{ PCI_VDEVICE(HP, PCI_DEVICE_ID_HP_MMC) },
131ad2575f8SCorey Minyard 	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_SMIC, ~0) },
132ad2575f8SCorey Minyard 	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_KCS, ~0) },
133ad2575f8SCorey Minyard 	{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_BT, ~0) },
13413d0b35cSCorey Minyard 	{ 0, }
13513d0b35cSCorey Minyard };
13613d0b35cSCorey Minyard MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
13713d0b35cSCorey Minyard 
13813d0b35cSCorey Minyard static struct pci_driver ipmi_pci_driver = {
139104fb25fSCorey Minyard 	.name =         SI_DEVICE_NAME,
14013d0b35cSCorey Minyard 	.id_table =     ipmi_pci_devices,
14113d0b35cSCorey Minyard 	.probe =        ipmi_pci_probe,
14213d0b35cSCorey Minyard 	.remove =       ipmi_pci_remove,
14313d0b35cSCorey Minyard };
14413d0b35cSCorey Minyard 
ipmi_si_pci_init(void)14513d0b35cSCorey Minyard void ipmi_si_pci_init(void)
14613d0b35cSCorey Minyard {
14713d0b35cSCorey Minyard 	if (si_trypci) {
14813d0b35cSCorey Minyard 		int rv = pci_register_driver(&ipmi_pci_driver);
14913d0b35cSCorey Minyard 		if (rv)
15025880f7dSJoe Perches 			pr_err("Unable to register PCI driver: %d\n", rv);
15113d0b35cSCorey Minyard 		else
15213d0b35cSCorey Minyard 			pci_registered = true;
15313d0b35cSCorey Minyard 	}
15413d0b35cSCorey Minyard }
15513d0b35cSCorey Minyard 
ipmi_si_pci_shutdown(void)15613d0b35cSCorey Minyard void ipmi_si_pci_shutdown(void)
15713d0b35cSCorey Minyard {
15813d0b35cSCorey Minyard 	if (pci_registered)
15913d0b35cSCorey Minyard 		pci_unregister_driver(&ipmi_pci_driver);
16013d0b35cSCorey Minyard }
161