// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: pci_bus.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 ============================================
//////////////////module functions////////////////
// print interesting info about this module
pciDevMapIterator dmIter
;
printf(" bridge=<%s>\n", bridgeName
);
for(uint8_t i
= 0; i
< PCI_NSPACES
; i
++){
printf("%s",pci_space_name((pci_space_t
)i
));
for(dmIter
= pciAddrSpace
[i
].begin(); dmIter
!= pciAddrSpace
[i
].end(); dmIter
++)
pciBus::parse_arg(const char *arg
){
if (argval("bridge", arg
, &bridgeName
))
debug_more("%s: bridge=<%s>\n", HERE
, bridgeName
);
//pciBus::module_added(mmi_instance_t, const char *target_name){
pciBus::module_added(mmi_instance_t target_mod
, const char *target_name
){
if (!strcmp(bridgeName
, target_name
)) {
bridgeMod
= target_mod
;//mmi_get_module(bridgeName);
bridgeIf
= (pciBridgeIf
*) mmi_get_interface(bridgeMod
, PCI_BRIDGE_INTERFACE
);
debug_info("%s: bridge <%s> connected\n", HERE
, bridgeName
);
debug_err("%s: ERROR: bridge <%s> has no interface\n", HERE
, bridgeName
);
//pciBus::module_deleted(mmi_instance_t, const char *target_name){
pciBus::module_deleted(mmi_instance_t
, const char *target_name
){
if (!strcmp(bridgeName
, target_name
)) {
debug_info("%s: bridge <%s> disconnected\n", HERE
, bridgeName
);
busif_delete_device(target_name
);
pciBus::get_interface(const char *name
){
if (!strcmp(name
, PCI_BUS_INTERFACE
))
debug_err("%s: ERROR: must specify a host bridge\n", HERE
);
return Module::get_help_string();
Module::get_help_string(){
return "new pci bus impl";
Module::create(const char *_modname
, const char *_instance_name
){
return new pciBus(_modname
, _instance_name
);
pciBus::pciBus(const char *_modname
, const char *_instance_name
)
: Module(_modname
, _instance_name
),
bridgeName(0), bridgeMod(0), bridgeIf(0){}
debug_more("%s: destructor\n", HERE
);
/////////////////////exported interface functions///////////////
bool pciBus::busif_add_device(const char *devname
, uint8_t device
, uint8_t function
){
debug_info("%s: busif_add_device: <%s> dev=%d fun=%d\n", HERE
, devname
, device
, function
);
mmi_instance_t dev_instance
= mmi_get_instance(devname
);
debug_err("%s: Device named <%s> is not a module\n", HERE
, devname
);
if(searchDevInfoListByName(devname
)){
debug_err("%s: Device named <%s> already exists\n", HERE
, devname
);
if(searchDevInfoListByDevFun(device
,function
)){
debug_err("%s: Can't install <%s>: device already exists at dev=%d fun=%d\n",\
HERE
, devname
, device
, function
);
genericPciDevIf
* dI
= (genericPciDevIf
*)mmi_get_interface(dev_instance
,PCI_GENERIC_DEV_INTERFACE
);
debug_err("%s: Device named <%s> has no device interface\n", HERE
, devname
);
pciDevInfo
* devInfo
= new pciDevInfo(devname
, dev_instance
, dI
, device
, function
);
uint64_t base
= device
<< 11 | function
<< 8;
//map the configuration space. this space is always accessible and cannot be unmapped etc.
if(!addSpace(new pciRange(base
, base
+ 0xff, devInfo
),PCI_CFG
)){
debug_err("%s: cannot add configuration space for <%s>. Conflict in ranges!!\n",HERE
,devname
);
devInfoList
.push_back(devInfo
);
pciBus::busif_delete_device(const char *devname
){
pciDevInfo
* pdi
= searchDevInfoListByName(devname
);
debug_err("%s: cannot remove <%s>. non - existent device !!\n",HERE
,devname
);
bool pciBus::busif_map(const char *devname
, pci_space_t space
, uint64_t base
, uint64_t size
){
pciDevInfo
* pdi
= searchDevInfoListByName(devname
);
if(!addSpace(new pciRange(base
, base
+ size
- 1,pdi
),space
)){
debug_more("busif_map: can not map in space for device <%s>. Conflicting range!!\n", devname
);
debug_err("busif_map: device <%s> is not added to bus list\n",devname
);
bool pciBus::busif_unmap(const char *devname
, pci_space_t space
,uint64_t base
){
pciDevInfo
* pdi
= searchDevInfoListByName(devname
);
if(!removeSpace(base
, space
)){
debug_err("busif_unmap: can not unmap space for device <%s>. map does not exist!!\n", devname
);
debug_err("busif_unmap: device <%s> is not added to bus list\n",devname
);
pciBus::busif_add_interrupt(int dev_num
, int dev_type
, int *slot_irl
, bool isMultiFunction
){
return bridgeIf
->busif_add_interrupt(getInstance(), dev_num
, dev_type
,slot_irl
,isMultiFunction
);
pciBus::busif_free_interrupt(int dev_number
){
return bridgeIf
->busif_free_interrupt(getInstance(),dev_number
);
pciBus::busif_interrupt_in(bool set
,int dev_num
, int line
, SAM_DeviceId
*id
)
bridgeIf
->busif_interrupt_in(set
,getInstance(),dev_num
,line
, id
);
pciBus::busif_get_lowest_base(pci_space_t space
, uint64_t sz
){
pciDevMapIterator dmIter
;
dmIter
= pciAddrSpace
[space
].begin();
if(dmIter
== pciAddrSpace
[space
].end()){
debug_info("%s:returning address 0x%llx, size %llx, space %s\n",getName(),0,sz
,pci_space_name(space
));
return 0; // there is no other mapped device.
uint64_t end_prev
= dmIter
->second
->end
;
for(; dmIter
!=pciAddrSpace
[space
].end(); dmIter
++){
uint64_t base_cur
= dmIter
->second
->base
;
// align base to 'sz' bytes
base
= base
+ (sz
- base
%sz
);
if( (base_cur
- base
) >= sz
)
debug_info("%s:returning address %llx, size%llx, space %s\n",getName(),base
,sz
,pci_space_name(space
));
end_prev
= dmIter
->second
->end
;
// no fit found till the end of list.
base
= base
+ (sz
- base
%sz
);
debug_info("%s:returning address %llx, size%llx, space %s\n",getName(),base
,sz
,pci_space_name(space
));
pciBus::busif_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
){
debug_info("%s: %s %s: paddr %llx offset %llx size %x\n", HERE
, wr
?"WRITE":"READ ", pci_space_name(space
), paddr
, offset
, size
);
int target_bus
= offset
>> 16 & 0xff;
if(target_bus
!= busif_get_busno()){
printf("%s: type 1 transactions not supported on pci bus\n",getName());
offset
-= busif_get_busno() << 16;
pciDevMapIterator dmIter
;
dmIter
= pciAddrSpace
[space
].lower_bound(offset
);
//dmIter->second->print();
if(dmIter
== pciAddrSpace
[space
].end()){
debug_more("unmapped access space = %s paddr=%llx, offset=%llx\n",pci_space_name(space
), paddr
,offset
);
}else if(dmIter
->second
->end
< offset
){
debug_more("unmapped access space = %s paddr=%llx, offset=%llx\n",pci_space_name(space
), paddr
,offset
);
//return (dmIter->second->devInfo->devIf->devif_access_w_size(space, paddr, (offset - dmIter->second->base), wr, buf, size));
return (dmIter
->second
->devInfo
->devIf
->devif_access_w_size(space
, paddr
, offset
, wr
, buf
, size
, id
));
pciXactnStatus
pciBus::busif_access_w_byte_enables(pci_space_t space
, uint64_t paddr
, uint64_t offset
, bool_t wr
, uint64_t* buf
, uint8_t byte_enable
, SAM_DeviceId
* id
){
debug_info("%s: %s %s: paddr %llx offset %llx byte_enable %x\n", HERE
, wr
?"WRITE":"READ ", pci_space_name(space
), paddr
, offset
, byte_enable
);
pciDevMapIterator dmIter
;
dmIter
= pciAddrSpace
[space
].upper_bound(offset
);
if(dmIter
== pciAddrSpace
[space
].end()){
debug_err("unmapped access space = %s paddr=%llx\n",pci_space_name(space
), paddr
);
}else if(dmIter
->second
->end
< offset
){
debug_err("unmapped access space = %s paddr=%llx\n",pci_space_name(space
), paddr
);
offset
-= busif_get_busno() << 16;
return (dmIter
->second
->devInfo
->devIf
->devif_access_w_size(space
, paddr
, (offset
- dmIter
->second
->base
), wr
, buf
, byte_enable
, id
));
pciBus::busif_dma(bool wr
, uint64_t vaddr
, void *data
, long count
, SAM_DeviceId
*id
){
debug_info("%s: busif_dma_%s: vaddr 0x%llx count 0x%x\n", HERE
, wr
?"write":"read",vaddr
, count
);
bridgeIf
->busif_dma_out(vaddr
, data
, count
, getInstance(), 0, id
);
bridgeIf
->busif_dma_in(vaddr
, data
, count
, getInstance(), 0, id
);
pciXactnStatus
pciBus::busif_special_cycle(uint16_t mssg
, uint16_t data
){
list
<pciDevInfo
*>::iterator i
;
for(i
= devInfoList
.begin(); i
!= devInfoList
.end(); i
++)
(*i
)->devIf
->devif_special_cycle(mssg
,data
);
pciXactnStatus
pciBus::busif_intr_ack(uint64_t * data
){
list
<pciDevInfo
*>::iterator i
;
for(i
= devInfoList
.begin(); i
!= devInfoList
.end(); i
++)
(*i
)->devIf
->devif_intr_ack(data
);