1/** 2 * \file 3 * \brief PCI configuration space access 4 */ 5 6/* 7 * Copyright (c) 2008, 2009, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <barrelfish/barrelfish.h> 16#include <stdio.h> 17#include <stdlib.h> 18#include <acpi_client/acpi_client.h> 19#include <pci/confspace/pci_confspace.h> 20 21static uint8_t startbus, endbus; 22static struct memobj_one_frame_lazy *memobj = NULL; 23static struct vregion *vregion = NULL; 24static struct capref region_cap; 25 26/// Enable PCIe. Default is yes. 27static bool pcie_enabled = true; 28 29/* FIXME: XXX: super-hacky bitfield to track if we already mapped something */ 30static uint8_t *mapped_bitfield; 31 32int pcie_confspace_init(struct capref ram_cap, lpaddr_t base, uint16_t segment, uint8_t startbusarg, 33 uint8_t endbusarg) 34{ 35 errval_t err; 36 37 assert(segment == 0); // unhandled! 38 39 startbus = startbusarg; 40 endbus = endbusarg; 41 42 // compute size of region 43 size_t region_pages = (endbus + 1 - startbus) << 8; 44 size_t region_bytes = region_pages * BASE_PAGE_SIZE; 45 46 region_cap = ram_cap; 47 48 memobj = malloc(sizeof(struct memobj_one_frame_lazy)); 49 assert(memobj); 50 vregion = malloc(sizeof(struct vregion)); 51 assert(vregion); 52 err = memobj_create_one_frame_lazy(memobj, region_bytes, 0, region_cap, 53 BASE_PAGE_SIZE); 54 if (err_is_fail(err)) { 55 DEBUG_ERR(err, "memobj_create_one_frame_lazy failed"); 56 return -1; 57 } 58 err = vregion_map(vregion, get_current_vspace(), &memobj->m, 0, region_bytes, 59 VREGION_FLAGS_READ_WRITE_NOCACHE); 60 if (err_is_fail(err)) { 61 DEBUG_ERR(err, "vregion_map failed"); 62 return -1; 63 } 64 65 /* allocate space for bitfield */ 66 mapped_bitfield = calloc(region_pages / NBBY, 1); 67 assert(mapped_bitfield != NULL); 68 69 return 0; 70} 71 72static bool is_mapped(uint64_t page) 73{ 74 return mapped_bitfield[page / NBBY] & (1 << page % NBBY); 75} 76 77static void set_mapped(uint64_t page) 78{ 79 mapped_bitfield[page / NBBY] |= (1 << page % NBBY); 80} 81 82static lvaddr_t map_page(uint64_t page) 83{ 84 errval_t err; 85 86 if (!is_mapped(page)) { 87 err = memobj->m.f.pagefault(&memobj->m, vregion, page * BASE_PAGE_SIZE, 0); 88 if (err_is_fail(err)) { 89 DEBUG_ERR(err, "memobj->f.pagefault failed"); 90 return 0; 91 } 92 set_mapped(page); 93 } 94 95 genvaddr_t genvaddr = vregion_get_base_addr(vregion); 96 return genvaddr + page * BASE_PAGE_SIZE; 97} 98 99lvaddr_t pcie_confspace_access(struct pci_address addr) 100{ 101 if (vregion == NULL || !pcie_enabled || addr.bus < startbus 102 || addr.bus > endbus) { 103 return 0; 104 } 105 106 uint64_t page = (addr.bus << 8) | (addr.device << 3) | addr.function; 107 return map_page(page); 108} 109 110uint8_t pcie_get_endbus(void) 111{ 112 return endbus; 113} 114 115void pcie_enable(void) 116{ 117 pcie_enabled = true; 118} 119 120void pcie_disable(void) 121{ 122 pcie_enabled = false; 123} 124