LCOV - code coverage report
Current view: top level - drivers/acpi - ioapic.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 18 134 13.4 %
Date: 2022-04-01 14:58:12 Functions: 3 6 50.0 %
Branches: 4 84 4.8 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * IOAPIC/IOxAPIC/IOSAPIC driver
       4                 :            :  *
       5                 :            :  * Copyright (C) 2009 Fujitsu Limited.
       6                 :            :  * (c) Copyright 2009 Hewlett-Packard Development Company, L.P.
       7                 :            :  *
       8                 :            :  * Copyright (C) 2014 Intel Corporation
       9                 :            :  *
      10                 :            :  * Based on original drivers/pci/ioapic.c
      11                 :            :  *      Yinghai Lu <yinghai@kernel.org>
      12                 :            :  *      Jiang Liu <jiang.liu@intel.com>
      13                 :            :  */
      14                 :            : 
      15                 :            : /*
      16                 :            :  * This driver manages I/O APICs added by hotplug after boot.
      17                 :            :  * We try to claim all I/O APIC devices, but those present at boot were
      18                 :            :  * registered when we parsed the ACPI MADT.
      19                 :            :  */
      20                 :            : 
      21                 :            : #define pr_fmt(fmt) "ACPI: IOAPIC: " fmt
      22                 :            : 
      23                 :            : #include <linux/slab.h>
      24                 :            : #include <linux/acpi.h>
      25                 :            : #include <linux/pci.h>
      26                 :            : #include <acpi/acpi.h>
      27                 :            : 
      28                 :            : struct acpi_pci_ioapic {
      29                 :            :         acpi_handle     root_handle;
      30                 :            :         acpi_handle     handle;
      31                 :            :         u32             gsi_base;
      32                 :            :         struct resource res;
      33                 :            :         struct pci_dev  *pdev;
      34                 :            :         struct list_head list;
      35                 :            : };
      36                 :            : 
      37                 :            : static LIST_HEAD(ioapic_list);
      38                 :            : static DEFINE_MUTEX(ioapic_list_lock);
      39                 :            : 
      40                 :          0 : static acpi_status setup_res(struct acpi_resource *acpi_res, void *data)
      41                 :            : {
      42                 :          0 :         struct resource *res = data;
      43                 :          0 :         struct resource_win win;
      44                 :            : 
      45                 :            :         /*
      46                 :            :          * We might assign this to 'res' later, make sure all pointers are
      47                 :            :          * cleared before the resource is added to the global list
      48                 :            :          */
      49                 :          0 :         memset(&win, 0, sizeof(win));
      50                 :            : 
      51                 :          0 :         res->flags = 0;
      52         [ #  # ]:          0 :         if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM))
      53                 :            :                 return AE_OK;
      54                 :            : 
      55         [ #  # ]:          0 :         if (!acpi_dev_resource_memory(acpi_res, res)) {
      56   [ #  #  #  # ]:          0 :                 if (acpi_dev_resource_address_space(acpi_res, &win) ||
      57                 :          0 :                     acpi_dev_resource_ext_address_space(acpi_res, &win))
      58                 :          0 :                         *res = win.res;
      59                 :            :         }
      60         [ #  # ]:          0 :         if ((res->flags & IORESOURCE_PREFETCH) ||
      61                 :            :             (res->flags & IORESOURCE_DISABLED))
      62                 :          0 :                 res->flags = 0;
      63                 :            : 
      64                 :            :         return AE_CTRL_TERMINATE;
      65                 :            : }
      66                 :            : 
      67                 :        135 : static bool acpi_is_ioapic(acpi_handle handle, char **type)
      68                 :            : {
      69                 :        135 :         acpi_status status;
      70                 :        135 :         struct acpi_device_info *info;
      71                 :        135 :         char *hid = NULL;
      72                 :        135 :         bool match = false;
      73                 :            : 
      74         [ -  + ]:        135 :         if (!acpi_has_method(handle, "_GSB"))
      75                 :            :                 return false;
      76                 :            : 
      77                 :          0 :         status = acpi_get_object_info(handle, &info);
      78         [ #  # ]:          0 :         if (ACPI_SUCCESS(status)) {
      79         [ #  # ]:          0 :                 if (info->valid & ACPI_VALID_HID)
      80                 :          0 :                         hid = info->hardware_id.string;
      81         [ #  # ]:          0 :                 if (hid) {
      82         [ #  # ]:          0 :                         if (strcmp(hid, "ACPI0009") == 0) {
      83                 :          0 :                                 *type = "IOxAPIC";
      84                 :          0 :                                 match = true;
      85         [ #  # ]:          0 :                         } else if (strcmp(hid, "ACPI000A") == 0) {
      86                 :          0 :                                 *type = "IOAPIC";
      87                 :          0 :                                 match = true;
      88                 :            :                         }
      89                 :            :                 }
      90                 :          0 :                 kfree(info);
      91                 :            :         }
      92                 :            : 
      93                 :            :         return match;
      94                 :            : }
      95                 :            : 
      96                 :        135 : static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl,
      97                 :            :                                      void *context, void **rv)
      98                 :            : {
      99                 :        135 :         acpi_status status;
     100                 :        135 :         unsigned long long gsi_base;
     101                 :        135 :         struct acpi_pci_ioapic *ioapic;
     102                 :        135 :         struct pci_dev *dev = NULL;
     103                 :        135 :         struct resource *res = NULL, *pci_res = NULL, *crs_res;
     104                 :        135 :         char *type = NULL;
     105                 :            : 
     106         [ -  + ]:        135 :         if (!acpi_is_ioapic(handle, &type))
     107                 :            :                 return AE_OK;
     108                 :            : 
     109                 :          0 :         mutex_lock(&ioapic_list_lock);
     110         [ #  # ]:          0 :         list_for_each_entry(ioapic, &ioapic_list, list)
     111         [ #  # ]:          0 :                 if (ioapic->handle == handle) {
     112                 :          0 :                         mutex_unlock(&ioapic_list_lock);
     113                 :          0 :                         return AE_OK;
     114                 :            :                 }
     115                 :            : 
     116                 :          0 :         status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsi_base);
     117         [ #  # ]:          0 :         if (ACPI_FAILURE(status)) {
     118                 :          0 :                 acpi_handle_warn(handle, "failed to evaluate _GSB method\n");
     119                 :          0 :                 goto exit;
     120                 :            :         }
     121                 :            : 
     122                 :          0 :         ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
     123         [ #  # ]:          0 :         if (!ioapic) {
     124                 :          0 :                 pr_err("cannot allocate memory for new IOAPIC\n");
     125                 :          0 :                 goto exit;
     126                 :            :         } else {
     127                 :          0 :                 ioapic->root_handle = (acpi_handle)context;
     128                 :          0 :                 ioapic->handle = handle;
     129                 :          0 :                 ioapic->gsi_base = (u32)gsi_base;
     130                 :          0 :                 INIT_LIST_HEAD(&ioapic->list);
     131                 :            :         }
     132                 :            : 
     133         [ #  # ]:          0 :         if (acpi_ioapic_registered(handle, (u32)gsi_base))
     134                 :          0 :                 goto done;
     135                 :            : 
     136                 :          0 :         dev = acpi_get_pci_dev(handle);
     137   [ #  #  #  #  :          0 :         if (dev && pci_resource_len(dev, 0)) {
             #  #  #  # ]
     138         [ #  # ]:          0 :                 if (pci_enable_device(dev) < 0)
     139                 :          0 :                         goto exit_put;
     140                 :          0 :                 pci_set_master(dev);
     141         [ #  # ]:          0 :                 if (pci_request_region(dev, 0, type))
     142                 :          0 :                         goto exit_disable;
     143                 :          0 :                 pci_res = &dev->resource[0];
     144                 :          0 :                 ioapic->pdev = dev;
     145                 :            :         } else {
     146                 :          0 :                 pci_dev_put(dev);
     147                 :          0 :                 dev = NULL;
     148                 :            :         }
     149                 :            : 
     150                 :          0 :         crs_res = &ioapic->res;
     151                 :          0 :         acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, crs_res);
     152                 :          0 :         crs_res->name = type;
     153                 :          0 :         crs_res->flags |= IORESOURCE_BUSY;
     154                 :          0 :         if (crs_res->flags == 0) {
     155                 :            :                 acpi_handle_warn(handle, "failed to get resource\n");
     156                 :            :                 goto exit_release;
     157         [ #  # ]:          0 :         } else if (insert_resource(&iomem_resource, crs_res)) {
     158                 :          0 :                 acpi_handle_warn(handle, "failed to insert resource\n");
     159                 :          0 :                 goto exit_release;
     160                 :            :         }
     161                 :            : 
     162                 :            :         /* try pci resource first, then "_CRS" resource */
     163                 :          0 :         res = pci_res;
     164   [ #  #  #  # ]:          0 :         if (!res || !res->flags)
     165                 :          0 :                 res = crs_res;
     166                 :            : 
     167         [ #  # ]:          0 :         if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) {
     168                 :          0 :                 acpi_handle_warn(handle, "failed to register IOAPIC\n");
     169                 :          0 :                 goto exit_release;
     170                 :            :         }
     171                 :          0 : done:
     172                 :          0 :         list_add(&ioapic->list, &ioapic_list);
     173                 :          0 :         mutex_unlock(&ioapic_list_lock);
     174                 :            : 
     175         [ #  # ]:          0 :         if (dev)
     176                 :          0 :                 dev_info(&dev->dev, "%s at %pR, GSI %u\n",
     177                 :            :                          type, res, (u32)gsi_base);
     178                 :            :         else
     179                 :          0 :                 acpi_handle_info(handle, "%s at %pR, GSI %u\n",
     180                 :            :                                  type, res, (u32)gsi_base);
     181                 :            : 
     182                 :            :         return AE_OK;
     183                 :            : 
     184                 :          0 : exit_release:
     185         [ #  # ]:          0 :         if (dev)
     186                 :          0 :                 pci_release_region(dev, 0);
     187   [ #  #  #  # ]:          0 :         if (ioapic->res.flags && ioapic->res.parent)
     188                 :          0 :                 release_resource(&ioapic->res);
     189                 :          0 : exit_disable:
     190         [ #  # ]:          0 :         if (dev)
     191                 :          0 :                 pci_disable_device(dev);
     192                 :          0 : exit_put:
     193                 :          0 :         pci_dev_put(dev);
     194                 :          0 :         kfree(ioapic);
     195                 :          0 : exit:
     196                 :          0 :         mutex_unlock(&ioapic_list_lock);
     197                 :          0 :         *(acpi_status *)rv = AE_ERROR;
     198                 :          0 :         return AE_OK;
     199                 :            : }
     200                 :            : 
     201                 :          3 : int acpi_ioapic_add(acpi_handle root_handle)
     202                 :            : {
     203                 :          3 :         acpi_status status, retval = AE_OK;
     204                 :            : 
     205                 :          3 :         status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root_handle,
     206                 :            :                                      UINT_MAX, handle_ioapic_add, NULL,
     207                 :            :                                      root_handle, (void **)&retval);
     208                 :            : 
     209   [ +  -  -  + ]:          3 :         return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV;
     210                 :            : }
     211                 :            : 
     212                 :          0 : void pci_ioapic_remove(struct acpi_pci_root *root)
     213                 :            : {
     214                 :          0 :         struct acpi_pci_ioapic *ioapic, *tmp;
     215                 :            : 
     216                 :          0 :         mutex_lock(&ioapic_list_lock);
     217         [ #  # ]:          0 :         list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
     218         [ #  # ]:          0 :                 if (root->device->handle != ioapic->root_handle)
     219                 :          0 :                         continue;
     220         [ #  # ]:          0 :                 if (ioapic->pdev) {
     221                 :          0 :                         pci_release_region(ioapic->pdev, 0);
     222                 :          0 :                         pci_disable_device(ioapic->pdev);
     223                 :          0 :                         pci_dev_put(ioapic->pdev);
     224                 :            :                 }
     225                 :            :         }
     226                 :          0 :         mutex_unlock(&ioapic_list_lock);
     227                 :          0 : }
     228                 :            : 
     229                 :          0 : int acpi_ioapic_remove(struct acpi_pci_root *root)
     230                 :            : {
     231                 :          0 :         int retval = 0;
     232                 :          0 :         struct acpi_pci_ioapic *ioapic, *tmp;
     233                 :            : 
     234                 :          0 :         mutex_lock(&ioapic_list_lock);
     235         [ #  # ]:          0 :         list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
     236         [ #  # ]:          0 :                 if (root->device->handle != ioapic->root_handle)
     237                 :          0 :                         continue;
     238         [ #  # ]:          0 :                 if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base))
     239                 :          0 :                         retval = -EBUSY;
     240   [ #  #  #  # ]:          0 :                 if (ioapic->res.flags && ioapic->res.parent)
     241                 :          0 :                         release_resource(&ioapic->res);
     242                 :          0 :                 list_del(&ioapic->list);
     243                 :          0 :                 kfree(ioapic);
     244                 :            :         }
     245                 :          0 :         mutex_unlock(&ioapic_list_lock);
     246                 :            : 
     247                 :          0 :         return retval;
     248                 :            : }

Generated by: LCOV version 1.14