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