Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / ll / ll_mod.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: ll_mod.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
/*
* Copyright 2004 by Sun Microsystems, Inc.
* All rights reserved.
*
* W% 04/08/04
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "types.h"
#include "mmi.h"
#include "ll_mod.h"
//#include "schizo_module.h"
#include "ll_props.h"
// downstream I/O access
pciXactnStatus LL::pciTarget_mem32access(uint64_t offset, bool wr,uint64_t * buf, uint8_t size){
debug_info("%s: %s MEM32: offset %llx size %x\n", HERE, wr?"WRITE":"READ ", offset, size);
int retval = reg_access((char*)buf, offset - pciMem32_base,wr);
return SUCCESS;
}
// one-line help
const char *
Module::get_help_string()
{
return "Local Loopback Filesystem";
}
// factory function
Module *
Module::create(const char *_modname, const char *_instance_name)
{
return new LL(_modname, _instance_name);
}
// return help string
const char *
LL::get_help()
{
return Module::get_help_string();
}
// constructor
LL::LL(const char *_modname, const char *_instance_name)
: Module(_modname, _instance_name),
sp(NULL), rdce_head(NULL), rdce_tail(NULL)
{
initialized =FALSE;
allocation_obj();
pciMem32_size = 0x2000;
/*
cfg->pci_device_id = 0x1a;
cfg->vendor_id = 0x0;
cfg->class_code = 0x0;
*/
}
// destructor
LL::~LL()
{
debug_more("%s: destructor\n", instance_name);
DR_unregister((void*)this);
if (sp)
free((void*)sp);
}
// parse an arg
bool
LL::parse_arg(const char *arg)
{
if(restore_v4_dump()){
if(argval("mem32_base",arg,&pciMem32_base)){
debug_more("%s:mem32_base = %llx\n",getName(),pciMem32_base);
return true;
}else if(argval("mem32_size",arg,&pciMem32_size)){
debug_more("%s:mem32_size = %llx\n",getName(),pciMem32_size);
return true;
}
}
return dev_parse_arg(arg);
}
// check args for sanity
bool
LL::check_args()
{
return dev_check_args();
}
// called once after blaze has initialized devices and cpu data structs
void
LL::init_done()
{
dev_init_done(debug_level);
initPci();
#ifdef V5_FAKEPROM
// map in the device. these functions would normally be
// performed by the boot prom
// 1. get the lowest available base address on the bus
// if this is a new v5 run
if(!DR_is_restoreOP)
pciMem32_base = getBase(PCI_MEM32,pciMem32_size);
// Map in the address if this is a v4 restore or a new v5 run
if(restore_v4_dump() || !restore_v5_dump()){
// 2. set the base address 0 register
confSpace->confAccessSize(PCI_CONF_BASE0,true,&pciMem32_base,4);
// 3. enable the pci mem32 access by setting the command reg.
uint64_t command = 2;
confSpace->confAccessSize(PCI_CONF_COMM,true,&command,2);
}
get_dev_props();
plist->writeToFakeProm();
if(Module::debug_level >= 2)
plist->print();
#endif
}
// called each time a new module instance has been created
void
LL::module_added(mmi_instance_t target, const char *target_name)
{
dev_module_added(target_name);
}
// called each time a new module instance has been unloaded
void
LL::module_deleted(mmi_instance_t target, const char *target_name)
{
dev_module_deleted(target_name);
}
// print interesting info about this module
void
LL::modinfo()
{
printf("%s: This is a Local Looback PCI device\n", getName());
pciDevInfo();
}
// return pointer to interface
void *
LL::get_interface(const char *name)
{
if (!strcmp(name, PCI_GENERIC_DEV_INTERFACE))
return (genericPciDevIf*)this;
return NULL;
}
void
LL::get_dev_props()
{
ll_props[0].size = strlen(devif_getBusName())+1;
ll_props[0].value= strdup(devif_getBusName());
ll_reg[0].pci_phys_hi = 0x00000000 | devif_getDevice() << 11;
ll_reg[0].pci_phys_mid = ll_reg[0].pci_phys_low = 0;
ll_reg[0].pci_size_hi = ll_reg[0].pci_size_low = 0;
//ll_reg[1].pci_phys_hi = 0x82000000 | device << 11;
ll_reg[1].pci_phys_hi = 0x02000000 | devif_getDevice() << 11 | devif_getFunction() << 8 | PCI_CONF_BASE0;
ll_reg[1].pci_phys_mid = 0;
ll_reg[1].pci_phys_low = 0;
ll_reg[1].pci_size_hi = 0;
ll_reg[1].pci_size_low = pciMem32_size;
ll_assigned_addr[0].pci_phys_hi = 0x82000000 | devif_getDevice() << 11 | devif_getFunction() << 8 | PCI_CONF_BASE0;
ll_assigned_addr[0].pci_phys_mid = 0;
ll_assigned_addr[0].pci_phys_low = pciMem32_base;
ll_assigned_addr[0].pci_size_hi = 0;
ll_assigned_addr[0].pci_size_low = pciMem32_size;
plist->add_bunch(ll_props);
}
void LL::initPci(){
//add the configuration registers - - format is pciConfReg(name, size, por value, write mask, call back data)
// call back data defaults to 0.
// write mask defines bits that can be written to. a 0 in write mask makes the bit read only.
// this is a rather simple minded pseudo device. doesn't care about
// device id, vendor id etc. the properties required by the driver
// need to be added at the 'OK' prompt in case of boot prom. (the obp has
// no idea what ll device is !!)
confSpace->addConfReg(new pciConfReg("LL vendor id",2,0x108e,0x0,0x0),PCI_CONF_VENID);
confSpace->addConfReg(new pciConfReg("LL device id",2,0x0,0x0,0x0),PCI_CONF_DEVID);
confSpace->addConfReg(new pciCommandReg("LL command reg",(genericPciDev*)this,0x2),PCI_CONF_COMM); // only bit 1 is writable to allow mapping in mem32 space
confSpace->addConfReg(new baseAddrReg("LL Base address reg 0",(genericPciDev*)this,pciMem32_size,PCI_MEM32),PCI_CONF_BASE0);
// 8KB, relocatable, non prefethable register space in 32 bit memory space
// all the other registers would be read-only with value of 0
}
mmi_instance_t LL::pciDev_getInstance(){ return Module::getInstance();}
const char * LL::pciDev_getName(){ return Module::getName();}
void LL::pciDev_confAccessCb(bool_t wr, uint64_t offset, uint8_t size){
if(!wr)
return;
if(offset == PCI_CONF_BASE0){
assert(size == 4);
pciMem32_base = confSpace->readConf(offset) & 0xfffffff0;
}
return;
}