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 void ipmi_pci_cleanup(struct si_sm_io *io) 2513d0b35cSCorey Minyard { 2613d0b35cSCorey Minyard struct pci_dev *pdev = io->addr_source_data; 2713d0b35cSCorey Minyard 2813d0b35cSCorey Minyard pci_disable_device(pdev); 2913d0b35cSCorey Minyard } 3013d0b35cSCorey Minyard 3113d0b35cSCorey Minyard static int ipmi_pci_probe_regspacing(struct si_sm_io *io) 3213d0b35cSCorey Minyard { 3313d0b35cSCorey Minyard if (io->si_type == SI_KCS) { 3413d0b35cSCorey Minyard unsigned char status; 3513d0b35cSCorey Minyard int regspacing; 3613d0b35cSCorey Minyard 3713d0b35cSCorey Minyard io->regsize = DEFAULT_REGSIZE; 3813d0b35cSCorey Minyard io->regshift = 0; 3913d0b35cSCorey Minyard 4013d0b35cSCorey Minyard /* detect 1, 4, 16byte spacing */ 4113d0b35cSCorey Minyard for (regspacing = DEFAULT_REGSPACING; regspacing <= 16;) { 4213d0b35cSCorey Minyard io->regspacing = regspacing; 4313d0b35cSCorey Minyard if (io->io_setup(io)) { 4425880f7dSJoe Perches dev_err(io->dev, "Could not setup I/O space\n"); 4513d0b35cSCorey Minyard return DEFAULT_REGSPACING; 4613d0b35cSCorey Minyard } 4713d0b35cSCorey Minyard /* write invalid cmd */ 4813d0b35cSCorey Minyard io->outputb(io, 1, 0x10); 4913d0b35cSCorey Minyard /* read status back */ 5013d0b35cSCorey Minyard status = io->inputb(io, 1); 5113d0b35cSCorey Minyard io->io_cleanup(io); 5213d0b35cSCorey Minyard if (status) 5313d0b35cSCorey Minyard return regspacing; 5413d0b35cSCorey Minyard regspacing *= 4; 5513d0b35cSCorey Minyard } 5613d0b35cSCorey Minyard } 5713d0b35cSCorey Minyard return DEFAULT_REGSPACING; 5813d0b35cSCorey Minyard } 5913d0b35cSCorey Minyard 60bc48fa1bSCorey Minyard static struct pci_device_id ipmi_pci_blacklist[] = { 61bc48fa1bSCorey Minyard /* 62bc48fa1bSCorey Minyard * This is a "Virtual IPMI device", whatever that is. It appears 63bc48fa1bSCorey Minyard * as a KCS device by the class, but it is not one. 64bc48fa1bSCorey Minyard */ 65bc48fa1bSCorey Minyard { PCI_VDEVICE(REALTEK, 0x816c) }, 66bc48fa1bSCorey Minyard { 0, } 67bc48fa1bSCorey Minyard }; 68bc48fa1bSCorey Minyard 6913d0b35cSCorey Minyard static int ipmi_pci_probe(struct pci_dev *pdev, 7013d0b35cSCorey Minyard const struct pci_device_id *ent) 7113d0b35cSCorey Minyard { 7213d0b35cSCorey Minyard int rv; 7313d0b35cSCorey Minyard struct si_sm_io io; 7413d0b35cSCorey Minyard 75bc48fa1bSCorey Minyard if (pci_match_id(ipmi_pci_blacklist, pdev)) 76bc48fa1bSCorey Minyard return -ENODEV; 77bc48fa1bSCorey Minyard 7813d0b35cSCorey Minyard memset(&io, 0, sizeof(io)); 7913d0b35cSCorey Minyard io.addr_source = SI_PCI; 8013d0b35cSCorey Minyard dev_info(&pdev->dev, "probing via PCI"); 8113d0b35cSCorey Minyard 82ad2575f8SCorey Minyard switch (pdev->class) { 83ad2575f8SCorey Minyard case PCI_CLASS_SERIAL_IPMI_SMIC: 8413d0b35cSCorey Minyard io.si_type = SI_SMIC; 8513d0b35cSCorey Minyard break; 8613d0b35cSCorey Minyard 87ad2575f8SCorey Minyard case PCI_CLASS_SERIAL_IPMI_KCS: 8813d0b35cSCorey Minyard io.si_type = SI_KCS; 8913d0b35cSCorey Minyard break; 9013d0b35cSCorey Minyard 91ad2575f8SCorey Minyard case PCI_CLASS_SERIAL_IPMI_BT: 9213d0b35cSCorey Minyard io.si_type = SI_BT; 9313d0b35cSCorey Minyard break; 9413d0b35cSCorey Minyard 9513d0b35cSCorey Minyard default: 96ad2575f8SCorey Minyard dev_info(&pdev->dev, "Unknown IPMI class: %x\n", pdev->class); 9713d0b35cSCorey Minyard return -ENOMEM; 9813d0b35cSCorey Minyard } 9913d0b35cSCorey Minyard 10013d0b35cSCorey Minyard rv = pci_enable_device(pdev); 10113d0b35cSCorey Minyard if (rv) { 10213d0b35cSCorey Minyard dev_err(&pdev->dev, "couldn't enable PCI device\n"); 10313d0b35cSCorey Minyard return rv; 10413d0b35cSCorey Minyard } 10513d0b35cSCorey Minyard 10613d0b35cSCorey Minyard io.addr_source_cleanup = ipmi_pci_cleanup; 10713d0b35cSCorey Minyard io.addr_source_data = pdev; 10813d0b35cSCorey Minyard 1091ac8aa8dSCorey Minyard if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { 11013d0b35cSCorey Minyard io.addr_type = IPMI_IO_ADDR_SPACE; 1111ac8aa8dSCorey Minyard io.io_setup = ipmi_si_port_setup; 1121ac8aa8dSCorey Minyard } else { 11313d0b35cSCorey Minyard io.addr_type = IPMI_MEM_ADDR_SPACE; 1141ac8aa8dSCorey Minyard io.io_setup = ipmi_si_mem_setup; 1151ac8aa8dSCorey Minyard } 11613d0b35cSCorey Minyard io.addr_data = pci_resource_start(pdev, 0); 11713d0b35cSCorey Minyard 11813d0b35cSCorey Minyard io.regspacing = ipmi_pci_probe_regspacing(&io); 11913d0b35cSCorey Minyard io.regsize = DEFAULT_REGSIZE; 12013d0b35cSCorey Minyard io.regshift = 0; 12113d0b35cSCorey Minyard 12213d0b35cSCorey Minyard io.irq = pdev->irq; 12313d0b35cSCorey Minyard if (io.irq) 12413d0b35cSCorey Minyard io.irq_setup = ipmi_std_irq_setup; 12513d0b35cSCorey Minyard 12613d0b35cSCorey Minyard io.dev = &pdev->dev; 12713d0b35cSCorey Minyard 12813d0b35cSCorey Minyard dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n", 12913d0b35cSCorey Minyard &pdev->resource[0], io.regsize, io.regspacing, io.irq); 13013d0b35cSCorey Minyard 13113d0b35cSCorey Minyard rv = ipmi_si_add_smi(&io); 13213d0b35cSCorey Minyard if (rv) 13313d0b35cSCorey Minyard pci_disable_device(pdev); 13413d0b35cSCorey Minyard 13513d0b35cSCorey Minyard return rv; 13613d0b35cSCorey Minyard } 13713d0b35cSCorey Minyard 13813d0b35cSCorey Minyard static void ipmi_pci_remove(struct pci_dev *pdev) 13913d0b35cSCorey Minyard { 14013d0b35cSCorey Minyard ipmi_si_remove_by_dev(&pdev->dev); 14113d0b35cSCorey Minyard } 14213d0b35cSCorey Minyard 14313d0b35cSCorey Minyard static const struct pci_device_id ipmi_pci_devices[] = { 144ad2575f8SCorey Minyard { PCI_VDEVICE(HP, PCI_DEVICE_ID_HP_MMC) }, 145ad2575f8SCorey Minyard { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_SMIC, ~0) }, 146ad2575f8SCorey Minyard { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_KCS, ~0) }, 147ad2575f8SCorey Minyard { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_BT, ~0) }, 14813d0b35cSCorey Minyard { 0, } 14913d0b35cSCorey Minyard }; 15013d0b35cSCorey Minyard MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); 15113d0b35cSCorey Minyard 15213d0b35cSCorey Minyard static struct pci_driver ipmi_pci_driver = { 15313d0b35cSCorey Minyard .name = DEVICE_NAME, 15413d0b35cSCorey Minyard .id_table = ipmi_pci_devices, 15513d0b35cSCorey Minyard .probe = ipmi_pci_probe, 15613d0b35cSCorey Minyard .remove = ipmi_pci_remove, 15713d0b35cSCorey Minyard }; 15813d0b35cSCorey Minyard 15913d0b35cSCorey Minyard void ipmi_si_pci_init(void) 16013d0b35cSCorey Minyard { 16113d0b35cSCorey Minyard if (si_trypci) { 16213d0b35cSCorey Minyard int rv = pci_register_driver(&ipmi_pci_driver); 16313d0b35cSCorey Minyard if (rv) 16425880f7dSJoe Perches pr_err("Unable to register PCI driver: %d\n", rv); 16513d0b35cSCorey Minyard else 16613d0b35cSCorey Minyard pci_registered = true; 16713d0b35cSCorey Minyard } 16813d0b35cSCorey Minyard } 16913d0b35cSCorey Minyard 17013d0b35cSCorey Minyard void ipmi_si_pci_shutdown(void) 17113d0b35cSCorey Minyard { 17213d0b35cSCorey Minyard if (pci_registered) 17313d0b35cSCorey Minyard pci_unregister_driver(&ipmi_pci_driver); 17413d0b35cSCorey Minyard } 175