Linux-libre 5.4.39-gnu
[librecmc/linux-libre.git] / drivers / pci / hotplug / cpci_hotplug_core.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * CompactPCI Hot Plug Driver
4  *
5  * Copyright (C) 2002,2005 SOMA Networks, Inc.
6  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
7  * Copyright (C) 2001 IBM Corp.
8  *
9  * All rights reserved.
10  *
11  * Send feedback to <scottm@somanetworks.com>
12  */
13
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/sched/signal.h>
17 #include <linux/slab.h>
18 #include <linux/pci.h>
19 #include <linux/pci_hotplug.h>
20 #include <linux/init.h>
21 #include <linux/interrupt.h>
22 #include <linux/atomic.h>
23 #include <linux/delay.h>
24 #include <linux/kthread.h>
25 #include "cpci_hotplug.h"
26
27 #define DRIVER_AUTHOR   "Scott Murray <scottm@somanetworks.com>"
28 #define DRIVER_DESC     "CompactPCI Hot Plug Core"
29
30 #define MY_NAME "cpci_hotplug"
31
32 #define dbg(format, arg...)                                     \
33         do {                                                    \
34                 if (cpci_debug)                                 \
35                         printk(KERN_DEBUG "%s: " format "\n",   \
36                                 MY_NAME, ## arg);               \
37         } while (0)
38 #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME, ## arg)
39 #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME, ## arg)
40 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME, ## arg)
41
42 /* local variables */
43 static DECLARE_RWSEM(list_rwsem);
44 static LIST_HEAD(slot_list);
45 static int slots;
46 static atomic_t extracting;
47 int cpci_debug;
48 static struct cpci_hp_controller *controller;
49 static struct task_struct *cpci_thread;
50 static int thread_finished;
51
52 static int enable_slot(struct hotplug_slot *slot);
53 static int disable_slot(struct hotplug_slot *slot);
54 static int set_attention_status(struct hotplug_slot *slot, u8 value);
55 static int get_power_status(struct hotplug_slot *slot, u8 *value);
56 static int get_attention_status(struct hotplug_slot *slot, u8 *value);
57 static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
58 static int get_latch_status(struct hotplug_slot *slot, u8 *value);
59
60 static const struct hotplug_slot_ops cpci_hotplug_slot_ops = {
61         .enable_slot = enable_slot,
62         .disable_slot = disable_slot,
63         .set_attention_status = set_attention_status,
64         .get_power_status = get_power_status,
65         .get_attention_status = get_attention_status,
66         .get_adapter_status = get_adapter_status,
67         .get_latch_status = get_latch_status,
68 };
69
70 static int
71 enable_slot(struct hotplug_slot *hotplug_slot)
72 {
73         struct slot *slot = to_slot(hotplug_slot);
74         int retval = 0;
75
76         dbg("%s - physical_slot = %s", __func__, slot_name(slot));
77
78         if (controller->ops->set_power)
79                 retval = controller->ops->set_power(slot, 1);
80         return retval;
81 }
82
83 static int
84 disable_slot(struct hotplug_slot *hotplug_slot)
85 {
86         struct slot *slot = to_slot(hotplug_slot);
87         int retval = 0;
88
89         dbg("%s - physical_slot = %s", __func__, slot_name(slot));
90
91         down_write(&list_rwsem);
92
93         /* Unconfigure device */
94         dbg("%s - unconfiguring slot %s", __func__, slot_name(slot));
95         retval = cpci_unconfigure_slot(slot);
96         if (retval) {
97                 err("%s - could not unconfigure slot %s",
98                     __func__, slot_name(slot));
99                 goto disable_error;
100         }
101         dbg("%s - finished unconfiguring slot %s", __func__, slot_name(slot));
102
103         /* Clear EXT (by setting it) */
104         if (cpci_clear_ext(slot)) {
105                 err("%s - could not clear EXT for slot %s",
106                     __func__, slot_name(slot));
107                 retval = -ENODEV;
108                 goto disable_error;
109         }
110         cpci_led_on(slot);
111
112         if (controller->ops->set_power) {
113                 retval = controller->ops->set_power(slot, 0);
114                 if (retval)
115                         goto disable_error;
116         }
117
118         slot->adapter_status = 0;
119
120         if (slot->extracting) {
121                 slot->extracting = 0;
122                 atomic_dec(&extracting);
123         }
124 disable_error:
125         up_write(&list_rwsem);
126         return retval;
127 }
128
129 static u8
130 cpci_get_power_status(struct slot *slot)
131 {
132         u8 power = 1;
133
134         if (controller->ops->get_power)
135                 power = controller->ops->get_power(slot);
136         return power;
137 }
138
139 static int
140 get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
141 {
142         struct slot *slot = to_slot(hotplug_slot);
143
144         *value = cpci_get_power_status(slot);
145         return 0;
146 }
147
148 static int
149 get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
150 {
151         struct slot *slot = to_slot(hotplug_slot);
152
153         *value = cpci_get_attention_status(slot);
154         return 0;
155 }
156
157 static int
158 set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
159 {
160         return cpci_set_attention_status(to_slot(hotplug_slot), status);
161 }
162
163 static int
164 get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
165 {
166         struct slot *slot = to_slot(hotplug_slot);
167
168         *value = slot->adapter_status;
169         return 0;
170 }
171
172 static int
173 get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
174 {
175         struct slot *slot = to_slot(hotplug_slot);
176
177         *value = slot->latch_status;
178         return 0;
179 }
180
181 static void release_slot(struct slot *slot)
182 {
183         pci_dev_put(slot->dev);
184         kfree(slot);
185 }
186
187 #define SLOT_NAME_SIZE  6
188
189 int
190 cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
191 {
192         struct slot *slot;
193         char name[SLOT_NAME_SIZE];
194         int status;
195         int i;
196
197         if (!(controller && bus))
198                 return -ENODEV;
199
200         /*
201          * Create a structure for each slot, and register that slot
202          * with the pci_hotplug subsystem.
203          */
204         for (i = first; i <= last; ++i) {
205                 slot = kzalloc(sizeof(struct slot), GFP_KERNEL);
206                 if (!slot) {
207                         status = -ENOMEM;
208                         goto error;
209                 }
210
211                 slot->bus = bus;
212                 slot->number = i;
213                 slot->devfn = PCI_DEVFN(i, 0);
214
215                 snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i);
216
217                 slot->hotplug_slot.ops = &cpci_hotplug_slot_ops;
218
219                 dbg("registering slot %s", name);
220                 status = pci_hp_register(&slot->hotplug_slot, bus, i, name);
221                 if (status) {
222                         err("pci_hp_register failed with error %d", status);
223                         goto error_slot;
224                 }
225                 dbg("slot registered with name: %s", slot_name(slot));
226
227                 /* Add slot to our internal list */
228                 down_write(&list_rwsem);
229                 list_add(&slot->slot_list, &slot_list);
230                 slots++;
231                 up_write(&list_rwsem);
232         }
233         return 0;
234 error_slot:
235         kfree(slot);
236 error:
237         return status;
238 }
239 EXPORT_SYMBOL_GPL(cpci_hp_register_bus);
240
241 int
242 cpci_hp_unregister_bus(struct pci_bus *bus)
243 {
244         struct slot *slot;
245         struct slot *tmp;
246         int status = 0;
247
248         down_write(&list_rwsem);
249         if (!slots) {
250                 up_write(&list_rwsem);
251                 return -1;
252         }
253         list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
254                 if (slot->bus == bus) {
255                         list_del(&slot->slot_list);
256                         slots--;
257
258                         dbg("deregistering slot %s", slot_name(slot));
259                         pci_hp_deregister(&slot->hotplug_slot);
260                         release_slot(slot);
261                 }
262         }
263         up_write(&list_rwsem);
264         return status;
265 }
266 EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus);
267
268 /* This is the interrupt mode interrupt handler */
269 static irqreturn_t
270 cpci_hp_intr(int irq, void *data)
271 {
272         dbg("entered cpci_hp_intr");
273
274         /* Check to see if it was our interrupt */
275         if ((controller->irq_flags & IRQF_SHARED) &&
276             !controller->ops->check_irq(controller->dev_id)) {
277                 dbg("exited cpci_hp_intr, not our interrupt");
278                 return IRQ_NONE;
279         }
280
281         /* Disable ENUM interrupt */
282         controller->ops->disable_irq();
283
284         /* Trigger processing by the event thread */
285         wake_up_process(cpci_thread);
286         return IRQ_HANDLED;
287 }
288
289 /*
290  * According to PICMG 2.1 R2.0, section 6.3.2, upon
291  * initialization, the system driver shall clear the
292  * INS bits of the cold-inserted devices.
293  */
294 static int
295 init_slots(int clear_ins)
296 {
297         struct slot *slot;
298         struct pci_dev *dev;
299
300         dbg("%s - enter", __func__);
301         down_read(&list_rwsem);
302         if (!slots) {
303                 up_read(&list_rwsem);
304                 return -1;
305         }
306         list_for_each_entry(slot, &slot_list, slot_list) {
307                 dbg("%s - looking at slot %s", __func__, slot_name(slot));
308                 if (clear_ins && cpci_check_and_clear_ins(slot))
309                         dbg("%s - cleared INS for slot %s",
310                             __func__, slot_name(slot));
311                 dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
312                 if (dev) {
313                         slot->adapter_status = 1;
314                         slot->latch_status = 1;
315                         slot->dev = dev;
316                 }
317         }
318         up_read(&list_rwsem);
319         dbg("%s - exit", __func__);
320         return 0;
321 }
322
323 static int
324 check_slots(void)
325 {
326         struct slot *slot;
327         int extracted;
328         int inserted;
329         u16 hs_csr;
330
331         down_read(&list_rwsem);
332         if (!slots) {
333                 up_read(&list_rwsem);
334                 err("no slots registered, shutting down");
335                 return -1;
336         }
337         extracted = inserted = 0;
338         list_for_each_entry(slot, &slot_list, slot_list) {
339                 dbg("%s - looking at slot %s", __func__, slot_name(slot));
340                 if (cpci_check_and_clear_ins(slot)) {
341                         /*
342                          * Some broken hardware (e.g. PLX 9054AB) asserts
343                          * ENUM# twice...
344                          */
345                         if (slot->dev) {
346                                 warn("slot %s already inserted",
347                                      slot_name(slot));
348                                 inserted++;
349                                 continue;
350                         }
351
352                         /* Process insertion */
353                         dbg("%s - slot %s inserted", __func__, slot_name(slot));
354
355                         /* GSM, debug */
356                         hs_csr = cpci_get_hs_csr(slot);
357                         dbg("%s - slot %s HS_CSR (1) = %04x",
358                             __func__, slot_name(slot), hs_csr);
359
360                         /* Configure device */
361                         dbg("%s - configuring slot %s",
362                             __func__, slot_name(slot));
363                         if (cpci_configure_slot(slot)) {
364                                 err("%s - could not configure slot %s",
365                                     __func__, slot_name(slot));
366                                 continue;
367                         }
368                         dbg("%s - finished configuring slot %s",
369                             __func__, slot_name(slot));
370
371                         /* GSM, debug */
372                         hs_csr = cpci_get_hs_csr(slot);
373                         dbg("%s - slot %s HS_CSR (2) = %04x",
374                             __func__, slot_name(slot), hs_csr);
375
376                         slot->latch_status = 1;
377                         slot->adapter_status = 1;
378
379                         cpci_led_off(slot);
380
381                         /* GSM, debug */
382                         hs_csr = cpci_get_hs_csr(slot);
383                         dbg("%s - slot %s HS_CSR (3) = %04x",
384                             __func__, slot_name(slot), hs_csr);
385
386                         inserted++;
387                 } else if (cpci_check_ext(slot)) {
388                         /* Process extraction request */
389                         dbg("%s - slot %s extracted",
390                             __func__, slot_name(slot));
391
392                         /* GSM, debug */
393                         hs_csr = cpci_get_hs_csr(slot);
394                         dbg("%s - slot %s HS_CSR = %04x",
395                             __func__, slot_name(slot), hs_csr);
396
397                         if (!slot->extracting) {
398                                 slot->latch_status = 0;
399                                 slot->extracting = 1;
400                                 atomic_inc(&extracting);
401                         }
402                         extracted++;
403                 } else if (slot->extracting) {
404                         hs_csr = cpci_get_hs_csr(slot);
405                         if (hs_csr == 0xffff) {
406                                 /*
407                                  * Hmmm, we're likely hosed at this point, should we
408                                  * bother trying to tell the driver or not?
409                                  */
410                                 err("card in slot %s was improperly removed",
411                                     slot_name(slot));
412                                 slot->adapter_status = 0;
413                                 slot->extracting = 0;
414                                 atomic_dec(&extracting);
415                         }
416                 }
417         }
418         up_read(&list_rwsem);
419         dbg("inserted=%d, extracted=%d, extracting=%d",
420             inserted, extracted, atomic_read(&extracting));
421         if (inserted || extracted)
422                 return extracted;
423         else if (!atomic_read(&extracting)) {
424                 err("cannot find ENUM# source, shutting down");
425                 return -1;
426         }
427         return 0;
428 }
429
430 /* This is the interrupt mode worker thread body */
431 static int
432 event_thread(void *data)
433 {
434         int rc;
435
436         dbg("%s - event thread started", __func__);
437         while (1) {
438                 dbg("event thread sleeping");
439                 set_current_state(TASK_INTERRUPTIBLE);
440                 schedule();
441                 if (kthread_should_stop())
442                         break;
443                 do {
444                         rc = check_slots();
445                         if (rc > 0) {
446                                 /* Give userspace a chance to handle extraction */
447                                 msleep(500);
448                         } else if (rc < 0) {
449                                 dbg("%s - error checking slots", __func__);
450                                 thread_finished = 1;
451                                 goto out;
452                         }
453                 } while (atomic_read(&extracting) && !kthread_should_stop());
454                 if (kthread_should_stop())
455                         break;
456
457                 /* Re-enable ENUM# interrupt */
458                 dbg("%s - re-enabling irq", __func__);
459                 controller->ops->enable_irq();
460         }
461  out:
462         return 0;
463 }
464
465 /* This is the polling mode worker thread body */
466 static int
467 poll_thread(void *data)
468 {
469         int rc;
470
471         while (1) {
472                 if (kthread_should_stop() || signal_pending(current))
473                         break;
474                 if (controller->ops->query_enum()) {
475                         do {
476                                 rc = check_slots();
477                                 if (rc > 0) {
478                                         /* Give userspace a chance to handle extraction */
479                                         msleep(500);
480                                 } else if (rc < 0) {
481                                         dbg("%s - error checking slots", __func__);
482                                         thread_finished = 1;
483                                         goto out;
484                                 }
485                         } while (atomic_read(&extracting) && !kthread_should_stop());
486                 }
487                 msleep(100);
488         }
489  out:
490         return 0;
491 }
492
493 static int
494 cpci_start_thread(void)
495 {
496         if (controller->irq)
497                 cpci_thread = kthread_run(event_thread, NULL, "cpci_hp_eventd");
498         else
499                 cpci_thread = kthread_run(poll_thread, NULL, "cpci_hp_polld");
500         if (IS_ERR(cpci_thread)) {
501                 err("Can't start up our thread");
502                 return PTR_ERR(cpci_thread);
503         }
504         thread_finished = 0;
505         return 0;
506 }
507
508 static void
509 cpci_stop_thread(void)
510 {
511         kthread_stop(cpci_thread);
512         thread_finished = 1;
513 }
514
515 int
516 cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
517 {
518         int status = 0;
519
520         if (controller)
521                 return -1;
522         if (!(new_controller && new_controller->ops))
523                 return -EINVAL;
524         if (new_controller->irq) {
525                 if (!(new_controller->ops->enable_irq &&
526                      new_controller->ops->disable_irq))
527                         status = -EINVAL;
528                 if (request_irq(new_controller->irq,
529                                cpci_hp_intr,
530                                new_controller->irq_flags,
531                                MY_NAME,
532                                new_controller->dev_id)) {
533                         err("Can't get irq %d for the hotplug cPCI controller",
534                             new_controller->irq);
535                         status = -ENODEV;
536                 }
537                 dbg("%s - acquired controller irq %d",
538                     __func__, new_controller->irq);
539         }
540         if (!status)
541                 controller = new_controller;
542         return status;
543 }
544 EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
545
546 static void
547 cleanup_slots(void)
548 {
549         struct slot *slot;
550         struct slot *tmp;
551
552         /*
553          * Unregister all of our slots with the pci_hotplug subsystem,
554          * and free up all memory that we had allocated.
555          */
556         down_write(&list_rwsem);
557         if (!slots)
558                 goto cleanup_null;
559         list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
560                 list_del(&slot->slot_list);
561                 pci_hp_deregister(&slot->hotplug_slot);
562                 release_slot(slot);
563         }
564 cleanup_null:
565         up_write(&list_rwsem);
566 }
567
568 int
569 cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
570 {
571         int status = 0;
572
573         if (controller) {
574                 if (!thread_finished)
575                         cpci_stop_thread();
576                 if (controller->irq)
577                         free_irq(controller->irq, controller->dev_id);
578                 controller = NULL;
579                 cleanup_slots();
580         } else
581                 status = -ENODEV;
582         return status;
583 }
584 EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller);
585
586 int
587 cpci_hp_start(void)
588 {
589         static int first = 1;
590         int status;
591
592         dbg("%s - enter", __func__);
593         if (!controller)
594                 return -ENODEV;
595
596         down_read(&list_rwsem);
597         if (list_empty(&slot_list)) {
598                 up_read(&list_rwsem);
599                 return -ENODEV;
600         }
601         up_read(&list_rwsem);
602
603         status = init_slots(first);
604         if (first)
605                 first = 0;
606         if (status)
607                 return status;
608
609         status = cpci_start_thread();
610         if (status)
611                 return status;
612         dbg("%s - thread started", __func__);
613
614         if (controller->irq) {
615                 /* Start enum interrupt processing */
616                 dbg("%s - enabling irq", __func__);
617                 controller->ops->enable_irq();
618         }
619         dbg("%s - exit", __func__);
620         return 0;
621 }
622 EXPORT_SYMBOL_GPL(cpci_hp_start);
623
624 int
625 cpci_hp_stop(void)
626 {
627         if (!controller)
628                 return -ENODEV;
629         if (controller->irq) {
630                 /* Stop enum interrupt processing */
631                 dbg("%s - disabling irq", __func__);
632                 controller->ops->disable_irq();
633         }
634         cpci_stop_thread();
635         return 0;
636 }
637 EXPORT_SYMBOL_GPL(cpci_hp_stop);
638
639 int __init
640 cpci_hotplug_init(int debug)
641 {
642         cpci_debug = debug;
643         return 0;
644 }