• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  
2  /*
3   * IBM ASM Service Processor Device Driver
4   *
5   * This program is free software; you can redistribute it and/or modify
6   * it under the terms of the GNU General Public License as published by
7   * the Free Software Foundation; either version 2 of the License, or
8   * (at your option) any later version.
9   *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18   *
19   * Copyright (C) IBM Corporation, 2004
20   *
21   * Author: Max Asböck <amax@us.ibm.com>
22   *
23   * This driver is based on code originally written by Pete Reynolds
24   * and others.
25   *
26   */
27  
28  /*
29   * The ASM device driver does the following things:
30   *
31   * 1) When loaded it sends a message to the service processor,
32   * indicating that an OS is * running. This causes the service processor
33   * to send periodic heartbeats to the OS.
34   *
35   * 2) Answers the periodic heartbeats sent by the service processor.
36   * Failure to do so would result in system reboot.
37   *
38   * 3) Acts as a pass through for dot commands sent from user applications.
39   * The interface for this is the ibmasmfs file system.
40   *
41   * 4) Allows user applications to register for event notification. Events
42   * are sent to the driver through interrupts. They can be read from user
43   * space through the ibmasmfs file system.
44   *
45   * 5) Allows user space applications to send heartbeats to the service
46   * processor (aka reverse heartbeats). Again this happens through ibmasmfs.
47   *
48   * 6) Handles remote mouse and keyboard event interrupts and makes them
49   * available to user applications through ibmasmfs.
50   *
51   */
52  
53  #include <linux/pci.h>
54  #include <linux/init.h>
55  #include <linux/slab.h>
56  #include "ibmasm.h"
57  #include "lowlevel.h"
58  #include "remote.h"
59  
60  int ibmasm_debug = 0;
61  module_param(ibmasm_debug, int , S_IRUGO | S_IWUSR);
62  MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off");
63  
64  
ibmasm_init_one(struct pci_dev * pdev,const struct pci_device_id * id)65  static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
66  {
67  	int result;
68  	struct service_processor *sp;
69  
70  	if ((result = pci_enable_device(pdev))) {
71  		dev_err(&pdev->dev, "Failed to enable PCI device\n");
72  		return result;
73  	}
74  	if ((result = pci_request_regions(pdev, DRIVER_NAME))) {
75  		dev_err(&pdev->dev, "Failed to allocate PCI resources\n");
76  		goto error_resources;
77  	}
78  	/* vnc client won't work without bus-mastering */
79  	pci_set_master(pdev);
80  
81  	sp = kzalloc(sizeof(struct service_processor), GFP_KERNEL);
82  	if (sp == NULL) {
83  		dev_err(&pdev->dev, "Failed to allocate memory\n");
84  		result = -ENOMEM;
85  		goto error_kmalloc;
86  	}
87  
88  	spin_lock_init(&sp->lock);
89  	INIT_LIST_HEAD(&sp->command_queue);
90  
91  	pci_set_drvdata(pdev, (void *)sp);
92  	sp->dev = &pdev->dev;
93  	sp->number = pdev->bus->number;
94  	snprintf(sp->dirname, IBMASM_NAME_SIZE, "%d", sp->number);
95  	snprintf(sp->devname, IBMASM_NAME_SIZE, "%s%d", DRIVER_NAME, sp->number);
96  
97  	if (ibmasm_event_buffer_init(sp)) {
98  		dev_err(sp->dev, "Failed to allocate event buffer\n");
99  		goto error_eventbuffer;
100  	}
101  
102  	if (ibmasm_heartbeat_init(sp)) {
103  		dev_err(sp->dev, "Failed to allocate heartbeat command\n");
104  		goto error_heartbeat;
105  	}
106  
107  	sp->irq = pdev->irq;
108  	sp->base_address = pci_ioremap_bar(pdev, 0);
109  	if (!sp->base_address) {
110  		dev_err(sp->dev, "Failed to ioremap pci memory\n");
111  		result =  -ENODEV;
112  		goto error_ioremap;
113  	}
114  
115  	result = request_irq(sp->irq, ibmasm_interrupt_handler, IRQF_SHARED, sp->devname, (void*)sp);
116  	if (result) {
117  		dev_err(sp->dev, "Failed to register interrupt handler\n");
118  		goto error_request_irq;
119  	}
120  
121  	enable_sp_interrupts(sp->base_address);
122  
123  	result = ibmasm_init_remote_input_dev(sp);
124  	if (result) {
125  		dev_err(sp->dev, "Failed to initialize remote queue\n");
126  		goto error_send_message;
127  	}
128  
129  	result = ibmasm_send_driver_vpd(sp);
130  	if (result) {
131  		dev_err(sp->dev, "Failed to send driver VPD to service processor\n");
132  		goto error_send_message;
133  	}
134  	result = ibmasm_send_os_state(sp, SYSTEM_STATE_OS_UP);
135  	if (result) {
136  		dev_err(sp->dev, "Failed to send OS state to service processor\n");
137  		goto error_send_message;
138  	}
139  	ibmasmfs_add_sp(sp);
140  
141  	ibmasm_register_uart(sp);
142  
143  	return 0;
144  
145  error_send_message:
146  	disable_sp_interrupts(sp->base_address);
147  	ibmasm_free_remote_input_dev(sp);
148  	free_irq(sp->irq, (void *)sp);
149  error_request_irq:
150  	iounmap(sp->base_address);
151  error_ioremap:
152  	ibmasm_heartbeat_exit(sp);
153  error_heartbeat:
154  	ibmasm_event_buffer_exit(sp);
155  error_eventbuffer:
156  	kfree(sp);
157  error_kmalloc:
158          pci_release_regions(pdev);
159  error_resources:
160          pci_disable_device(pdev);
161  
162  	return result;
163  }
164  
ibmasm_remove_one(struct pci_dev * pdev)165  static void ibmasm_remove_one(struct pci_dev *pdev)
166  {
167  	struct service_processor *sp = pci_get_drvdata(pdev);
168  
169  	dbg("Unregistering UART\n");
170  	ibmasm_unregister_uart(sp);
171  	dbg("Sending OS down message\n");
172  	if (ibmasm_send_os_state(sp, SYSTEM_STATE_OS_DOWN))
173  		err("failed to get response to 'Send OS State' command\n");
174  	dbg("Disabling heartbeats\n");
175  	ibmasm_heartbeat_exit(sp);
176  	dbg("Disabling interrupts\n");
177  	disable_sp_interrupts(sp->base_address);
178  	dbg("Freeing SP irq\n");
179  	free_irq(sp->irq, (void *)sp);
180  	dbg("Cleaning up\n");
181  	ibmasm_free_remote_input_dev(sp);
182  	iounmap(sp->base_address);
183  	ibmasm_event_buffer_exit(sp);
184  	kfree(sp);
185  	pci_release_regions(pdev);
186  	pci_disable_device(pdev);
187  }
188  
189  static struct pci_device_id ibmasm_pci_table[] =
190  {
191  	{ PCI_DEVICE(VENDORID_IBM, DEVICEID_RSA) },
192  	{},
193  };
194  
195  static struct pci_driver ibmasm_driver = {
196  	.name		= DRIVER_NAME,
197  	.id_table	= ibmasm_pci_table,
198  	.probe		= ibmasm_init_one,
199  	.remove		= ibmasm_remove_one,
200  };
201  
ibmasm_exit(void)202  static void __exit ibmasm_exit (void)
203  {
204  	ibmasm_unregister_panic_notifier();
205  	ibmasmfs_unregister();
206  	pci_unregister_driver(&ibmasm_driver);
207  	info(DRIVER_DESC " version " DRIVER_VERSION " unloaded");
208  }
209  
ibmasm_init(void)210  static int __init ibmasm_init(void)
211  {
212  	int result = pci_register_driver(&ibmasm_driver);
213  	if (result)
214  		return result;
215  
216  	result = ibmasmfs_register();
217  	if (result) {
218  		pci_unregister_driver(&ibmasm_driver);
219  		err("Failed to register ibmasmfs file system");
220  		return result;
221  	}
222  
223  	ibmasm_register_panic_notifier();
224  	info(DRIVER_DESC " version " DRIVER_VERSION " loaded");
225  	return 0;
226  }
227  
228  module_init(ibmasm_init);
229  module_exit(ibmasm_exit);
230  
231  MODULE_AUTHOR(DRIVER_AUTHOR);
232  MODULE_DESCRIPTION(DRIVER_DESC);
233  MODULE_LICENSE("GPL");
234  MODULE_DEVICE_TABLE(pci, ibmasm_pci_table);
235  
236