1 /*
2 * SCOM FSI Client device driver
3 *
4 * Copyright (C) IBM Corporation 2016
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
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 * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16 #include <linux/fsi.h>
17 #include <linux/module.h>
18 #include <linux/cdev.h>
19 #include <linux/delay.h>
20 #include <linux/fs.h>
21 #include <linux/uaccess.h>
22 #include <linux/slab.h>
23 #include <linux/cdev.h>
24 #include <linux/list.h>
25
26 #include <uapi/linux/fsi.h>
27
28 #define FSI_ENGID_SCOM 0x5
29
30 /* SCOM engine register set */
31 #define SCOM_DATA0_REG 0x00
32 #define SCOM_DATA1_REG 0x04
33 #define SCOM_CMD_REG 0x08
34 #define SCOM_FSI2PIB_RESET_REG 0x18
35 #define SCOM_STATUS_REG 0x1C /* Read */
36 #define SCOM_PIB_RESET_REG 0x1C /* Write */
37
38 /* Command register */
39 #define SCOM_WRITE_CMD 0x80000000
40 #define SCOM_READ_CMD 0x00000000
41
42 /* Status register bits */
43 #define SCOM_STATUS_ERR_SUMMARY 0x80000000
44 #define SCOM_STATUS_PROTECTION 0x01000000
45 #define SCOM_STATUS_PARITY 0x04000000
46 #define SCOM_STATUS_PIB_ABORT 0x00100000
47 #define SCOM_STATUS_PIB_RESP_MASK 0x00007000
48 #define SCOM_STATUS_PIB_RESP_SHIFT 12
49
50 #define SCOM_STATUS_ANY_ERR (SCOM_STATUS_ERR_SUMMARY | \
51 SCOM_STATUS_PROTECTION | \
52 SCOM_STATUS_PARITY | \
53 SCOM_STATUS_PIB_ABORT | \
54 SCOM_STATUS_PIB_RESP_MASK)
55 /* SCOM address encodings */
56 #define XSCOM_ADDR_IND_FLAG BIT_ULL(63)
57 #define XSCOM_ADDR_INF_FORM1 BIT_ULL(60)
58
59 /* SCOM indirect stuff */
60 #define XSCOM_ADDR_DIRECT_PART 0x7fffffffull
61 #define XSCOM_ADDR_INDIRECT_PART 0x000fffff00000000ull
62 #define XSCOM_DATA_IND_READ BIT_ULL(63)
63 #define XSCOM_DATA_IND_COMPLETE BIT_ULL(31)
64 #define XSCOM_DATA_IND_ERR_MASK 0x70000000ull
65 #define XSCOM_DATA_IND_ERR_SHIFT 28
66 #define XSCOM_DATA_IND_DATA 0x0000ffffull
67 #define XSCOM_DATA_IND_FORM1_DATA 0x000fffffffffffffull
68 #define XSCOM_ADDR_FORM1_LOW 0x000ffffffffull
69 #define XSCOM_ADDR_FORM1_HI 0xfff00000000ull
70 #define XSCOM_ADDR_FORM1_HI_SHIFT 20
71
72 /* Retries */
73 #define SCOM_MAX_RETRIES 100 /* Retries on busy */
74 #define SCOM_MAX_IND_RETRIES 10 /* Retries indirect not ready */
75
76 struct scom_device {
77 struct list_head link;
78 struct fsi_device *fsi_dev;
79 struct device dev;
80 struct cdev cdev;
81 struct mutex lock;
82 bool dead;
83 };
84
__put_scom(struct scom_device * scom_dev,uint64_t value,uint32_t addr,uint32_t * status)85 static int __put_scom(struct scom_device *scom_dev, uint64_t value,
86 uint32_t addr, uint32_t *status)
87 {
88 __be32 data, raw_status;
89 int rc;
90
91 data = cpu_to_be32((value >> 32) & 0xffffffff);
92 rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA0_REG, &data,
93 sizeof(uint32_t));
94 if (rc)
95 return rc;
96
97 data = cpu_to_be32(value & 0xffffffff);
98 rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA1_REG, &data,
99 sizeof(uint32_t));
100 if (rc)
101 return rc;
102
103 data = cpu_to_be32(SCOM_WRITE_CMD | addr);
104 rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data,
105 sizeof(uint32_t));
106 if (rc)
107 return rc;
108 rc = fsi_device_read(scom_dev->fsi_dev, SCOM_STATUS_REG, &raw_status,
109 sizeof(uint32_t));
110 if (rc)
111 return rc;
112 *status = be32_to_cpu(raw_status);
113
114 return 0;
115 }
116
__get_scom(struct scom_device * scom_dev,uint64_t * value,uint32_t addr,uint32_t * status)117 static int __get_scom(struct scom_device *scom_dev, uint64_t *value,
118 uint32_t addr, uint32_t *status)
119 {
120 __be32 data, raw_status;
121 int rc;
122
123
124 *value = 0ULL;
125 data = cpu_to_be32(SCOM_READ_CMD | addr);
126 rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data,
127 sizeof(uint32_t));
128 if (rc)
129 return rc;
130 rc = fsi_device_read(scom_dev->fsi_dev, SCOM_STATUS_REG, &raw_status,
131 sizeof(uint32_t));
132 if (rc)
133 return rc;
134
135 /*
136 * Read the data registers even on error, so we don't have
137 * to interpret the status register here.
138 */
139 rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA0_REG, &data,
140 sizeof(uint32_t));
141 if (rc)
142 return rc;
143 *value |= (uint64_t)be32_to_cpu(data) << 32;
144 rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA1_REG, &data,
145 sizeof(uint32_t));
146 if (rc)
147 return rc;
148 *value |= be32_to_cpu(data);
149 *status = be32_to_cpu(raw_status);
150
151 return rc;
152 }
153
put_indirect_scom_form0(struct scom_device * scom,uint64_t value,uint64_t addr,uint32_t * status)154 static int put_indirect_scom_form0(struct scom_device *scom, uint64_t value,
155 uint64_t addr, uint32_t *status)
156 {
157 uint64_t ind_data, ind_addr;
158 int rc, retries, err = 0;
159
160 if (value & ~XSCOM_DATA_IND_DATA)
161 return -EINVAL;
162
163 ind_addr = addr & XSCOM_ADDR_DIRECT_PART;
164 ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | value;
165 rc = __put_scom(scom, ind_data, ind_addr, status);
166 if (rc || (*status & SCOM_STATUS_ANY_ERR))
167 return rc;
168
169 for (retries = 0; retries < SCOM_MAX_IND_RETRIES; retries++) {
170 rc = __get_scom(scom, &ind_data, addr, status);
171 if (rc || (*status & SCOM_STATUS_ANY_ERR))
172 return rc;
173
174 err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
175 *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
176 if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err != SCOM_PIB_BLOCKED))
177 return 0;
178
179 msleep(1);
180 }
181 return rc;
182 }
183
put_indirect_scom_form1(struct scom_device * scom,uint64_t value,uint64_t addr,uint32_t * status)184 static int put_indirect_scom_form1(struct scom_device *scom, uint64_t value,
185 uint64_t addr, uint32_t *status)
186 {
187 uint64_t ind_data, ind_addr;
188
189 if (value & ~XSCOM_DATA_IND_FORM1_DATA)
190 return -EINVAL;
191
192 ind_addr = addr & XSCOM_ADDR_FORM1_LOW;
193 ind_data = value | (addr & XSCOM_ADDR_FORM1_HI) << XSCOM_ADDR_FORM1_HI_SHIFT;
194 return __put_scom(scom, ind_data, ind_addr, status);
195 }
196
get_indirect_scom_form0(struct scom_device * scom,uint64_t * value,uint64_t addr,uint32_t * status)197 static int get_indirect_scom_form0(struct scom_device *scom, uint64_t *value,
198 uint64_t addr, uint32_t *status)
199 {
200 uint64_t ind_data, ind_addr;
201 int rc, retries, err = 0;
202
203 ind_addr = addr & XSCOM_ADDR_DIRECT_PART;
204 ind_data = (addr & XSCOM_ADDR_INDIRECT_PART) | XSCOM_DATA_IND_READ;
205 rc = __put_scom(scom, ind_data, ind_addr, status);
206 if (rc || (*status & SCOM_STATUS_ANY_ERR))
207 return rc;
208
209 for (retries = 0; retries < SCOM_MAX_IND_RETRIES; retries++) {
210 rc = __get_scom(scom, &ind_data, addr, status);
211 if (rc || (*status & SCOM_STATUS_ANY_ERR))
212 return rc;
213
214 err = (ind_data & XSCOM_DATA_IND_ERR_MASK) >> XSCOM_DATA_IND_ERR_SHIFT;
215 *status = err << SCOM_STATUS_PIB_RESP_SHIFT;
216 *value = ind_data & XSCOM_DATA_IND_DATA;
217
218 if ((ind_data & XSCOM_DATA_IND_COMPLETE) || (err != SCOM_PIB_BLOCKED))
219 return 0;
220
221 msleep(1);
222 }
223 return rc;
224 }
225
raw_put_scom(struct scom_device * scom,uint64_t value,uint64_t addr,uint32_t * status)226 static int raw_put_scom(struct scom_device *scom, uint64_t value,
227 uint64_t addr, uint32_t *status)
228 {
229 if (addr & XSCOM_ADDR_IND_FLAG) {
230 if (addr & XSCOM_ADDR_INF_FORM1)
231 return put_indirect_scom_form1(scom, value, addr, status);
232 else
233 return put_indirect_scom_form0(scom, value, addr, status);
234 } else
235 return __put_scom(scom, value, addr, status);
236 }
237
raw_get_scom(struct scom_device * scom,uint64_t * value,uint64_t addr,uint32_t * status)238 static int raw_get_scom(struct scom_device *scom, uint64_t *value,
239 uint64_t addr, uint32_t *status)
240 {
241 if (addr & XSCOM_ADDR_IND_FLAG) {
242 if (addr & XSCOM_ADDR_INF_FORM1)
243 return -ENXIO;
244 return get_indirect_scom_form0(scom, value, addr, status);
245 } else
246 return __get_scom(scom, value, addr, status);
247 }
248
handle_fsi2pib_status(struct scom_device * scom,uint32_t status)249 static int handle_fsi2pib_status(struct scom_device *scom, uint32_t status)
250 {
251 uint32_t dummy = -1;
252
253 if (status & SCOM_STATUS_PROTECTION)
254 return -EPERM;
255 if (status & SCOM_STATUS_PARITY) {
256 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
257 sizeof(uint32_t));
258 return -EIO;
259 }
260 /* Return -EBUSY on PIB abort to force a retry */
261 if (status & SCOM_STATUS_PIB_ABORT)
262 return -EBUSY;
263 if (status & SCOM_STATUS_ERR_SUMMARY) {
264 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
265 sizeof(uint32_t));
266 return -EIO;
267 }
268 return 0;
269 }
270
handle_pib_status(struct scom_device * scom,uint8_t status)271 static int handle_pib_status(struct scom_device *scom, uint8_t status)
272 {
273 uint32_t dummy = -1;
274
275 if (status == SCOM_PIB_SUCCESS)
276 return 0;
277 if (status == SCOM_PIB_BLOCKED)
278 return -EBUSY;
279
280 /* Reset the bridge */
281 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
282 sizeof(uint32_t));
283
284 switch(status) {
285 case SCOM_PIB_OFFLINE:
286 return -ENODEV;
287 case SCOM_PIB_BAD_ADDR:
288 return -ENXIO;
289 case SCOM_PIB_TIMEOUT:
290 return -ETIMEDOUT;
291 case SCOM_PIB_PARTIAL:
292 case SCOM_PIB_CLK_ERR:
293 case SCOM_PIB_PARITY_ERR:
294 default:
295 return -EIO;
296 }
297 }
298
put_scom(struct scom_device * scom,uint64_t value,uint64_t addr)299 static int put_scom(struct scom_device *scom, uint64_t value,
300 uint64_t addr)
301 {
302 uint32_t status, dummy = -1;
303 int rc, retries;
304
305 for (retries = 0; retries < SCOM_MAX_RETRIES; retries++) {
306 rc = raw_put_scom(scom, value, addr, &status);
307 if (rc) {
308 /* Try resetting the bridge if FSI fails */
309 if (rc != -ENODEV && retries == 0) {
310 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG,
311 &dummy, sizeof(uint32_t));
312 rc = -EBUSY;
313 } else
314 return rc;
315 } else
316 rc = handle_fsi2pib_status(scom, status);
317 if (rc && rc != -EBUSY)
318 break;
319 if (rc == 0) {
320 rc = handle_pib_status(scom,
321 (status & SCOM_STATUS_PIB_RESP_MASK)
322 >> SCOM_STATUS_PIB_RESP_SHIFT);
323 if (rc && rc != -EBUSY)
324 break;
325 }
326 if (rc == 0)
327 break;
328 msleep(1);
329 }
330 return rc;
331 }
332
get_scom(struct scom_device * scom,uint64_t * value,uint64_t addr)333 static int get_scom(struct scom_device *scom, uint64_t *value,
334 uint64_t addr)
335 {
336 uint32_t status, dummy = -1;
337 int rc, retries;
338
339 for (retries = 0; retries < SCOM_MAX_RETRIES; retries++) {
340 rc = raw_get_scom(scom, value, addr, &status);
341 if (rc) {
342 /* Try resetting the bridge if FSI fails */
343 if (rc != -ENODEV && retries == 0) {
344 fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG,
345 &dummy, sizeof(uint32_t));
346 rc = -EBUSY;
347 } else
348 return rc;
349 } else
350 rc = handle_fsi2pib_status(scom, status);
351 if (rc && rc != -EBUSY)
352 break;
353 if (rc == 0) {
354 rc = handle_pib_status(scom,
355 (status & SCOM_STATUS_PIB_RESP_MASK)
356 >> SCOM_STATUS_PIB_RESP_SHIFT);
357 if (rc && rc != -EBUSY)
358 break;
359 }
360 if (rc == 0)
361 break;
362 msleep(1);
363 }
364 return rc;
365 }
366
scom_read(struct file * filep,char __user * buf,size_t len,loff_t * offset)367 static ssize_t scom_read(struct file *filep, char __user *buf, size_t len,
368 loff_t *offset)
369 {
370 struct scom_device *scom = filep->private_data;
371 struct device *dev = &scom->fsi_dev->dev;
372 uint64_t val;
373 int rc;
374
375 if (len != sizeof(uint64_t))
376 return -EINVAL;
377
378 mutex_lock(&scom->lock);
379 if (scom->dead)
380 rc = -ENODEV;
381 else
382 rc = get_scom(scom, &val, *offset);
383 mutex_unlock(&scom->lock);
384 if (rc) {
385 dev_dbg(dev, "get_scom fail:%d\n", rc);
386 return rc;
387 }
388
389 rc = copy_to_user(buf, &val, len);
390 if (rc)
391 dev_dbg(dev, "copy to user failed:%d\n", rc);
392
393 return rc ? rc : len;
394 }
395
scom_write(struct file * filep,const char __user * buf,size_t len,loff_t * offset)396 static ssize_t scom_write(struct file *filep, const char __user *buf,
397 size_t len, loff_t *offset)
398 {
399 int rc;
400 struct scom_device *scom = filep->private_data;
401 struct device *dev = &scom->fsi_dev->dev;
402 uint64_t val;
403
404 if (len != sizeof(uint64_t))
405 return -EINVAL;
406
407 rc = copy_from_user(&val, buf, len);
408 if (rc) {
409 dev_dbg(dev, "copy from user failed:%d\n", rc);
410 return -EINVAL;
411 }
412
413 mutex_lock(&scom->lock);
414 if (scom->dead)
415 rc = -ENODEV;
416 else
417 rc = put_scom(scom, val, *offset);
418 mutex_unlock(&scom->lock);
419 if (rc) {
420 dev_dbg(dev, "put_scom failed with:%d\n", rc);
421 return rc;
422 }
423
424 return len;
425 }
426
scom_llseek(struct file * file,loff_t offset,int whence)427 static loff_t scom_llseek(struct file *file, loff_t offset, int whence)
428 {
429 switch (whence) {
430 case SEEK_CUR:
431 break;
432 case SEEK_SET:
433 file->f_pos = offset;
434 break;
435 default:
436 return -EINVAL;
437 }
438
439 return offset;
440 }
441
raw_convert_status(struct scom_access * acc,uint32_t status)442 static void raw_convert_status(struct scom_access *acc, uint32_t status)
443 {
444 acc->pib_status = (status & SCOM_STATUS_PIB_RESP_MASK) >>
445 SCOM_STATUS_PIB_RESP_SHIFT;
446 acc->intf_errors = 0;
447
448 if (status & SCOM_STATUS_PROTECTION)
449 acc->intf_errors |= SCOM_INTF_ERR_PROTECTION;
450 else if (status & SCOM_STATUS_PARITY)
451 acc->intf_errors |= SCOM_INTF_ERR_PARITY;
452 else if (status & SCOM_STATUS_PIB_ABORT)
453 acc->intf_errors |= SCOM_INTF_ERR_ABORT;
454 else if (status & SCOM_STATUS_ERR_SUMMARY)
455 acc->intf_errors |= SCOM_INTF_ERR_UNKNOWN;
456 }
457
scom_raw_read(struct scom_device * scom,void __user * argp)458 static int scom_raw_read(struct scom_device *scom, void __user *argp)
459 {
460 struct scom_access acc;
461 uint32_t status;
462 int rc;
463
464 if (copy_from_user(&acc, argp, sizeof(struct scom_access)))
465 return -EFAULT;
466
467 rc = raw_get_scom(scom, &acc.data, acc.addr, &status);
468 if (rc)
469 return rc;
470 raw_convert_status(&acc, status);
471 if (copy_to_user(argp, &acc, sizeof(struct scom_access)))
472 return -EFAULT;
473 return 0;
474 }
475
scom_raw_write(struct scom_device * scom,void __user * argp)476 static int scom_raw_write(struct scom_device *scom, void __user *argp)
477 {
478 u64 prev_data, mask, data;
479 struct scom_access acc;
480 uint32_t status;
481 int rc;
482
483 if (copy_from_user(&acc, argp, sizeof(struct scom_access)))
484 return -EFAULT;
485
486 if (acc.mask) {
487 rc = raw_get_scom(scom, &prev_data, acc.addr, &status);
488 if (rc)
489 return rc;
490 if (status & SCOM_STATUS_ANY_ERR)
491 goto fail;
492 mask = acc.mask;
493 } else {
494 prev_data = mask = -1ull;
495 }
496 data = (prev_data & ~mask) | (acc.data & mask);
497 rc = raw_put_scom(scom, data, acc.addr, &status);
498 if (rc)
499 return rc;
500 fail:
501 raw_convert_status(&acc, status);
502 if (copy_to_user(argp, &acc, sizeof(struct scom_access)))
503 return -EFAULT;
504 return 0;
505 }
506
scom_reset(struct scom_device * scom,void __user * argp)507 static int scom_reset(struct scom_device *scom, void __user *argp)
508 {
509 uint32_t flags, dummy = -1;
510 int rc = 0;
511
512 if (get_user(flags, (__u32 __user *)argp))
513 return -EFAULT;
514 if (flags & SCOM_RESET_PIB)
515 rc = fsi_device_write(scom->fsi_dev, SCOM_PIB_RESET_REG, &dummy,
516 sizeof(uint32_t));
517 if (!rc && (flags & (SCOM_RESET_PIB | SCOM_RESET_INTF)))
518 rc = fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, &dummy,
519 sizeof(uint32_t));
520 return rc;
521 }
522
scom_check(struct scom_device * scom,void __user * argp)523 static int scom_check(struct scom_device *scom, void __user *argp)
524 {
525 /* Still need to find out how to get "protected" */
526 return put_user(SCOM_CHECK_SUPPORTED, (__u32 __user *)argp);
527 }
528
scom_ioctl(struct file * file,unsigned int cmd,unsigned long arg)529 static long scom_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
530 {
531 struct scom_device *scom = file->private_data;
532 void __user *argp = (void __user *)arg;
533 int rc = -ENOTTY;
534
535 mutex_lock(&scom->lock);
536 if (scom->dead) {
537 mutex_unlock(&scom->lock);
538 return -ENODEV;
539 }
540 switch(cmd) {
541 case FSI_SCOM_CHECK:
542 rc = scom_check(scom, argp);
543 break;
544 case FSI_SCOM_READ:
545 rc = scom_raw_read(scom, argp);
546 break;
547 case FSI_SCOM_WRITE:
548 rc = scom_raw_write(scom, argp);
549 break;
550 case FSI_SCOM_RESET:
551 rc = scom_reset(scom, argp);
552 break;
553 }
554 mutex_unlock(&scom->lock);
555 return rc;
556 }
557
scom_open(struct inode * inode,struct file * file)558 static int scom_open(struct inode *inode, struct file *file)
559 {
560 struct scom_device *scom = container_of(inode->i_cdev, struct scom_device, cdev);
561
562 file->private_data = scom;
563
564 return 0;
565 }
566
567 static const struct file_operations scom_fops = {
568 .owner = THIS_MODULE,
569 .open = scom_open,
570 .llseek = scom_llseek,
571 .read = scom_read,
572 .write = scom_write,
573 .unlocked_ioctl = scom_ioctl,
574 };
575
scom_free(struct device * dev)576 static void scom_free(struct device *dev)
577 {
578 struct scom_device *scom = container_of(dev, struct scom_device, dev);
579
580 put_device(&scom->fsi_dev->dev);
581 kfree(scom);
582 }
583
scom_probe(struct device * dev)584 static int scom_probe(struct device *dev)
585 {
586 struct fsi_device *fsi_dev = to_fsi_dev(dev);
587 struct scom_device *scom;
588 int rc, didx;
589
590 scom = kzalloc(sizeof(*scom), GFP_KERNEL);
591 if (!scom)
592 return -ENOMEM;
593 dev_set_drvdata(dev, scom);
594 mutex_init(&scom->lock);
595
596 /* Grab a reference to the device (parent of our cdev), we'll drop it later */
597 if (!get_device(dev)) {
598 kfree(scom);
599 return -ENODEV;
600 }
601 scom->fsi_dev = fsi_dev;
602
603 /* Create chardev for userspace access */
604 scom->dev.type = &fsi_cdev_type;
605 scom->dev.parent = dev;
606 scom->dev.release = scom_free;
607 device_initialize(&scom->dev);
608
609 /* Allocate a minor in the FSI space */
610 rc = fsi_get_new_minor(fsi_dev, fsi_dev_scom, &scom->dev.devt, &didx);
611 if (rc)
612 goto err;
613
614 dev_set_name(&scom->dev, "scom%d", didx);
615 cdev_init(&scom->cdev, &scom_fops);
616 rc = cdev_device_add(&scom->cdev, &scom->dev);
617 if (rc) {
618 dev_err(dev, "Error %d creating char device %s\n",
619 rc, dev_name(&scom->dev));
620 goto err_free_minor;
621 }
622
623 return 0;
624 err_free_minor:
625 fsi_free_minor(scom->dev.devt);
626 err:
627 put_device(&scom->dev);
628 return rc;
629 }
630
scom_remove(struct device * dev)631 static int scom_remove(struct device *dev)
632 {
633 struct scom_device *scom = dev_get_drvdata(dev);
634
635 mutex_lock(&scom->lock);
636 scom->dead = true;
637 mutex_unlock(&scom->lock);
638 cdev_device_del(&scom->cdev, &scom->dev);
639 fsi_free_minor(scom->dev.devt);
640 put_device(&scom->dev);
641
642 return 0;
643 }
644
645 static struct fsi_device_id scom_ids[] = {
646 {
647 .engine_type = FSI_ENGID_SCOM,
648 .version = FSI_VERSION_ANY,
649 },
650 { 0 }
651 };
652
653 static struct fsi_driver scom_drv = {
654 .id_table = scom_ids,
655 .drv = {
656 .name = "scom",
657 .bus = &fsi_bus_type,
658 .probe = scom_probe,
659 .remove = scom_remove,
660 }
661 };
662
scom_init(void)663 static int scom_init(void)
664 {
665 return fsi_driver_register(&scom_drv);
666 }
667
scom_exit(void)668 static void scom_exit(void)
669 {
670 fsi_driver_unregister(&scom_drv);
671 }
672
673 module_init(scom_init);
674 module_exit(scom_exit);
675 MODULE_LICENSE("GPL");
676