LCOV - code coverage report
Current view: top level - drivers/pci/hotplug - cpci_hotplug_core.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 3 309 1.0 %
Date: 2022-03-28 13:20:08 Functions: 1 21 4.8 %
Branches: 0 218 0.0 %

           Branch data     Line data    Source code
       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                 :          0 : enable_slot(struct hotplug_slot *hotplug_slot)
      72                 :            : {
      73         [ #  # ]:          0 :         struct slot *slot = to_slot(hotplug_slot);
      74                 :          0 :         int retval = 0;
      75                 :            : 
      76         [ #  # ]:          0 :         dbg("%s - physical_slot = %s", __func__, slot_name(slot));
      77                 :            : 
      78         [ #  # ]:          0 :         if (controller->ops->set_power)
      79                 :          0 :                 retval = controller->ops->set_power(slot, 1);
      80                 :          0 :         return retval;
      81                 :            : }
      82                 :            : 
      83                 :            : static int
      84                 :          0 : disable_slot(struct hotplug_slot *hotplug_slot)
      85                 :            : {
      86         [ #  # ]:          0 :         struct slot *slot = to_slot(hotplug_slot);
      87                 :          0 :         int retval = 0;
      88                 :            : 
      89         [ #  # ]:          0 :         dbg("%s - physical_slot = %s", __func__, slot_name(slot));
      90                 :            : 
      91                 :          0 :         down_write(&list_rwsem);
      92                 :            : 
      93                 :            :         /* Unconfigure device */
      94         [ #  # ]:          0 :         dbg("%s - unconfiguring slot %s", __func__, slot_name(slot));
      95                 :          0 :         retval = cpci_unconfigure_slot(slot);
      96         [ #  # ]:          0 :         if (retval) {
      97                 :          0 :                 err("%s - could not unconfigure slot %s",
      98                 :            :                     __func__, slot_name(slot));
      99                 :          0 :                 goto disable_error;
     100                 :            :         }
     101         [ #  # ]:          0 :         dbg("%s - finished unconfiguring slot %s", __func__, slot_name(slot));
     102                 :            : 
     103                 :            :         /* Clear EXT (by setting it) */
     104         [ #  # ]:          0 :         if (cpci_clear_ext(slot)) {
     105                 :          0 :                 err("%s - could not clear EXT for slot %s",
     106                 :            :                     __func__, slot_name(slot));
     107                 :          0 :                 retval = -ENODEV;
     108                 :          0 :                 goto disable_error;
     109                 :            :         }
     110                 :          0 :         cpci_led_on(slot);
     111                 :            : 
     112         [ #  # ]:          0 :         if (controller->ops->set_power) {
     113                 :          0 :                 retval = controller->ops->set_power(slot, 0);
     114         [ #  # ]:          0 :                 if (retval)
     115                 :          0 :                         goto disable_error;
     116                 :            :         }
     117                 :            : 
     118                 :          0 :         slot->adapter_status = 0;
     119                 :            : 
     120         [ #  # ]:          0 :         if (slot->extracting) {
     121                 :          0 :                 slot->extracting = 0;
     122                 :          0 :                 atomic_dec(&extracting);
     123                 :            :         }
     124                 :          0 : disable_error:
     125                 :          0 :         up_write(&list_rwsem);
     126                 :          0 :         return retval;
     127                 :            : }
     128                 :            : 
     129                 :            : static u8
     130                 :          0 : cpci_get_power_status(struct slot *slot)
     131                 :            : {
     132                 :          0 :         u8 power = 1;
     133                 :            : 
     134                 :          0 :         if (controller->ops->get_power)
     135                 :          0 :                 power = controller->ops->get_power(slot);
     136                 :          0 :         return power;
     137                 :            : }
     138                 :            : 
     139                 :            : static int
     140                 :          0 : get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
     141                 :            : {
     142         [ #  # ]:          0 :         struct slot *slot = to_slot(hotplug_slot);
     143                 :            : 
     144         [ #  # ]:          0 :         *value = cpci_get_power_status(slot);
     145                 :          0 :         return 0;
     146                 :            : }
     147                 :            : 
     148                 :            : static int
     149                 :          0 : get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
     150                 :            : {
     151                 :          0 :         struct slot *slot = to_slot(hotplug_slot);
     152                 :            : 
     153                 :          0 :         *value = cpci_get_attention_status(slot);
     154                 :          0 :         return 0;
     155                 :            : }
     156                 :            : 
     157                 :            : static int
     158                 :          0 : set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
     159                 :            : {
     160                 :          0 :         return cpci_set_attention_status(to_slot(hotplug_slot), status);
     161                 :            : }
     162                 :            : 
     163                 :            : static int
     164                 :          0 : get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
     165                 :            : {
     166                 :          0 :         struct slot *slot = to_slot(hotplug_slot);
     167                 :            : 
     168                 :          0 :         *value = slot->adapter_status;
     169                 :          0 :         return 0;
     170                 :            : }
     171                 :            : 
     172                 :            : static int
     173                 :          0 : get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
     174                 :            : {
     175                 :          0 :         struct slot *slot = to_slot(hotplug_slot);
     176                 :            : 
     177                 :          0 :         *value = slot->latch_status;
     178                 :          0 :         return 0;
     179                 :            : }
     180                 :            : 
     181                 :          0 : static void release_slot(struct slot *slot)
     182                 :            : {
     183                 :          0 :         pci_dev_put(slot->dev);
     184                 :          0 :         kfree(slot);
     185                 :          0 : }
     186                 :            : 
     187                 :            : #define SLOT_NAME_SIZE  6
     188                 :            : 
     189                 :            : int
     190                 :          0 : cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
     191                 :            : {
     192                 :          0 :         struct slot *slot;
     193                 :          0 :         char name[SLOT_NAME_SIZE];
     194                 :          0 :         int status;
     195                 :          0 :         int i;
     196                 :            : 
     197   [ #  #  #  # ]:          0 :         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         [ #  # ]:          0 :         for (i = first; i <= last; ++i) {
     205                 :          0 :                 slot = kzalloc(sizeof(struct slot), GFP_KERNEL);
     206         [ #  # ]:          0 :                 if (!slot) {
     207                 :          0 :                         status = -ENOMEM;
     208                 :          0 :                         goto error;
     209                 :            :                 }
     210                 :            : 
     211                 :          0 :                 slot->bus = bus;
     212                 :          0 :                 slot->number = i;
     213                 :          0 :                 slot->devfn = PCI_DEVFN(i, 0);
     214                 :            : 
     215                 :          0 :                 snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i);
     216                 :            : 
     217                 :          0 :                 slot->hotplug_slot.ops = &cpci_hotplug_slot_ops;
     218                 :            : 
     219         [ #  # ]:          0 :                 dbg("registering slot %s", name);
     220                 :          0 :                 status = pci_hp_register(&slot->hotplug_slot, bus, i, name);
     221         [ #  # ]:          0 :                 if (status) {
     222                 :          0 :                         err("pci_hp_register failed with error %d", status);
     223                 :          0 :                         goto error_slot;
     224                 :            :                 }
     225         [ #  # ]:          0 :                 dbg("slot registered with name: %s", slot_name(slot));
     226                 :            : 
     227                 :            :                 /* Add slot to our internal list */
     228                 :          0 :                 down_write(&list_rwsem);
     229                 :          0 :                 list_add(&slot->slot_list, &slot_list);
     230                 :          0 :                 slots++;
     231                 :          0 :                 up_write(&list_rwsem);
     232                 :            :         }
     233                 :            :         return 0;
     234                 :            : error_slot:
     235                 :          0 :         kfree(slot);
     236                 :            : error:
     237                 :            :         return status;
     238                 :            : }
     239                 :            : EXPORT_SYMBOL_GPL(cpci_hp_register_bus);
     240                 :            : 
     241                 :            : int
     242                 :          0 : cpci_hp_unregister_bus(struct pci_bus *bus)
     243                 :            : {
     244                 :          0 :         struct slot *slot;
     245                 :          0 :         struct slot *tmp;
     246                 :          0 :         int status = 0;
     247                 :            : 
     248                 :          0 :         down_write(&list_rwsem);
     249         [ #  # ]:          0 :         if (!slots) {
     250                 :          0 :                 up_write(&list_rwsem);
     251                 :          0 :                 return -1;
     252                 :            :         }
     253         [ #  # ]:          0 :         list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
     254         [ #  # ]:          0 :                 if (slot->bus == bus) {
     255         [ #  # ]:          0 :                         list_del(&slot->slot_list);
     256                 :          0 :                         slots--;
     257                 :            : 
     258         [ #  # ]:          0 :                         dbg("deregistering slot %s", slot_name(slot));
     259                 :          0 :                         pci_hp_deregister(&slot->hotplug_slot);
     260                 :          0 :                         release_slot(slot);
     261                 :            :                 }
     262                 :            :         }
     263                 :          0 :         up_write(&list_rwsem);
     264                 :          0 :         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                 :          0 : cpci_hp_intr(int irq, void *data)
     271                 :            : {
     272         [ #  # ]:          0 :         dbg("entered cpci_hp_intr");
     273                 :            : 
     274                 :            :         /* Check to see if it was our interrupt */
     275   [ #  #  #  # ]:          0 :         if ((controller->irq_flags & IRQF_SHARED) &&
     276                 :          0 :             !controller->ops->check_irq(controller->dev_id)) {
     277         [ #  # ]:          0 :                 dbg("exited cpci_hp_intr, not our interrupt");
     278                 :          0 :                 return IRQ_NONE;
     279                 :            :         }
     280                 :            : 
     281                 :            :         /* Disable ENUM interrupt */
     282                 :          0 :         controller->ops->disable_irq();
     283                 :            : 
     284                 :            :         /* Trigger processing by the event thread */
     285                 :          0 :         wake_up_process(cpci_thread);
     286                 :          0 :         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                 :          0 : init_slots(int clear_ins)
     296                 :            : {
     297                 :          0 :         struct slot *slot;
     298                 :          0 :         struct pci_dev *dev;
     299                 :            : 
     300         [ #  # ]:          0 :         dbg("%s - enter", __func__);
     301                 :          0 :         down_read(&list_rwsem);
     302         [ #  # ]:          0 :         if (!slots) {
     303                 :          0 :                 up_read(&list_rwsem);
     304                 :          0 :                 return -1;
     305                 :            :         }
     306         [ #  # ]:          0 :         list_for_each_entry(slot, &slot_list, slot_list) {
     307         [ #  # ]:          0 :                 dbg("%s - looking at slot %s", __func__, slot_name(slot));
     308   [ #  #  #  # ]:          0 :                 if (clear_ins && cpci_check_and_clear_ins(slot))
     309         [ #  # ]:          0 :                         dbg("%s - cleared INS for slot %s",
     310                 :            :                             __func__, slot_name(slot));
     311                 :          0 :                 dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
     312         [ #  # ]:          0 :                 if (dev) {
     313                 :          0 :                         slot->adapter_status = 1;
     314                 :          0 :                         slot->latch_status = 1;
     315                 :          0 :                         slot->dev = dev;
     316                 :            :                 }
     317                 :            :         }
     318                 :          0 :         up_read(&list_rwsem);
     319         [ #  # ]:          0 :         dbg("%s - exit", __func__);
     320                 :            :         return 0;
     321                 :            : }
     322                 :            : 
     323                 :            : static int
     324                 :          0 : check_slots(void)
     325                 :            : {
     326                 :          0 :         struct slot *slot;
     327                 :          0 :         int extracted;
     328                 :          0 :         int inserted;
     329                 :          0 :         u16 hs_csr;
     330                 :            : 
     331                 :          0 :         down_read(&list_rwsem);
     332         [ #  # ]:          0 :         if (!slots) {
     333                 :          0 :                 up_read(&list_rwsem);
     334                 :          0 :                 err("no slots registered, shutting down");
     335                 :          0 :                 return -1;
     336                 :            :         }
     337                 :          0 :         extracted = inserted = 0;
     338         [ #  # ]:          0 :         list_for_each_entry(slot, &slot_list, slot_list) {
     339         [ #  # ]:          0 :                 dbg("%s - looking at slot %s", __func__, slot_name(slot));
     340         [ #  # ]:          0 :                 if (cpci_check_and_clear_ins(slot)) {
     341                 :            :                         /*
     342                 :            :                          * Some broken hardware (e.g. PLX 9054AB) asserts
     343                 :            :                          * ENUM# twice...
     344                 :            :                          */
     345         [ #  # ]:          0 :                         if (slot->dev) {
     346                 :          0 :                                 warn("slot %s already inserted",
     347                 :            :                                      slot_name(slot));
     348                 :          0 :                                 inserted++;
     349                 :          0 :                                 continue;
     350                 :            :                         }
     351                 :            : 
     352                 :            :                         /* Process insertion */
     353         [ #  # ]:          0 :                         dbg("%s - slot %s inserted", __func__, slot_name(slot));
     354                 :            : 
     355                 :            :                         /* GSM, debug */
     356                 :          0 :                         hs_csr = cpci_get_hs_csr(slot);
     357         [ #  # ]:          0 :                         dbg("%s - slot %s HS_CSR (1) = %04x",
     358                 :            :                             __func__, slot_name(slot), hs_csr);
     359                 :            : 
     360                 :            :                         /* Configure device */
     361         [ #  # ]:          0 :                         dbg("%s - configuring slot %s",
     362                 :            :                             __func__, slot_name(slot));
     363         [ #  # ]:          0 :                         if (cpci_configure_slot(slot)) {
     364                 :          0 :                                 err("%s - could not configure slot %s",
     365                 :            :                                     __func__, slot_name(slot));
     366                 :          0 :                                 continue;
     367                 :            :                         }
     368         [ #  # ]:          0 :                         dbg("%s - finished configuring slot %s",
     369                 :            :                             __func__, slot_name(slot));
     370                 :            : 
     371                 :            :                         /* GSM, debug */
     372                 :          0 :                         hs_csr = cpci_get_hs_csr(slot);
     373         [ #  # ]:          0 :                         dbg("%s - slot %s HS_CSR (2) = %04x",
     374                 :            :                             __func__, slot_name(slot), hs_csr);
     375                 :            : 
     376                 :          0 :                         slot->latch_status = 1;
     377                 :          0 :                         slot->adapter_status = 1;
     378                 :            : 
     379                 :          0 :                         cpci_led_off(slot);
     380                 :            : 
     381                 :            :                         /* GSM, debug */
     382                 :          0 :                         hs_csr = cpci_get_hs_csr(slot);
     383         [ #  # ]:          0 :                         dbg("%s - slot %s HS_CSR (3) = %04x",
     384                 :            :                             __func__, slot_name(slot), hs_csr);
     385                 :            : 
     386                 :          0 :                         inserted++;
     387         [ #  # ]:          0 :                 } else if (cpci_check_ext(slot)) {
     388                 :            :                         /* Process extraction request */
     389         [ #  # ]:          0 :                         dbg("%s - slot %s extracted",
     390                 :            :                             __func__, slot_name(slot));
     391                 :            : 
     392                 :            :                         /* GSM, debug */
     393                 :          0 :                         hs_csr = cpci_get_hs_csr(slot);
     394         [ #  # ]:          0 :                         dbg("%s - slot %s HS_CSR = %04x",
     395                 :            :                             __func__, slot_name(slot), hs_csr);
     396                 :            : 
     397         [ #  # ]:          0 :                         if (!slot->extracting) {
     398                 :          0 :                                 slot->latch_status = 0;
     399                 :          0 :                                 slot->extracting = 1;
     400                 :          0 :                                 atomic_inc(&extracting);
     401                 :            :                         }
     402                 :          0 :                         extracted++;
     403         [ #  # ]:          0 :                 } else if (slot->extracting) {
     404                 :          0 :                         hs_csr = cpci_get_hs_csr(slot);
     405         [ #  # ]:          0 :                         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                 :          0 :                                 err("card in slot %s was improperly removed",
     411                 :            :                                     slot_name(slot));
     412                 :          0 :                                 slot->adapter_status = 0;
     413                 :          0 :                                 slot->extracting = 0;
     414                 :          0 :                                 atomic_dec(&extracting);
     415                 :            :                         }
     416                 :            :                 }
     417                 :            :         }
     418                 :          0 :         up_read(&list_rwsem);
     419         [ #  # ]:          0 :         dbg("inserted=%d, extracted=%d, extracting=%d",
     420                 :            :             inserted, extracted, atomic_read(&extracting));
     421         [ #  # ]:          0 :         if (inserted || extracted)
     422                 :            :                 return extracted;
     423         [ #  # ]:          0 :         else if (!atomic_read(&extracting)) {
     424                 :          0 :                 err("cannot find ENUM# source, shutting down");
     425                 :          0 :                 return -1;
     426                 :            :         }
     427                 :            :         return 0;
     428                 :            : }
     429                 :            : 
     430                 :            : /* This is the interrupt mode worker thread body */
     431                 :            : static int
     432                 :          0 : event_thread(void *data)
     433                 :            : {
     434                 :          0 :         int rc;
     435                 :            : 
     436         [ #  # ]:          0 :         dbg("%s - event thread started", __func__);
     437                 :          0 :         while (1) {
     438         [ #  # ]:          0 :                 dbg("event thread sleeping");
     439                 :          0 :                 set_current_state(TASK_INTERRUPTIBLE);
     440                 :          0 :                 schedule();
     441         [ #  # ]:          0 :                 if (kthread_should_stop())
     442                 :            :                         break;
     443                 :          0 :                 do {
     444                 :          0 :                         rc = check_slots();
     445         [ #  # ]:          0 :                         if (rc > 0) {
     446                 :            :                                 /* Give userspace a chance to handle extraction */
     447                 :          0 :                                 msleep(500);
     448         [ #  # ]:          0 :                         } else if (rc < 0) {
     449         [ #  # ]:          0 :                                 dbg("%s - error checking slots", __func__);
     450                 :          0 :                                 thread_finished = 1;
     451                 :          0 :                                 goto out;
     452                 :            :                         }
     453   [ #  #  #  # ]:          0 :                 } while (atomic_read(&extracting) && !kthread_should_stop());
     454         [ #  # ]:          0 :                 if (kthread_should_stop())
     455                 :            :                         break;
     456                 :            : 
     457                 :            :                 /* Re-enable ENUM# interrupt */
     458         [ #  # ]:          0 :                 dbg("%s - re-enabling irq", __func__);
     459                 :          0 :                 controller->ops->enable_irq();
     460                 :            :         }
     461                 :          0 :  out:
     462                 :          0 :         return 0;
     463                 :            : }
     464                 :            : 
     465                 :            : /* This is the polling mode worker thread body */
     466                 :            : static int
     467                 :          0 : poll_thread(void *data)
     468                 :            : {
     469                 :          0 :         int rc;
     470                 :            : 
     471                 :          0 :         while (1) {
     472   [ #  #  #  # ]:          0 :                 if (kthread_should_stop() || signal_pending(current))
     473                 :            :                         break;
     474         [ #  # ]:          0 :                 if (controller->ops->query_enum()) {
     475                 :          0 :                         do {
     476                 :          0 :                                 rc = check_slots();
     477         [ #  # ]:          0 :                                 if (rc > 0) {
     478                 :            :                                         /* Give userspace a chance to handle extraction */
     479                 :          0 :                                         msleep(500);
     480         [ #  # ]:          0 :                                 } else if (rc < 0) {
     481         [ #  # ]:          0 :                                         dbg("%s - error checking slots", __func__);
     482                 :          0 :                                         thread_finished = 1;
     483                 :          0 :                                         goto out;
     484                 :            :                                 }
     485   [ #  #  #  # ]:          0 :                         } while (atomic_read(&extracting) && !kthread_should_stop());
     486                 :            :                 }
     487                 :          0 :                 msleep(100);
     488                 :            :         }
     489                 :          0 :  out:
     490                 :          0 :         return 0;
     491                 :            : }
     492                 :            : 
     493                 :            : static int
     494                 :          0 : cpci_start_thread(void)
     495                 :            : {
     496         [ #  # ]:          0 :         if (controller->irq)
     497         [ #  # ]:          0 :                 cpci_thread = kthread_run(event_thread, NULL, "cpci_hp_eventd");
     498                 :            :         else
     499         [ #  # ]:          0 :                 cpci_thread = kthread_run(poll_thread, NULL, "cpci_hp_polld");
     500         [ #  # ]:          0 :         if (IS_ERR(cpci_thread)) {
     501                 :          0 :                 err("Can't start up our thread");
     502                 :          0 :                 return PTR_ERR(cpci_thread);
     503                 :            :         }
     504                 :          0 :         thread_finished = 0;
     505                 :          0 :         return 0;
     506                 :            : }
     507                 :            : 
     508                 :            : static void
     509                 :          0 : cpci_stop_thread(void)
     510                 :            : {
     511                 :          0 :         kthread_stop(cpci_thread);
     512                 :          0 :         thread_finished = 1;
     513                 :          0 : }
     514                 :            : 
     515                 :            : int
     516                 :          0 : cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
     517                 :            : {
     518                 :          0 :         int status = 0;
     519                 :            : 
     520         [ #  # ]:          0 :         if (controller)
     521                 :            :                 return -1;
     522   [ #  #  #  # ]:          0 :         if (!(new_controller && new_controller->ops))
     523                 :            :                 return -EINVAL;
     524         [ #  # ]:          0 :         if (new_controller->irq) {
     525         [ #  # ]:          0 :                 if (!(new_controller->ops->enable_irq &&
     526         [ #  # ]:          0 :                      new_controller->ops->disable_irq))
     527                 :          0 :                         status = -EINVAL;
     528         [ #  # ]:          0 :                 if (request_irq(new_controller->irq,
     529                 :            :                                cpci_hp_intr,
     530                 :            :                                new_controller->irq_flags,
     531                 :            :                                MY_NAME,
     532                 :            :                                new_controller->dev_id)) {
     533                 :          0 :                         err("Can't get irq %d for the hotplug cPCI controller",
     534                 :            :                             new_controller->irq);
     535                 :          0 :                         status = -ENODEV;
     536                 :            :                 }
     537         [ #  # ]:          0 :                 dbg("%s - acquired controller irq %d",
     538                 :            :                     __func__, new_controller->irq);
     539                 :            :         }
     540         [ #  # ]:          0 :         if (!status)
     541                 :          0 :                 controller = new_controller;
     542                 :            :         return status;
     543                 :            : }
     544                 :            : EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
     545                 :            : 
     546                 :            : static void
     547                 :          0 : cleanup_slots(void)
     548                 :            : {
     549                 :          0 :         struct slot *slot;
     550                 :          0 :         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                 :          0 :         down_write(&list_rwsem);
     557         [ #  # ]:          0 :         if (!slots)
     558                 :          0 :                 goto cleanup_null;
     559         [ #  # ]:          0 :         list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
     560                 :          0 :                 list_del(&slot->slot_list);
     561                 :          0 :                 pci_hp_deregister(&slot->hotplug_slot);
     562                 :          0 :                 release_slot(slot);
     563                 :            :         }
     564                 :          0 : cleanup_null:
     565                 :          0 :         up_write(&list_rwsem);
     566                 :          0 : }
     567                 :            : 
     568                 :            : int
     569                 :          0 : cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
     570                 :            : {
     571                 :          0 :         int status = 0;
     572                 :            : 
     573         [ #  # ]:          0 :         if (controller) {
     574         [ #  # ]:          0 :                 if (!thread_finished)
     575                 :          0 :                         cpci_stop_thread();
     576         [ #  # ]:          0 :                 if (controller->irq)
     577                 :          0 :                         free_irq(controller->irq, controller->dev_id);
     578                 :          0 :                 controller = NULL;
     579                 :          0 :                 cleanup_slots();
     580                 :            :         } else
     581                 :            :                 status = -ENODEV;
     582                 :          0 :         return status;
     583                 :            : }
     584                 :            : EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller);
     585                 :            : 
     586                 :            : int
     587                 :          0 : cpci_hp_start(void)
     588                 :            : {
     589                 :          0 :         static int first = 1;
     590                 :          0 :         int status;
     591                 :            : 
     592         [ #  # ]:          0 :         dbg("%s - enter", __func__);
     593         [ #  # ]:          0 :         if (!controller)
     594                 :            :                 return -ENODEV;
     595                 :            : 
     596                 :          0 :         down_read(&list_rwsem);
     597         [ #  # ]:          0 :         if (list_empty(&slot_list)) {
     598                 :          0 :                 up_read(&list_rwsem);
     599                 :          0 :                 return -ENODEV;
     600                 :            :         }
     601                 :          0 :         up_read(&list_rwsem);
     602                 :            : 
     603                 :          0 :         status = init_slots(first);
     604         [ #  # ]:          0 :         if (first)
     605                 :          0 :                 first = 0;
     606         [ #  # ]:          0 :         if (status)
     607                 :            :                 return status;
     608                 :            : 
     609                 :          0 :         status = cpci_start_thread();
     610         [ #  # ]:          0 :         if (status)
     611                 :            :                 return status;
     612         [ #  # ]:          0 :         dbg("%s - thread started", __func__);
     613                 :            : 
     614         [ #  # ]:          0 :         if (controller->irq) {
     615                 :            :                 /* Start enum interrupt processing */
     616         [ #  # ]:          0 :                 dbg("%s - enabling irq", __func__);
     617                 :          0 :                 controller->ops->enable_irq();
     618                 :            :         }
     619         [ #  # ]:          0 :         dbg("%s - exit", __func__);
     620                 :            :         return 0;
     621                 :            : }
     622                 :            : EXPORT_SYMBOL_GPL(cpci_hp_start);
     623                 :            : 
     624                 :            : int
     625                 :          0 : cpci_hp_stop(void)
     626                 :            : {
     627         [ #  # ]:          0 :         if (!controller)
     628                 :            :                 return -ENODEV;
     629         [ #  # ]:          0 :         if (controller->irq) {
     630                 :            :                 /* Stop enum interrupt processing */
     631         [ #  # ]:          0 :                 dbg("%s - disabling irq", __func__);
     632                 :          0 :                 controller->ops->disable_irq();
     633                 :            :         }
     634                 :          0 :         cpci_stop_thread();
     635                 :          0 :         return 0;
     636                 :            : }
     637                 :            : EXPORT_SYMBOL_GPL(cpci_hp_stop);
     638                 :            : 
     639                 :            : int __init
     640                 :         30 : cpci_hotplug_init(int debug)
     641                 :            : {
     642                 :         30 :         cpci_debug = debug;
     643                 :         30 :         return 0;
     644                 :            : }

Generated by: LCOV version 1.14