LCOV - code coverage report
Current view: top level - drivers/char/agp - backend.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 17 143 11.9 %
Date: 2022-04-01 14:35:51 Functions: 3 12 25.0 %
Branches: 4 66 6.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * AGPGART driver backend routines.
       3                 :            :  * Copyright (C) 2004 Silicon Graphics, Inc.
       4                 :            :  * Copyright (C) 2002-2003 Dave Jones.
       5                 :            :  * Copyright (C) 1999 Jeff Hartmann.
       6                 :            :  * Copyright (C) 1999 Precision Insight, Inc.
       7                 :            :  * Copyright (C) 1999 Xi Graphics, Inc.
       8                 :            :  *
       9                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a
      10                 :            :  * copy of this software and associated documentation files (the "Software"),
      11                 :            :  * to deal in the Software without restriction, including without limitation
      12                 :            :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      13                 :            :  * and/or sell copies of the Software, and to permit persons to whom the
      14                 :            :  * Software is furnished to do so, subject to the following conditions:
      15                 :            :  *
      16                 :            :  * The above copyright notice and this permission notice shall be included
      17                 :            :  * in all copies or substantial portions of the Software.
      18                 :            :  *
      19                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      20                 :            :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      22                 :            :  * JEFF HARTMANN, DAVE JONES, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
      23                 :            :  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
      24                 :            :  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
      25                 :            :  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      26                 :            :  *
      27                 :            :  * TODO:
      28                 :            :  * - Allocate more than order 0 pages to avoid too much linear map splitting.
      29                 :            :  */
      30                 :            : #include <linux/module.h>
      31                 :            : #include <linux/pci.h>
      32                 :            : #include <linux/init.h>
      33                 :            : #include <linux/slab.h>
      34                 :            : #include <linux/pagemap.h>
      35                 :            : #include <linux/miscdevice.h>
      36                 :            : #include <linux/pm.h>
      37                 :            : #include <linux/agp_backend.h>
      38                 :            : #include <linux/agpgart.h>
      39                 :            : #include <linux/vmalloc.h>
      40                 :            : #include <asm/io.h>
      41                 :            : #include "agp.h"
      42                 :            : 
      43                 :            : /* Due to XFree86 brain-damage, we can't go to 1.0 until they
      44                 :            :  * fix some real stupidity. It's only by chance we can bump
      45                 :            :  * past 0.99 at all due to some boolean logic error. */
      46                 :            : #define AGPGART_VERSION_MAJOR 0
      47                 :            : #define AGPGART_VERSION_MINOR 103
      48                 :            : static const struct agp_version agp_current_version =
      49                 :            : {
      50                 :            :         .major = AGPGART_VERSION_MAJOR,
      51                 :            :         .minor = AGPGART_VERSION_MINOR,
      52                 :            : };
      53                 :            : 
      54                 :            : struct agp_bridge_data *(*agp_find_bridge)(struct pci_dev *) =
      55                 :            :         &agp_generic_find_bridge;
      56                 :            : 
      57                 :            : struct agp_bridge_data *agp_bridge;
      58                 :            : LIST_HEAD(agp_bridges);
      59                 :            : EXPORT_SYMBOL(agp_bridge);
      60                 :            : EXPORT_SYMBOL(agp_bridges);
      61                 :            : EXPORT_SYMBOL(agp_find_bridge);
      62                 :            : 
      63                 :            : /**
      64                 :            :  *      agp_backend_acquire  -  attempt to acquire an agp backend.
      65                 :            :  *
      66                 :            :  */
      67                 :          0 : struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev)
      68                 :            : {
      69                 :          0 :         struct agp_bridge_data *bridge;
      70                 :            : 
      71                 :          0 :         bridge = agp_find_bridge(pdev);
      72                 :            : 
      73         [ #  # ]:          0 :         if (!bridge)
      74                 :            :                 return NULL;
      75                 :            : 
      76         [ #  # ]:          0 :         if (atomic_read(&bridge->agp_in_use))
      77                 :            :                 return NULL;
      78                 :          0 :         atomic_inc(&bridge->agp_in_use);
      79                 :          0 :         return bridge;
      80                 :            : }
      81                 :            : EXPORT_SYMBOL(agp_backend_acquire);
      82                 :            : 
      83                 :            : 
      84                 :            : /**
      85                 :            :  *      agp_backend_release  -  release the lock on the agp backend.
      86                 :            :  *
      87                 :            :  *      The caller must insure that the graphics aperture translation table
      88                 :            :  *      is read for use by another entity.
      89                 :            :  *
      90                 :            :  *      (Ensure that all memory it bound is unbound.)
      91                 :            :  */
      92                 :          0 : void agp_backend_release(struct agp_bridge_data *bridge)
      93                 :            : {
      94                 :            : 
      95         [ #  # ]:          0 :         if (bridge)
      96                 :          0 :                 atomic_dec(&bridge->agp_in_use);
      97                 :          0 : }
      98                 :            : EXPORT_SYMBOL(agp_backend_release);
      99                 :            : 
     100                 :            : 
     101                 :            : static const struct { int mem, agp; } maxes_table[] = {
     102                 :            :         {0, 0},
     103                 :            :         {32, 4},
     104                 :            :         {64, 28},
     105                 :            :         {128, 96},
     106                 :            :         {256, 204},
     107                 :            :         {512, 440},
     108                 :            :         {1024, 942},
     109                 :            :         {2048, 1920},
     110                 :            :         {4096, 3932}
     111                 :            : };
     112                 :            : 
     113                 :          0 : static int agp_find_max(void)
     114                 :            : {
     115                 :          0 :         long memory, index, result;
     116                 :            : 
     117                 :            : #if PAGE_SHIFT < 20
     118                 :          0 :         memory = totalram_pages() >> (20 - PAGE_SHIFT);
     119                 :            : #else
     120                 :            :         memory = totalram_pages() << (PAGE_SHIFT - 20);
     121                 :            : #endif
     122                 :          0 :         index = 1;
     123                 :            : 
     124   [ #  #  #  # ]:          0 :         while ((memory > maxes_table[index].mem) && (index < 8))
     125                 :          0 :                 index++;
     126                 :            : 
     127                 :          0 :         result = maxes_table[index - 1].agp +
     128                 :          0 :            ( (memory - maxes_table[index - 1].mem)  *
     129                 :          0 :              (maxes_table[index].agp - maxes_table[index - 1].agp)) /
     130                 :          0 :            (maxes_table[index].mem - maxes_table[index - 1].mem);
     131                 :            : 
     132                 :          0 :         result = result << (20 - PAGE_SHIFT);
     133                 :          0 :         return result;
     134                 :            : }
     135                 :            : 
     136                 :            : 
     137                 :          0 : static int agp_backend_initialize(struct agp_bridge_data *bridge)
     138                 :            : {
     139                 :          0 :         int size_value, rc, got_gatt=0, got_keylist=0;
     140                 :            : 
     141                 :          0 :         bridge->max_memory_agp = agp_find_max();
     142                 :          0 :         bridge->version = &agp_current_version;
     143                 :            : 
     144         [ #  # ]:          0 :         if (bridge->driver->needs_scratch_page) {
     145                 :          0 :                 struct page *page = bridge->driver->agp_alloc_page(bridge);
     146                 :            : 
     147         [ #  # ]:          0 :                 if (!page) {
     148                 :          0 :                         dev_err(&bridge->dev->dev,
     149                 :            :                                 "can't get memory for scratch page\n");
     150                 :          0 :                         return -ENOMEM;
     151                 :            :                 }
     152                 :            : 
     153                 :          0 :                 bridge->scratch_page_page = page;
     154                 :          0 :                 bridge->scratch_page_dma = page_to_phys(page);
     155                 :            : 
     156                 :          0 :                 bridge->scratch_page = bridge->driver->mask_memory(bridge,
     157                 :            :                                                    bridge->scratch_page_dma, 0);
     158                 :            :         }
     159                 :            : 
     160                 :          0 :         size_value = bridge->driver->fetch_size();
     161         [ #  # ]:          0 :         if (size_value == 0) {
     162                 :          0 :                 dev_err(&bridge->dev->dev, "can't determine aperture size\n");
     163                 :          0 :                 rc = -EINVAL;
     164                 :          0 :                 goto err_out;
     165                 :            :         }
     166         [ #  # ]:          0 :         if (bridge->driver->create_gatt_table(bridge)) {
     167                 :          0 :                 dev_err(&bridge->dev->dev,
     168                 :            :                         "can't get memory for graphics translation table\n");
     169                 :          0 :                 rc = -ENOMEM;
     170                 :          0 :                 goto err_out;
     171                 :            :         }
     172                 :          0 :         got_gatt = 1;
     173                 :            : 
     174                 :          0 :         bridge->key_list = vzalloc(PAGE_SIZE * 4);
     175         [ #  # ]:          0 :         if (bridge->key_list == NULL) {
     176                 :          0 :                 dev_err(&bridge->dev->dev,
     177                 :            :                         "can't allocate memory for key lists\n");
     178                 :          0 :                 rc = -ENOMEM;
     179                 :          0 :                 goto err_out;
     180                 :            :         }
     181                 :          0 :         got_keylist = 1;
     182                 :            : 
     183                 :            :         /* FIXME vmalloc'd memory not guaranteed contiguous */
     184                 :            : 
     185         [ #  # ]:          0 :         if (bridge->driver->configure()) {
     186                 :          0 :                 dev_err(&bridge->dev->dev, "error configuring host chipset\n");
     187                 :          0 :                 rc = -EINVAL;
     188                 :          0 :                 goto err_out;
     189                 :            :         }
     190                 :          0 :         INIT_LIST_HEAD(&bridge->mapped_list);
     191                 :          0 :         spin_lock_init(&bridge->mapped_lock);
     192                 :            : 
     193                 :          0 :         return 0;
     194                 :            : 
     195                 :          0 : err_out:
     196         [ #  # ]:          0 :         if (bridge->driver->needs_scratch_page) {
     197                 :          0 :                 struct page *page = bridge->scratch_page_page;
     198                 :            : 
     199                 :          0 :                 bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_UNMAP);
     200                 :          0 :                 bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_FREE);
     201                 :            :         }
     202         [ #  # ]:          0 :         if (got_gatt)
     203                 :          0 :                 bridge->driver->free_gatt_table(bridge);
     204         [ #  # ]:          0 :         if (got_keylist) {
     205                 :          0 :                 vfree(bridge->key_list);
     206                 :          0 :                 bridge->key_list = NULL;
     207                 :            :         }
     208                 :            :         return rc;
     209                 :            : }
     210                 :            : 
     211                 :            : /* cannot be __exit b/c as it could be called from __init code */
     212                 :          0 : static void agp_backend_cleanup(struct agp_bridge_data *bridge)
     213                 :            : {
     214         [ #  # ]:          0 :         if (bridge->driver->cleanup)
     215                 :          0 :                 bridge->driver->cleanup();
     216         [ #  # ]:          0 :         if (bridge->driver->free_gatt_table)
     217                 :          0 :                 bridge->driver->free_gatt_table(bridge);
     218                 :            : 
     219                 :          0 :         vfree(bridge->key_list);
     220                 :          0 :         bridge->key_list = NULL;
     221                 :            : 
     222         [ #  # ]:          0 :         if (bridge->driver->agp_destroy_page &&
     223         [ #  # ]:          0 :             bridge->driver->needs_scratch_page) {
     224                 :          0 :                 struct page *page = bridge->scratch_page_page;
     225                 :            : 
     226                 :          0 :                 bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_UNMAP);
     227                 :          0 :                 bridge->driver->agp_destroy_page(page, AGP_PAGE_DESTROY_FREE);
     228                 :            :         }
     229                 :          0 : }
     230                 :            : 
     231                 :            : /* When we remove the global variable agp_bridge from all drivers
     232                 :            :  * then agp_alloc_bridge and agp_generic_find_bridge need to be updated
     233                 :            :  */
     234                 :            : 
     235                 :         21 : struct agp_bridge_data *agp_alloc_bridge(void)
     236                 :            : {
     237                 :         21 :         struct agp_bridge_data *bridge;
     238                 :            : 
     239                 :         21 :         bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
     240         [ +  - ]:         21 :         if (!bridge)
     241                 :            :                 return NULL;
     242                 :            : 
     243                 :         21 :         atomic_set(&bridge->agp_in_use, 0);
     244                 :         21 :         atomic_set(&bridge->current_memory_agp, 0);
     245                 :            : 
     246         [ +  - ]:         21 :         if (list_empty(&agp_bridges))
     247                 :         21 :                 agp_bridge = bridge;
     248                 :            : 
     249                 :            :         return bridge;
     250                 :            : }
     251                 :            : EXPORT_SYMBOL(agp_alloc_bridge);
     252                 :            : 
     253                 :            : 
     254                 :         21 : void agp_put_bridge(struct agp_bridge_data *bridge)
     255                 :            : {
     256                 :         21 :         kfree(bridge);
     257                 :            : 
     258   [ -  -  +  - ]:         21 :         if (list_empty(&agp_bridges))
     259                 :         21 :                 agp_bridge = NULL;
     260                 :         21 : }
     261                 :            : EXPORT_SYMBOL(agp_put_bridge);
     262                 :            : 
     263                 :            : 
     264                 :          0 : int agp_add_bridge(struct agp_bridge_data *bridge)
     265                 :            : {
     266                 :          0 :         int error;
     267                 :            : 
     268         [ #  # ]:          0 :         if (agp_off) {
     269                 :          0 :                 error = -ENODEV;
     270                 :          0 :                 goto err_put_bridge;
     271                 :            :         }
     272                 :            : 
     273         [ #  # ]:          0 :         if (!bridge->dev) {
     274                 :          0 :                 printk (KERN_DEBUG PFX "Erk, registering with no pci_dev!\n");
     275                 :          0 :                 error = -EINVAL;
     276                 :          0 :                 goto err_put_bridge;
     277                 :            :         }
     278                 :            : 
     279                 :            :         /* Grab reference on the chipset driver. */
     280         [ #  # ]:          0 :         if (!try_module_get(bridge->driver->owner)) {
     281                 :          0 :                 dev_info(&bridge->dev->dev, "can't lock chipset driver\n");
     282                 :          0 :                 error = -EINVAL;
     283                 :          0 :                 goto err_put_bridge;
     284                 :            :         }
     285                 :            : 
     286                 :          0 :         error = agp_backend_initialize(bridge);
     287         [ #  # ]:          0 :         if (error) {
     288                 :          0 :                 dev_info(&bridge->dev->dev,
     289                 :            :                          "agp_backend_initialize() failed\n");
     290                 :          0 :                 goto err_out;
     291                 :            :         }
     292                 :            : 
     293         [ #  # ]:          0 :         if (list_empty(&agp_bridges)) {
     294                 :          0 :                 error = agp_frontend_initialize();
     295         [ #  # ]:          0 :                 if (error) {
     296                 :          0 :                         dev_info(&bridge->dev->dev,
     297                 :            :                                  "agp_frontend_initialize() failed\n");
     298                 :          0 :                         goto frontend_err;
     299                 :            :                 }
     300                 :            : 
     301                 :          0 :                 dev_info(&bridge->dev->dev, "AGP aperture is %dM @ 0x%lx\n",
     302                 :            :                          bridge->driver->fetch_size(), bridge->gart_bus_addr);
     303                 :            : 
     304                 :            :         }
     305                 :            : 
     306                 :          0 :         list_add(&bridge->list, &agp_bridges);
     307                 :          0 :         return 0;
     308                 :            : 
     309                 :            : frontend_err:
     310                 :          0 :         agp_backend_cleanup(bridge);
     311                 :          0 : err_out:
     312                 :          0 :         module_put(bridge->driver->owner);
     313                 :          0 : err_put_bridge:
     314                 :          0 :         agp_put_bridge(bridge);
     315                 :            :         return error;
     316                 :            : }
     317                 :            : EXPORT_SYMBOL_GPL(agp_add_bridge);
     318                 :            : 
     319                 :            : 
     320                 :          0 : void agp_remove_bridge(struct agp_bridge_data *bridge)
     321                 :            : {
     322                 :          0 :         agp_backend_cleanup(bridge);
     323         [ #  # ]:          0 :         list_del(&bridge->list);
     324         [ #  # ]:          0 :         if (list_empty(&agp_bridges))
     325                 :          0 :                 agp_frontend_cleanup();
     326                 :          0 :         module_put(bridge->driver->owner);
     327                 :          0 : }
     328                 :            : EXPORT_SYMBOL_GPL(agp_remove_bridge);
     329                 :            : 
     330                 :            : int agp_off;
     331                 :            : int agp_try_unsupported_boot;
     332                 :            : EXPORT_SYMBOL(agp_off);
     333                 :            : EXPORT_SYMBOL(agp_try_unsupported_boot);
     334                 :            : 
     335                 :         21 : static int __init agp_init(void)
     336                 :            : {
     337         [ +  - ]:         21 :         if (!agp_off)
     338                 :         21 :                 printk(KERN_INFO "Linux agpgart interface v%d.%d\n",
     339                 :            :                         AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
     340                 :         21 :         return 0;
     341                 :            : }
     342                 :            : 
     343                 :          0 : static void __exit agp_exit(void)
     344                 :            : {
     345                 :          0 : }
     346                 :            : 
     347                 :            : #ifndef MODULE
     348                 :          0 : static __init int agp_setup(char *s)
     349                 :            : {
     350         [ #  # ]:          0 :         if (!strcmp(s,"off"))
     351                 :          0 :                 agp_off = 1;
     352         [ #  # ]:          0 :         if (!strcmp(s,"try_unsupported"))
     353                 :          0 :                 agp_try_unsupported_boot = 1;
     354                 :          0 :         return 1;
     355                 :            : }
     356                 :            : __setup("agp=", agp_setup);
     357                 :            : #endif
     358                 :            : 
     359                 :            : MODULE_AUTHOR("Dave Jones, Jeff Hartmann");
     360                 :            : MODULE_DESCRIPTION("AGP GART driver");
     361                 :            : MODULE_LICENSE("GPL and additional rights");
     362                 :            : MODULE_ALIAS_MISCDEV(AGPGART_MINOR);
     363                 :            : 
     364                 :            : module_init(agp_init);
     365                 :            : module_exit(agp_exit);
     366                 :            : 

Generated by: LCOV version 1.14