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); 1913d0b35cSCorey Minyard MODULE_PARM_DESC(trypci, "Setting this to zero will disable the" 2013d0b35cSCorey Minyard " default scan of the interfaces identified via pci"); 2113d0b35cSCorey Minyard 22ad2575f8SCorey Minyard #define PCI_DEVICE_ID_HP_MMC 0x121A 2313d0b35cSCorey Minyard 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 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 93*2dafddb8SAndy 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 121*2dafddb8SAndy Shevchenko return ipmi_si_add_smi(&io); 12213d0b35cSCorey Minyard } 12313d0b35cSCorey Minyard 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 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 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