diff --git a/programs/system/drivers/agp/agp.c b/programs/system/drivers/agp/agp.c index 152b5e5942..73d4a2b1b4 100644 --- a/programs/system/drivers/agp/agp.c +++ b/programs/system/drivers/agp/agp.c @@ -1,5 +1,6 @@ #include "types.h" +#include "link.h" #include #include @@ -11,7 +12,7 @@ #include "syscall.h" -agp_t agp_dev; +agp_t *bridge; int __stdcall srv_agp(ioctl_t *io); @@ -47,14 +48,16 @@ u32_t __stdcall drvEntry(int action) }; +#include "pci.inc" + static void intel_8xx_tlbflush(void *mem) { u32_t temp; - temp = pciReadLong(agp_dev.PciTag, INTEL_AGPCTRL); - pciWriteLong(agp_dev.PciTag, INTEL_AGPCTRL, temp & ~(1 << 7)); - temp = pciReadLong(agp_dev.PciTag, INTEL_AGPCTRL); - pciWriteLong(agp_dev.PciTag, INTEL_AGPCTRL, temp | (1 << 7)); + temp = pciReadLong(bridge->PciTag, INTEL_AGPCTRL); + pciWriteLong(bridge->PciTag, INTEL_AGPCTRL, temp & ~(1 << 7)); + temp = pciReadLong(bridge->PciTag, INTEL_AGPCTRL); + pciWriteLong(bridge->PciTag, INTEL_AGPCTRL, temp | (1 << 7)); } @@ -69,158 +72,92 @@ static aper_size_t intel_8xx_sizes[7] = { 4, 1024, 1, 63 } }; -#if 0 -static int agp_backend_initialize(struct agp_bridge_data *bridge) -{ - int size_value, rc, got_gatt=0, got_keylist=0; - - bridge->max_memory_agp = agp_find_max(); - bridge->version = &agp_current_version; - - if (bridge->driver->needs_scratch_page) { - void *addr = bridge->driver->agp_alloc_page(bridge); - - if (!addr) { - printk(KERN_ERR PFX "unable to get memory for scratch page.\n"); - return -ENOMEM; - } - flush_agp_mappings(); - - bridge->scratch_page_real = virt_to_gart(addr); - bridge->scratch_page = - bridge->driver->mask_memory(bridge, bridge->scratch_page_real, 0); - } - - size_value = bridge->driver->fetch_size(); - if (size_value == 0) { - printk(KERN_ERR PFX "unable to determine aperture size.\n"); - rc = -EINVAL; - goto err_out; - } - if (bridge->driver->create_gatt_table(bridge)) { - printk(KERN_ERR PFX - "unable to get memory for graphics translation table.\n"); - rc = -ENOMEM; - goto err_out; - } - got_gatt = 1; - - bridge->key_list = vmalloc(PAGE_SIZE * 4); - if (bridge->key_list == NULL) { - printk(KERN_ERR PFX "error allocating memory for key lists.\n"); - rc = -ENOMEM; - goto err_out; - } - got_keylist = 1; - - /* FIXME vmalloc'd memory not guaranteed contiguous */ - memset(bridge->key_list, 0, PAGE_SIZE * 4); - - if (bridge->driver->configure()) { - printk(KERN_ERR PFX "error configuring host chipset.\n"); - rc = -EINVAL; - goto err_out; - } - - return 0; - -err_out: - if (bridge->driver->needs_scratch_page) { - bridge->driver->agp_destroy_page( - gart_to_virt(bridge->scratch_page_real)); - flush_agp_mappings(); - } - if (got_gatt) - bridge->driver->free_gatt_table(bridge); - if (got_keylist) { - vfree(bridge->key_list); - bridge->key_list = NULL; - } - return rc; -} -#endif - - -static int intel_845_configure(void *bridge) +static int intel_845_configure() { u32_t temp; u8_t temp2; aper_size_t *current_size; - agp_t *agp = (agp_t*)bridge; - - current_size = agp->current_size; + current_size = bridge->current_size; /* aperture size */ - pciWriteByte(agp->PciTag, INTEL_APSIZE, current_size->size_value); + pciWriteByte(bridge->PciTag, INTEL_APSIZE, current_size->size_value); dbgprintf("INTEL_APSIZE %d\n", current_size->size_value ); - if (agp->apbase_config != 0) + if (bridge->apbase_config != 0) { - pciWriteLong(agp->PciTag, AGP_APBASE, agp->apbase_config); + pciWriteLong(bridge->PciTag, AGP_APBASE, bridge->apbase_config); } else { /* address to map to */ - temp = pciReadLong(agp->PciTag, AGP_APBASE); - agp->gart_addr = (temp & PCI_MAP_MEMORY_ADDRESS_MASK); - agp->apbase_config = temp; + temp = pciReadLong(bridge->PciTag, AGP_APBASE); + bridge->gart_addr = (temp & PCI_MAP_MEMORY_ADDRESS_MASK); + bridge->apbase_config = temp; } dbgprintf("AGP_APBASE %x\n", temp ); /* attbase - aperture base */ - pciWriteLong(agp->PciTag, INTEL_ATTBASE, agp->gatt_dma); + pciWriteLong(bridge->PciTag, INTEL_ATTBASE, bridge->gatt_dma); /* agpctrl */ - pciWriteLong(agp->PciTag, INTEL_AGPCTRL, 0x0000); + pciWriteLong(bridge->PciTag, INTEL_AGPCTRL, 0x0000); /* agpm */ - temp2 = pciReadByte(agp->PciTag, INTEL_I845_AGPM); - pciWriteByte(agp->PciTag, INTEL_I845_AGPM, temp2 | (1 << 1)); + temp2 = pciReadByte(bridge->PciTag, INTEL_I845_AGPM); + pciWriteByte(bridge->PciTag, INTEL_I845_AGPM, temp2 | (1 << 1)); /* clear any possible error conditions */ - pciWriteWord(agp->PciTag, INTEL_I845_ERRSTS, 0x001c); + pciWriteWord(bridge->PciTag, INTEL_I845_ERRSTS, 0x001c); return 0; } -int agp_generic_create_gatt_table(agp_t *bridge) +int agp_generic_create_gatt_table() { count_t pages; pages = bridge->current_size->pages_count; - bridge->gatt_dma = AllocPages(pages); - - bridge->gatt_table = (u32_t*)MapIoMem((void*)bridge->gatt_dma, - pages<<12, PG_SW+PG_NOCACHE); - - dbgprintf("gatt map %x at %x %d pages\n",bridge->gatt_dma , - bridge->gatt_table, pages); - - if (bridge->gatt_table == NULL) - return -30;//ENOMEM; + if( bridge->gatt_dma = AllocPages(pages)) + { + if(bridge->gatt_table = + (u32_t*)MapIoMem((void*)bridge->gatt_dma, + pages<<12, PG_SW+PG_NOCACHE)) + { + dbgprintf("gatt map %x at %x %d pages\n",bridge->gatt_dma , + bridge->gatt_table, pages); /* AK: bogus, should encode addresses > 4GB */ -// for (i = 0; i < num_entries; i++) { -// writel(bridge->scratch_page, bridge->gatt_table+i); -// readl(bridge->gatt_table+i); /* PCI Posting. */ -// } + u32_t volatile *table = bridge->gatt_table; + + count_t count = bridge->current_size->num_entries; + + while(count--) { /* FIXME memset */ + addr_t tmp; + + *table = 0; + table++; + } + return 1; + }; + }; + dbgprintf("unable to get memory for " + "graphics translation table.\n"); return 0; } - static int __intel_8xx_fetch_size(u8_t temp) { int i; aper_size_t *values; - // values = A_SIZE_8(agp_bridge->driver->aperture_sizes); + values = bridge->aperture_sizes; values = intel_8xx_sizes; @@ -228,9 +165,9 @@ static int __intel_8xx_fetch_size(u8_t temp) { if (temp == values[i].size_value) { - agp_dev.previous_size = - agp_dev.current_size = (void *) (values + i); - agp_dev.aperture_size_idx = i; + bridge->previous_size = + bridge->current_size = (void *) (values + i); + bridge->aperture_size_idx = i; return values[i].size; } } @@ -241,7 +178,7 @@ static int intel_8xx_fetch_size(void) { u8_t temp; - temp = pciReadByte(agp_dev.PciTag, INTEL_APSIZE); + temp = pciReadByte(bridge->PciTag, INTEL_APSIZE); return __intel_8xx_fetch_size(temp); } @@ -264,7 +201,7 @@ int agp_bind_memory(addr_t agp_addr, addr_t dma_addr, size_t size) // } // ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type); - u32_t volatile *table = &agp_dev.gatt_table[agp_addr>>12]; + u32_t volatile *table = &bridge->gatt_table[agp_addr>>12]; count = size >> 12; @@ -272,15 +209,12 @@ int agp_bind_memory(addr_t agp_addr, addr_t dma_addr, size_t size) while(count--) { - addr_t tmp; - *table = dma_addr; - tmp = *table; /* PCI Posting. */ table++; dma_addr+=4096; } - agp_dev.tlb_flush(NULL); + bridge->tlb_flush(NULL); // if (ret_val != 0) // return ret_val; @@ -290,10 +224,502 @@ int agp_bind_memory(addr_t agp_addr, addr_t dma_addr, size_t size) return 0; } +void get_agp_version(agp_t *bridge) +{ + u32_t ncapid; + + /* Exit early if already set by errata workarounds. */ + if (bridge->major_version != 0) + return; + + ncapid = pciReadLong(bridge->PciTag, bridge->capndx); + bridge->major_version = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf; + bridge->minor_version = (ncapid >> AGP_MINOR_VERSION_SHIFT) & 0xf; +} + +static void agp_v2_parse_one(u32_t *requested_mode, u32_t *bridge_agpstat, u32_t *vga_agpstat) +{ + u32_t tmp; + + if (*requested_mode & AGP2_RESERVED_MASK) { + dbgprintf("reserved bits set (%x) in mode 0x%x. Fixed.\n", + *requested_mode & AGP2_RESERVED_MASK, *requested_mode); + *requested_mode &= ~AGP2_RESERVED_MASK; + } + + /* Check the speed bits make sense. Only one should be set. */ + tmp = *requested_mode & 7; + switch (tmp) { + case 0: + dbgprintf("Setting to x1 mode.\n"); + *requested_mode |= AGPSTAT2_1X; + break; + case 1: + case 2: + break; + case 3: + *requested_mode &= ~(AGPSTAT2_1X); /* rate=2 */ + break; + case 4: + break; + case 5: + case 6: + case 7: + *requested_mode &= ~(AGPSTAT2_1X|AGPSTAT2_2X); /* rate=4*/ + break; + } + + /* disable SBA if it's not supported */ + if (!((*bridge_agpstat & AGPSTAT_SBA) && (*vga_agpstat & AGPSTAT_SBA) && (*requested_mode & AGPSTAT_SBA))) + *bridge_agpstat &= ~AGPSTAT_SBA; + + /* Set rate */ + if (!((*bridge_agpstat & AGPSTAT2_4X) && (*vga_agpstat & AGPSTAT2_4X) && (*requested_mode & AGPSTAT2_4X))) + *bridge_agpstat &= ~AGPSTAT2_4X; + + if (!((*bridge_agpstat & AGPSTAT2_2X) && (*vga_agpstat & AGPSTAT2_2X) && (*requested_mode & AGPSTAT2_2X))) + *bridge_agpstat &= ~AGPSTAT2_2X; + + if (!((*bridge_agpstat & AGPSTAT2_1X) && (*vga_agpstat & AGPSTAT2_1X) && (*requested_mode & AGPSTAT2_1X))) + *bridge_agpstat &= ~AGPSTAT2_1X; + + /* Now we know what mode it should be, clear out the unwanted bits. */ + if (*bridge_agpstat & AGPSTAT2_4X) + *bridge_agpstat &= ~(AGPSTAT2_1X | AGPSTAT2_2X); /* 4X */ + + if (*bridge_agpstat & AGPSTAT2_2X) + *bridge_agpstat &= ~(AGPSTAT2_1X | AGPSTAT2_4X); /* 2X */ + + if (*bridge_agpstat & AGPSTAT2_1X) + *bridge_agpstat &= ~(AGPSTAT2_2X | AGPSTAT2_4X); /* 1X */ + + /* Apply any errata. */ + if (bridge->flags & AGP_ERRATA_FASTWRITES) + *bridge_agpstat &= ~AGPSTAT_FW; + + if (bridge->flags & AGP_ERRATA_SBA) + *bridge_agpstat &= ~AGPSTAT_SBA; + + if (bridge->flags & AGP_ERRATA_1X) { + *bridge_agpstat &= ~(AGPSTAT2_2X | AGPSTAT2_4X); + *bridge_agpstat |= AGPSTAT2_1X; + } + + /* If we've dropped down to 1X, disable fast writes. */ + if (*bridge_agpstat & AGPSTAT2_1X) + *bridge_agpstat &= ~AGPSTAT_FW; +} + + +static void agp_v3_parse_one(u32_t *requested_mode, + u32_t *bridge_agpstat, + u32_t *vga_agpstat) +{ + u32_t origbridge = *bridge_agpstat, origvga = *vga_agpstat; + u32_t tmp; + + if (*requested_mode & AGP3_RESERVED_MASK) + { + dbgprintf("reserved bits set (%x) in mode 0x%x. Fixed.\n", + *requested_mode & AGP3_RESERVED_MASK, *requested_mode); + *requested_mode &= ~AGP3_RESERVED_MASK; + } + + /* Check the speed bits make sense. */ + tmp = *requested_mode & 7; + if (tmp == 0) { + dbgprintf("Setting to AGP3 x4 mode.\n"); + *requested_mode |= AGPSTAT3_4X; + } + if (tmp >= 3) { + dbgprintf("Setting to AGP3 x8 mode.\n"); + *requested_mode = (*requested_mode & ~7) | AGPSTAT3_8X; + } + + /* ARQSZ - Set the value to the maximum one. + * Don't allow the mode register to override values. */ + *bridge_agpstat = ((*bridge_agpstat & ~AGPSTAT_ARQSZ) | + max_t(u32_t,(*bridge_agpstat & AGPSTAT_ARQSZ),(*vga_agpstat & AGPSTAT_ARQSZ))); + + /* Calibration cycle. + * Don't allow the mode register to override values. */ + *bridge_agpstat = ((*bridge_agpstat & ~AGPSTAT_CAL_MASK) | + min_t(u32_t,(*bridge_agpstat & AGPSTAT_CAL_MASK),(*vga_agpstat & AGPSTAT_CAL_MASK))); + + /* SBA *must* be supported for AGP v3 */ + *bridge_agpstat |= AGPSTAT_SBA; + + /* + * Set speed. + * Check for invalid speeds. This can happen when applications + * written before the AGP 3.0 standard pass AGP2.x modes to AGP3 hardware + */ + if (*requested_mode & AGPSTAT_MODE_3_0) { + /* + * Caller hasn't a clue what it is doing. Bridge is in 3.0 mode, + * have been passed a 3.0 mode, but with 2.x speed bits set. + * AGP2.x 4x -> AGP3.0 4x. + */ + if (*requested_mode & AGPSTAT2_4X) { + dbgprintf("broken AGP3 flags (%x). Fixed.\n", *requested_mode); + *requested_mode &= ~AGPSTAT2_4X; + *requested_mode |= AGPSTAT3_4X; + } + } else { + /* + * The caller doesn't know what they are doing. We are in 3.0 mode, + * but have been passed an AGP 2.x mode. + * Convert AGP 1x,2x,4x -> AGP 3.0 4x. + */ + dbgprintf("broken AGP2 flags (%x) in AGP3 mode. Fixed.\n",*requested_mode); + *requested_mode &= ~(AGPSTAT2_4X | AGPSTAT2_2X | AGPSTAT2_1X); + *requested_mode |= AGPSTAT3_4X; + } + + if (*requested_mode & AGPSTAT3_8X) { + if (!(*bridge_agpstat & AGPSTAT3_8X)) { + *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); + *bridge_agpstat |= AGPSTAT3_4X; + dbgprintf("requested AGPx8 but bridge not capable.\n"); + return; + } + if (!(*vga_agpstat & AGPSTAT3_8X)) { + *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); + *bridge_agpstat |= AGPSTAT3_4X; + dbgprintf("requested AGPx8 but graphic card not capable.\n"); + return; + } + /* All set, bridge & device can do AGP x8*/ + *bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD); + goto done; + + } else { + + /* + * If we didn't specify AGPx8, we can only do x4. + * If the hardware can't do x4, we're up shit creek, and never + * should have got this far. + */ + *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); + if ((*bridge_agpstat & AGPSTAT3_4X) && (*vga_agpstat & AGPSTAT3_4X)) + *bridge_agpstat |= AGPSTAT3_4X; + else { + dbgprintf("Badness. Don't know which AGP mode to set. " + "[bridge_agpstat:%x vga_agpstat:%x fell back to:- bridge_agpstat:%x vga_agpstat:%x]\n", + origbridge, origvga, *bridge_agpstat, *vga_agpstat); + if (!(*bridge_agpstat & AGPSTAT3_4X)) + dbgprintf("Bridge couldn't do AGP x4.\n"); + if (!(*vga_agpstat & AGPSTAT3_4X)) + dbgprintf("Graphic card couldn't do AGP x4.\n"); + return; + } + } + +done: + /* Apply any errata. */ + if (bridge->flags & AGP_ERRATA_FASTWRITES) + *bridge_agpstat &= ~AGPSTAT_FW; + + if (bridge->flags & AGP_ERRATA_SBA) + *bridge_agpstat &= ~AGPSTAT_SBA; + + if (bridge->flags & AGP_ERRATA_1X) { + *bridge_agpstat &= ~(AGPSTAT2_2X | AGPSTAT2_4X); + *bridge_agpstat |= AGPSTAT2_1X; + } +} + + +u32_t agp_collect_device_status(agp_t *bridge, u32_t requested_mode, + u32_t bridge_agpstat) +{ + PCITAG vgaTag; + u32_t vga_agpstat; + int cap_ptr; + + for (;;) + { + vgaTag = pci_find_class(PCI_CLASS_DISPLAY_VGA); + if (vgaTag == -1) + { + dbgprintf("Couldn't find an AGP VGA controller.\n"); + return 0; + } + cap_ptr = pci_find_capability(vgaTag, PCI_CAP_ID_AGP); + if (cap_ptr) + break; + } + + /* + * Ok, here we have a AGP device. Disable impossible + * settings, and adjust the readqueue to the minimum. + */ + vga_agpstat = pciReadLong(vgaTag, cap_ptr+PCI_AGP_STATUS); + + /* adjust RQ depth */ + bridge_agpstat = ((bridge_agpstat & ~AGPSTAT_RQ_DEPTH) | + min_t(u32_t, (requested_mode & AGPSTAT_RQ_DEPTH), + min_t(u32_t, (bridge_agpstat & AGPSTAT_RQ_DEPTH), (vga_agpstat & AGPSTAT_RQ_DEPTH)))); + + /* disable FW if it's not supported */ + if (!((bridge_agpstat & AGPSTAT_FW) && + (vga_agpstat & AGPSTAT_FW) && + (requested_mode & AGPSTAT_FW))) + bridge_agpstat &= ~AGPSTAT_FW; + + /* Check to see if we are operating in 3.0 mode */ + if (bridge->mode & AGPSTAT_MODE_3_0) + agp_v3_parse_one(&requested_mode, &bridge_agpstat, &vga_agpstat); + else + agp_v2_parse_one(&requested_mode, &bridge_agpstat, &vga_agpstat); + + return bridge_agpstat; +} + + +void agp_device_command(u32_t bridge_agpstat, int agp_v3) +{ + PCITAG device = 0; + int mode; + + mode = bridge_agpstat & 0x7; + if (agp_v3) + mode *= 4; + + for_each_pci_dev(device) + { + int agp = pci_find_capability(device, PCI_CAP_ID_AGP); + if (!agp) + continue; + + dbgprintf("Putting AGP V%d device at into %dx mode\n", + agp_v3 ? 3 : 2, mode); + pciWriteLong(device, agp + PCI_AGP_COMMAND, bridge_agpstat); + } +} + + +struct agp_3_5_dev +{ + link_t link; + int capndx; + u32_t maxbw; + PCITAG tag; +}; + + +/* + * Fully configure and enable an AGP 3.0 host bridge and all the devices + * lying behind it. + */ +int agp_3_5_enable(agp_t *bridge) +{ + u8_t mcapndx; + u32_t isoch, arqsz; + u32_t tstatus, mstatus, ncapid; + u32_t mmajor; + u16_t mpstat; + + link_t dev_list; + + struct agp_3_5_dev *cur, *pos; + + unsigned int ndevs = 0; + PCITAG dev = 0; + int ret = 0; + + /* Extract some power-on defaults from the target */ + tstatus = pciReadLong(bridge->PciTag, bridge->capndx+AGPSTAT); + isoch = (tstatus >> 17) & 0x1; + if (isoch == 0) /* isoch xfers not available, bail out. */ + return -1; + + arqsz = (tstatus >> 13) & 0x7; + + list_initialize(&dev_list); + + /* Find all AGP devices, and add them to dev_list. */ + for_each_pci_dev(dev) + { + u16_t devclass; + + mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP); + if (mcapndx == 0) + continue; + + devclass = pciReadWord(dev, 0x0A); + + switch (devclass & 0xff00) + { + case 0x0600: /* Bridge */ + /* Skip bridges. We should call this function for each one. */ + continue; + + case 0x0001: /* Unclassified device */ + /* Don't know what this is, but log it for investigation. */ + if (mcapndx != 0) { + dbgprintf("Wacky, found unclassified AGP device.\n"); + } + continue; + + case 0x0300: /* Display controller */ + case 0x0400: /* Multimedia controller */ + if((cur = malloc(sizeof(*cur))) == NULL) + { + ret = -1; + goto free_and_exit; + } + cur->tag = dev; + list_prepend(&cur->link, &dev_list); + ndevs++; + continue; + + default: + continue; + } + } + + /* + * Take an initial pass through the devices lying behind our host + * bridge. Make sure each one is actually an AGP 3.0 device, otherwise + * exit with an error message. Along the way store the AGP 3.0 + * cap_ptr for each device + */ + + cur = (struct agp_3_5_dev*)dev_list.next; + + while(&cur->link != &dev_list) + { + dev = cur->tag; + + mpstat = pciReadWord(dev, PCI_STATUS); + if ((mpstat & PCI_STATUS_CAP_LIST) == 0) + continue; + + mcapndx = pciReadByte(dev, PCI_CAPABILITY_LIST); + if (mcapndx != 0) { + do { + ncapid = pciReadLong(dev, mcapndx); + if ((ncapid & 0xff) != 2) + mcapndx = (ncapid >> 8) & 0xff; + } + while (((ncapid & 0xff) != 2) && (mcapndx != 0)); + } + + if (mcapndx == 0) { + dbgprintf("woah! Non-AGP device " + "found on the secondary bus of an AGP 3.5 bridge!\n"); + ret = -1; + goto free_and_exit; + } + + mmajor = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf; + if (mmajor < 3) { + dbgprintf("woah! AGP 2.0 device " + "found on the secondary bus of an AGP 3.5 " + "bridge operating with AGP 3.0 electricals!\n"); + ret = -1; + goto free_and_exit; + } + + cur->capndx = mcapndx; + + mstatus = pciReadLong(dev, cur->capndx+AGPSTAT); + + if (((mstatus >> 3) & 0x1) == 0) { + dbgprintf("woah! AGP 3.x device " + "not operating in AGP 3.x mode found on the " + "secondary bus of an AGP 3.5 bridge operating " + "with AGP 3.0 electricals!\n"); + ret = -1; + goto free_and_exit; + } + cur = (struct agp_3_5_dev*)cur->link.next; + } + + /* + * Call functions to divide target resources amongst the AGP 3.0 + * masters. This process is dramatically different depending on + * whether isochronous transfers are supported. + */ + if (isoch) { + ret = agp_3_5_isochronous_node_enable(bridge, &dev_list, ndevs); + if (ret) { + dbgprintf("Something bad happened setting " + "up isochronous xfers. Falling back to " + "non-isochronous xfer mode.\n"); + } else { + goto free_and_exit; + } + } + agp_3_5_nonisochronous_node_enable(bridge, dev_list, ndevs); + +free_and_exit: + /* Be sure to free the dev_list */ + for (pos = (struct agp_3_5_dev*)dev_list.next; &pos->link != &dev_list; ) + { + cur = pos; + + pos = (struct agp_3_5_dev*)pos->link.next; + free(cur); + } + +get_out: + return ret; +} + + +void agp_generic_enable(u32_t requested_mode) +{ + u32_t bridge_agpstat, temp; + + get_agp_version(bridge); + + dbgprintf("Found an AGP %d.%d compliant device.\n", + bridge->major_version, bridge->minor_version); + + bridge_agpstat = pciReadLong(bridge->PciTag, + bridge->capndx + PCI_AGP_STATUS); + + bridge_agpstat = agp_collect_device_status(bridge, requested_mode, bridge_agpstat); + if (bridge_agpstat == 0) + /* Something bad happened. FIXME: Return error code? */ + return; + + bridge_agpstat |= AGPSTAT_AGP_ENABLE; + + /* Do AGP version specific frobbing. */ + if (bridge->major_version >= 3) + { + if (bridge->mode & AGPSTAT_MODE_3_0) + { + /* If we have 3.5, we can do the isoch stuff. */ + if (bridge->minor_version >= 5) + agp_3_5_enable(bridge); + agp_device_command(bridge_agpstat, TRUE); + return; + } + else + { + /* Disable calibration cycle in RX91<1> when not in AGP3.0 mode of operation.*/ + bridge_agpstat &= ~(7<<10) ; + temp = pciReadLong(bridge->PciTag, bridge->capndx+AGPCTRL); + temp |= (1<<9); + pciWriteLong(bridge->PciTag, bridge->capndx+AGPCTRL, temp); + + dbgprintf("Device is in legacy mode," + " falling back to 2.x\n"); + } + } + + /* AGP v<3 */ + agp_device_command(bridge_agpstat, FALSE); +} + static agp_t intel_845_driver = { -// .aperture_sizes = intel_8xx_sizes, + .aperture_sizes = intel_8xx_sizes, // .size_type = U8_APER_SIZE, // .num_aperture_sizes = 7, .configure = intel_845_configure, @@ -304,7 +730,7 @@ static agp_t intel_845_driver = // .masks = intel_generic_masks, // .agp_enable = agp_generic_enable, // .cache_flush = global_cache_flush, -// .create_gatt_table = agp_generic_create_gatt_table, + .create_gatt_table = agp_generic_create_gatt_table, // .free_gatt_table = agp_generic_free_gatt_table, // .insert_memory = agp_generic_insert_memory, // .remove_memory = agp_generic_remove_memory, @@ -314,5 +740,32 @@ static agp_t intel_845_driver = // .agp_destroy_page = agp_generic_destroy_page, }; +int init_bridge(PCITAG pciTag) +{ + size_t size_value; + + bridge = &intel_845_driver; + + bridge->PciTag = pciTag; + + bridge->capndx = pci_find_capability(pciTag, PCI_CAP_ID_AGP); + + size_value = bridge->fetch_size(); + + if (size_value == 0) { + dbgprintf("unable to determine aperture size.\n"); + return 0; + }; + + dbgprintf("fetch size = %x\n", size_value); + + if( bridge->create_gatt_table() ) + { + bridge->configure(); + return 1; + } + return 0; +} + #include "detect.inc" diff --git a/programs/system/drivers/agp/agp.h b/programs/system/drivers/agp/agp.h index b6e834ea50..5b8e577d0a 100644 --- a/programs/system/drivers/agp/agp.h +++ b/programs/system/drivers/agp/agp.h @@ -1,10 +1,59 @@ +/* Chipset independant registers (from AGP Spec) */ +#define AGP_APBASE 0x10 + +#define AGPSTAT 0x4 +#define AGPCMD 0x8 +#define AGPNISTAT 0xc +#define AGPCTRL 0x10 +#define AGPAPSIZE 0x14 +#define AGPNEPG 0x16 +#define AGPGARTLO 0x18 +#define AGPGARTHI 0x1c +#define AGPNICMD 0x20 + + +#define AGP_MAJOR_VERSION_SHIFT (20) +#define AGP_MINOR_VERSION_SHIFT (16) + +#define AGPSTAT_RQ_DEPTH (0xff000000) +#define AGPSTAT_RQ_DEPTH_SHIFT 24 + +#define AGPSTAT_CAL_MASK (1<<12|1<<11|1<<10) +#define AGPSTAT_ARQSZ (1<<15|1<<14|1<<13) +#define AGPSTAT_ARQSZ_SHIFT 13 + +#define AGPSTAT_SBA (1<<9) +#define AGPSTAT_AGP_ENABLE (1<<8) +#define AGPSTAT_FW (1<<4) +#define AGPSTAT_MODE_3_0 (1<<3) + +#define AGPSTAT2_1X (1<<0) +#define AGPSTAT2_2X (1<<1) +#define AGPSTAT2_4X (1<<2) + +#define AGPSTAT3_RSVD (1<<2) +#define AGPSTAT3_8X (1<<1) +#define AGPSTAT3_4X (1) + +#define AGPCTRL_APERENB (1<<8) +#define AGPCTRL_GTLBEN (1<<7) + +#define AGP2_RESERVED_MASK 0x00fffcc8 +#define AGP3_RESERVED_MASK 0x00ff00c4 + +#define AGP_ERRATA_FASTWRITES 1<<0 +#define AGP_ERRATA_SBA 1<<1 +#define AGP_ERRATA_1X 1<<2 + + + /* Intel registers */ -#define INTEL_APSIZE 0xb4 -#define INTEL_ATTBASE 0xb8 -#define INTEL_AGPCTRL 0xb0 -#define INTEL_NBXCFG 0x50 -#define INTEL_ERRSTS 0x91 +#define INTEL_APSIZE 0xb4 +#define INTEL_ATTBASE 0xb8 +#define INTEL_AGPCTRL 0xb0 +#define INTEL_NBXCFG 0x50 +#define INTEL_ERRSTS 0x91 /* Intel i845 registers */ #define INTEL_I845_AGPM 0x51 @@ -25,8 +74,9 @@ typedef struct { PCITAG PciTag; - aper_size_t *previous_size; + aper_size_t *aperture_sizes; aper_size_t *current_size; + aper_size_t *previous_size; int aperture_size_idx; u32_t volatile *gatt_table; @@ -35,20 +85,27 @@ typedef struct addr_t apbase_config; addr_t gart_addr; -// void *aperture_sizes; + u32_t flags; + u32_t mode; + + int capndx; + + char major_version; + char minor_version; + // int num_aperture_sizes; // enum aper_size_type size_type; // int cant_use_aperture; // int needs_scratch_page; // struct gatt_mask *masks; - int (*fetch_size)(void *); - int (*configure)(void *); + int (*fetch_size)(); + int (*configure)(); // void (*agp_enable)(struct agp_bridge_data *, u32); // void (*cleanup)(void); - void (*tlb_flush)(void *); + void (*tlb_flush)(); // u32_t (*mask_memory)(struct agp_bridge_data *,u32_t, int); // void (*cache_flush)(void); -// int (*create_gatt_table)(struct agp_bridge_data *); + int (*create_gatt_table)(); // int (*free_gatt_table)(struct agp_bridge_data *); // int (*insert_memory)(struct agp_memory *, off_t, int); // int (*remove_memory)(struct agp_memory *, off_t, int); diff --git a/programs/system/drivers/agp/agp.lk b/programs/system/drivers/agp/agp.lk index f05f03a416..0abd38fee5 100644 --- a/programs/system/drivers/agp/agp.lk +++ b/programs/system/drivers/agp/agp.lk @@ -13,6 +13,7 @@ IMP _CreateRingBuffer core.CreateRingBuffer, _PciApi core.PciApi, _PciRead8 core.PciRead8, + _PciRead16 core.PciRead16, _PciRead32 core.PciRead32, _PciWrite8 core.PciWrite8, _PciWrite16 core.PciWrite16, diff --git a/programs/system/drivers/agp/detect.inc b/programs/system/drivers/agp/detect.inc index ebcc90484e..1261335d67 100644 --- a/programs/system/drivers/agp/detect.inc +++ b/programs/system/drivers/agp/detect.inc @@ -103,15 +103,14 @@ int FindPciDevice() if( (dev = agp_dev_match(pciId, agp_dev_table))!=NULL) { dbgprintf("detect agp host %x\n",dev->id); - agp_dev.PciTag = pciTag(bus,(devfn>>3)&0x1F,devfn&0x7); - dbgprintf("fetch size = %x\n", intel_8xx_fetch_size()); - agp_generic_create_gatt_table(&agp_dev); - intel_845_configure(&agp_dev); - return 1; + + PCITAG PciTag = pciTag(bus,(devfn>>3)&0x1F,devfn&0x7); + + return init_bridge(PciTag); }; - - }; }; return 0; }; + + diff --git a/programs/system/drivers/agp/link.h b/programs/system/drivers/agp/link.h new file mode 100644 index 0000000000..adf9c1de63 --- /dev/null +++ b/programs/system/drivers/agp/link.h @@ -0,0 +1,60 @@ + +typedef struct link +{ + struct link *prev; + struct link *next; +}link_t; + +#define LIST_INITIALIZE(name) \ + link_t name = { .prev = &name, .next = &name } + +#define list_get_instance(link, type, member) \ + ((type *)(((u8_t *)(link)) - ((u8_t *)&(((type *)NULL)->member)))) + +static inline void link_initialize(link_t *link) +{ + link->prev = NULL; + link->next = NULL; +} + +static inline void list_initialize(link_t *head) +{ + head->prev = head; + head->next = head; +} + +static inline void list_append(link_t *link, link_t *head) +{ + link->prev = head->prev; + link->next = head; + head->prev->next = link; + head->prev = link; +} + +static inline void list_remove(link_t *link) +{ + link->next->prev = link->prev; + link->prev->next = link->next; + link_initialize(link); +} + +static inline Bool list_empty(link_t *head) +{ + return head->next == head ? TRUE : FALSE; +} + +static inline void list_prepend(link_t *link, link_t *head) +{ + link->next = head->next; + link->prev = head; + head->next->prev = link; + head->next = link; +} + +static inline list_insert(link_t *new, link_t *old) +{ + new->prev = old->prev; + new->next = old; + new->prev->next = new; + old->prev = new; +} diff --git a/programs/system/drivers/agp/makefile b/programs/system/drivers/agp/makefile index 709ba2003b..1b122f64ed 100644 --- a/programs/system/drivers/agp/makefile +++ b/programs/system/drivers/agp/makefile @@ -7,7 +7,8 @@ LDRHD = -shared -T ld.x -s --file-alignment 32 HFILES:= syscall.h \ pci.h \ -SRC_DEP:= detect.inc +SRC_DEP:= pci.inc \ + detect.inc AGP_SRC:= agp.c diff --git a/programs/system/drivers/agp/pci.h b/programs/system/drivers/agp/pci.h index ef2556470c..90a2efedc4 100644 --- a/programs/system/drivers/agp/pci.h +++ b/programs/system/drivers/agp/pci.h @@ -11,6 +11,105 @@ typedef struct #define VENDOR_ATI 0x1002 +#define PCI_CLASS_DISPLAY_VGA 0x0300 +/* + * Under PCI, each device has 256 bytes of configuration address space, + * of which the first 64 bytes are standardized as follows: + */ +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_COMMAND_IO 0x01 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x02 /* Enable response in Memory space */ +#define PCI_COMMAND_MASTER 0x04 /* Enable bus mastering */ +#define PCI_COMMAND_SPECIAL 0x08 /* Enable response to special cycles */ +#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ +#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ +#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ +#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ +#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ +#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ +#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ + +#define PCI_STATUS 0x06 /* 16 bits */ +#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ +#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ +#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ +#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ +#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ +#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ +#define PCI_STATUS_DEVSEL_FAST 0x000 +#define PCI_STATUS_DEVSEL_MEDIUM 0x200 +#define PCI_STATUS_DEVSEL_SLOW 0x400 +#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ +#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ +#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ +#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ +#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ + +#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ +#define PCI_REVISION_ID 0x08 /* Revision ID */ +#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ +#define PCI_CLASS_DEVICE 0x0a /* Device class */ + +#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ +#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ +#define PCI_HEADER_TYPE 0x0e /* 8 bits */ +#define PCI_HEADER_TYPE_NORMAL 0 +#define PCI_HEADER_TYPE_BRIDGE 1 +#define PCI_HEADER_TYPE_CARDBUS 2 + +#define PCI_BIST 0x0f /* 8 bits */ +#define PCI_BIST_CODE_MASK 0x0f /* Return result */ +#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ +#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ + +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ +#define PCI_CB_CAPABILITY_LIST 0x14 +/* Capability lists */ + +#define PCI_CAP_LIST_ID 0 /* Capability ID */ +#define PCI_CAP_ID_PM 0x01 /* Power Management */ +#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ +#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ +#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ +#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ +#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ +#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */ +#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ +#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ +#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ +#define PCI_CAP_SIZEOF 4 + + +/* AGP registers */ + +#define PCI_AGP_VERSION 2 /* BCD version number */ +#define PCI_AGP_RFU 3 /* Rest of capability flags */ +#define PCI_AGP_STATUS 4 /* Status register */ +#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ +#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ +#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ +#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ +#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ +#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ +#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ +#define PCI_AGP_COMMAND 8 /* Control register */ +#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ +#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ +#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ +#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ +#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ +#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ +#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ +#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ +#define PCI_AGP_SIZEOF 12 + + #define PCI_MAP_REG_START 0x10 #define PCI_MAP_REG_END 0x28 #define PCI_MAP_ROM_REG 0x30 @@ -77,3 +176,7 @@ pciTag(int busnum, int devnum, int funcnum) const PciChipset_t *PciDevMatch(u16_t dev,const PciChipset_t *list); u32_t pciGetBaseSize(int bus, int devfn, int index, Bool destructive, Bool *min); + +#define PCI_ANY_ID (~0) + +#define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d))!=-1) diff --git a/programs/system/drivers/agp/pci.inc b/programs/system/drivers/agp/pci.inc new file mode 100644 index 0000000000..91fc4393b1 --- /dev/null +++ b/programs/system/drivers/agp/pci.inc @@ -0,0 +1,128 @@ + +#define PCI_FIND_CAP_TTL 48 + +static int __pci_find_next_cap_ttl(PCITAG pciTag, u8_t pos, + int cap, int *ttl) +{ + u8_t id; + + while ((*ttl)--) + { + pos = pciReadByte(pciTag, pos); + if (pos < 0x40) + break; + pos &= ~3; + id = pciReadByte(pciTag, pos + PCI_CAP_LIST_ID); + if (id == 0xff) + break; + if (id == cap) + return pos; + pos += PCI_CAP_LIST_NEXT; + } + return 0; +} + +static int __pci_find_next_cap(PCITAG pciTag, u8_t pos, int cap) +{ + int ttl = PCI_FIND_CAP_TTL; + + return __pci_find_next_cap_ttl(pciTag, pos, cap, &ttl); +} + +static int __pci_bus_find_cap_start(PCITAG pciTag) +{ + u16_t status; + u8_t hdr_type; + + status = pciReadWord(pciTag, PCI_STATUS); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + + hdr_type = pciReadByte(pciTag, 0x0E); + switch (hdr_type) + { + case PCI_HEADER_TYPE_NORMAL: + case PCI_HEADER_TYPE_BRIDGE: + return PCI_CAPABILITY_LIST; + case PCI_HEADER_TYPE_CARDBUS: + return PCI_CB_CAPABILITY_LIST; + default: + return 0; + } + return 0; +} + + +int pci_find_capability(PCITAG pciTag, int cap) +{ + int pos; + + pos = __pci_bus_find_cap_start(pciTag); + if (pos) + pos = __pci_find_next_cap(pciTag, pos, cap); + + return pos; +} + + +PCITAG pci_find_class(u16_t class) +{ + u32_t bus, last_bus; + PCITAG tag; + + if( (last_bus = PciApi(1))==-1) + return -1; + + for(bus=0;bus<=last_bus;bus++) + { + u32_t devfn; + + for(devfn=0;devfn<256;devfn++) + { + u16_t devclass; + + devclass = PciRead16(bus,devfn, 0x0A); + + if( devclass != class) + continue; + + return pciTag(bus,(devfn>>3)&0x1F,devfn&0x7); + }; + }; + return -1; +}; + + +PCITAG pci_get_device(u32_t vendor, u32_t device, PCITAG from) +{ + u32_t bus, last_bus; + u32_t devfn; + + if( (last_bus = PciApi(1))==-1) + return -1; + + bus = PCI_BUS_FROM_TAG(from); + devfn = PCI_DFN_FROM_TAG(from); + + devfn++; + + for(;bus<=last_bus; bus++) + { + for(;devfn < 256;devfn++) + { + u32_t tmp; + u32_t dev_vendor; + u32_t dev_id; + + tmp = PciRead32(bus,devfn, 0); + + dev_vendor = (u16_t)tmp; + dev_id = tmp >> 16; + + if ((vendor == PCI_ANY_ID || dev_vendor == vendor)) + return pciTag(bus,(devfn>>3)&0x1F,devfn&0x7); + }; + }; + return -1; +} + diff --git a/programs/system/drivers/agp/syscall.h b/programs/system/drivers/agp/syscall.h index a389666966..6b12ea6aa7 100644 --- a/programs/system/drivers/agp/syscall.h +++ b/programs/system/drivers/agp/syscall.h @@ -63,15 +63,18 @@ u8_t STDCALL PciRead8 (u32_t bus, u32_t devfn, u32_t reg)__asm__("PciRead8"); u16_t STDCALL PciRead16(u32_t bus, u32_t devfn, u32_t reg)__asm__("PciRead16"); u32_t STDCALL PciRead32(u32_t bus, u32_t devfn, u32_t reg)__asm__("PciRead32"); -#define pciReadLong(tag, reg) \ - PciRead32(PCI_BUS_FROM_TAG(tag),PCI_DFN_FROM_TAG(tag),(reg)) +u32_t STDCALL PciWrite8 (u32_t bus, u32_t devfn, u32_t reg,u8_t val) __asm__("PciWrite8"); +u32_t STDCALL PciWrite16(u32_t bus, u32_t devfn, u32_t reg,u16_t val)__asm__("PciWrite16"); +u32_t STDCALL PciWrite32(u32_t bus, u32_t devfn, u32_t reg,u32_t val)__asm__("PciWrite32"); #define pciReadByte(tag, reg) \ PciRead8(PCI_BUS_FROM_TAG(tag),PCI_DFN_FROM_TAG(tag),(reg)) -u32_t STDCALL PciWrite8 (u32_t bus, u32_t devfn, u32_t reg,u8_t val) __asm__("PciWrite8"); -u32_t STDCALL PciWrite16(u32_t bus, u32_t devfn, u32_t reg,u16_t val)__asm__("PciWrite16"); -u32_t STDCALL PciWrite32(u32_t bus, u32_t devfn, u32_t reg,u32_t val)__asm__("PciWrite32"); +#define pciReadWord(tag, reg) \ + PciRead16(PCI_BUS_FROM_TAG(tag),PCI_DFN_FROM_TAG(tag),(reg)) + +#define pciReadLong(tag, reg) \ + PciRead32(PCI_BUS_FROM_TAG(tag),PCI_DFN_FROM_TAG(tag),(reg)) #define pciWriteByte(tag, reg, val) \ PciWrite8(PCI_BUS_FROM_TAG(tag),PCI_DFN_FROM_TAG(tag),(reg),(val)) diff --git a/programs/system/drivers/agp/types.h b/programs/system/drivers/agp/types.h index cef0bba8a3..ec44c986b3 100644 --- a/programs/system/drivers/agp/types.h +++ b/programs/system/drivers/agp/types.h @@ -18,4 +18,9 @@ typedef unsigned int Bool; #define TRUE (Bool)1 #define FALSE (Bool)0 +#define min_t(type,x,y) \ + ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) +#define max_t(type,x,y) \ + ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) +