| 1 | /* |
| 2 | * ========== Copyright Header Begin ========================================== |
| 3 | * |
| 4 | * OpenSPARC T2 Processor File: bridge.h |
| 5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. |
| 6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. |
| 7 | * |
| 8 | * The above named program is free software; you can redistribute it and/or |
| 9 | * modify it under the terms of the GNU General Public |
| 10 | * License version 2 as published by the Free Software Foundation. |
| 11 | * |
| 12 | * The above named program is distributed in the hope that it will be |
| 13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | * General Public License for more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU General Public |
| 18 | * License along with this work; if not, write to the Free Software |
| 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. |
| 20 | * |
| 21 | * ========== Copyright Header End ============================================ |
| 22 | */ |
| 23 | #ifndef _PCIE2PCI_BRIDGE_ |
| 24 | #define _PCIE2PCI_BRIDGE_ |
| 25 | |
| 26 | #include "pci.h" |
| 27 | #include "pcie.h" |
| 28 | #include "module.h" |
| 29 | #include "arg.h" |
| 30 | #include "pci_bridge.h" |
| 31 | #include "dr.h" |
| 32 | #include <list> |
| 33 | |
| 34 | |
| 35 | #define PCI_BCNF_BCNF 0x40 |
| 36 | #define PCI_BCNF_MTT 0x42 |
| 37 | #define PCI_BCNF_PCLKC 0x43 |
| 38 | #define PCI_BCNF_EXP_CAPID 0x44 |
| 39 | #define PCI_BCNF_EXP_NXTP 0x45 |
| 40 | #define PCI_BCNF_EXP_CAP 0x46 |
| 41 | #define PCI_BCNF_EXP_DCAP 0x48 |
| 42 | #define PCI_BCNF_EXP_DCTL 0x4c |
| 43 | #define PCI_BCNF_EXP_DSTS 0x4e |
| 44 | #define PCI_BCNF_EXP_LCAP 0x50 |
| 45 | |
| 46 | extern "C"{ |
| 47 | int pcieToPciBridge_ui_cmd(void*, int argc, char * argv[]); |
| 48 | } |
| 49 | |
| 50 | |
| 51 | class pcieToPciBridge: public genericPcieDev, public pciBridgeIf, public Module{ |
| 52 | // pciBridgeIf is exported to the downstream pci Bus. |
| 53 | |
| 54 | pciBusIf *secBusIf; // pci bus intf on the downstream/secondary interface |
| 55 | const char * secBusName; |
| 56 | |
| 57 | // pcie bus intf on the primary side is member of genericPcieDev |
| 58 | |
| 59 | uint32_t mem32_base, mem32_limit, io_base, io_limit; |
| 60 | uint64_t mem64_base, mem64_limit; |
| 61 | |
| 62 | pciExpMsgCode map_pin_vpin(int device, int line, bool ast); |
| 63 | uint32_t pcie_eh1_pci0_translation(uint32_t addr); |
| 64 | |
| 65 | |
| 66 | bridgeCommandReg * bCR; |
| 67 | bool io_mapped() {return bCR->io_mapped();} |
| 68 | bool mem_mapped() {return bCR->mem_mapped();} |
| 69 | |
| 70 | |
| 71 | bool pendingIntr[4]; |
| 72 | typedef std::list<int > intxStatus; |
| 73 | intxStatus intLine[4]; // 4 lists of pending Intx interrupts, |
| 74 | // indexed with INT[A|B|C|D] type. |
| 75 | // Holds the downstream device # |
| 76 | // As long as there is an entry, an Intx |
| 77 | // message is pended to upstream bridge, |
| 78 | // otherwise a deassertIntx is send. |
| 79 | pthread_mutex_t intMutex; |
| 80 | |
| 81 | // route the received Intx message to upstream bridge. |
| 82 | pcieCompleter assertIntx(pciExpMsgCode messageCode, int device, SAM_DeviceId *id){ |
| 83 | |
| 84 | assert(messageCode >= MSG_Assert_INTA && messageCode <= MSG_Assert_INTD); |
| 85 | int line = messageCode - MSG_Assert_INTA; |
| 86 | |
| 87 | assert(0 <= line && line <= 3); |
| 88 | |
| 89 | pthread_mutex_lock(&intMutex); |
| 90 | intLine[line].push_back(device); |
| 91 | intLine[line].sort(); |
| 92 | intLine[line].unique(); |
| 93 | |
| 94 | if(pendingIntr[line]){ |
| 95 | debug_more("%s: asserting Intr%c from device %d - line already asserted\n",getName(),'A' + line, device); |
| 96 | |
| 97 | pthread_mutex_unlock(&intMutex); |
| 98 | return pcieCompleter(SC,getId()); |
| 99 | } |
| 100 | |
| 101 | pendingIntr[line] = true; |
| 102 | pthread_mutex_unlock(&intMutex); |
| 103 | |
| 104 | debug_more("%s: asserting Intr%c from device %d\n",getName(),'A' + line, device); |
| 105 | |
| 106 | return busIf->busif_msgAccess((uint8_t)messageCode, msgDB->msgCode2Routing(messageCode), getId(),id); |
| 107 | |
| 108 | } |
| 109 | |
| 110 | pcieCompleter deassertIntx(pciExpMsgCode messageCode, int device, SAM_DeviceId *id){ |
| 111 | |
| 112 | assert(messageCode >= MSG_Deassert_INTA && messageCode <= MSG_Deassert_INTD); |
| 113 | int line = messageCode - MSG_Deassert_INTA; |
| 114 | |
| 115 | assert(0 <= line && line <= 3); |
| 116 | |
| 117 | pthread_mutex_lock(&intMutex); |
| 118 | |
| 119 | intLine[line].remove(device); |
| 120 | if(!intLine[line].empty()){ |
| 121 | debug_more("%s: deasserting Intr%c from device %d - line still asserted\n",getName(),'A' + line, device); |
| 122 | |
| 123 | pthread_mutex_unlock(&intMutex); |
| 124 | return pcieCompleter(SC,getId()); |
| 125 | } |
| 126 | |
| 127 | pendingIntr[line] = false; |
| 128 | pthread_mutex_unlock(&intMutex); |
| 129 | |
| 130 | debug_more("%s: Deasserting Intr%c from device %d\n",getName(),'A' + line, device); |
| 131 | return busIf->busif_msgAccess((uint8_t)messageCode, msgDB->msgCode2Routing(messageCode), getId(),id); |
| 132 | |
| 133 | } |
| 134 | |
| 135 | const char * dump_version1_0; |
| 136 | const char * current_dump_version; |
| 137 | |
| 138 | public: |
| 139 | |
| 140 | bool devif_isBridge(){return true;} |
| 141 | pcieToPciBridge(const char* modname, const char * instance_name); |
| 142 | ~pcieToPciBridge(); |
| 143 | void initPci(); |
| 144 | void init_regs(); |
| 145 | void map_pci(pci_space_t space, uint64_t mask, uint64_t match,uint64_t size); |
| 146 | |
| 147 | mmi_instance_t devif_getInstance() {return Module::instance;} |
| 148 | const char *devif_getName() {return Module::getName();} |
| 149 | void devif_confAccessCb(bool wr, uint64_t offset, uint8_t be=0xf); |
| 150 | |
| 151 | // Module functions |
| 152 | const char *get_help(); |
| 153 | bool parse_arg(const char *); |
| 154 | bool check_args(); |
| 155 | void init_done(); |
| 156 | void module_added(mmi_instance_t, const char*); |
| 157 | void module_deleted(mmi_instance_t, const char*); |
| 158 | void modinfo(); |
| 159 | void *get_interface(const char*); |
| 160 | |
| 161 | // genericPcieDev virtual/unimplemented functions |
| 162 | // or functions that need to be overridden eg |
| 163 | // devif_memAccess, devif_ioAccess, etc. |
| 164 | pcieCompleter devif_memAccess(bool wr, uint64_t addr, addrMd_xactnType mode, void * data,\ |
| 165 | uint16_t length, uint8_t be, uint16_t reqId, tlp_X args, SAM_DeviceId *id); |
| 166 | |
| 167 | pcieCompleter devif_confAccess(bool wr, uint32_t offset, void * data, \ |
| 168 | uint8_t be,uint16_t reqId, addrMd_xactnType tType, uint16_t length, tlp_X args, SAM_DeviceId *id); |
| 169 | |
| 170 | pcieCompleter devif_ioAccess(bool wr, uint64_t addr, void * data, uint8_t be, \ |
| 171 | uint16_t reqId, uint16_t length, tlp_X args, SAM_DeviceId *id); |
| 172 | |
| 173 | pcieCompleter devif_msgAccess(uint8_t messageCode, msgRouting route, uint64_t tarIdOrAddr, uint16_t reqId, \ |
| 174 | void * data, uint16_t length, uint16_t vendorId, uint32_t vendor_data, tlp_X args,SAM_DeviceId *id); |
| 175 | int devif_getBusNo() {return (confSpace->readConf(PCI_BCNF_SECBUS) & 0xff);} |
| 176 | int devif_getSubBusNo() {return (confSpace->readConf(PCI_BCNF_SUBBUS) & 0xff);} |
| 177 | |
| 178 | // implement pciBridgeIf functions as applicable. |
| 179 | |
| 180 | int busif_add_interrupt(mmi_instance_t busMod,int device,int dev_type, int slot_irl[],bool isMulti); |
| 181 | int busif_free_interrupt(mmi_instance_t busMod, int dev_number); |
| 182 | int busif_interrupt_in(bool set,mmi_instance_t busMod, int device, int line, SAM_DeviceId *id); |
| 183 | int busif_dma_out(uint64_t vaddr, void *data, long count, mmi_instance_t caller,uint16_t requesterId,SAM_DeviceId *id); |
| 184 | int busif_dma_in(uint64_t vaddr, void *data, long count, mmi_instance_t |
| 185 | caller,uint16_t requesterId, SAM_DeviceId *id); |
| 186 | int busif_get_secondary_busno() {return (confSpace->readConf(PCI_BCNF_SECBUS) & 0xff);} |
| 187 | |
| 188 | // XXX NOTE : we may need to implement some functions in pciTargetIf as well |
| 189 | // to support all the possible accesses from downstream devices. I am still |
| 190 | // looking into the possible cases. |
| 191 | |
| 192 | pciXactnStatus pciTarget_mem32access(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){return SIM_INTERNAL_ERROR;} |
| 193 | pciXactnStatus pciTarget_mem64access(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){return SIM_INTERNAL_ERROR;} |
| 194 | pciXactnStatus pciTarget_ioaccess(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){return SIM_INTERNAL_ERROR;} |
| 195 | pciXactnStatus pciTarget_special_cycle(uint16_t mssg, uint16_t data){return SIM_INTERNAL_ERROR;} |
| 196 | pciXactnStatus pciTarget_intr_ack(uint64_t *data){return SIM_INTERNAL_ERROR;} |
| 197 | |
| 198 | |
| 199 | bool dump(FILE *fp); |
| 200 | bool restore(FILE *fp); |
| 201 | void handle_ui(int, char**); |
| 202 | void ui_cmd_usage(){ |
| 203 | printf("ui format: %s <command> <command args> ... \n",getName()); |
| 204 | printf("%s supports following UI commands\n",getName()); |
| 205 | printf(" debug [<level>]\n\ |
| 206 | set the debug level for debug prints to \'level\'\n\ |
| 207 | if \'level\' not provided, print current debug level\n\ |
| 208 | \'level\' = [0|1|2]\n"); |
| 209 | printf(" dump [<filename>]\n \ |
| 210 | dump the PCIE CSR contents to <filename>.pci in cwd\n \ |
| 211 | default is stderr\n \ |
| 212 | dump format is: <csr pciconf offset> <csr value> <csr r/w mask> <csr size> <csr name>\n"); |
| 213 | printf(" restore <filename>\n\ |
| 214 | restore the PCIE CSR contents from <filename>.pci in cwd \n\ |
| 215 | restore file format is same as dump file format\n"); |
| 216 | } |
| 217 | }; |
| 218 | |
| 219 | #endif |