--- upstream/dynamips-0.2.7/dev_c2600_pci.c 2007/10/06 16:29:14 10 +++ upstream/dynamips-0.2.8-RC1/dev_c2600_pci.c 2007/10/06 16:33:40 11 @@ -21,8 +21,12 @@ /* Debugging flags */ #define DEBUG_ACCESS 0 #define DEBUG_UNKNOWN 1 +#define DEBUG_PCI 1 -/* Galileo GT64xxx/GT96xxx system controller */ +#define C2600_PCI_BRIDGE_VENDOR_ID 0x10ee +#define C2600_PCI_BRIDGE_PRODUCT_ID 0x4013 + +/* C2600 PCI controller */ struct c2600_pci_data { char *name; vm_obj_t vm_obj; @@ -31,6 +35,7 @@ vm_instance_t *vm; struct pci_bus *bus; + m_uint32_t bridge_bar0,bridge_bar1; }; /* @@ -41,29 +46,58 @@ m_uint64_t *data) { struct c2600_pci_data *d = dev->priv_data; + struct pci_device *pci_dev; + u_int bus,device,function,reg; if (op_type == MTS_READ) *data = 0x0; - switch(offset) { - case 0x500: - pci_dev_addr_handler(cpu,d->bus,op_type,FALSE,data); - break; - - case 0x504: - pci_dev_data_handler(cpu,d->bus,op_type,FALSE,data); - break; + bus = 0; + device = (offset >> 12) & 0x0F; + function = (offset >> 8) & 0x07; + reg = offset & 0xFF; + + /* Find the corresponding PCI device */ + pci_dev = pci_dev_lookup(d->bus,bus,device,function); + +#if DEBUG_PCI + if (op_type == MTS_READ) { + cpu_log(cpu,"PCI","read request at pc=0x%llx: " + "bus=%d,device=%d,function=%d,reg=0x%2.2x\n", + cpu_get_pc(cpu), bus, device, function, reg); + } else { + cpu_log(cpu,"PCI","write request (data=0x%8.8llx) at pc=0x%llx: " + "bus=%d,device=%d,function=%d,reg=0x%2.2x\n", + *data, cpu_get_pc(cpu), bus, device, function, reg); + } +#endif -#if DEBUG_UNKNOWN - default: - if (op_type == MTS_READ) { - cpu_log(cpu,d->name,"read from addr 0x%x, pc=0x%llx\n", - offset,cpu_get_pc(cpu)); - } else { - cpu_log(cpu,d->name,"write to addr 0x%x, value=0x%llx, " - "pc=0x%llx\n",offset,*data,cpu_get_pc(cpu)); + if (!pci_dev) { + if (op_type == MTS_READ) { + cpu_log(cpu,"PCI","read request for unknown device at pc=0x%llx " + "(bus=%d,device=%d,function=%d,reg=0x%2.2x).\n", + cpu_get_pc(cpu), bus, device, function, reg); + } else { + cpu_log(cpu,"PCI","write request (data=0x%8.8llx) for unknown device " + "at pc=0x%llx (bus=%d,device=%d,function=%d,reg=0x%2.2x).\n", + *data, cpu_get_pc(cpu), bus, device, function, reg); + } + + /* Returns an invalid device ID */ + if ((op_type == MTS_READ) && (reg == PCI_REG_ID)) + *data = 0xffffffff; + } else { + if (op_type == MTS_WRITE) { + if (pci_dev->write_register != NULL) + pci_dev->write_register(cpu,pci_dev,reg,*data); + } else { + if (reg == PCI_REG_ID) + *data = (pci_dev->product_id << 16) | pci_dev->vendor_id; + else { + if (pci_dev->read_register != NULL) + *data = pci_dev->read_register(cpu,pci_dev,reg); } -#endif + } } return NULL; @@ -81,6 +115,52 @@ } } +/* PCI bridge read access */ +static m_uint32_t dev_c2600_pci_bridge_read(cpu_gen_t *cpu, + struct pci_device *dev, + int reg) +{ + struct c2600_pci_data *d = dev->priv_data; + + switch(reg) { + case 0x10: + return(d->bridge_bar0); + case 0x14: + return(d->bridge_bar1); + default: + return(0); + } +} + +/* PCI bridge read access */ +static void dev_c2600_pci_bridge_write(cpu_gen_t *cpu,struct pci_device *dev, + int reg,m_uint32_t value) +{ + struct c2600_pci_data *d = dev->priv_data; + + switch(reg) { + case 0x10: + /* BAR0 must be at 0x00000000 for correct RAM access */ + if (value != 0x00000000) { + vm_error(d->vm,"C2600_PCI", + "Trying to set bridge BAR0 at 0x%8.8x!\n", + value); + } + d->bridge_bar0 = value; + break; + case 0x14: + /* BAR1 = byte swapped zone */ + if (!d->bridge_bar1) { + d->bridge_bar1 = value; + + /* XXX */ + dev_bswap_init(d->vm,"pci_bswap",d->bridge_bar1,0x10000000, + 0x00000000); + } + break; + } +} + /* Create the c2600 PCI controller device */ int dev_c2600_pci_init(vm_instance_t *vm,char *name, m_uint64_t paddr,m_uint32_t len, @@ -110,6 +190,13 @@ d->dev.phys_len = len; d->dev.handler = dev_c2600_pci_access; + pci_dev_add(d->bus,"pci_bridge", + C2600_PCI_BRIDGE_VENDOR_ID,C2600_PCI_BRIDGE_PRODUCT_ID, + 15,0,-1,d, + NULL, + dev_c2600_pci_bridge_read, + dev_c2600_pci_bridge_write); + /* Map this device to the VM */ vm_bind_device(vm,&d->dev); vm_object_add(vm,&d->vm_obj);