netfilter: netns: shrink netns_ct struct
[linux-2.6-microblaze.git] / drivers / fsi / fsi-scom.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
663 static int scom_init(void)
664 {
665         return fsi_driver_register(&scom_drv);
666 }
667
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");