Blame view

drivers/misc/ibmasm/module.c 6.44 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  
  /*
   * IBM ASM Service Processor Device Driver
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   *
   * Copyright (C) IBM Corporation, 2004
   *
3110dc7a8   Dmitry Torokhov   IBMASM: whitespac...
21
   * Author: Max Asböck <amax@us.ibm.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
   *
3110dc7a8   Dmitry Torokhov   IBMASM: whitespac...
23
   * This driver is based on code originally written by Pete Reynolds
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
30
31
32
   * and others.
   *
   */
  
  /*
   * The ASM device driver does the following things:
   *
   * 1) When loaded it sends a message to the service processor,
   * indicating that an OS is * running. This causes the service processor
3110dc7a8   Dmitry Torokhov   IBMASM: whitespac...
33
   * to send periodic heartbeats to the OS.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
   *
   * 2) Answers the periodic heartbeats sent by the service processor.
   * Failure to do so would result in system reboot.
   *
   * 3) Acts as a pass through for dot commands sent from user applications.
3110dc7a8   Dmitry Torokhov   IBMASM: whitespac...
39
   * The interface for this is the ibmasmfs file system.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
   *
   * 4) Allows user applications to register for event notification. Events
   * are sent to the driver through interrupts. They can be read from user
   * space through the ibmasmfs file system.
   *
   * 5) Allows user space applications to send heartbeats to the service
   * processor (aka reverse heartbeats). Again this happens through ibmasmfs.
   *
   * 6) Handles remote mouse and keyboard event interrupts and makes them
   * available to user applications through ibmasmfs.
   *
   */
  
  #include <linux/pci.h>
  #include <linux/init.h>
  #include "ibmasm.h"
  #include "lowlevel.h"
  #include "remote.h"
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
58
59
60
  int ibmasm_debug = 0;
  module_param(ibmasm_debug, int , S_IRUGO | S_IWUSR);
  MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
  
  static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
  {
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
64
  	int result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  	struct service_processor *sp;
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
66
67
68
69
70
71
72
73
74
  	if ((result = pci_enable_device(pdev))) {
  		dev_err(&pdev->dev, "Failed to enable PCI device
  ");
  		return result;
  	}
  	if ((result = pci_request_regions(pdev, DRIVER_NAME))) {
  		dev_err(&pdev->dev, "Failed to allocate PCI resources
  ");
  		goto error_resources;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	}
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
76
77
  	/* vnc client won't work without bus-mastering */
  	pci_set_master(pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

dd00cc486   Yoann Padioleau   some kmalloc/mems...
79
  	sp = kzalloc(sizeof(struct service_processor), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
84
85
  	if (sp == NULL) {
  		dev_err(&pdev->dev, "Failed to allocate memory
  ");
  		result = -ENOMEM;
  		goto error_kmalloc;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86

34af946a2   Ingo Molnar   [PATCH] spin/rwlo...
87
  	spin_lock_init(&sp->lock);
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
88
  	INIT_LIST_HEAD(&sp->command_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  	pci_set_drvdata(pdev, (void *)sp);
  	sp->dev = &pdev->dev;
  	sp->number = pdev->bus->number;
  	snprintf(sp->dirname, IBMASM_NAME_SIZE, "%d", sp->number);
  	snprintf(sp->devname, IBMASM_NAME_SIZE, "%s%d", DRIVER_NAME, sp->number);
  
  	if (ibmasm_event_buffer_init(sp)) {
  		dev_err(sp->dev, "Failed to allocate event buffer
  ");
  		goto error_eventbuffer;
  	}
  
  	if (ibmasm_heartbeat_init(sp)) {
  		dev_err(sp->dev, "Failed to allocate heartbeat command
  ");
  		goto error_heartbeat;
  	}
  
  	sp->irq = pdev->irq;
bdbeed75b   Arjan van de Ven   pci: use pci_iore...
108
  	sp->base_address = pci_ioremap_bar(pdev, 0);
5cf83b9b1   Al Viro   NULL noise: drive...
109
  	if (!sp->base_address) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
  		dev_err(sp->dev, "Failed to ioremap pci memory
  ");
  		result =  -ENODEV;
  		goto error_ioremap;
  	}
dace14537   Thomas Gleixner   [PATCH] irq-flags...
115
  	result = request_irq(sp->irq, ibmasm_interrupt_handler, IRQF_SHARED, sp->devname, (void*)sp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
121
122
  	if (result) {
  		dev_err(sp->dev, "Failed to register interrupt handler
  ");
  		goto error_request_irq;
  	}
  
  	enable_sp_interrupts(sp->base_address);
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
123
124
125
126
127
128
129
  
  	result = ibmasm_init_remote_input_dev(sp);
  	if (result) {
  		dev_err(sp->dev, "Failed to initialize remote queue
  ");
  		goto error_send_message;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  
  	result = ibmasm_send_driver_vpd(sp);
  	if (result) {
  		dev_err(sp->dev, "Failed to send driver VPD to service processor
  ");
  		goto error_send_message;
  	}
  	result = ibmasm_send_os_state(sp, SYSTEM_STATE_OS_UP);
  	if (result) {
  		dev_err(sp->dev, "Failed to send OS state to service processor
  ");
  		goto error_send_message;
  	}
  	ibmasmfs_add_sp(sp);
  
  	ibmasm_register_uart(sp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
  	return 0;
  
  error_send_message:
  	disable_sp_interrupts(sp->base_address);
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
150
  	ibmasm_free_remote_input_dev(sp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
  	free_irq(sp->irq, (void *)sp);
  error_request_irq:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
  	iounmap(sp->base_address);
  error_ioremap:
  	ibmasm_heartbeat_exit(sp);
  error_heartbeat:
  	ibmasm_event_buffer_exit(sp);
  error_eventbuffer:
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
159
  	pci_set_drvdata(pdev, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
  	kfree(sp);
  error_kmalloc:
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
162
163
164
          pci_release_regions(pdev);
  error_resources:
          pci_disable_device(pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
169
170
171
  
  	return result;
  }
  
  static void __devexit ibmasm_remove_one(struct pci_dev *pdev)
  {
  	struct service_processor *sp = (struct service_processor *)pci_get_drvdata(pdev);
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
172
173
  	dbg("Unregistering UART
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  	ibmasm_unregister_uart(sp);
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
175
176
177
178
179
180
181
182
183
184
  	dbg("Sending OS down message
  ");
  	if (ibmasm_send_os_state(sp, SYSTEM_STATE_OS_DOWN))
  		err("failed to get repsonse to 'Send OS State' command
  ");
  	dbg("Disabling heartbeats
  ");
  	ibmasm_heartbeat_exit(sp);
  	dbg("Disabling interrupts
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  	disable_sp_interrupts(sp->base_address);
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
186
187
  	dbg("Freeing SP irq
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  	free_irq(sp->irq, (void *)sp);
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
189
190
191
  	dbg("Cleaning up
  ");
  	ibmasm_free_remote_input_dev(sp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
  	iounmap(sp->base_address);
  	ibmasm_event_buffer_exit(sp);
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
194
  	pci_set_drvdata(pdev, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  	kfree(sp);
278d72ae8   Max Asbock   [PATCH] ibmasm dr...
196
  	pci_release_regions(pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
  	pci_disable_device(pdev);
  }
  
  static struct pci_device_id ibmasm_pci_table[] =
  {
  	{ PCI_DEVICE(VENDORID_IBM, DEVICEID_RSA) },
  	{},
  };
  
  static struct pci_driver ibmasm_driver = {
  	.name		= DRIVER_NAME,
  	.id_table	= ibmasm_pci_table,
  	.probe		= ibmasm_init_one,
  	.remove		= __devexit_p(ibmasm_remove_one),
  };
  
  static void __exit ibmasm_exit (void)
  {
  	ibmasm_unregister_panic_notifier();
  	ibmasmfs_unregister();
  	pci_unregister_driver(&ibmasm_driver);
  	info(DRIVER_DESC " version " DRIVER_VERSION " unloaded");
  }
  
  static int __init ibmasm_init(void)
  {
  	int result;
  
  	result = ibmasmfs_register();
  	if (result) {
  		err("Failed to register ibmasmfs file system");
  		return result;
  	}
  	result = pci_register_driver(&ibmasm_driver);
  	if (result) {
  		ibmasmfs_unregister();
  		return result;
  	}
  	ibmasm_register_panic_notifier();
  	info(DRIVER_DESC " version " DRIVER_VERSION " loaded");
  	return 0;
  }
  
  module_init(ibmasm_init);
  module_exit(ibmasm_exit);
  
  MODULE_AUTHOR(DRIVER_AUTHOR);
  MODULE_DESCRIPTION(DRIVER_DESC);
  MODULE_LICENSE("GPL");
  MODULE_DEVICE_TABLE(pci, ibmasm_pci_table);