xref: /OK3568_Linux_fs/kernel/drivers/char/ipmi/ipmi_si_pci.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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