CTC++ Coverage Report - Execution Profile    #30/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: arch/x86_64/kernel/aperture.c
Instrumentation mode: function-decision-multicondition
TER: 14 % ( 20/139)

Start/ End/    
True False - Line Source

  1 /* 
  2  * Firmware replacement code.
  3  * 
  4  * Work around broken BIOSes that don't set an aperture or only set the
  5  * aperture in the AGP bridge. 
  6  * If all fails map the aperture over some low memory.  This is cheaper than 
  7  * doing bounce buffering. The memory is lost. This is done at early boot 
  8  * because only the bootmem allocator can allocate 32+MB. 
  9  * 
  10  * Copyright 2002 Andi Kleen, SuSE Labs.
  11  * $Id: aperture.c,v 1.7 2003/08/01 03:36:18 ak Exp $
  12  */
  13 #include <linux/config.h>
  14 #include <linux/kernel.h>
  15 #include <linux/types.h>
  16 #include <linux/init.h>
  17 #include <linux/bootmem.h>
  18 #include <linux/mmzone.h>
  19 #include <linux/pci_ids.h>
  20 #include <linux/pci.h>
  21 #include <linux/bitops.h>
  22 #include <asm/e820.h>
  23 #include <asm/io.h>
  24 #include <asm/proto.h>
  25 #include <asm/pci-direct.h>
  26 #include <asm/dma.h>
  27 
  28 int iommu_aperture;
  29 int iommu_aperture_disabled __initdata = 0;
  30 int iommu_aperture_allowed __initdata = 0;
  31 
  32 int fallback_aper_order __initdata = 1; /* 64MB */
  33 int fallback_aper_force __initdata = 0; 
  34 
  35 int fix_aperture __initdata = 1;
  36 
  37 /* This code runs before the PCI subsystem is initialized, so just
  38    access the northbridge directly. */
  39 
  40 #define NB_ID_3 (PCI_VENDOR_ID_AMD | (0x1103<<16))
  41 
 
- 42 static u32 __init allocate_aperture(void) 
  43 {
  44    pg_data_t *nd0 = NODE_DATA(0);
  45    u32 aper_size;
  46    void *p; 
  47 
- 48    if (fallback_aper_order > 7) 
  49       fallback_aper_order = 7; 
  50    aper_size = (32 * 1024 * 1024) << fallback_aper_order; 
  51 
  52    /* 
  53     * Aperture has to be naturally aligned. This means an 2GB aperture won't
  54     * have much chances to find a place in the lower 4GB of memory.
  55     * Unfortunately we cannot move it up because that would make the
  56     * IOMMU useless.
  57     */
  58    p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0); 
- 59    if (!p || __pa(p)+aper_size > 0xffffffff) {
 - 59   T || _
 - 59   F || T
 - 59   F || F
- 59 ternary-?: ( ( unsigned long ) ( p ) >= 0xffff..
  60       printk("Cannot allocate aperture memory hole (%p,%uK)\n",
  61              p, aper_size>>10);
- 62       if (p)
  63          free_bootmem_node(nd0, (unsigned long)p, aper_size); 
 - 64       return 0;
  65    }
  66    printk("Mapping aperture over %d KB of RAM @ %lx\n",
    67           aper_size >> 10, __pa(p)); 
- 67 ternary-?: ( ( unsigned long ) ( p ) >= 0xffff..
    68    return (u32)__pa(p); 
- 68 ternary-?: ( ( unsigned long ) ( p ) >= 0xffff..
 - 68 return ( u32 ) ( ( ( unsigned long ) ( p ) >= ..
  69 }
  70 
 
  71 static int __init aperture_valid(char *name, u64 aper_base, u32 aper_size) 
  72 
- 73    if (!aper_base) 
 - 74       return 0;
- 75    if (aper_size < 64*1024*1024) { 
  76       printk("Aperture from %s too small (%d MB)\n", name, aper_size>>20); 
 - 77       return 0;
  78    }
- 79    if (aper_base + aper_size >= 0xffffffff) { 
  80       printk("Aperture from %s beyond 4GB. Ignoring.\n",name);
 - 81       return 0; 
  82    }
- 83    if (e820_mapped(aper_base, aper_base + aper_size, E820_RAM)) {  
  84       printk("Aperture from %s pointing to e820 RAM. Ignoring.\n",name);
 - 85       return 0; 
  86    } 
   87    return 1;
  88 
  89 
  90 /* Find a PCI capability */
 
- 91 static __u32 __init find_cap(int num, int slot, int func, int cap) 
  92 
  93    u8 pos;
  94    int bytes;
- 95    if (!(read_pci_config_16(num,slot,func,PCI_STATUS) & PCI_STATUS_CAP_LIST))
 - 96       return 0;
  97    pos = read_pci_config_byte(num,slot,func,PCI_CAPABILITY_LIST);
- 98    for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { 
 - 98   T && T
 - 98   T && F
 - 98   F && _
  99       u8 id;
  100       pos &= ~3; 
  101       id = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_ID);
- 102       if (id == 0xff)
 - 103          break;
- 104       if (id == cap) 
 - 105          return pos; 
  106       pos = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_NEXT); 
  107    } 
 - 108    return 0;
  109 
  110 
  111 /* Read a standard AGPv3 bridge header */
 
- 112 static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
  113 
  114    u32 apsize;
  115    u32 apsizereg;
  116    int nbits;
  117    u32 aper_low, aper_hi;
  118    u64 aper;
  119 
  120    printk("AGP bridge at %02x:%02x:%02x\n", num, slot, func);
  121    apsizereg = read_pci_config_16(num,slot,func, cap + 0x14);
- 122    if (apsizereg == 0xffffffff) {
  123       printk("APSIZE in AGP bridge unreadable\n");
 - 124       return 0;
  125    }
  126 
  127    apsize = apsizereg & 0xfff;
  128    /* Some BIOS use weird encodings not in the AGPv3 table. */
- 129    if (apsize & 0xff) 
  130       apsize |= 0xf00; 
  131    nbits = hweight16(apsize);
  132    *order = 7 - nbits;
- 133    if ((int)*order < 0) /* < 32MB */
  134       *order = 0;
  135    
  136    aper_low = read_pci_config(num,slot,func, 0x10);
  137    aper_hi = read_pci_config(num,slot,func,0x14);
  138    aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
  139 
  140    printk("Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n", 
  141           aper, 32 << *order, apsizereg);
  142 
- 143    if (!aperture_valid("AGP bridge", aper, (32*1024*1024) << *order))
 - 144        return 0;
 - 145    return (u32)aper; 
  146 
  147 
  148 /* Look for an AGP bridge. Windows only expects the aperture in the
  149    AGP bridge and some BIOS forget to initialize the Northbridge too.
  150    Work around this here. 
  151 
  152    Do an PCI bus scan by hand because we're running before the PCI
  153    subsystem. 
  154 
  155    All K8 AGP bridges are AGPv3 compliant, so we can do this scan
  156    generically. It's probably overkill to always scan all slots because
  157    the AGP bridges should be always an own bus on the HT hierarchy, 
  158    but do it here for future safety. */
 
- 159 static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
  160 {
  161    int num, slot, func;
  162 
  163    /* Poor man's PCI discovery */
- 164    for (num = 0; num < 32; num++) { 
- 165       for (slot = 0; slot < 32; slot++) { 
- 166          for (func = 0; func < 8; func++) { 
  167             u32 class, cap;
  168             u8 type;
  169             class = read_pci_config(num,slot,func,
  170                      PCI_CLASS_REVISION);
- 171             if (class == 0xffffffff)
 - 172                break; 
  173             
    174             switch (class >> 16) { 
 - 175             case PCI_CLASS_BRIDGE_HOST:
 - 176             case PCI_CLASS_BRIDGE_OTHER: /* needed? */
  177                /* AGP bridge? */
  178                cap = find_cap(num,slot,func,PCI_CAP_ID_AGP);
- 179                if (!cap)
 - 180                   break;
  181                *valid_agp = 1; 
 - 182                return read_agp(num,slot,func,cap,order);
  183             } 
  184             
  185             /* No multi-function device? */
  186             type = read_pci_config_byte(num,slot,func,
  187                             PCI_HEADER_TYPE);
- 188             if (!(type & 0x80))
 - 189                break;
  190          } 
  191       } 
  192    }
  193    printk("No AGP bridge found\n"); 
 - 194    return 0;
  195 }
  196 
 
  197 void __init iommu_hole_init(void) 
  198 
  199    int fix, num; 
  200    u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
  201    u64 aper_base, last_aper_base = 0;
  202    int valid_agp = 0;
  203 
- 204    if (iommu_aperture_disabled || !fix_aperture)
 - 204   T || _
 - 204   F || T
   204   F || F
 - 205       return;
  206 
  207    printk("Checking aperture...\n"); 
  208 
  209    fix = 0;
48   210    for (num = 24; num < 32; num++) {      
  211       char name[30];
42   212       if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) 
42    213          continue;   
  214 
  215       iommu_aperture = 1; 
  216 
  217       aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7; 
  218       aper_size = (32 * 1024 * 1024) << aper_order; 
  219       aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
  220       aper_base <<= 25; 
  221 
  222       printk("CPU %d: aperture @ %Lx size %u MB\n", num-24, 
  223              aper_base, aper_size>>20);
  224       
  225       sprintf(name, "northbridge cpu %d", num-24); 
  226 
- 227       if (!aperture_valid(name, aper_base, aper_size)) { 
  228          fix = 1; 
 - 229          break; 
  230       }
  231 
  232       if ((last_aper_order && aper_order != last_aper_order) ||
- 233           (last_aper_base && aper_base != last_aper_base)) {
 - 233     (T && T) || (_ && _)
 - 233     (T && F) || (T && T)
 - 233     (F && _) || (T && T)
 - 233     (T && F) || (T && F)
 - 233     (T && F) || (F && _)
 - 233     (F && _) || (T && F)
   233     (F && _) || (F && _)
  234          fix = 1;
 - 235          break;
  236       }
  237       last_aper_order = aper_order;
  238       last_aper_base = aper_base;
  239    } 
  240 
- 241    if (!fix && !fallback_aper_force) 
   241   T && T
 - 241   T && F
 - 241   F && _
   242       return; 
  243 
- 244    if (!fallback_aper_force)
  245       aper_alloc = search_agp_bridge(&aper_order, &valid_agp); 
  246       
- 247    if (aper_alloc) { 
  248       /* Got the aperture from the AGP bridge */
- 249    } else if (swiotlb && !valid_agp) {
 - 249   T && T
 - 249   T && F
 - 249   F && _
  250       /* Do nothing */
  251    } else if ((!no_iommu && end_pfn > MAX_DMA32_PFN) ||
  252          force_iommu ||
  253          valid_agp ||
- 254          fallback_aper_force) { 
 - 254   (T && T) || _ || _ || _
 - 254   (T && F) || T || _ || _
 - 254   (T && F) || F || T || _
 - 254   (T && F) || F || F || T
 - 254   (F && _) || T || _ || _
 - 254   (F && _) || F || T || _
 - 254   (F && _) || F || F || T
 - 254   (T && F) || F || F || F
 - 254   (F && _) || F || F || F
  255       printk("Your BIOS doesn't leave a aperture memory hole\n");
  256       printk("Please enable the IOMMU option in the BIOS setup\n");
  257       printk("This costs you %d MB of RAM\n",
  258              32 << fallback_aper_order);
  259 
  260       aper_order = fallback_aper_order;
  261       aper_alloc = allocate_aperture();
- 262       if (!aper_alloc) { 
  263          /* Could disable AGP and IOMMU here, but it's probably
  264             not worth it. But the later users cannot deal with
  265             bad apertures and turning on the aperture over memory
  266             causes very strange problems, so it's better to 
  267             panic early. */
  268          panic("Not enough memory for aperture");
  269       }
    270    } else { 
 - 271       return; 
  272    } 
  273 
  274    /* Fix up the north bridges */
- 275    for (num = 24; num < 32; num++) {       
- 276       if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) 
 - 277          continue;   
  278 
  279       /* Don't enable translation yet. That is done later. 
  280          Assume this BIOS didn't initialise the GART so 
  281          just overwrite all previous bits */ 
  282       write_pci_config(0, num, 3, 0x90, aper_order<<1); 
  283       write_pci_config(0, num, 3, 0x94, aper_alloc>>25); 
  284    } 
  285 
***TER 14% (20/139) of SOURCE FILE aperture.c

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last | Top