| 1 | /* |
| 2 | * ========== Copyright Header Begin ========================================== |
| 3 | * |
| 4 | * OpenSPARC T2 Processor File: schizo_module.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 | /* |
| 24 | * Copyright 2004 by Sun Microsystems, Inc. |
| 25 | * All rights reserved. |
| 26 | * |
| 27 | * W% 04/08/04 |
| 28 | */ |
| 29 | #ifndef _SCHIZO_MODULE_H |
| 30 | #define _SCHIZO_MODULE_H |
| 31 | |
| 32 | #include <assert.h> |
| 33 | #include <strings.h> |
| 34 | #include "pci.h" |
| 35 | #include "pci_dev.h" |
| 36 | #include "mmi.h" |
| 37 | #include "module.h" |
| 38 | #include "schizo_impl.h" |
| 39 | extern devRegistry * samDevs; |
| 40 | |
| 41 | #define MAX_SCHIZO_DEVICES 10 // 8 devices, pciA, pciB |
| 42 | #define V4_MAX_SCHIZO_DEVICES 64 |
| 43 | |
| 44 | #define LO_U32(x) ((uint32_t)((uint32_t *)&(x))[1]) |
| 45 | #define HI_U32(x) ((uint32_t)((uint32_t *)&(x))[0]) |
| 46 | |
| 47 | #define swap_hword(value) \ |
| 48 | (((value) & 0xff) << 8 | (value) >> 8) |
| 49 | |
| 50 | #define swap_word(value) \ |
| 51 | ((uint32_t)swap_hword((uint16_t)((value) & 0xffff)) << 16 | \ |
| 52 | (uint32_t)swap_hword((uint16_t)((value) >> 16))) |
| 53 | |
| 54 | #define swap_lword(value) \ |
| 55 | ((uint64_t)swap_word(LO_U32(value)) << 32 | \ |
| 56 | (uint64_t)swap_word(HI_U32(value))) |
| 57 | |
| 58 | #define NUM_PAIRS 8 |
| 59 | |
| 60 | #define NID(X) ((X & 0x3e0) >> 5) |
| 61 | typedef struct {uint64_t addr, value;} addr_val_pair; |
| 62 | |
| 63 | typedef enum {LEAFA, LEAFB, NLEAF} leaf_t; |
| 64 | |
| 65 | typedef struct pci_info { |
| 66 | const char *name; |
| 67 | mmi_instance_t bus; |
| 68 | pciBusIf *busif; |
| 69 | uint64_t base, size, mask; |
| 70 | pci_space_t space; |
| 71 | leaf_t leaf; |
| 72 | } pci_info_t; |
| 73 | |
| 74 | class schizoPciDev; |
| 75 | |
| 76 | |
| 77 | //structure to map pci devices to interrupt number. |
| 78 | //each PCI device is allocated 4 interrupts, based |
| 79 | //upon the slot from 0-31. The other interrupts are |
| 80 | //reserved for Schizo internal interrupts, OBIO and |
| 81 | //new link. |
| 82 | struct pciDevIntrInfo{ |
| 83 | mmi_instance_t busMod; //module pointer of bus on which device is attached |
| 84 | uint8_t devNum; //sysconf device argument of device |
| 85 | uint8_t devType; //type of device eg network etc |
| 86 | }; |
| 87 | |
| 88 | |
| 89 | extern "C" int schizo_access (uint32_t cpu_id, void* obj, uint64_t paddr, mmi_bool_t wr, uint32_t size, uint64_t* buf,uint8_t bytemask=PHYSIO_BYTEMASK_ALL); |
| 90 | extern "C" int pci_access (uint32_t cpu_id, void* obj, uint64_t paddr, mmi_bool_t wr, uint32_t size, uint64_t* buf, uint8_t bytemask=PHYSIO_BYTEMASK_ALL); |
| 91 | |
| 92 | |
| 93 | class Schizo : public Module, pciBridgeIf { |
| 94 | private: |
| 95 | const char *pciA, *pciB; |
| 96 | pci_info_t pci_info[NLEAF][PCI_NSPACES]; |
| 97 | uint64_t cpuPaddr; |
| 98 | int aid; |
| 99 | static const uint64_t IO_SPACE_ADDR = 0x40000000000ULL; |
| 100 | static const uint64_t PCI_CONF_IO_ADDR =0x40200000000ULL; |
| 101 | static const uint64_t PCI_IO_ADDR_OFFSET = 0x1000000ULL; |
| 102 | static const uint64_t PCI_MEM_ADDR = 0x40400000000ULL; |
| 103 | static const int NUM_ENTRIES = 16; // number of TLB/TSB entries in Schizo |
| 104 | int boot_flag; |
| 105 | schizo_structT* msp; |
| 106 | |
| 107 | bool retDevIntfA; |
| 108 | schizoPciDev * pciDevA; |
| 109 | schizoPciDev * pciDevB; |
| 110 | pciDevIntrInfo pciIntrInfo[V4_MAX_SCHIZO_DEVICES]; |
| 111 | char fkPromBus_A_Str[7]; |
| 112 | char fkPromBus_B_Str[7]; |
| 113 | addr_val_pair av_pairs[NUM_PAIRS]; |
| 114 | |
| 115 | private: |
| 116 | bool dump(FILE *); |
| 117 | bool restore(FILE *); |
| 118 | bool restore_v4(FILE *); |
| 119 | bool restore_v5(FILE *); |
| 120 | void init_msp(); |
| 121 | void init_mdu_regs(); |
| 122 | void init_regs(); |
| 123 | void init_pci(); |
| 124 | void destroy_pci(); |
| 125 | int rd_wr_mdu_reg(uint32_t paddr, uint64_t* buf, bool_t wr); |
| 126 | Register_set regs_range(uint64_t phy_addr); |
| 127 | Address_space calc_range(uint64_t *pyaddr); |
| 128 | Safari_space get_range(uint64_t *pyaddr); |
| 129 | int access_schizo_internals(uint32_t cpu_id, uint64_t paddr, bool_t wr, uint32_t, uint64_t *buf,SAM_DeviceId * samId); |
| 130 | int range_scsrbase(uint64_t paddr, bool_t wr, uint64_t *buf); |
| 131 | int range_pci_a_csrbase(uint32_t cpu_id, uint64_t paddr, bool_t wr, uint64_t *buf); |
| 132 | int range_pci_b_csrbase(uint32_t cpu_id, uint64_t paddr, bool_t wr, uint64_t *buf); |
| 133 | int rd_wr_stc_b_diags(uint32_t paddr, uint64_t* buf, bool_t wr); |
| 134 | int rd_wr_stc_a_diags(uint32_t paddr, uint64_t* buf, bool_t wr); |
| 135 | |
| 136 | // mmu a |
| 137 | public: |
| 138 | uint64_t a_iommu_va2pa(int isRead, uint64_t vaddr); |
| 139 | private: |
| 140 | bool_t a_flush_entry(uint32_t vaddr); |
| 141 | void a_flush_entries(uint32_t context); |
| 142 | bool_t a_iommu_match(Tlb_entry_t* entry, uint32_t vaddr); |
| 143 | int a_get_lru_entry(); |
| 144 | uint64_t a_calc_tsb_ptr( uint32_t vaddr); |
| 145 | bool_t a_schizo_iommu_lookup(uint32_t vaddr); |
| 146 | bool_t a_schizo_iommu_load_tte_tlb(uint32_t vaddr, uint64_t tte_entry); |
| 147 | uint64_t a_translate_to_paddr(uint32_t vaddr); |
| 148 | uint64_t a_vaddr2paddr(uint32_t vaddr, Tlb_entry_t* line); |
| 149 | void a_update_lru_status(int num); |
| 150 | int a_rd_wr_iommu_diags(uint32_t paddr, uint64_t* buf, bool_t wr); |
| 151 | bool_t a_check_all_used(); |
| 152 | uint64_t a_compare_entry(uint32_t vpn); |
| 153 | bool_t a_any_match(Tlb_entry_t* entry, uint32_t vpn); |
| 154 | |
| 155 | // mmu b |
| 156 | public: |
| 157 | uint64_t b_iommu_va2pa(int isRead, uint64_t vaddr); |
| 158 | private: |
| 159 | bool_t b_flush_entry(uint32_t vaddr); |
| 160 | void b_flush_entries(uint32_t context); |
| 161 | bool_t b_iommu_match(Tlb_entry_t* entry, uint32_t vaddr); |
| 162 | int b_get_lru_entry(); |
| 163 | uint64_t b_calc_tsb_ptr( uint32_t vaddr); |
| 164 | bool_t b_schizo_iommu_lookup(uint32_t vaddr); |
| 165 | bool_t b_schizo_iommu_load_tte_tlb(uint32_t vaddr, uint64_t tte_entry); |
| 166 | uint64_t b_translate_to_paddr(uint32_t vaddr); |
| 167 | uint64_t b_vaddr2paddr(uint32_t vaddr, Tlb_entry_t* line); |
| 168 | void b_update_lru_status(int num); |
| 169 | int b_rd_wr_iommu_diags(uint32_t paddr, uint64_t* buf, bool_t wr); |
| 170 | bool_t b_check_all_used(); |
| 171 | uint64_t b_compare_entry(uint32_t vpn); |
| 172 | bool_t b_any_match(Tlb_entry_t* entry, uint32_t vpn); |
| 173 | |
| 174 | static const uint64_t ULL(int n) { return (uint64_t)(n); }; |
| 175 | static const uint64_t KB(int n) { return 1024ULL * ULL(n); }; |
| 176 | static const uint64_t MB(int n) { return (1024ULL * KB(n)); }; |
| 177 | static const uint64_t GB(int n) { return (1024ULL * MB(n)); }; |
| 178 | static const uint64_t BIT(int n) { return 1ULL << (n); }; |
| 179 | static const int LO(uint64_t n) { return (int)n; }; |
| 180 | static const int HI(uint64_t n) { return (int)(n >> 32); }; |
| 181 | static const int FFS(uint64_t n) { return n ? (LO(n) ? ffs(LO(n)) : (32 + ffs(HI(n)))) : 0; }; |
| 182 | |
| 183 | friend int schizo_access(uint32_t cpu_id, void* obj, uint64_t paddr, mmi_bool_t wr, uint32_t size, uint64_t* buf,uint8_t bytemask); |
| 184 | friend int pci_access(uint32_t cpu_id, void* obj, uint64_t paddr, mmi_bool_t wr, uint32_t size, uint64_t* buf, uint8_t bytemask); |
| 185 | |
| 186 | int access_memory_controllers(uint32_t cpu_id, uint64_t paddr, bool_t wr, uint32_t, uint64_t *buf); |
| 187 | |
| 188 | void map_pci(leaf_t leaf, pci_space_t, uint64_t , uint64_t ,uint64_t); |
| 189 | void unmap_pci(leaf_t leaf, pci_space_t); |
| 190 | |
| 191 | void send_mondo_intr(uint64_t mondo, uint32_t dev_type, uint32_t dev_id); |
| 192 | int Schizo::interrupt_deassert(int indx); |
| 193 | |
| 194 | public: |
| 195 | Schizo(const char *modname, const char *instance_name); |
| 196 | ~Schizo(); |
| 197 | |
| 198 | public: |
| 199 | int busif_add_interrupt(mmi_instance_t busMod,int device,int dev_type, int slot_irl[], bool isMulti); |
| 200 | int busif_free_interrupt(mmi_instance_t busMod, int dev_number); |
| 201 | int busif_interrupt_in(bool set,mmi_instance_t busMod, int device, int line, SAM_DeviceId *id); |
| 202 | int busif_dma_out(uint64_t vaddr, void *data, long count, mmi_instance_t caller,uint16_t requesterId,SAM_DeviceId *id); |
| 203 | int busif_dma_in(uint64_t vaddr, void *data, long count, mmi_instance_t caller,uint16_t requesterId, SAM_DeviceId *id); |
| 204 | |
| 205 | // override the pciTargetIf functions. they do nothing in schizo impl. and should be never called |
| 206 | |
| 207 | pciXactnStatus pciTarget_mem32access(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){return SIM_INTERNAL_ERROR;} |
| 208 | pciXactnStatus pciTarget_mem64access(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){return SIM_INTERNAL_ERROR;} |
| 209 | pciXactnStatus pciTarget_ioaccess(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){return SIM_INTERNAL_ERROR;} |
| 210 | pciXactnStatus pciTarget_special_cycle(uint16_t mssg, uint16_t data){return SIM_INTERNAL_ERROR;} |
| 211 | pciXactnStatus pciTarget_intr_ack(uint64_t *data){return SIM_INTERNAL_ERROR;} |
| 212 | |
| 213 | // the bus number is hardwired in schizo to 0 |
| 214 | int busif_get_secondary_busno(){return 0;} |
| 215 | |
| 216 | |
| 217 | public: // Module interface |
| 218 | void record_mapping(uint64_t, uint64_t); |
| 219 | const char *get_help(); |
| 220 | bool parse_arg(const char *); |
| 221 | bool check_args(); |
| 222 | void init_done(); |
| 223 | void module_added(mmi_instance_t, const char*); |
| 224 | void module_deleted(mmi_instance_t, const char*); |
| 225 | void modinfo(); |
| 226 | void *get_interface(const char*); |
| 227 | |
| 228 | void get_dev_props(); |
| 229 | static void swapBuf(int size, uint64_t *buf); |
| 230 | #ifndef V5_FAKEPROM |
| 231 | int getStartInterruptIndex(mmi_instance_t busMod, int devNum); |
| 232 | #endif |
| 233 | |
| 234 | }; |
| 235 | |
| 236 | |
| 237 | //schizo appears as device 0 function 0 on the |
| 238 | //pci buses it controls. |
| 239 | |
| 240 | class schizoPciDev:public genericPciDevIf{ |
| 241 | |
| 242 | uint8_t deviceNumber; |
| 243 | uint8_t functionNumber; |
| 244 | const char *busName; |
| 245 | bool isBusA; |
| 246 | Schizo* schizo; |
| 247 | pciConfSpace * confSpace; |
| 248 | |
| 249 | public: |
| 250 | |
| 251 | |
| 252 | const char *devif_getBusName(){return busName;} |
| 253 | int devif_getDevice(){return deviceNumber;} |
| 254 | int devif_getFunction(){return functionNumber;} |
| 255 | mmi_instance_t devif_getInstance(){return schizo->getInstance();} |
| 256 | const char *devif_getName(){return schizo->getName();} |
| 257 | |
| 258 | pciXactnStatus devif_access_w_byte_enable(pci_space_t, uint64_t paddr, uint64_t offset, bool_t wr, uint64_t* buf, uint8_t byte_enable,SAM_DeviceId * id){ |
| 259 | if(id) *id = schizo->samId; |
| 260 | return MASTER_ABORT; |
| 261 | } |
| 262 | |
| 263 | pciXactnStatus devif_special_cycle(uint16_t mssg, uint16_t data){ |
| 264 | return MASTER_ABORT; |
| 265 | } |
| 266 | |
| 267 | pciXactnStatus devif_intr_ack(uint64_t * data){ |
| 268 | return MASTER_ABORT; |
| 269 | } |
| 270 | |
| 271 | pciXactnStatus devif_access_w_size(pci_space_t space, uint64_t paddr, uint64_t offset, bool_t wr, uint64_t* buf, uint8_t size,SAM_DeviceId * id){ |
| 272 | if(id) *id = schizo->samId; |
| 273 | confSpace->confAccessSize(offset,wr,buf,size); |
| 274 | if(space == PCI_CFG) |
| 275 | return SUCCESS; |
| 276 | else |
| 277 | return MASTER_ABORT; |
| 278 | } |
| 279 | |
| 280 | schizoPciDev(Schizo * ptr,const char * bus_name, bool bus){ |
| 281 | schizo = ptr; |
| 282 | deviceNumber = 0; |
| 283 | functionNumber = 0; |
| 284 | busName = strdup(bus_name); |
| 285 | isBusA = bus; |
| 286 | confSpace = new pciConfSpace(pciHeaderNull); |
| 287 | initPci(isBusA); |
| 288 | |
| 289 | }; |
| 290 | private: |
| 291 | void initPci(bool bus){ |
| 292 | char reg_descr[100]; |
| 293 | |
| 294 | snprintf(reg_descr,100,"%s-%s Vendor ID", devif_getName(),busName); |
| 295 | confSpace->addConfReg(new pciConfReg(reg_descr, 2,0x108e,0x0,0x0),PCI_CONF_VENID);//0x108e, ro |
| 296 | |
| 297 | snprintf(reg_descr,100,"%s-%s Device ID", devif_getName(),busName); |
| 298 | confSpace->addConfReg(new pciConfReg(reg_descr, 2,0x8001,0x0,0x0),PCI_CONF_DEVID); //0x8001, ro |
| 299 | |
| 300 | snprintf(reg_descr,100,"%s-%s command reg", devif_getName(),busName); |
| 301 | confSpace->addConfReg(new pciCommandReg(reg_descr,(genericPciDev*)this,0x140,0x6),PCI_CONF_COMM);// write mask = 0x140 |
| 302 | |
| 303 | snprintf(reg_descr,100,"%s-%s status reg", devif_getName(),busName); |
| 304 | confSpace->addConfReg(new pciStatusReg(reg_descr,(genericPciDev*)this,bus?0x280:0x2a0,0xf900),PCI_CONF_STAT);//write mask = 0xf900 |
| 305 | // this reg has some rw1c bit fields. over-ride the pciStatusReg class r/w functions in case OS ever complains. |
| 306 | |
| 307 | snprintf(reg_descr,100,"%s-%s revision id", devif_getName(),busName); |
| 308 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0,0x0),PCI_CONF_REVID);// rev id = 0x00, ro |
| 309 | |
| 310 | snprintf(reg_descr,100,"%s-%s prog class",devif_getName(),busName); |
| 311 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_CONF_PROGCLASS);//0x00, ro |
| 312 | |
| 313 | snprintf(reg_descr,100,"%s-%s sub class",devif_getName(),busName); |
| 314 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0x0),PCI_CONF_SUBCLASS);//0x00, ro |
| 315 | |
| 316 | snprintf(reg_descr,100,"%s-%s base class",devif_getName(),busName); |
| 317 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x06,0x0),PCI_CONF_BASCLASS);//0x06, ro |
| 318 | |
| 319 | snprintf(reg_descr,100,"%s-%s latency timer",devif_getName(),busName); |
| 320 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x0,0xf8),PCI_CONF_LATENCY_TIMER);//0x00, |
| 321 | |
| 322 | snprintf(reg_descr,100,"%s-%s Header type",devif_getName(),busName); |
| 323 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0x00),PCI_CONF_HEADER); //0x00,ro |
| 324 | |
| 325 | snprintf(reg_descr,100,"%s-%s Bus number",devif_getName(),busName); |
| 326 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xff),0x40); //0x00, rw |
| 327 | |
| 328 | snprintf(reg_descr,100,"%s-%s Subordinate bus number",devif_getName(),busName); |
| 329 | confSpace->addConfReg(new pciConfReg(reg_descr,1,0x00,0xff),0x41); //0x00, rw |
| 330 | } |
| 331 | }; |
| 332 | |
| 333 | |
| 334 | |
| 335 | #endif /* _SCHIZO_MODULE_H */ |