13446Smrj /* 26742Sms148562 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 33446Smrj * Use is subject to license terms. 43446Smrj */ 53446Smrj /* 63446Smrj * Portions Philip Brown phil@bolthole.com Dec 2001 73446Smrj */ 83446Smrj 93446Smrj 103446Smrj /* 113446Smrj * agpgart driver 123446Smrj * 133446Smrj * This driver is primary targeted at providing memory support for INTEL 143446Smrj * AGP device, INTEL memory less video card, and AMD64 cpu GART devices. 153446Smrj * So there are four main architectures, ARC_IGD810, ARC_IGD830, ARC_INTELAGP, 165376Scg149915 * ARC_AMD64AGP to agpgart driver. However, the memory 173446Smrj * interfaces are the same for these architectures. The difference is how to 183446Smrj * manage the hardware GART table for them. 193446Smrj * 203446Smrj * For large memory allocation, this driver use direct mapping to userland 213446Smrj * application interface to save kernel virtual memory . 223446Smrj */ 233446Smrj 243446Smrj #include <sys/types.h> 253446Smrj #include <sys/pci.h> 263446Smrj #include <sys/systm.h> 273446Smrj #include <sys/conf.h> 283446Smrj #include <sys/file.h> 293446Smrj #include <sys/kstat.h> 303446Smrj #include <sys/stat.h> 313446Smrj #include <sys/modctl.h> 323446Smrj #include <sys/ddi.h> 333446Smrj #include <sys/sunddi.h> 343446Smrj #include <sys/sunldi.h> 353446Smrj #include <sys/policy.h> 363446Smrj #include <sys/ddidevmap.h> 373446Smrj #include <vm/seg_dev.h> 383446Smrj #include <sys/pmem.h> 393446Smrj #include <sys/agpgart.h> 403446Smrj #include <sys/agp/agpdefs.h> 413446Smrj #include <sys/agp/agpgart_impl.h> 423446Smrj #include <sys/agp/agpamd64gart_io.h> 433446Smrj #include <sys/agp/agpmaster_io.h> 443446Smrj #include <sys/agp/agptarget_io.h> 453446Smrj 463446Smrj /* Dynamic debug support */ 473446Smrj int agp_debug_var = 0; 483446Smrj #define AGPDB_PRINT1(fmt) if (agp_debug_var == 1) cmn_err fmt 493446Smrj #define AGPDB_PRINT2(fmt) if (agp_debug_var >= 1) cmn_err fmt 503446Smrj 513446Smrj /* Driver global softstate handle */ 523446Smrj static void *agpgart_glob_soft_handle; 533446Smrj 543446Smrj #define MAX_INSTNUM 16 553446Smrj 563446Smrj #define AGP_DEV2INST(devt) (getminor((devt)) >> 4) 573446Smrj #define AGP_INST2MINOR(instance) ((instance) << 4) 583446Smrj #define IS_INTEL_830(type) ((type) == ARC_IGD830) 593446Smrj #define IS_TRUE_AGP(type) (((type) == ARC_INTELAGP) || \ 603446Smrj ((type) == ARC_AMD64AGP)) 613446Smrj 623446Smrj #define agpinfo_default_to_32(v, v32) \ 633446Smrj { \ 643446Smrj (v32).agpi32_version = (v).agpi_version; \ 653446Smrj (v32).agpi32_devid = (v).agpi_devid; \ 663446Smrj (v32).agpi32_mode = (v).agpi_mode; \ 677165Shh224818 (v32).agpi32_aperbase = (uint32_t)(v).agpi_aperbase; \ 687165Shh224818 (v32).agpi32_apersize = (uint32_t)(v).agpi_apersize; \ 693446Smrj (v32).agpi32_pgtotal = (v).agpi_pgtotal; \ 703446Smrj (v32).agpi32_pgsystem = (v).agpi_pgsystem; \ 713446Smrj (v32).agpi32_pgused = (v).agpi_pgused; \ 723446Smrj } 733446Smrj 743446Smrj static ddi_dma_attr_t agpgart_dma_attr = { 753446Smrj DMA_ATTR_V0, 763446Smrj 0U, /* dma_attr_addr_lo */ 773446Smrj 0xffffffffU, /* dma_attr_addr_hi */ 783446Smrj 0xffffffffU, /* dma_attr_count_max */ 793446Smrj (uint64_t)AGP_PAGE_SIZE, /* dma_attr_align */ 803446Smrj 1, /* dma_attr_burstsizes */ 813446Smrj 1, /* dma_attr_minxfer */ 823446Smrj 0xffffffffU, /* dma_attr_maxxfer */ 833446Smrj 0xffffffffU, /* dma_attr_seg */ 843446Smrj 1, /* dma_attr_sgllen, variable */ 853446Smrj 4, /* dma_attr_granular */ 863446Smrj 0 /* dma_attr_flags */ 873446Smrj }; 883446Smrj 893446Smrj /* 903446Smrj * AMD64 supports gart table above 4G. See alloc_gart_table. 913446Smrj */ 923446Smrj static ddi_dma_attr_t garttable_dma_attr = { 933446Smrj DMA_ATTR_V0, 943446Smrj 0U, /* dma_attr_addr_lo */ 953446Smrj 0xffffffffU, /* dma_attr_addr_hi */ 963446Smrj 0xffffffffU, /* dma_attr_count_max */ 973446Smrj (uint64_t)AGP_PAGE_SIZE, /* dma_attr_align */ 983446Smrj 1, /* dma_attr_burstsizes */ 993446Smrj 1, /* dma_attr_minxfer */ 1003446Smrj 0xffffffffU, /* dma_attr_maxxfer */ 1013446Smrj 0xffffffffU, /* dma_attr_seg */ 1023446Smrj 1, /* dma_attr_sgllen, variable */ 1033446Smrj 4, /* dma_attr_granular */ 1043446Smrj 0 /* dma_attr_flags */ 1053446Smrj }; 1063446Smrj 1073446Smrj /* 1083446Smrj * AGPGART table need a physical contiguous memory. To assure that 1093446Smrj * each access to gart table is strongly ordered and uncachable, 1103446Smrj * we use DDI_STRICTORDER_ACC. 1113446Smrj */ 1123446Smrj static ddi_device_acc_attr_t gart_dev_acc_attr = { 1133446Smrj DDI_DEVICE_ATTR_V0, 1143446Smrj DDI_NEVERSWAP_ACC, 1153446Smrj DDI_STRICTORDER_ACC /* must be DDI_STRICTORDER_ACC */ 1163446Smrj }; 1173446Smrj 1183446Smrj /* 1193446Smrj * AGP memory is usually used as texture memory or for a framebuffer, so we 1203446Smrj * can set the memory attribute to write combining. Video drivers will 1213446Smrj * determine the frame buffer attributes, for example the memory is write 1223446Smrj * combinging or non-cachable. However, the interface between Xorg and agpgart 1233446Smrj * driver to support attribute selcetion doesn't exist yet. So we set agp memory 1243446Smrj * to non-cachable by default now. This attribute might be overridden 1253446Smrj * by MTTR in X86. 1263446Smrj */ 1273446Smrj static ddi_device_acc_attr_t mem_dev_acc_attr = { 1283446Smrj DDI_DEVICE_ATTR_V0, 1293446Smrj DDI_NEVERSWAP_ACC, 1303446Smrj DDI_STRICTORDER_ACC /* Can be DDI_MERGING_OK_ACC */ 1313446Smrj }; 1323446Smrj 1333446Smrj static keytable_ent_t * 1343446Smrj agp_find_bound_keyent(agpgart_softstate_t *softstate, uint32_t pg_offset); 1353446Smrj static void 1363446Smrj amd64_gart_unregister(amd64_garts_dev_t *cpu_garts); 1373446Smrj 1383446Smrj 1393446Smrj static void 1403446Smrj agp_devmap_unmap(devmap_cookie_t handle, void *devprivate, 1413446Smrj offset_t off, size_t len, devmap_cookie_t new_handle1, 1423446Smrj void **new_devprivate1, devmap_cookie_t new_handle2, 1433446Smrj void **new_devprivate2) 1443446Smrj { 1453446Smrj 1463446Smrj struct keytable_ent *mementry; 1473446Smrj agpgart_softstate_t *softstate; 1483446Smrj agpgart_ctx_t *ctxp, *newctxp1, *newctxp2; 1493446Smrj 1503446Smrj ASSERT(AGP_ALIGNED(len) && AGP_ALIGNED(off)); 1513446Smrj ASSERT(devprivate); 1523446Smrj ASSERT(handle); 1533446Smrj 1543446Smrj ctxp = (agpgart_ctx_t *)devprivate; 1553446Smrj softstate = ctxp->actx_sc; 1563446Smrj ASSERT(softstate); 1573446Smrj 1583446Smrj if (new_handle1 != NULL) { 1593446Smrj newctxp1 = kmem_zalloc(sizeof (agpgart_ctx_t), KM_SLEEP); 1603446Smrj newctxp1->actx_sc = softstate; 1613446Smrj newctxp1->actx_off = ctxp->actx_off; 1623446Smrj *new_devprivate1 = newctxp1; 1633446Smrj } 1643446Smrj 1653446Smrj if (new_handle2 != NULL) { 1663446Smrj newctxp2 = kmem_zalloc(sizeof (agpgart_ctx_t), KM_SLEEP); 1673446Smrj newctxp2->actx_sc = softstate; 1683446Smrj newctxp2->actx_off = off + len; 1693446Smrj *new_devprivate2 = newctxp2; 1703446Smrj } 1713446Smrj 1723446Smrj mutex_enter(&softstate->asoft_instmutex); 1733446Smrj if ((new_handle1 == NULL) && (new_handle2 == NULL)) { 1743446Smrj mementry = 1753446Smrj agp_find_bound_keyent(softstate, AGP_BYTES2PAGES(off)); 1763446Smrj ASSERT(mementry); 1773446Smrj mementry->kte_refcnt--; 1783446Smrj } else if ((new_handle1 != NULL) && (new_handle2 != NULL)) { 1793446Smrj mementry = 1803446Smrj agp_find_bound_keyent(softstate, AGP_BYTES2PAGES(off)); 1813446Smrj ASSERT(mementry); 1823446Smrj mementry->kte_refcnt++; 1833446Smrj } 1843446Smrj ASSERT(mementry->kte_refcnt >= 0); 1853446Smrj mutex_exit(&softstate->asoft_instmutex); 1863446Smrj kmem_free(ctxp, sizeof (struct agpgart_ctx)); 1873446Smrj } 1883446Smrj 1893446Smrj /*ARGSUSED*/ 1903446Smrj static int 1913446Smrj agp_devmap_map(devmap_cookie_t handle, dev_t dev, 1923446Smrj uint_t flags, offset_t offset, size_t len, void **new_devprivate) 1933446Smrj { 1943446Smrj agpgart_softstate_t *softstate; 1953446Smrj int instance; 1963446Smrj struct keytable_ent *mementry; 1973446Smrj agpgart_ctx_t *newctxp; 1983446Smrj 1993446Smrj ASSERT(handle); 2003446Smrj instance = AGP_DEV2INST(dev); 2013446Smrj softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance); 2023446Smrj if (softstate == NULL) { 2033446Smrj AGPDB_PRINT2((CE_WARN, "agp_devmap_map: get soft state err")); 2043446Smrj return (ENXIO); 2053446Smrj } 2063446Smrj 2073446Smrj ASSERT(softstate); 2083446Smrj ASSERT(mutex_owned(&softstate->asoft_instmutex)); 2093446Smrj ASSERT(len); 2103446Smrj ASSERT(AGP_ALIGNED(offset) && AGP_ALIGNED(len)); 2113446Smrj 2123446Smrj mementry = 2133446Smrj agp_find_bound_keyent(softstate, AGP_BYTES2PAGES(offset)); 2143446Smrj ASSERT(mementry); 2153446Smrj mementry->kte_refcnt++; 2163446Smrj ASSERT(mementry->kte_refcnt >= 0); 2173446Smrj newctxp = kmem_zalloc(sizeof (agpgart_ctx_t), KM_SLEEP); 2183446Smrj newctxp->actx_off = offset; 2193446Smrj newctxp->actx_sc = softstate; 2203446Smrj *new_devprivate = newctxp; 2213446Smrj 2223446Smrj return (0); 2233446Smrj } 2243446Smrj 2253446Smrj /*ARGSUSED*/ 2263446Smrj static int agp_devmap_dup(devmap_cookie_t handle, void *devprivate, 2273446Smrj devmap_cookie_t new_handle, void **new_devprivate) 2283446Smrj { 2293446Smrj struct keytable_ent *mementry; 2303446Smrj agpgart_ctx_t *newctxp, *ctxp; 2313446Smrj agpgart_softstate_t *softstate; 2323446Smrj 2333446Smrj ASSERT(devprivate); 2343446Smrj ASSERT(handle && new_handle); 2353446Smrj 2363446Smrj ctxp = (agpgart_ctx_t *)devprivate; 2373446Smrj ASSERT(AGP_ALIGNED(ctxp->actx_off)); 2383446Smrj 2393446Smrj newctxp = kmem_zalloc(sizeof (agpgart_ctx_t), KM_SLEEP); 2403446Smrj newctxp->actx_off = ctxp->actx_off; 2413446Smrj newctxp->actx_sc = ctxp->actx_sc; 2423446Smrj softstate = (agpgart_softstate_t *)newctxp->actx_sc; 2433446Smrj 2443446Smrj mutex_enter(&softstate->asoft_instmutex); 2453446Smrj mementry = agp_find_bound_keyent(softstate, 2463446Smrj AGP_BYTES2PAGES(newctxp->actx_off)); 2473446Smrj mementry->kte_refcnt++; 2483446Smrj ASSERT(mementry->kte_refcnt >= 0); 2493446Smrj mutex_exit(&softstate->asoft_instmutex); 2503446Smrj *new_devprivate = newctxp; 2513446Smrj 2523446Smrj return (0); 2533446Smrj } 2543446Smrj 2553446Smrj struct devmap_callback_ctl agp_devmap_cb = { 2563446Smrj DEVMAP_OPS_REV, /* rev */ 2573446Smrj agp_devmap_map, /* map */ 2583446Smrj NULL, /* access */ 2593446Smrj agp_devmap_dup, /* dup */ 2603446Smrj agp_devmap_unmap, /* unmap */ 2613446Smrj }; 2623446Smrj 2633446Smrj /* 2643446Smrj * agp_master_regis_byname() 2653446Smrj * 2663446Smrj * Description: 2673446Smrj * Open the AGP master device node by device path name and 2683446Smrj * register the device handle for later operations. 2693446Smrj * We check all possible driver instance from 0 2703446Smrj * to MAX_INSTNUM because the master device could be 2713446Smrj * at any instance number. Only one AGP master is supported. 2723446Smrj * 2733446Smrj * Arguments: 2743446Smrj * master_hdlp AGP master device LDI handle pointer 2753446Smrj * agpgart_l AGPGART driver LDI identifier 2763446Smrj * 2773446Smrj * Returns: 2783446Smrj * -1 failed 2793446Smrj * 0 success 2803446Smrj */ 2813446Smrj static int 2823446Smrj agp_master_regis_byname(ldi_handle_t *master_hdlp, ldi_ident_t agpgart_li) 2833446Smrj { 2843446Smrj int i; 2853446Smrj char buf[MAXPATHLEN]; 2863446Smrj 2873446Smrj ASSERT(master_hdlp); 2883446Smrj ASSERT(agpgart_li); 2893446Smrj 2903446Smrj /* 2913446Smrj * Search all possible instance numbers for the agp master device. 2923446Smrj * Only one master device is supported now, so the search ends 2933446Smrj * when one master device is found. 2943446Smrj */ 2953446Smrj for (i = 0; i < MAX_INSTNUM; i++) { 2963446Smrj (void) snprintf(buf, MAXPATHLEN, "%s%d", AGPMASTER_DEVLINK, i); 2973446Smrj if ((ldi_open_by_name(buf, 0, kcred, 2983446Smrj master_hdlp, agpgart_li))) 2993446Smrj continue; 3003446Smrj AGPDB_PRINT1((CE_NOTE, 3013446Smrj "master device found: instance number=%d", i)); 3023446Smrj break; 3033446Smrj 3043446Smrj } 3053446Smrj 3063446Smrj /* AGP master device not found */ 3073446Smrj if (i == MAX_INSTNUM) 3083446Smrj return (-1); 3093446Smrj 3103446Smrj return (0); 3113446Smrj } 3123446Smrj 3133446Smrj /* 3143446Smrj * agp_target_regis_byname() 3153446Smrj * 3163446Smrj * Description: 3173446Smrj * This function opens agp bridge device node by 3183446Smrj * device path name and registers the device handle 3193446Smrj * for later operations. 3203446Smrj * We check driver instance from 0 to MAX_INSTNUM 3213446Smrj * because the master device could be at any instance 3223446Smrj * number. Only one agp target is supported. 3233446Smrj * 3243446Smrj * 3253446Smrj * Arguments: 3263446Smrj * target_hdlp AGP target device LDI handle pointer 3273446Smrj * agpgart_l AGPGART driver LDI identifier 3283446Smrj * 3293446Smrj * Returns: 3303446Smrj * -1 failed 3313446Smrj * 0 success 3323446Smrj */ 3333446Smrj static int 3343446Smrj agp_target_regis_byname(ldi_handle_t *target_hdlp, ldi_ident_t agpgart_li) 3353446Smrj { 3363446Smrj int i; 3373446Smrj char buf[MAXPATHLEN]; 3383446Smrj 3393446Smrj ASSERT(target_hdlp); 3403446Smrj ASSERT(agpgart_li); 3413446Smrj 3423446Smrj for (i = 0; i < MAX_INSTNUM; i++) { 3433446Smrj (void) snprintf(buf, MAXPATHLEN, "%s%d", AGPTARGET_DEVLINK, i); 3443446Smrj if ((ldi_open_by_name(buf, 0, kcred, 3453446Smrj target_hdlp, agpgart_li))) 3463446Smrj continue; 3473446Smrj 3483446Smrj AGPDB_PRINT1((CE_NOTE, 3493446Smrj "bridge device found: instance number=%d", i)); 3503446Smrj break; 3513446Smrj 3523446Smrj } 3533446Smrj 3543446Smrj /* AGP bridge device not found */ 3553446Smrj if (i == MAX_INSTNUM) { 3563446Smrj AGPDB_PRINT2((CE_WARN, "bridge device not found")); 3573446Smrj return (-1); 3583446Smrj } 3593446Smrj 3603446Smrj return (0); 3613446Smrj } 3623446Smrj 3633446Smrj /* 3643446Smrj * amd64_gart_regis_byname() 3653446Smrj * 3663446Smrj * Description: 3673446Smrj * Open all amd64 gart device nodes by deice path name and 3683446Smrj * register the device handles for later operations. Each cpu 3693446Smrj * has its own amd64 gart device. 3703446Smrj * 3713446Smrj * Arguments: 3723446Smrj * cpu_garts cpu garts device list header 3733446Smrj * agpgart_l AGPGART driver LDI identifier 3743446Smrj * 3753446Smrj * Returns: 3763446Smrj * -1 failed 3773446Smrj * 0 success 3783446Smrj */ 3793446Smrj static int 3803446Smrj amd64_gart_regis_byname(amd64_garts_dev_t *cpu_garts, ldi_ident_t agpgart_li) 3813446Smrj { 3823446Smrj amd64_gart_dev_list_t *gart_list; 3833446Smrj int i; 3843446Smrj char buf[MAXPATHLEN]; 3853446Smrj ldi_handle_t gart_hdl; 3863446Smrj int ret; 3873446Smrj 3883446Smrj ASSERT(cpu_garts); 3893446Smrj ASSERT(agpgart_li); 3903446Smrj 3913446Smrj /* 3923446Smrj * Search all possible instance numbers for the gart devices. 3933446Smrj * There can be multiple on-cpu gart devices for Opteron server. 3943446Smrj */ 3953446Smrj for (i = 0; i < MAX_INSTNUM; i++) { 3963446Smrj (void) snprintf(buf, MAXPATHLEN, "%s%d", CPUGART_DEVLINK, i); 3973446Smrj ret = ldi_open_by_name(buf, 0, kcred, 3983446Smrj &gart_hdl, agpgart_li); 3993446Smrj 4003446Smrj if (ret == ENODEV) 4013446Smrj continue; 4023446Smrj else if (ret != 0) { /* There was an error opening the device */ 4033446Smrj amd64_gart_unregister(cpu_garts); 4043446Smrj return (ret); 4053446Smrj } 4063446Smrj 4073446Smrj AGPDB_PRINT1((CE_NOTE, 4083446Smrj "amd64 gart device found: instance number=%d", i)); 4093446Smrj 4103446Smrj gart_list = (amd64_gart_dev_list_t *) 4113446Smrj kmem_zalloc(sizeof (amd64_gart_dev_list_t), KM_SLEEP); 4123446Smrj 4133446Smrj /* Add new item to the head of the gart device list */ 4143446Smrj gart_list->gart_devhdl = gart_hdl; 4153446Smrj gart_list->next = cpu_garts->gart_dev_list_head; 4163446Smrj cpu_garts->gart_dev_list_head = gart_list; 4173446Smrj cpu_garts->gart_device_num++; 4183446Smrj } 4193446Smrj 4203446Smrj if (cpu_garts->gart_device_num == 0) 4213446Smrj return (ENODEV); 4223446Smrj return (0); 4233446Smrj } 4243446Smrj 4253446Smrj /* 4263446Smrj * Unregister agp master device handle 4273446Smrj */ 4283446Smrj static void 4293446Smrj agp_master_unregister(ldi_handle_t *master_hdlp) 4303446Smrj { 4313446Smrj ASSERT(master_hdlp); 4323446Smrj 4333446Smrj if (master_hdlp) { 4343446Smrj (void) ldi_close(*master_hdlp, 0, kcred); 4353446Smrj *master_hdlp = NULL; 4363446Smrj } 4373446Smrj } 4383446Smrj 4393446Smrj /* 4403446Smrj * Unregister agp bridge device handle 4413446Smrj */ 4423446Smrj static void 4433446Smrj agp_target_unregister(ldi_handle_t *target_hdlp) 4443446Smrj { 4453446Smrj if (target_hdlp) { 4463446Smrj (void) ldi_close(*target_hdlp, 0, kcred); 4473446Smrj *target_hdlp = NULL; 4483446Smrj } 4493446Smrj } 4503446Smrj 4513446Smrj /* 4523446Smrj * Unregister all amd64 gart device handles 4533446Smrj */ 4543446Smrj static void 4553446Smrj amd64_gart_unregister(amd64_garts_dev_t *cpu_garts) 4563446Smrj { 4573446Smrj amd64_gart_dev_list_t *gart_list; 4583446Smrj amd64_gart_dev_list_t *next; 4593446Smrj 4603446Smrj ASSERT(cpu_garts); 4613446Smrj 4623446Smrj for (gart_list = cpu_garts->gart_dev_list_head; 4633446Smrj gart_list; gart_list = next) { 4643446Smrj 4653446Smrj ASSERT(gart_list->gart_devhdl); 4663446Smrj (void) ldi_close(gart_list->gart_devhdl, 0, kcred); 4673446Smrj next = gart_list->next; 4683446Smrj /* Free allocated memory */ 4693446Smrj kmem_free(gart_list, sizeof (amd64_gart_dev_list_t)); 4703446Smrj } 4713446Smrj cpu_garts->gart_dev_list_head = NULL; 4723446Smrj cpu_garts->gart_device_num = 0; 4733446Smrj } 4743446Smrj 4753446Smrj /* 4763446Smrj * lyr_detect_master_type() 4773446Smrj * 4783446Smrj * Description: 4793446Smrj * This function gets agp master type by querying agp master device. 4803446Smrj * 4813446Smrj * Arguments: 4823446Smrj * master_hdlp agp master device ldi handle pointer 4833446Smrj * 4843446Smrj * Returns: 4853446Smrj * -1 unsupported device 4863446Smrj * DEVICE_IS_I810 i810 series 4873446Smrj * DEVICE_IS_I810 i830 series 4883446Smrj * DEVICE_IS_AGP true agp master 4893446Smrj */ 4903446Smrj static int 4913446Smrj lyr_detect_master_type(ldi_handle_t *master_hdlp) 4923446Smrj { 4933446Smrj int vtype; 4943446Smrj int err; 4953446Smrj 4963446Smrj ASSERT(master_hdlp); 4973446Smrj 4983446Smrj /* ldi_ioctl(agpmaster) */ 4993446Smrj err = ldi_ioctl(*master_hdlp, DEVICE_DETECT, 5003446Smrj (intptr_t)&vtype, FKIOCTL, kcred, 0); 5013446Smrj if (err) /* Unsupported graphics device */ 5023446Smrj return (-1); 5033446Smrj return (vtype); 5043446Smrj } 5053446Smrj 5063446Smrj /* 5073446Smrj * devtect_target_type() 5083446Smrj * 5093446Smrj * Description: 5103446Smrj * This function gets the host bridge chipset type by querying the agp 5113446Smrj * target device. 5123446Smrj * 5133446Smrj * Arguments: 5143446Smrj * target_hdlp agp target device LDI handle pointer 5153446Smrj * 5163446Smrj * Returns: 5173446Smrj * CHIP_IS_INTEL Intel agp chipsets 5183446Smrj * CHIP_IS_AMD AMD agp chipset 5193446Smrj * -1 unsupported chipset 5203446Smrj */ 5213446Smrj static int 5223446Smrj lyr_detect_target_type(ldi_handle_t *target_hdlp) 5233446Smrj { 5243446Smrj int btype; 5253446Smrj int err; 5263446Smrj 5273446Smrj ASSERT(target_hdlp); 5283446Smrj 5293446Smrj err = ldi_ioctl(*target_hdlp, CHIP_DETECT, (intptr_t)&btype, 5303446Smrj FKIOCTL, kcred, 0); 5313446Smrj if (err) /* Unsupported bridge device */ 5323446Smrj return (-1); 5333446Smrj return (btype); 5343446Smrj } 5353446Smrj 5363446Smrj /* 5373446Smrj * lyr_init() 5383446Smrj * 5393446Smrj * Description: 5403446Smrj * This function detects the graphics system architecture and 5413446Smrj * registers all relative device handles in a global structure 5423446Smrj * "agp_regdev". Then it stores the system arc type in driver 5433446Smrj * soft state. 5443446Smrj * 5453446Smrj * Arguments: 5463446Smrj * agp_regdev AGP devices registration struct pointer 5473446Smrj * agpgart_l AGPGART driver LDI identifier 5483446Smrj * 5493446Smrj * Returns: 5503446Smrj * 0 System arc supported and agp devices registration successed. 5513446Smrj * -1 System arc not supported or device registration failed. 5523446Smrj */ 5533446Smrj int 5543446Smrj lyr_init(agp_registered_dev_t *agp_regdev, ldi_ident_t agpgart_li) 5553446Smrj { 5563446Smrj ldi_handle_t *master_hdlp; 5573446Smrj ldi_handle_t *target_hdlp; 5583446Smrj amd64_garts_dev_t *garts_dev; 5593446Smrj int card_type, chip_type; 5603446Smrj int ret; 5613446Smrj 5623446Smrj ASSERT(agp_regdev); 5633446Smrj 5643446Smrj bzero(agp_regdev, sizeof (agp_registered_dev_t)); 5653446Smrj agp_regdev->agprd_arctype = ARC_UNKNOWN; 5663446Smrj /* 5673446Smrj * Register agp devices, assuming all instances attached, and 5683446Smrj * detect which agp architucture this server belongs to. This 5693446Smrj * must be done before the agpgart driver starts to use layered 5703446Smrj * driver interfaces. 5713446Smrj */ 5723446Smrj master_hdlp = &agp_regdev->agprd_masterhdl; 5733446Smrj target_hdlp = &agp_regdev->agprd_targethdl; 5743446Smrj garts_dev = &agp_regdev->agprd_cpugarts; 5753446Smrj 5763446Smrj /* Check whether the system is amd64 arc */ 5773446Smrj if ((ret = amd64_gart_regis_byname(garts_dev, agpgart_li)) == ENODEV) { 5783446Smrj /* No amd64 gart devices */ 5793446Smrj AGPDB_PRINT1((CE_NOTE, 5803446Smrj "lyr_init: this is not an amd64 system")); 5813446Smrj if (agp_master_regis_byname(master_hdlp, agpgart_li)) { 5823446Smrj AGPDB_PRINT2((CE_WARN, 5833446Smrj "lyr_init: register master device unsuccessful")); 5843446Smrj goto err1; 5853446Smrj } 5863446Smrj if (agp_target_regis_byname(target_hdlp, agpgart_li)) { 5873446Smrj AGPDB_PRINT2((CE_WARN, 5883446Smrj "lyr_init: register target device unsuccessful")); 5893446Smrj goto err2; 5903446Smrj } 5913446Smrj card_type = lyr_detect_master_type(master_hdlp); 5923446Smrj /* 5933446Smrj * Detect system arc by master device. If it is a intel 5943446Smrj * integrated device, finish the detection successfully. 5953446Smrj */ 5963446Smrj switch (card_type) { 5973446Smrj case DEVICE_IS_I810: /* I810 likewise graphics */ 5983446Smrj AGPDB_PRINT1((CE_NOTE, 5993446Smrj "lyr_init: the system is Intel 810 arch")); 6003446Smrj agp_regdev->agprd_arctype = ARC_IGD810; 6013446Smrj return (0); 6023446Smrj case DEVICE_IS_I830: /* I830 likewise graphics */ 6033446Smrj AGPDB_PRINT1((CE_NOTE, 6043446Smrj "lyr_init: the system is Intel 830 arch")); 6053446Smrj agp_regdev->agprd_arctype = ARC_IGD830; 6063446Smrj return (0); 6073446Smrj case DEVICE_IS_AGP: /* AGP graphics */ 6083446Smrj break; 6093446Smrj default: /* Non IGD/AGP graphics */ 6103446Smrj AGPDB_PRINT2((CE_WARN, 6113446Smrj "lyr_init: non-supported master device")); 6123446Smrj goto err3; 6133446Smrj } 6143446Smrj 6153446Smrj chip_type = lyr_detect_target_type(target_hdlp); 6163446Smrj 6173446Smrj /* Continue to detect AGP arc by target device */ 6183446Smrj switch (chip_type) { 6193446Smrj case CHIP_IS_INTEL: /* Intel chipset */ 6203446Smrj AGPDB_PRINT1((CE_NOTE, 6213446Smrj "lyr_init: Intel AGP arch detected")); 6223446Smrj agp_regdev->agprd_arctype = ARC_INTELAGP; 6233446Smrj return (0); 6243446Smrj case CHIP_IS_AMD: /* AMD chipset */ 6253446Smrj AGPDB_PRINT2((CE_WARN, 6263446Smrj "lyr_init: no cpu gart, but have AMD64 chipsets")); 6273446Smrj goto err3; 6283446Smrj default: /* Non supported chipset */ 6293446Smrj AGPDB_PRINT2((CE_WARN, 6303446Smrj "lyr_init: detection can not continue")); 6313446Smrj goto err3; 6323446Smrj } 6333446Smrj 6343446Smrj } 6353446Smrj 6363446Smrj if (ret) 6373446Smrj return (-1); /* Errors in open amd64 cpu gart devices */ 6383446Smrj 6393446Smrj /* 6403446Smrj * AMD64 cpu gart device exsits, continue detection 6413446Smrj */ 6423446Smrj if (agp_master_regis_byname(master_hdlp, agpgart_li)) { 6435376Scg149915 AGPDB_PRINT1((CE_NOTE, "lyr_init: no AGP master in amd64")); 6445376Scg149915 goto err1; 6453446Smrj } 6463446Smrj 6473446Smrj if (agp_target_regis_byname(target_hdlp, agpgart_li)) { 6483446Smrj AGPDB_PRINT1((CE_NOTE, 6495376Scg149915 "lyr_init: no AGP bridge")); 6505376Scg149915 goto err2; 6513446Smrj } 6523446Smrj 6533446Smrj AGPDB_PRINT1((CE_NOTE, 6543446Smrj "lyr_init: the system is AMD64 AGP architecture")); 6553446Smrj 6563446Smrj agp_regdev->agprd_arctype = ARC_AMD64AGP; 6573446Smrj 6583446Smrj return (0); /* Finished successfully */ 6593446Smrj 6603446Smrj err3: 6613446Smrj agp_target_unregister(&agp_regdev->agprd_targethdl); 6623446Smrj err2: 6633446Smrj agp_master_unregister(&agp_regdev->agprd_masterhdl); 6643446Smrj err1: 6655517Scg149915 /* AMD64 CPU gart registered ? */ 6665517Scg149915 if (ret == 0) { 6675517Scg149915 amd64_gart_unregister(garts_dev); 6685517Scg149915 } 6693446Smrj agp_regdev->agprd_arctype = ARC_UNKNOWN; 6703446Smrj return (-1); 6713446Smrj } 6723446Smrj 6733446Smrj void 6743446Smrj lyr_end(agp_registered_dev_t *agp_regdev) 6753446Smrj { 6763446Smrj ASSERT(agp_regdev); 6773446Smrj 6783446Smrj switch (agp_regdev->agprd_arctype) { 6793446Smrj case ARC_IGD810: 6803446Smrj case ARC_IGD830: 6813446Smrj case ARC_INTELAGP: 6823446Smrj agp_master_unregister(&agp_regdev->agprd_masterhdl); 6833446Smrj agp_target_unregister(&agp_regdev->agprd_targethdl); 6843446Smrj 6853446Smrj return; 6863446Smrj case ARC_AMD64AGP: 6873446Smrj agp_master_unregister(&agp_regdev->agprd_masterhdl); 6883446Smrj agp_target_unregister(&agp_regdev->agprd_targethdl); 6893446Smrj amd64_gart_unregister(&agp_regdev->agprd_cpugarts); 6903446Smrj 6913446Smrj return; 6923446Smrj default: 6933446Smrj ASSERT(0); 6943446Smrj return; 6953446Smrj } 6963446Smrj } 6973446Smrj 6983446Smrj int 6993446Smrj lyr_get_info(agp_kern_info_t *info, agp_registered_dev_t *agp_regdev) 7003446Smrj { 7013446Smrj ldi_handle_t hdl; 7023446Smrj igd_info_t value1; 7033446Smrj i_agp_info_t value2; 7043446Smrj size_t prealloc_size; 7053446Smrj int err; 7063446Smrj 7073446Smrj ASSERT(info); 7083446Smrj ASSERT(agp_regdev); 7093446Smrj 7103446Smrj switch (agp_regdev->agprd_arctype) { 7113446Smrj case ARC_IGD810: 7123446Smrj hdl = agp_regdev->agprd_masterhdl; 7133446Smrj err = ldi_ioctl(hdl, I8XX_GET_INFO, (intptr_t)&value1, 7143446Smrj FKIOCTL, kcred, 0); 7153446Smrj if (err) 7163446Smrj return (-1); 7173446Smrj info->agpki_mdevid = value1.igd_devid; 7183446Smrj info->agpki_aperbase = value1.igd_aperbase; 7197165Shh224818 info->agpki_apersize = (uint32_t)value1.igd_apersize; 7203446Smrj 7213446Smrj hdl = agp_regdev->agprd_targethdl; 7223446Smrj err = ldi_ioctl(hdl, I8XX_GET_PREALLOC_SIZE, 7233446Smrj (intptr_t)&prealloc_size, FKIOCTL, kcred, 0); 7243446Smrj if (err) 7253446Smrj return (-1); 7263446Smrj info->agpki_presize = prealloc_size; 7273446Smrj 7283446Smrj break; 7293446Smrj 7303446Smrj case ARC_IGD830: 7313446Smrj hdl = agp_regdev->agprd_masterhdl; 7323446Smrj err = ldi_ioctl(hdl, I8XX_GET_INFO, (intptr_t)&value1, 7333446Smrj FKIOCTL, kcred, 0); 7343446Smrj if (err) 7353446Smrj return (-1); 7363446Smrj info->agpki_mdevid = value1.igd_devid; 7373446Smrj info->agpki_aperbase = value1.igd_aperbase; 7387165Shh224818 info->agpki_apersize = (uint32_t)value1.igd_apersize; 7393446Smrj 7403446Smrj hdl = agp_regdev->agprd_targethdl; 7413446Smrj err = ldi_ioctl(hdl, I8XX_GET_PREALLOC_SIZE, 7423446Smrj (intptr_t)&prealloc_size, FKIOCTL, kcred, 0); 7433446Smrj if (err) 7443446Smrj return (-1); 7453446Smrj 7463446Smrj /* 7473446Smrj * Assume all units are kilobytes unless explicitly 7483446Smrj * stated below: 7493446Smrj * preallocated GTT memory = preallocated memory - GTT size 7503446Smrj * - scratch page size 7513446Smrj * 7523446Smrj * scratch page size = 4 7535036Skz151634 * GTT size (KB) = aperture size (MB) 7543446Smrj * this algorithm came from Xorg source code 7553446Smrj */ 7565036Skz151634 if (prealloc_size > (info->agpki_apersize + 4)) 7575036Skz151634 prealloc_size = 7585036Skz151634 prealloc_size - info->agpki_apersize - 4; 7595036Skz151634 else { 7605036Skz151634 AGPDB_PRINT2((CE_WARN, "lyr_get_info: " 7615036Skz151634 "pre-allocated memory too small, setting to zero")); 7625036Skz151634 prealloc_size = 0; 7635036Skz151634 } 7643446Smrj info->agpki_presize = prealloc_size; 7654478Skz151634 AGPDB_PRINT2((CE_NOTE, 7664478Skz151634 "lyr_get_info: prealloc_size = %ldKB, apersize = %dMB", 7674478Skz151634 prealloc_size, info->agpki_apersize)); 7683446Smrj break; 7693446Smrj case ARC_INTELAGP: 7703446Smrj case ARC_AMD64AGP: 7713446Smrj /* AGP devices */ 7723446Smrj hdl = agp_regdev->agprd_masterhdl; 7733446Smrj err = ldi_ioctl(hdl, AGP_MASTER_GETINFO, 7743446Smrj (intptr_t)&value2, FKIOCTL, kcred, 0); 7753446Smrj if (err) 7763446Smrj return (-1); 7773446Smrj info->agpki_mdevid = value2.iagp_devid; 7783446Smrj info->agpki_mver = value2.iagp_ver; 7793446Smrj info->agpki_mstatus = value2.iagp_mode; 7803446Smrj hdl = agp_regdev->agprd_targethdl; 7813446Smrj err = ldi_ioctl(hdl, AGP_TARGET_GETINFO, 7823446Smrj (intptr_t)&value2, FKIOCTL, kcred, 0); 7833446Smrj if (err) 7843446Smrj return (-1); 7853446Smrj info->agpki_tdevid = value2.iagp_devid; 7863446Smrj info->agpki_tver = value2.iagp_ver; 7873446Smrj info->agpki_tstatus = value2.iagp_mode; 7883446Smrj info->agpki_aperbase = value2.iagp_aperbase; 7897165Shh224818 info->agpki_apersize = (uint32_t)value2.iagp_apersize; 7903446Smrj break; 7913446Smrj default: 7923446Smrj AGPDB_PRINT2((CE_WARN, 7933446Smrj "lyr_get_info: function doesn't work for unknown arc")); 7943446Smrj return (-1); 7953446Smrj } 7963446Smrj if ((info->agpki_apersize >= MAXAPERMEGAS) || 7973446Smrj (info->agpki_apersize == 0) || 7983446Smrj (info->agpki_aperbase == 0)) { 7993446Smrj AGPDB_PRINT2((CE_WARN, 8003446Smrj "lyr_get_info: aperture is not programmed correctly!")); 8013446Smrj return (-1); 8023446Smrj } 8033446Smrj 8043446Smrj return (0); 8053446Smrj } 8063446Smrj 8073446Smrj /* 8083446Smrj * lyr_i8xx_add_to_gtt() 8093446Smrj * 8103446Smrj * Description: 8113446Smrj * This function sets up the integrated video device gtt table 8123446Smrj * via an ioclt to the AGP master driver. 8133446Smrj * 8143446Smrj * Arguments: 8153446Smrj * pg_offset The start entry to be setup 8163446Smrj * keyent Keytable entity pointer 8173446Smrj * agp_regdev AGP devices registration struct pointer 8183446Smrj * 8193446Smrj * Returns: 8203446Smrj * 0 success 8213446Smrj * -1 invalid operations 8223446Smrj */ 8233446Smrj int 8243446Smrj lyr_i8xx_add_to_gtt(uint32_t pg_offset, keytable_ent_t *keyent, 8253446Smrj agp_registered_dev_t *agp_regdev) 8263446Smrj { 8273446Smrj int err = 0; 8283446Smrj int rval; 8293446Smrj ldi_handle_t hdl; 8303446Smrj igd_gtt_seg_t gttseg; 8313446Smrj uint32_t *addrp, i; 8323446Smrj uint32_t npages; 8333446Smrj 8343446Smrj ASSERT(keyent); 8353446Smrj ASSERT(agp_regdev); 8363446Smrj gttseg.igs_pgstart = pg_offset; 8373446Smrj npages = keyent->kte_pages; 8383446Smrj gttseg.igs_npage = npages; 8393446Smrj gttseg.igs_type = keyent->kte_type; 8403446Smrj gttseg.igs_phyaddr = (uint32_t *)kmem_zalloc 8414478Skz151634 (sizeof (uint32_t) * gttseg.igs_npage, KM_SLEEP); 8423446Smrj 8433446Smrj addrp = gttseg.igs_phyaddr; 8443446Smrj for (i = 0; i < npages; i++, addrp++) { 8453446Smrj *addrp = 8463446Smrj (uint32_t)((keyent->kte_pfnarray[i]) << GTT_PAGE_SHIFT); 8473446Smrj } 8483446Smrj 8493446Smrj hdl = agp_regdev->agprd_masterhdl; 8503446Smrj if (ldi_ioctl(hdl, I8XX_ADD2GTT, (intptr_t)>tseg, FKIOCTL, 8513446Smrj kcred, &rval)) { 8523446Smrj AGPDB_PRINT2((CE_WARN, "lyr_i8xx_add_to_gtt: ldi_ioctl error")); 8533446Smrj AGPDB_PRINT2((CE_WARN, "lyr_i8xx_add_to_gtt: pg_start=0x%x", 8543446Smrj gttseg.igs_pgstart)); 8553446Smrj AGPDB_PRINT2((CE_WARN, "lyr_i8xx_add_to_gtt: pages=0x%x", 8563446Smrj gttseg.igs_npage)); 8573446Smrj AGPDB_PRINT2((CE_WARN, "lyr_i8xx_add_to_gtt: type=0x%x", 8583446Smrj gttseg.igs_type)); 8593446Smrj err = -1; 8603446Smrj } 8613446Smrj kmem_free(gttseg.igs_phyaddr, sizeof (uint32_t) * gttseg.igs_npage); 8623446Smrj return (err); 8633446Smrj } 8643446Smrj 8653446Smrj /* 8663446Smrj * lyr_i8xx_remove_from_gtt() 8673446Smrj * 8683446Smrj * Description: 8693446Smrj * This function clears the integrated video device gtt table via 8703446Smrj * an ioctl to the agp master device. 8713446Smrj * 8723446Smrj * Arguments: 8733446Smrj * pg_offset The starting entry to be cleared 8743446Smrj * npage The number of entries to be cleared 8753446Smrj * agp_regdev AGP devices struct pointer 8763446Smrj * 8773446Smrj * Returns: 8783446Smrj * 0 success 8793446Smrj * -1 invalid operations 8803446Smrj */ 8813446Smrj int 8823446Smrj lyr_i8xx_remove_from_gtt(uint32_t pg_offset, uint32_t npage, 8833446Smrj agp_registered_dev_t *agp_regdev) 8843446Smrj { 8853446Smrj int rval; 8863446Smrj ldi_handle_t hdl; 8873446Smrj igd_gtt_seg_t gttseg; 8883446Smrj 8893446Smrj gttseg.igs_pgstart = pg_offset; 8903446Smrj gttseg.igs_npage = npage; 8913446Smrj 8923446Smrj hdl = agp_regdev->agprd_masterhdl; 8933446Smrj if (ldi_ioctl(hdl, I8XX_REM_GTT, (intptr_t)>tseg, FKIOCTL, 8943446Smrj kcred, &rval)) 8953446Smrj return (-1); 8963446Smrj 8973446Smrj return (0); 8983446Smrj } 8993446Smrj 9003446Smrj /* 9013446Smrj * lyr_set_gart_addr() 9023446Smrj * 9033446Smrj * Description: 9043446Smrj * This function puts the gart table physical address in the 9053446Smrj * gart base register. 9063446Smrj * Please refer to gart and gtt table base register format for 9073446Smrj * gart base register format in agpdefs.h. 9083446Smrj * 9093446Smrj * Arguments: 9103446Smrj * phy_base The base physical address of gart table 9113446Smrj * agp_regdev AGP devices registration struct pointer 9123446Smrj * 9133446Smrj * Returns: 9143446Smrj * 0 success 9153446Smrj * -1 failed 9163446Smrj * 9173446Smrj */ 9183446Smrj 9193446Smrj int 9203446Smrj lyr_set_gart_addr(uint64_t phy_base, agp_registered_dev_t *agp_regdev) 9213446Smrj { 9223446Smrj amd64_gart_dev_list_t *gart_list; 9233446Smrj ldi_handle_t hdl; 9243446Smrj int err = 0; 9253446Smrj 9263446Smrj ASSERT(agp_regdev); 9273446Smrj switch (agp_regdev->agprd_arctype) { 9283446Smrj case ARC_IGD810: 9293446Smrj { 9303446Smrj uint32_t base; 9313446Smrj 9326742Sms148562 ASSERT((phy_base & I810_POINTER_MASK) == 0); 9333446Smrj base = (uint32_t)phy_base; 9343446Smrj 9353446Smrj hdl = agp_regdev->agprd_masterhdl; 9363446Smrj err = ldi_ioctl(hdl, I810_SET_GTT_BASE, 9373446Smrj (intptr_t)&base, FKIOCTL, kcred, 0); 9383446Smrj break; 9393446Smrj } 9403446Smrj case ARC_INTELAGP: 9413446Smrj { 9423446Smrj uint32_t addr; 9433446Smrj addr = (uint32_t)phy_base; 9443446Smrj 9456742Sms148562 ASSERT((phy_base & GTT_POINTER_MASK) == 0); 9463446Smrj hdl = agp_regdev->agprd_targethdl; 9473446Smrj err = ldi_ioctl(hdl, AGP_TARGET_SET_GATTADDR, 9483446Smrj (intptr_t)&addr, FKIOCTL, kcred, 0); 9493446Smrj break; 9503446Smrj } 9513446Smrj case ARC_AMD64AGP: 9523446Smrj { 9533446Smrj uint32_t addr; 9543446Smrj 9556742Sms148562 ASSERT((phy_base & AMD64_POINTER_MASK) == 0); 9563446Smrj addr = (uint32_t)((phy_base >> AMD64_GARTBASE_SHIFT) 9573446Smrj & AMD64_GARTBASE_MASK); 9583446Smrj 9593446Smrj for (gart_list = agp_regdev->agprd_cpugarts.gart_dev_list_head; 9603446Smrj gart_list; 9613446Smrj gart_list = gart_list->next) { 9623446Smrj hdl = gart_list->gart_devhdl; 9633446Smrj if (ldi_ioctl(hdl, AMD64_SET_GART_ADDR, 9643446Smrj (intptr_t)&addr, FKIOCTL, kcred, 0)) { 9653446Smrj err = -1; 9663446Smrj break; 9673446Smrj } 9683446Smrj } 9693446Smrj break; 9703446Smrj } 9713446Smrj default: 9723446Smrj err = -1; 9733446Smrj } 9743446Smrj 9753446Smrj if (err) 9763446Smrj return (-1); 9773446Smrj 9783446Smrj return (0); 9793446Smrj } 9803446Smrj 9813446Smrj int 9823446Smrj lyr_set_agp_cmd(uint32_t cmd, agp_registered_dev_t *agp_regdev) 9833446Smrj { 9843446Smrj ldi_handle_t hdl; 9853446Smrj uint32_t command; 9863446Smrj 9873446Smrj ASSERT(agp_regdev); 9883446Smrj command = cmd; 9893446Smrj hdl = agp_regdev->agprd_targethdl; 9903446Smrj if (ldi_ioctl(hdl, AGP_TARGET_SETCMD, 9913446Smrj (intptr_t)&command, FKIOCTL, kcred, 0)) 9923446Smrj return (-1); 9933446Smrj hdl = agp_regdev->agprd_masterhdl; 9943446Smrj if (ldi_ioctl(hdl, AGP_MASTER_SETCMD, 9953446Smrj (intptr_t)&command, FKIOCTL, kcred, 0)) 9963446Smrj return (-1); 9973446Smrj 9983446Smrj return (0); 9993446Smrj } 10003446Smrj 10013446Smrj int 10023446Smrj lyr_config_devices(agp_registered_dev_t *agp_regdev) 10033446Smrj { 10043446Smrj amd64_gart_dev_list_t *gart_list; 10053446Smrj ldi_handle_t hdl; 10063446Smrj int rc = 0; 10073446Smrj 10083446Smrj ASSERT(agp_regdev); 10093446Smrj switch (agp_regdev->agprd_arctype) { 10103446Smrj case ARC_IGD830: 10113446Smrj case ARC_IGD810: 10123446Smrj break; 10133446Smrj case ARC_INTELAGP: 10143446Smrj { 10153446Smrj hdl = agp_regdev->agprd_targethdl; 10163446Smrj rc = ldi_ioctl(hdl, AGP_TARGET_CONFIGURE, 10173446Smrj 0, FKIOCTL, kcred, 0); 10183446Smrj break; 10193446Smrj } 10203446Smrj case ARC_AMD64AGP: 10213446Smrj { 10223446Smrj /* 10233446Smrj * BIOS always shadow registers such like Aperture Base 10243446Smrj * register, Aperture Size Register from the AGP bridge 10253446Smrj * to the AMD64 CPU host bridge. If future BIOSes are broken 10263446Smrj * in this regard, we may need to shadow these registers 10273446Smrj * in driver. 10283446Smrj */ 10293446Smrj 10303446Smrj for (gart_list = agp_regdev->agprd_cpugarts.gart_dev_list_head; 10313446Smrj gart_list; 10323446Smrj gart_list = gart_list->next) { 10333446Smrj hdl = gart_list->gart_devhdl; 10343446Smrj if (ldi_ioctl(hdl, AMD64_CONFIGURE, 10353446Smrj 0, FKIOCTL, kcred, 0)) { 10363446Smrj rc = -1; 10373446Smrj break; 10383446Smrj } 10393446Smrj } 10403446Smrj break; 10413446Smrj } 10423446Smrj default: 10433446Smrj rc = -1; 10443446Smrj } 10453446Smrj 10463446Smrj if (rc) 10473446Smrj return (-1); 10483446Smrj 10493446Smrj return (0); 10503446Smrj } 10513446Smrj 10523446Smrj int 10533446Smrj lyr_unconfig_devices(agp_registered_dev_t *agp_regdev) 10543446Smrj { 10553446Smrj amd64_gart_dev_list_t *gart_list; 10563446Smrj ldi_handle_t hdl; 10573446Smrj int rc = 0; 10583446Smrj 10593446Smrj ASSERT(agp_regdev); 10603446Smrj switch (agp_regdev->agprd_arctype) { 10613446Smrj case ARC_IGD830: 10623446Smrj case ARC_IGD810: 10633446Smrj { 10643446Smrj hdl = agp_regdev->agprd_masterhdl; 10653446Smrj rc = ldi_ioctl(hdl, I8XX_UNCONFIG, 0, FKIOCTL, kcred, 0); 10663446Smrj break; 10673446Smrj } 10683446Smrj case ARC_INTELAGP: 10693446Smrj { 10703446Smrj hdl = agp_regdev->agprd_targethdl; 10713446Smrj rc = ldi_ioctl(hdl, AGP_TARGET_UNCONFIG, 10723446Smrj 0, FKIOCTL, kcred, 0); 10733446Smrj break; 10743446Smrj } 10753446Smrj case ARC_AMD64AGP: 10763446Smrj { 10773446Smrj for (gart_list = agp_regdev->agprd_cpugarts.gart_dev_list_head; 10783446Smrj gart_list; gart_list = gart_list->next) { 10793446Smrj hdl = gart_list->gart_devhdl; 10803446Smrj if (ldi_ioctl(hdl, AMD64_UNCONFIG, 10813446Smrj 0, FKIOCTL, kcred, 0)) { 10823446Smrj rc = -1; 10833446Smrj break; 10843446Smrj } 10853446Smrj } 10863446Smrj break; 10873446Smrj } 10883446Smrj default: 10893446Smrj rc = -1; 10903446Smrj } 10913446Smrj 10923446Smrj if (rc) 10933446Smrj return (-1); 10943446Smrj 10953446Smrj return (0); 10963446Smrj } 10973446Smrj 10983446Smrj /* 10993446Smrj * lyr_flush_gart_cache() 11003446Smrj * 11013446Smrj * Description: 11023446Smrj * This function flushes the GART translation look-aside buffer. All 11033446Smrj * GART translation caches will be flushed after this operation. 11043446Smrj * 11053446Smrj * Arguments: 11063446Smrj * agp_regdev AGP devices struct pointer 11073446Smrj */ 11083446Smrj void 11093446Smrj lyr_flush_gart_cache(agp_registered_dev_t *agp_regdev) 11103446Smrj { 11113446Smrj amd64_gart_dev_list_t *gart_list; 11123446Smrj ldi_handle_t hdl; 11133446Smrj 11143446Smrj ASSERT(agp_regdev); 11155376Scg149915 if (agp_regdev->agprd_arctype == ARC_AMD64AGP) { 11163446Smrj for (gart_list = agp_regdev->agprd_cpugarts.gart_dev_list_head; 11173446Smrj gart_list; gart_list = gart_list->next) { 11183446Smrj hdl = gart_list->gart_devhdl; 11193446Smrj (void) ldi_ioctl(hdl, AMD64_FLUSH_GTLB, 11203446Smrj 0, FKIOCTL, kcred, 0); 11213446Smrj } 11223446Smrj } else if (agp_regdev->agprd_arctype == ARC_INTELAGP) { 11233446Smrj hdl = agp_regdev->agprd_targethdl; 11243446Smrj (void) ldi_ioctl(hdl, AGP_TARGET_FLUSH_GTLB, 0, 11253446Smrj FKIOCTL, kcred, 0); 11263446Smrj } 11273446Smrj } 11283446Smrj 11293446Smrj /* 11303446Smrj * get_max_pages() 11313446Smrj * 11323446Smrj * Description: 11333446Smrj * This function compute the total pages allowed for agp aperture 11343446Smrj * based on the ammount of physical pages. 11353446Smrj * The algorithm is: compare the aperture size with 1/4 of total 11363446Smrj * physical pages, and use the smaller one to for the max available 11373446Smrj * pages. 11383446Smrj * 11393446Smrj * Arguments: 11403446Smrj * aper_size system agp aperture size (in MB) 11413446Smrj * 11423446Smrj * Returns: 11433446Smrj * The max possible number of agp memory pages available to users 11443446Smrj */ 11453446Smrj static uint32_t 11463446Smrj get_max_pages(uint32_t aper_size) 11473446Smrj { 11483446Smrj uint32_t i, j; 11493446Smrj 11503446Smrj ASSERT(aper_size <= MAXAPERMEGAS); 11513446Smrj 11523446Smrj i = AGP_MB2PAGES(aper_size); 11533446Smrj j = (physmem >> 2); 11543446Smrj 11553446Smrj return ((i < j) ? i : j); 11563446Smrj } 11573446Smrj 11583446Smrj /* 11593446Smrj * agp_fill_empty_keyent() 11603446Smrj * 11613446Smrj * Description: 11623446Smrj * This function finds a empty key table slot and 11633446Smrj * fills it with a new entity. 11643446Smrj * 11653446Smrj * Arguments: 11663446Smrj * softsate driver soft state pointer 11673446Smrj * entryp new entity data pointer 11683446Smrj * 11693446Smrj * Returns: 11703446Smrj * NULL no key table slot available 11713446Smrj * entryp the new entity slot pointer 11723446Smrj */ 11733446Smrj static keytable_ent_t * 11743446Smrj agp_fill_empty_keyent(agpgart_softstate_t *softstate, keytable_ent_t *entryp) 11753446Smrj { 11763446Smrj int key; 11773446Smrj keytable_ent_t *newentryp; 11783446Smrj 11793446Smrj ASSERT(softstate); 11803446Smrj ASSERT(entryp); 11813446Smrj ASSERT(entryp->kte_memhdl); 11823446Smrj ASSERT(entryp->kte_pfnarray); 11833446Smrj ASSERT(mutex_owned(&softstate->asoft_instmutex)); 11843446Smrj 11853446Smrj for (key = 0; key < AGP_MAXKEYS; key++) { 11863446Smrj newentryp = &softstate->asoft_table[key]; 11873446Smrj if (newentryp->kte_memhdl == NULL) { 11883446Smrj break; 11893446Smrj } 11903446Smrj } 11913446Smrj 11923446Smrj if (key >= AGP_MAXKEYS) { 11933446Smrj AGPDB_PRINT2((CE_WARN, 11943446Smrj "agp_fill_empty_keyent: key table exhausted")); 11953446Smrj return (NULL); 11963446Smrj } 11973446Smrj 11983446Smrj ASSERT(newentryp->kte_pfnarray == NULL); 11993446Smrj bcopy(entryp, newentryp, sizeof (keytable_ent_t)); 12003446Smrj newentryp->kte_key = key; 12013446Smrj 12023446Smrj return (newentryp); 12033446Smrj } 12043446Smrj 12053446Smrj /* 12063446Smrj * agp_find_bound_keyent() 12073446Smrj * 12083446Smrj * Description: 12093446Smrj * This function finds the key table entity by agp aperture page offset. 12103446Smrj * Every keytable entity will have an agp aperture range after the binding 12113446Smrj * operation. 12123446Smrj * 12133446Smrj * Arguments: 12143446Smrj * softsate driver soft state pointer 12153446Smrj * pg_offset agp aperture page offset 12163446Smrj * 12173446Smrj * Returns: 12183446Smrj * NULL no such keytable entity 12193446Smrj * pointer key table entity pointer found 12203446Smrj */ 12213446Smrj static keytable_ent_t * 12223446Smrj agp_find_bound_keyent(agpgart_softstate_t *softstate, uint32_t pg_offset) 12233446Smrj { 12243446Smrj int keycount; 12253446Smrj keytable_ent_t *entryp; 12263446Smrj 12273446Smrj ASSERT(softstate); 12283446Smrj ASSERT(mutex_owned(&softstate->asoft_instmutex)); 12293446Smrj 12303446Smrj for (keycount = 0; keycount < AGP_MAXKEYS; keycount++) { 12313446Smrj entryp = &softstate->asoft_table[keycount]; 12323446Smrj if (entryp->kte_bound == 0) { 12333446Smrj continue; 12343446Smrj } 12353446Smrj 12363446Smrj if (pg_offset < entryp->kte_pgoff) 12373446Smrj continue; 12383446Smrj if (pg_offset >= (entryp->kte_pgoff + entryp->kte_pages)) 12393446Smrj continue; 12403446Smrj 12413446Smrj ASSERT(entryp->kte_memhdl); 12423446Smrj ASSERT(entryp->kte_pfnarray); 12433446Smrj 12443446Smrj return (entryp); 12453446Smrj } 12463446Smrj 12473446Smrj return (NULL); 12483446Smrj } 12493446Smrj 12503446Smrj /* 12513446Smrj * agp_check_off() 12523446Smrj * 12533446Smrj * Description: 12543446Smrj * This function checks whether an AGP aperture range to be bound 12553446Smrj * overlaps with AGP offset already bound. 12563446Smrj * 12573446Smrj * Arguments: 12583446Smrj * entryp key table start entry pointer 12593446Smrj * pg_start AGP range start page offset 12603446Smrj * pg_num pages number to be bound 12613446Smrj * 12623446Smrj * Returns: 12633446Smrj * 0 Does not overlap 12643446Smrj * -1 Overlaps 12653446Smrj */ 12663446Smrj 12673446Smrj static int 12683446Smrj agp_check_off(keytable_ent_t *entryp, uint32_t pg_start, uint32_t pg_num) 12693446Smrj { 12703446Smrj int key; 12713446Smrj uint64_t pg_end; 12723446Smrj uint64_t kpg_end; 12733446Smrj 12743446Smrj ASSERT(entryp); 12753446Smrj 12763446Smrj pg_end = pg_start + pg_num; 12773446Smrj for (key = 0; key < AGP_MAXKEYS; key++) { 12783446Smrj if (!entryp[key].kte_bound) 12793446Smrj continue; 12803446Smrj 12813446Smrj kpg_end = entryp[key].kte_pgoff + entryp[key].kte_pages; 12823446Smrj if (!((pg_end <= entryp[key].kte_pgoff) || 12833446Smrj (pg_start >= kpg_end))) 12843446Smrj break; 12853446Smrj } 12863446Smrj 12873446Smrj if (key == AGP_MAXKEYS) 12883446Smrj return (0); 12893446Smrj else 12903446Smrj return (-1); 12913446Smrj } 12923446Smrj 12933446Smrj static int 12943446Smrj is_controlling_proc(agpgart_softstate_t *st) 12953446Smrj { 12963446Smrj ASSERT(st); 12973446Smrj 12983446Smrj if (!st->asoft_acquired) { 12993446Smrj AGPDB_PRINT2((CE_WARN, 13003446Smrj "ioctl_agpgart_setup: gart not acquired")); 13013446Smrj return (-1); 13023446Smrj } 13033446Smrj if (st->asoft_curpid != ddi_get_pid()) { 13043446Smrj AGPDB_PRINT2((CE_WARN, 13053446Smrj "ioctl_agpgart_release: not controlling process")); 13063446Smrj return (-1); 13073446Smrj } 13083446Smrj 13093446Smrj return (0); 13103446Smrj } 13113446Smrj 13123446Smrj static void release_control(agpgart_softstate_t *st) 13133446Smrj { 13143446Smrj st->asoft_curpid = 0; 13153446Smrj st->asoft_acquired = 0; 13163446Smrj } 13173446Smrj 13183446Smrj static void acquire_control(agpgart_softstate_t *st) 13193446Smrj { 13203446Smrj st->asoft_curpid = ddi_get_pid(); 13213446Smrj st->asoft_acquired = 1; 13223446Smrj } 13233446Smrj 13243446Smrj /* 13253446Smrj * agp_remove_from_gart() 13263446Smrj * 13273446Smrj * Description: 13283446Smrj * This function fills the gart table entries by a given page 13293446Smrj * frame number array and setup the agp aperture page to physical 13303446Smrj * memory page translation. 13313446Smrj * Arguments: 13323446Smrj * pg_offset Starting aperture page to be bound 13333446Smrj * entries the number of pages to be bound 13343446Smrj * acc_hdl GART table dma memory acc handle 13353446Smrj * tablep GART table kernel virtual address 13363446Smrj */ 13373446Smrj static void 13383446Smrj agp_remove_from_gart( 13393446Smrj uint32_t pg_offset, 13403446Smrj uint32_t entries, 13413446Smrj ddi_dma_handle_t dma_hdl, 13423446Smrj uint32_t *tablep) 13433446Smrj { 13443446Smrj uint32_t items = 0; 13453446Smrj uint32_t *entryp; 13463446Smrj 13473446Smrj entryp = tablep + pg_offset; 13483446Smrj while (items < entries) { 13493446Smrj *(entryp + items) = 0; 13503446Smrj items++; 13513446Smrj } 13523446Smrj (void) ddi_dma_sync(dma_hdl, pg_offset * sizeof (uint32_t), 13533446Smrj entries * sizeof (uint32_t), DDI_DMA_SYNC_FORDEV); 13543446Smrj } 13553446Smrj 13563446Smrj /* 13573446Smrj * agp_unbind_key() 13583446Smrj * 13593446Smrj * Description: 13603446Smrj * This function unbinds AGP memory from the gart table. It will clear 13613446Smrj * all the gart entries related to this agp memory. 13623446Smrj * 13633446Smrj * Arguments: 13643446Smrj * softstate driver soft state pointer 13653446Smrj * entryp key table entity pointer 13663446Smrj * 13673446Smrj * Returns: 13683446Smrj * EINVAL invalid key table entity pointer 13693446Smrj * 0 success 13703446Smrj * 13713446Smrj */ 13723446Smrj static int 13733446Smrj agp_unbind_key(agpgart_softstate_t *softstate, keytable_ent_t *entryp) 13743446Smrj { 13753446Smrj int retval = 0; 13763446Smrj 13773446Smrj ASSERT(entryp); 13783446Smrj ASSERT((entryp->kte_key >= 0) && (entryp->kte_key < AGP_MAXKEYS)); 13793446Smrj 13803446Smrj if (!entryp->kte_bound) { 13813446Smrj AGPDB_PRINT2((CE_WARN, 13823446Smrj "agp_unbind_key: key = 0x%x, not bound", 13833446Smrj entryp->kte_key)); 13843446Smrj return (EINVAL); 13853446Smrj } 13863446Smrj if (entryp->kte_refcnt) { 13873446Smrj AGPDB_PRINT2((CE_WARN, 13883446Smrj "agp_unbind_key: memory is exported to users")); 13893446Smrj return (EINVAL); 13903446Smrj } 13913446Smrj 13923446Smrj ASSERT((entryp->kte_pgoff + entryp->kte_pages) <= 13933446Smrj AGP_MB2PAGES(softstate->asoft_info.agpki_apersize)); 13943446Smrj ASSERT((softstate->asoft_devreg.agprd_arctype != ARC_UNKNOWN)); 13953446Smrj 13963446Smrj switch (softstate->asoft_devreg.agprd_arctype) { 13973446Smrj case ARC_IGD810: 13983446Smrj case ARC_IGD830: 13993446Smrj retval = lyr_i8xx_remove_from_gtt( 14003446Smrj entryp->kte_pgoff, entryp->kte_pages, 14013446Smrj &softstate->asoft_devreg); 14023446Smrj if (retval) { 14033446Smrj AGPDB_PRINT2((CE_WARN, 14043446Smrj "agp_unbind_key: Key = 0x%x, clear table error", 14053446Smrj entryp->kte_key)); 14063446Smrj return (EIO); 14073446Smrj } 14083446Smrj break; 14093446Smrj case ARC_INTELAGP: 14103446Smrj case ARC_AMD64AGP: 14113446Smrj agp_remove_from_gart(entryp->kte_pgoff, 14123446Smrj entryp->kte_pages, 14133446Smrj softstate->gart_dma_handle, 14143446Smrj (uint32_t *)softstate->gart_vbase); 14153446Smrj /* Flush GTLB table */ 14163446Smrj lyr_flush_gart_cache(&softstate->asoft_devreg); 14173446Smrj 14183446Smrj break; 14193446Smrj } 14203446Smrj 14213446Smrj entryp->kte_bound = 0; 14223446Smrj 14233446Smrj return (0); 14243446Smrj } 14253446Smrj 14263446Smrj /* 14273446Smrj * agp_dealloc_kmem() 14283446Smrj * 14293446Smrj * Description: 14303446Smrj * This function deallocates dma memory resources for userland 14313446Smrj * applications. 14323446Smrj * 14333446Smrj * Arguments: 14343446Smrj * entryp keytable entity pointer 14353446Smrj */ 14363446Smrj static void 14373446Smrj agp_dealloc_kmem(keytable_ent_t *entryp) 14383446Smrj { 14393446Smrj kmem_free(entryp->kte_pfnarray, sizeof (pfn_t) * entryp->kte_pages); 14403446Smrj entryp->kte_pfnarray = NULL; 14413446Smrj 14423446Smrj (void) ddi_dma_unbind_handle(KMEMP(entryp->kte_memhdl)->kmem_handle); 14433446Smrj KMEMP(entryp->kte_memhdl)->kmem_cookies_num = 0; 14443446Smrj ddi_dma_mem_free(&KMEMP(entryp->kte_memhdl)->kmem_acchdl); 14453446Smrj KMEMP(entryp->kte_memhdl)->kmem_acchdl = NULL; 14463446Smrj KMEMP(entryp->kte_memhdl)->kmem_reallen = 0; 14473446Smrj KMEMP(entryp->kte_memhdl)->kmem_kvaddr = NULL; 14483446Smrj 14493446Smrj ddi_dma_free_handle(&(KMEMP(entryp->kte_memhdl)->kmem_handle)); 14503446Smrj KMEMP(entryp->kte_memhdl)->kmem_handle = NULL; 14513446Smrj 14523446Smrj kmem_free(entryp->kte_memhdl, sizeof (agp_kmem_handle_t)); 14533446Smrj entryp->kte_memhdl = NULL; 14543446Smrj } 14553446Smrj 14563446Smrj /* 14573446Smrj * agp_dealloc_mem() 14583446Smrj * 14593446Smrj * Description: 14603446Smrj * This function deallocates physical memory resources allocated for 14613446Smrj * userland applications. 14623446Smrj * 14633446Smrj * Arguments: 14643446Smrj * st driver soft state pointer 14653446Smrj * entryp key table entity pointer 14663446Smrj * 14673446Smrj * Returns: 14683446Smrj * -1 not a valid memory type or the memory is mapped by 14693446Smrj * user area applications 14703446Smrj * 0 success 14713446Smrj */ 14723446Smrj static int 14733446Smrj agp_dealloc_mem(agpgart_softstate_t *st, keytable_ent_t *entryp) 14743446Smrj { 14753446Smrj 14763446Smrj ASSERT(entryp); 14773446Smrj ASSERT(st); 14783446Smrj ASSERT(entryp->kte_memhdl); 14793446Smrj ASSERT(mutex_owned(&st->asoft_instmutex)); 14803446Smrj 14813446Smrj /* auto unbind here */ 14823446Smrj if (entryp->kte_bound && !entryp->kte_refcnt) { 14833446Smrj AGPDB_PRINT2((CE_WARN, 14843446Smrj "agp_dealloc_mem: key=0x%x, auto unbind", 14853446Smrj entryp->kte_key)); 14863446Smrj 14873446Smrj /* 14883446Smrj * agp_dealloc_mem may be called indirectly by agp_detach. 14893446Smrj * In the agp_detach function, agpgart_close is already 14903446Smrj * called which will free the gart table. agp_unbind_key 14913446Smrj * will panic if no valid gart table exists. So test if 14923446Smrj * gart table exsits here. 14933446Smrj */ 14943446Smrj if (st->asoft_opened) 14954478Skz151634 (void) agp_unbind_key(st, entryp); 14963446Smrj } 14973446Smrj if (entryp->kte_refcnt) { 14983446Smrj AGPDB_PRINT2((CE_WARN, 14996742Sms148562 "agp_dealloc_mem: memory is exported to users")); 15003446Smrj return (-1); 15013446Smrj } 15023446Smrj 15033446Smrj switch (entryp->kte_type) { 15043446Smrj case AGP_NORMAL: 15053446Smrj case AGP_PHYSICAL: 15063446Smrj agp_dealloc_kmem(entryp); 15073446Smrj break; 15083446Smrj default: 15093446Smrj return (-1); 15103446Smrj } 15113446Smrj 15123446Smrj return (0); 15133446Smrj } 15143446Smrj 15153446Smrj /* 15163446Smrj * agp_del_allkeys() 15173446Smrj * 15183446Smrj * Description: 15193446Smrj * This function calls agp_dealloc_mem to release all the agp memory 15203446Smrj * resource allocated. 15213446Smrj * 15223446Smrj * Arguments: 15233446Smrj * softsate driver soft state pointer 15243446Smrj * Returns: 15253446Smrj * -1 can not free all agp memory 15263446Smrj * 0 success 15273446Smrj * 15283446Smrj */ 15293446Smrj static int 15303446Smrj agp_del_allkeys(agpgart_softstate_t *softstate) 15313446Smrj { 15323446Smrj int key; 15333446Smrj int ret = 0; 15343446Smrj 15353446Smrj ASSERT(softstate); 15363446Smrj for (key = 0; key < AGP_MAXKEYS; key++) { 15373446Smrj if (softstate->asoft_table[key].kte_memhdl != NULL) { 15383446Smrj /* 15393446Smrj * Check if we can free agp memory now. 15403446Smrj * If agp memory is exported to user 15413446Smrj * applications, agp_dealloc_mem will fail. 15423446Smrj */ 15433446Smrj if (agp_dealloc_mem(softstate, 15443446Smrj &softstate->asoft_table[key])) 15453446Smrj ret = -1; 15463446Smrj } 15473446Smrj } 15483446Smrj 15493446Smrj return (ret); 15503446Smrj } 15513446Smrj 15523446Smrj /* 15533446Smrj * pfn2gartentry() 15543446Smrj * 15553446Smrj * Description: 15563446Smrj * This function converts a physical address to GART entry. 15573446Smrj * For AMD64, hardware only support addresses below 40bits, 15583446Smrj * about 1024G physical address, so the largest pfn 15593446Smrj * number is below 28 bits. Please refer to GART and GTT entry 15603446Smrj * format table in agpdefs.h for entry format. Intel IGD only 15613446Smrj * only supports GTT entry below 1G. Intel AGP only supports 15623446Smrj * GART entry below 4G. 15633446Smrj * 15643446Smrj * Arguments: 15653446Smrj * arc_type system agp arc type 15663446Smrj * pfn page frame number 15673446Smrj * itemv the entry item to be returned 15683446Smrj * Returns: 15693446Smrj * -1 not a invalid page frame 15703446Smrj * 0 conversion success 15713446Smrj */ 15723446Smrj static int 15733446Smrj pfn2gartentry(agp_arc_type_t arc_type, pfn_t pfn, uint32_t *itemv) 15743446Smrj { 15753446Smrj uint64_t paddr; 15763446Smrj 15776742Sms148562 paddr = (uint64_t)pfn << AGP_PAGE_SHIFT; 15786742Sms148562 AGPDB_PRINT1((CE_NOTE, "checking pfn number %lu for type %d", 15796742Sms148562 pfn, arc_type)); 15803446Smrj 15813446Smrj switch (arc_type) { 15823446Smrj case ARC_INTELAGP: 15833446Smrj { 15843446Smrj /* Only support 32-bit hardware address */ 15856742Sms148562 if ((paddr & AGP_INTEL_POINTER_MASK) != 0) { 15863446Smrj AGPDB_PRINT2((CE_WARN, 15873446Smrj "INTEL AGP Hardware only support 32 bits")); 15883446Smrj return (-1); 15893446Smrj } 15903446Smrj *itemv = (pfn << AGP_PAGE_SHIFT) | AGP_ENTRY_VALID; 15913446Smrj 15923446Smrj break; 15933446Smrj } 15943446Smrj case ARC_AMD64AGP: 15953446Smrj { 15963446Smrj uint32_t value1, value2; 15973446Smrj /* Physaddr should not exceed 40-bit */ 15986742Sms148562 if ((paddr & AMD64_POINTER_MASK) != 0) { 15993446Smrj AGPDB_PRINT2((CE_WARN, 16003446Smrj "AMD64 GART hardware only supoort 40 bits")); 16013446Smrj return (-1); 16023446Smrj } 16033446Smrj value1 = (uint32_t)pfn >> 20; 16043446Smrj value1 <<= 4; 16053446Smrj value2 = (uint32_t)pfn << 12; 16063446Smrj 16073446Smrj *itemv = value1 | value2 | AMD64_ENTRY_VALID; 16083446Smrj break; 16093446Smrj } 16103446Smrj case ARC_IGD810: 16116742Sms148562 if ((paddr & I810_POINTER_MASK) != 0) { 16123446Smrj AGPDB_PRINT2((CE_WARN, 16133446Smrj "Intel i810 only support 30 bits")); 16143446Smrj return (-1); 16153446Smrj } 16163446Smrj break; 16173446Smrj 16183446Smrj case ARC_IGD830: 16196742Sms148562 if ((paddr & GTT_POINTER_MASK) != 0) { 16203446Smrj AGPDB_PRINT2((CE_WARN, 16213446Smrj "Intel IGD only support 32 bits")); 16223446Smrj return (-1); 16233446Smrj } 16243446Smrj break; 16253446Smrj default: 16263446Smrj AGPDB_PRINT2((CE_WARN, 16273446Smrj "pfn2gartentry: arc type = %d, not support", arc_type)); 16283446Smrj return (-1); 16293446Smrj } 16303446Smrj return (0); 16313446Smrj } 16323446Smrj 16333446Smrj /* 16343446Smrj * Check allocated physical pages validity, only called in DEBUG 16353446Smrj * mode. 16363446Smrj */ 16373446Smrj static int 16383446Smrj agp_check_pfns(agp_arc_type_t arc_type, pfn_t *pfnarray, int items) 16393446Smrj { 16403446Smrj int count; 16413446Smrj uint32_t ret; 16423446Smrj 16433446Smrj for (count = 0; count < items; count++) { 16443446Smrj if (pfn2gartentry(arc_type, pfnarray[count], &ret)) 16453446Smrj break; 16463446Smrj } 16473446Smrj if (count < items) 16483446Smrj return (-1); 16493446Smrj else 16503446Smrj return (0); 16513446Smrj } 16523446Smrj 16533446Smrj /* 16543446Smrj * kmem_getpfns() 16553446Smrj * 16563446Smrj * Description: 16573446Smrj * This function gets page frame numbers from dma handle. 16583446Smrj * 16593446Smrj * Arguments: 16603446Smrj * dma_handle dma hanle allocated by ddi_dma_alloc_handle 16613446Smrj * dma_cookip dma cookie pointer 16623446Smrj * cookies_num cookies number 16633446Smrj * pfnarray array to store page frames 16643446Smrj * 16653446Smrj * Returns: 16663446Smrj * 0 success 16673446Smrj */ 16683446Smrj static int 16693446Smrj kmem_getpfns( 16703446Smrj ddi_dma_handle_t dma_handle, 16713446Smrj ddi_dma_cookie_t *dma_cookiep, 16723446Smrj int cookies_num, 16733446Smrj pfn_t *pfnarray) 16743446Smrj { 16753446Smrj int num_cookies; 16763446Smrj int index = 0; 16773446Smrj 16783446Smrj num_cookies = cookies_num; 16793446Smrj 16803446Smrj while (num_cookies > 0) { 16813446Smrj uint64_t ck_startaddr, ck_length, ck_end; 16823446Smrj ck_startaddr = dma_cookiep->dmac_address; 16833446Smrj ck_length = dma_cookiep->dmac_size; 16843446Smrj 16853446Smrj ck_end = ck_startaddr + ck_length; 16863446Smrj while (ck_startaddr < ck_end) { 16873446Smrj pfnarray[index] = (pfn_t)ck_startaddr >> AGP_PAGE_SHIFT; 16883446Smrj ck_startaddr += AGP_PAGE_SIZE; 16893446Smrj index++; 16903446Smrj } 16913446Smrj 16923446Smrj num_cookies--; 16933446Smrj if (num_cookies > 0) { 16943446Smrj ddi_dma_nextcookie(dma_handle, dma_cookiep); 16953446Smrj } 16963446Smrj } 16973446Smrj 16983446Smrj return (0); 16993446Smrj } 17003446Smrj 17013446Smrj static int 17023446Smrj copyinfo(agpgart_softstate_t *softstate, agp_info_t *info) 17033446Smrj { 17043446Smrj switch (softstate->asoft_devreg.agprd_arctype) { 17053446Smrj case ARC_IGD810: 17063446Smrj case ARC_IGD830: 17073446Smrj info->agpi_version.agpv_major = 0; 17083446Smrj info->agpi_version.agpv_minor = 0; 17093446Smrj info->agpi_devid = softstate->asoft_info.agpki_mdevid; 17103446Smrj info->agpi_mode = 0; 17113446Smrj break; 17123446Smrj case ARC_INTELAGP: 17133446Smrj case ARC_AMD64AGP: 17143446Smrj info->agpi_version = softstate->asoft_info.agpki_tver; 17153446Smrj info->agpi_devid = softstate->asoft_info.agpki_tdevid; 17163446Smrj info->agpi_mode = softstate->asoft_info.agpki_tstatus; 17173446Smrj break; 17183446Smrj default: 17193446Smrj AGPDB_PRINT2((CE_WARN, "copyinfo: UNKNOW ARC")); 17203446Smrj return (-1); 17213446Smrj } 17223446Smrj /* 17233446Smrj * 64bit->32bit conversion possible 17243446Smrj */ 17253446Smrj info->agpi_aperbase = softstate->asoft_info.agpki_aperbase; 17263446Smrj info->agpi_apersize = softstate->asoft_info.agpki_apersize; 17273446Smrj info->agpi_pgtotal = softstate->asoft_pgtotal; 17283446Smrj info->agpi_pgsystem = info->agpi_pgtotal; 17293446Smrj info->agpi_pgused = softstate->asoft_pgused; 17303446Smrj 17313446Smrj return (0); 17323446Smrj } 17333446Smrj 17343446Smrj static uint32_t 17353446Smrj agp_v2_setup(uint32_t tstatus, uint32_t mstatus, uint32_t mode) 17363446Smrj { 17373446Smrj uint32_t cmd; 17383446Smrj int rq, sba, over4g, fw, rate; 17393446Smrj 17403446Smrj /* 17413446Smrj * tstatus: target device status 17423446Smrj * mstatus: master device status 17433446Smrj * mode: the agp mode to be sent 17443446Smrj */ 17453446Smrj 17463446Smrj /* 17473446Smrj * RQ - Request Queue size 17483446Smrj * set RQ to the min of mode and tstatus 17493446Smrj * if mode set a RQ larger than hardware can support, 17503446Smrj * use the max RQ which hardware can support. 17513446Smrj * tstatus & AGPSTAT_RQ_MASK is the max RQ hardware can support 17523446Smrj * Corelogic will enqueue agp transaction 17533446Smrj */ 17543446Smrj rq = mode & AGPSTAT_RQ_MASK; 17553446Smrj if ((tstatus & AGPSTAT_RQ_MASK) < rq) 17563446Smrj rq = tstatus & AGPSTAT_RQ_MASK; 17573446Smrj 17583446Smrj /* 17593446Smrj * SBA - Sideband Addressing 17603446Smrj * 17613446Smrj * Sideband Addressing provides an additional bus to pass requests 17623446Smrj * (address and command) to the target from the master. 17633446Smrj * 17643446Smrj * set SBA if all three support it 17653446Smrj */ 17663446Smrj sba = (tstatus & AGPSTAT_SBA) & (mstatus & AGPSTAT_SBA) 17674478Skz151634 & (mode & AGPSTAT_SBA); 17683446Smrj 17693446Smrj /* set OVER4G if all three support it */ 17703446Smrj over4g = (tstatus & AGPSTAT_OVER4G) & (mstatus & AGPSTAT_OVER4G) 17714478Skz151634 & (mode & AGPSTAT_OVER4G); 17723446Smrj 17733446Smrj /* 17743446Smrj * FW - fast write 17753446Smrj * 17763446Smrj * acceleration of memory write transactions from the corelogic to the 17773446Smrj * A.G.P. master device acting like a PCI target. 17783446Smrj * 17793446Smrj * set FW if all three support it 17803446Smrj */ 17813446Smrj fw = (tstatus & AGPSTAT_FW) & (mstatus & AGPSTAT_FW) 17824478Skz151634 & (mode & AGPSTAT_FW); 17833446Smrj 17843446Smrj /* 17853446Smrj * figure out the max rate 17863446Smrj * AGP v2 support: 4X, 2X, 1X speed 17873446Smrj * status bit meaning 17883446Smrj * --------------------------------------------- 17893446Smrj * 7:3 others 17903446Smrj * 3 0 stand for V2 support 17913446Smrj * 0:2 001:1X, 010:2X, 100:4X 17923446Smrj * ---------------------------------------------- 17933446Smrj */ 17943446Smrj rate = (tstatus & AGPSTAT_RATE_MASK) & (mstatus & AGPSTAT_RATE_MASK) 17954478Skz151634 & (mode & AGPSTAT_RATE_MASK); 17963446Smrj if (rate & AGP2_RATE_4X) 17973446Smrj rate = AGP2_RATE_4X; 17983446Smrj else if (rate & AGP2_RATE_2X) 17993446Smrj rate = AGP2_RATE_2X; 18003446Smrj else 18013446Smrj rate = AGP2_RATE_1X; 18023446Smrj 18033446Smrj cmd = rq | sba | over4g | fw | rate; 18043446Smrj /* enable agp mode */ 18053446Smrj cmd |= AGPCMD_AGPEN; 18063446Smrj 18073446Smrj return (cmd); 18083446Smrj } 18093446Smrj 18103446Smrj static uint32_t 18113446Smrj agp_v3_setup(uint32_t tstatus, uint32_t mstatus, uint32_t mode) 18123446Smrj { 18133446Smrj uint32_t cmd = 0; 18143446Smrj uint32_t rq, arqsz, cal, sba, over4g, fw, rate; 18153446Smrj 18163446Smrj /* 18173446Smrj * tstatus: target device status 18183446Smrj * mstatus: master device status 18193446Smrj * mode: the agp mode to be set 18203446Smrj */ 18213446Smrj 18223446Smrj /* 18233446Smrj * RQ - Request Queue size 18243446Smrj * Set RQ to the min of mode and tstatus 18253446Smrj * If mode set a RQ larger than hardware can support, 18263446Smrj * use the max RQ which hardware can support. 18273446Smrj * tstatus & AGPSTAT_RQ_MASK is the max RQ hardware can support 18283446Smrj * Corelogic will enqueue agp transaction; 18293446Smrj */ 18303446Smrj rq = mode & AGPSTAT_RQ_MASK; 18313446Smrj if ((tstatus & AGPSTAT_RQ_MASK) < rq) 18323446Smrj rq = tstatus & AGPSTAT_RQ_MASK; 18333446Smrj 18343446Smrj /* 18353446Smrj * ARQSZ - Asynchronous Request Queue size 18363446Smrj * Set the value equal to tstatus. 18373446Smrj * Don't allow the mode register to override values 18383446Smrj */ 18393446Smrj arqsz = tstatus & AGPSTAT_ARQSZ_MASK; 18403446Smrj 18413446Smrj /* 18423446Smrj * CAL - Calibration cycle 18433446Smrj * Set to the min of tstatus and mstatus 18443446Smrj * Don't allow override by mode register 18453446Smrj */ 18463446Smrj cal = tstatus & AGPSTAT_CAL_MASK; 18473446Smrj if ((mstatus & AGPSTAT_CAL_MASK) < cal) 18483446Smrj cal = mstatus & AGPSTAT_CAL_MASK; 18493446Smrj 18503446Smrj /* 18513446Smrj * SBA - Sideband Addressing 18523446Smrj * 18533446Smrj * Sideband Addressing provides an additional bus to pass requests 18543446Smrj * (address and command) to the target from the master. 18553446Smrj * 18563446Smrj * SBA in agp v3.0 must be set 18573446Smrj */ 18583446Smrj sba = AGPCMD_SBAEN; 18593446Smrj 18603446Smrj /* GART64B is not set since no hardware supports it now */ 18613446Smrj 18623446Smrj /* Set OVER4G if all three support it */ 18633446Smrj over4g = (tstatus & AGPSTAT_OVER4G) & (mstatus & AGPSTAT_OVER4G) 18644478Skz151634 & (mode & AGPSTAT_OVER4G); 18653446Smrj 18663446Smrj /* 18673446Smrj * FW - fast write 18683446Smrj * 18693446Smrj * Acceleration of memory write transactions from the corelogic to the 18703446Smrj * A.G.P. master device acting like a PCI target. 18713446Smrj * 18723446Smrj * Always set FW in AGP 3.0 18733446Smrj */ 18743446Smrj fw = (tstatus & AGPSTAT_FW) & (mstatus & AGPSTAT_FW) 18754478Skz151634 & (mode & AGPSTAT_FW); 18763446Smrj 18773446Smrj /* 18783446Smrj * Figure out the max rate 18793446Smrj * 18803446Smrj * AGP v3 support: 8X, 4X speed 18813446Smrj * 18823446Smrj * status bit meaning 18833446Smrj * --------------------------------------------- 18843446Smrj * 7:3 others 18853446Smrj * 3 1 stand for V3 support 18863446Smrj * 0:2 001:4X, 010:8X, 011:4X,8X 18873446Smrj * ---------------------------------------------- 18883446Smrj */ 18893446Smrj rate = (tstatus & AGPSTAT_RATE_MASK) & (mstatus & AGPSTAT_RATE_MASK) 18904478Skz151634 & (mode & AGPSTAT_RATE_MASK); 18913446Smrj if (rate & AGP3_RATE_8X) 18923446Smrj rate = AGP3_RATE_8X; 18933446Smrj else 18943446Smrj rate = AGP3_RATE_4X; 18953446Smrj 18963446Smrj cmd = rq | arqsz | cal | sba | over4g | fw | rate; 18973446Smrj /* Enable AGP mode */ 18983446Smrj cmd |= AGPCMD_AGPEN; 18993446Smrj 19003446Smrj return (cmd); 19013446Smrj } 19023446Smrj 19033446Smrj static int 19043446Smrj agp_setup(agpgart_softstate_t *softstate, uint32_t mode) 19053446Smrj { 19063446Smrj uint32_t tstatus, mstatus; 19073446Smrj uint32_t agp_mode; 19083446Smrj 19093446Smrj tstatus = softstate->asoft_info.agpki_tstatus; 19103446Smrj mstatus = softstate->asoft_info.agpki_mstatus; 19113446Smrj 19123446Smrj /* 19133446Smrj * There are three kinds of AGP mode. AGP mode 1.0, 2.0, 3.0 19143446Smrj * AGP mode 2.0 is fully compatible with AGP mode 1.0, so we 19153446Smrj * only check 2.0 and 3.0 mode. AGP 3.0 device can work in 19163446Smrj * two AGP 2.0 or AGP 3.0 mode. By checking AGP status register, 19173446Smrj * we can get which mode it is working at. The working mode of 19183446Smrj * AGP master and AGP target must be consistent. That is, both 19193446Smrj * of them must work on AGP 3.0 mode or AGP 2.0 mode. 19203446Smrj */ 19213446Smrj if ((softstate->asoft_info.agpki_tver.agpv_major == 3) && 19223446Smrj (tstatus & AGPSTAT_MODE3)) { 19233446Smrj /* Master device should be 3.0 mode, too */ 19243446Smrj if ((softstate->asoft_info.agpki_mver.agpv_major != 3) || 19253446Smrj ((mstatus & AGPSTAT_MODE3) == 0)) 19263446Smrj return (EIO); 19273446Smrj 19283446Smrj agp_mode = agp_v3_setup(tstatus, mstatus, mode); 19293446Smrj /* Write to the AGPCMD register of target and master devices */ 19303446Smrj if (lyr_set_agp_cmd(agp_mode, 19313446Smrj &softstate->asoft_devreg)) 19323446Smrj return (EIO); 19333446Smrj 19343446Smrj softstate->asoft_mode = agp_mode; 19353446Smrj 19363446Smrj return (0); 19373446Smrj } 19383446Smrj 19393446Smrj /* 19403446Smrj * If agp taget device doesn't work in AGP 3.0 mode, 19413446Smrj * it must work in AGP 2.0 mode. And make sure 19423446Smrj * master device work in AGP 2.0 mode too 19433446Smrj */ 19443446Smrj if ((softstate->asoft_info.agpki_mver.agpv_major == 3) && 19453446Smrj (mstatus & AGPSTAT_MODE3)) 19463446Smrj return (EIO); 19473446Smrj 19483446Smrj agp_mode = agp_v2_setup(tstatus, mstatus, mode); 19493446Smrj if (lyr_set_agp_cmd(agp_mode, &softstate->asoft_devreg)) 19503446Smrj return (EIO); 19513446Smrj softstate->asoft_mode = agp_mode; 19523446Smrj 19533446Smrj return (0); 19543446Smrj } 19553446Smrj 19563446Smrj /* 19573446Smrj * agp_alloc_kmem() 19583446Smrj * 19593446Smrj * Description: 19603446Smrj * This function allocates physical memory for userland applications 19616742Sms148562 * by ddi interfaces. This function can also be called to allocate 19623446Smrj * small phsyical contiguous pages, usually tens of kilobytes. 19633446Smrj * 19643446Smrj * Arguments: 19653446Smrj * softsate driver soft state pointer 19663446Smrj * length memory size 19673446Smrj * 19683446Smrj * Returns: 19693446Smrj * entryp new keytable entity pointer 19703446Smrj * NULL no keytable slot available or no physical 19713446Smrj * memory available 19723446Smrj */ 19733446Smrj static keytable_ent_t * 19746742Sms148562 agp_alloc_kmem(agpgart_softstate_t *softstate, size_t length, int type) 19753446Smrj { 19763446Smrj keytable_ent_t keyentry; 19773446Smrj keytable_ent_t *entryp; 19783446Smrj int ret; 19793446Smrj 19803446Smrj ASSERT(AGP_ALIGNED(length)); 19813446Smrj 19823446Smrj bzero(&keyentry, sizeof (keytable_ent_t)); 19833446Smrj 19843446Smrj keyentry.kte_pages = AGP_BYTES2PAGES(length); 19856742Sms148562 keyentry.kte_type = type; 19863446Smrj 19873446Smrj /* 19883446Smrj * Set dma_attr_sgllen to assure contiguous physical pages 19893446Smrj */ 19906742Sms148562 if (type == AGP_PHYSICAL) 19916742Sms148562 agpgart_dma_attr.dma_attr_sgllen = 1; 19926742Sms148562 else 19937165Shh224818 agpgart_dma_attr.dma_attr_sgllen = (int)keyentry.kte_pages; 19943446Smrj 19953446Smrj /* 4k size pages */ 19963446Smrj keyentry.kte_memhdl = kmem_zalloc(sizeof (agp_kmem_handle_t), KM_SLEEP); 19973446Smrj 19983446Smrj if (ddi_dma_alloc_handle(softstate->asoft_dip, 19993446Smrj &agpgart_dma_attr, 20003446Smrj DDI_DMA_SLEEP, NULL, 20013446Smrj &(KMEMP(keyentry.kte_memhdl)->kmem_handle))) { 20023446Smrj AGPDB_PRINT2((CE_WARN, 20033446Smrj "agp_alloc_kmem: ddi_dma_allco_hanlde error")); 20043446Smrj goto err4; 20053446Smrj } 20063446Smrj 20073446Smrj if ((ret = ddi_dma_mem_alloc( 20083446Smrj KMEMP(keyentry.kte_memhdl)->kmem_handle, 20093446Smrj length, 20103446Smrj &gart_dev_acc_attr, 20113446Smrj DDI_DMA_CONSISTENT, 20123446Smrj DDI_DMA_SLEEP, NULL, 20133446Smrj &KMEMP(keyentry.kte_memhdl)->kmem_kvaddr, 20143446Smrj &KMEMP(keyentry.kte_memhdl)->kmem_reallen, 20153446Smrj &KMEMP(keyentry.kte_memhdl)->kmem_acchdl)) != 0) { 20163446Smrj AGPDB_PRINT2((CE_WARN, 20173446Smrj "agp_alloc_kmem: ddi_dma_mem_alloc error")); 20183446Smrj 20193446Smrj goto err3; 20203446Smrj } 20213446Smrj 20223446Smrj ret = ddi_dma_addr_bind_handle( 20233446Smrj KMEMP(keyentry.kte_memhdl)->kmem_handle, 20243446Smrj NULL, 20253446Smrj KMEMP(keyentry.kte_memhdl)->kmem_kvaddr, 20263446Smrj length, 20273446Smrj DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 20283446Smrj DDI_DMA_SLEEP, 20293446Smrj NULL, 20303446Smrj &KMEMP(keyentry.kte_memhdl)->kmem_dcookie, 20313446Smrj &KMEMP(keyentry.kte_memhdl)->kmem_cookies_num); 20323446Smrj 20333446Smrj /* 20343446Smrj * Even dma_attr_sgllen = 1, ddi_dma_addr_bind_handle may return more 20353446Smrj * than one cookie, we check this in the if statement. 20363446Smrj */ 20373446Smrj 20383446Smrj if ((ret != DDI_DMA_MAPPED) || 20396742Sms148562 ((agpgart_dma_attr.dma_attr_sgllen == 1) && 20406742Sms148562 (KMEMP(keyentry.kte_memhdl)->kmem_cookies_num != 1))) { 20413446Smrj AGPDB_PRINT2((CE_WARN, 20423446Smrj "agp_alloc_kmem: can not alloc physical memory properly")); 20433446Smrj goto err2; 20443446Smrj } 20453446Smrj 20463446Smrj keyentry.kte_pfnarray = (pfn_t *)kmem_zalloc(sizeof (pfn_t) * 20473446Smrj keyentry.kte_pages, KM_SLEEP); 20483446Smrj 20493446Smrj if (kmem_getpfns( 20503446Smrj KMEMP(keyentry.kte_memhdl)->kmem_handle, 20513446Smrj &KMEMP(keyentry.kte_memhdl)->kmem_dcookie, 20523446Smrj KMEMP(keyentry.kte_memhdl)->kmem_cookies_num, 20533446Smrj keyentry.kte_pfnarray)) { 20543446Smrj AGPDB_PRINT2((CE_WARN, "agp_alloc_kmem: get pfn array error")); 20553446Smrj goto err1; 20563446Smrj } 20573446Smrj 20583446Smrj ASSERT(!agp_check_pfns(softstate->asoft_devreg.agprd_arctype, 20593446Smrj keyentry.kte_pfnarray, keyentry.kte_pages)); 20606742Sms148562 if (agp_check_pfns(softstate->asoft_devreg.agprd_arctype, 20616742Sms148562 keyentry.kte_pfnarray, keyentry.kte_pages)) 20626742Sms148562 goto err1; 20633446Smrj entryp = agp_fill_empty_keyent(softstate, &keyentry); 20643446Smrj if (!entryp) { 20653446Smrj AGPDB_PRINT2((CE_WARN, 20663446Smrj "agp_alloc_kmem: agp_fill_empty_keyent error")); 20673446Smrj 20683446Smrj goto err1; 20693446Smrj } 20703446Smrj ASSERT((entryp->kte_key >= 0) && (entryp->kte_key < AGP_MAXKEYS)); 20713446Smrj 20723446Smrj return (entryp); 20733446Smrj 20743446Smrj err1: 20753446Smrj kmem_free(keyentry.kte_pfnarray, sizeof (pfn_t) * keyentry.kte_pages); 20763446Smrj keyentry.kte_pfnarray = NULL; 20773446Smrj (void) ddi_dma_unbind_handle(KMEMP(keyentry.kte_memhdl)->kmem_handle); 20783446Smrj KMEMP(keyentry.kte_memhdl)->kmem_cookies_num = 0; 20793446Smrj err2: 20803446Smrj ddi_dma_mem_free(&KMEMP(keyentry.kte_memhdl)->kmem_acchdl); 20813446Smrj KMEMP(keyentry.kte_memhdl)->kmem_acchdl = NULL; 20823446Smrj KMEMP(keyentry.kte_memhdl)->kmem_reallen = 0; 20833446Smrj KMEMP(keyentry.kte_memhdl)->kmem_kvaddr = NULL; 20843446Smrj err3: 20853446Smrj ddi_dma_free_handle(&(KMEMP(keyentry.kte_memhdl)->kmem_handle)); 20863446Smrj KMEMP(keyentry.kte_memhdl)->kmem_handle = NULL; 20873446Smrj err4: 20883446Smrj kmem_free(keyentry.kte_memhdl, sizeof (agp_kmem_handle_t)); 20893446Smrj keyentry.kte_memhdl = NULL; 20903446Smrj return (NULL); 20913446Smrj 20923446Smrj } 20933446Smrj 20943446Smrj /* 20953446Smrj * agp_alloc_mem() 20963446Smrj * 20973446Smrj * Description: 20983446Smrj * This function allocate physical memory for userland applications, 20993446Smrj * in order to save kernel virtual space, we use the direct mapping 21003446Smrj * memory interface if it is available. 21013446Smrj * 21023446Smrj * Arguments: 21033446Smrj * st driver soft state pointer 21043446Smrj * length memory size 21053446Smrj * type AGP_NORMAL: normal agp memory, AGP_PHISYCAL: specical 21063446Smrj * memory type for intel i810 IGD 21073446Smrj * 21083446Smrj * Returns: 21093446Smrj * NULL Invalid memory type or can not allocate memory 21106742Sms148562 * Keytable entry pointer returned by agp_alloc_kmem 21113446Smrj */ 21123446Smrj static keytable_ent_t * 21133446Smrj agp_alloc_mem(agpgart_softstate_t *st, size_t length, int type) 21143446Smrj { 21153446Smrj 21163446Smrj /* 21173446Smrj * AGP_PHYSICAL type require contiguous physical pages exported 21183446Smrj * to X drivers, like i810 HW cursor, ARGB cursor. the number of 21193446Smrj * pages needed is usuallysmall and contiguous, 4K, 16K. So we 21203446Smrj * use DDI interface to allocated such memory. And X use xsvc 21213446Smrj * drivers to map this memory into its own address space. 21223446Smrj */ 21233446Smrj ASSERT(st); 21243446Smrj 21253446Smrj switch (type) { 21263446Smrj case AGP_NORMAL: 21273446Smrj case AGP_PHYSICAL: 21286742Sms148562 return (agp_alloc_kmem(st, length, type)); 21293446Smrj default: 21303446Smrj return (NULL); 21313446Smrj } 21323446Smrj } 21333446Smrj 21343446Smrj /* 21353446Smrj * free_gart_table() 21363446Smrj * 21373446Smrj * Description: 21383446Smrj * This function frees the gart table memory allocated by driver. 21393446Smrj * Must disable gart table before calling this function. 21403446Smrj * 21413446Smrj * Arguments: 21423446Smrj * softstate driver soft state pointer 21433446Smrj * 21443446Smrj */ 21453446Smrj static void 21463446Smrj free_gart_table(agpgart_softstate_t *st) 21473446Smrj { 21483446Smrj 21493446Smrj if (st->gart_dma_handle == NULL) 21503446Smrj return; 21513446Smrj 21523446Smrj (void) ddi_dma_unbind_handle(st->gart_dma_handle); 21533446Smrj ddi_dma_mem_free(&st->gart_dma_acc_handle); 21543446Smrj st->gart_dma_acc_handle = NULL; 21553446Smrj ddi_dma_free_handle(&st->gart_dma_handle); 21563446Smrj st->gart_dma_handle = NULL; 21573446Smrj st->gart_vbase = 0; 21583446Smrj st->gart_size = 0; 21593446Smrj } 21603446Smrj 21613446Smrj /* 21623446Smrj * alloc_gart_table() 21633446Smrj * 21643446Smrj * Description: 21653446Smrj * This function allocates one physical continuous gart table. 21663446Smrj * INTEL integrated video device except i810 have their special 21673446Smrj * video bios; No need to allocate gart table for them. 21683446Smrj * 21693446Smrj * Arguments: 21703446Smrj * st driver soft state pointer 21713446Smrj * 21723446Smrj * Returns: 21733446Smrj * 0 success 21743446Smrj * -1 can not allocate gart tabl 21753446Smrj */ 21763446Smrj static int 21773446Smrj alloc_gart_table(agpgart_softstate_t *st) 21783446Smrj { 21793446Smrj int num_pages; 21803446Smrj size_t table_size; 21813446Smrj int ret = DDI_SUCCESS; 21823446Smrj ddi_dma_cookie_t cookie; 21833446Smrj uint32_t num_cookies; 21843446Smrj 21853446Smrj num_pages = AGP_MB2PAGES(st->asoft_info.agpki_apersize); 21863446Smrj 21873446Smrj /* 21883446Smrj * Only 40-bit maximum physical memory is supported by today's 21893446Smrj * AGP hardware (32-bit gart tables can hold 40-bit memory addresses). 21903446Smrj * No one supports 64-bit gart entries now, so the size of gart 21913446Smrj * entries defaults to 32-bit though AGP3.0 specifies the possibility 21923446Smrj * of 64-bit gart entries. 21933446Smrj */ 21943446Smrj 21953446Smrj table_size = num_pages * (sizeof (uint32_t)); 21963446Smrj 21973446Smrj /* 21983446Smrj * Only AMD64 can put gart table above 4G, 40 bits at maximum 21993446Smrj */ 22005376Scg149915 if (st->asoft_devreg.agprd_arctype == ARC_AMD64AGP) 22013446Smrj garttable_dma_attr.dma_attr_addr_hi = 0xffffffffffLL; 22023446Smrj else 22033446Smrj garttable_dma_attr.dma_attr_addr_hi = 0xffffffffU; 22043446Smrj /* Allocate physical continuous page frame for gart table */ 22053446Smrj if (ret = ddi_dma_alloc_handle(st->asoft_dip, 22063446Smrj &garttable_dma_attr, 22073446Smrj DDI_DMA_SLEEP, 22083446Smrj NULL, &st->gart_dma_handle)) { 22093446Smrj AGPDB_PRINT2((CE_WARN, 22103446Smrj "alloc_gart_table: ddi_dma_alloc_handle failed")); 22113446Smrj goto err3; 22123446Smrj } 22133446Smrj 22143446Smrj if (ret = ddi_dma_mem_alloc(st->gart_dma_handle, 22154478Skz151634 table_size, 22164478Skz151634 &gart_dev_acc_attr, 22174478Skz151634 DDI_DMA_CONSISTENT, 22184478Skz151634 DDI_DMA_SLEEP, NULL, 22194478Skz151634 &st->gart_vbase, 22204478Skz151634 &st->gart_size, 22214478Skz151634 &st->gart_dma_acc_handle)) { 22223446Smrj AGPDB_PRINT2((CE_WARN, 22233446Smrj "alloc_gart_table: ddi_dma_mem_alloc failed")); 22243446Smrj goto err2; 22253446Smrj 22263446Smrj } 22273446Smrj 22283446Smrj ret = ddi_dma_addr_bind_handle(st->gart_dma_handle, 22294478Skz151634 NULL, st->gart_vbase, 22304478Skz151634 table_size, 22314478Skz151634 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 22324478Skz151634 DDI_DMA_SLEEP, NULL, 22334478Skz151634 &cookie, &num_cookies); 22343446Smrj 22353446Smrj st->gart_pbase = cookie.dmac_address; 22363446Smrj 22373446Smrj if ((ret != DDI_DMA_MAPPED) || (num_cookies != 1)) { 22383446Smrj if (num_cookies > 1) 22393446Smrj (void) ddi_dma_unbind_handle(st->gart_dma_handle); 22403446Smrj AGPDB_PRINT2((CE_WARN, 22413446Smrj "alloc_gart_table: alloc contiguous phys memory failed")); 22423446Smrj goto err1; 22433446Smrj } 22443446Smrj 22453446Smrj return (0); 22463446Smrj err1: 22473446Smrj ddi_dma_mem_free(&st->gart_dma_acc_handle); 22483446Smrj st->gart_dma_acc_handle = NULL; 22493446Smrj err2: 22503446Smrj ddi_dma_free_handle(&st->gart_dma_handle); 22513446Smrj st->gart_dma_handle = NULL; 22523446Smrj err3: 22533446Smrj st->gart_pbase = 0; 22543446Smrj st->gart_size = 0; 22553446Smrj st->gart_vbase = 0; 22563446Smrj 22573446Smrj return (-1); 22583446Smrj } 22593446Smrj 22603446Smrj /* 22613446Smrj * agp_add_to_gart() 22623446Smrj * 22633446Smrj * Description: 22643446Smrj * This function fills the gart table entries by a given page frame number 22653446Smrj * array and set up the agp aperture page to physical memory page 22663446Smrj * translation. 22673446Smrj * Arguments: 22683446Smrj * type valid sytem arc types ARC_AMD64AGP, ARC_INTELAGP, 22693446Smrj * ARC_AMD64AGP 22703446Smrj * pfnarray allocated physical page frame number array 22713446Smrj * pg_offset agp aperture start page to be bound 22723446Smrj * entries the number of pages to be bound 22733446Smrj * dma_hdl gart table dma memory handle 22743446Smrj * tablep gart table kernel virtual address 22753446Smrj * Returns: 22763446Smrj * -1 failed 22773446Smrj * 0 success 22783446Smrj */ 22793446Smrj static int 22803446Smrj agp_add_to_gart( 22813446Smrj agp_arc_type_t type, 22823446Smrj pfn_t *pfnarray, 22833446Smrj uint32_t pg_offset, 22843446Smrj uint32_t entries, 22853446Smrj ddi_dma_handle_t dma_hdl, 22863446Smrj uint32_t *tablep) 22873446Smrj { 22883446Smrj int items = 0; 22893446Smrj uint32_t *entryp; 22903446Smrj uint32_t itemv; 22913446Smrj 22923446Smrj entryp = tablep + pg_offset; 22933446Smrj while (items < entries) { 22943446Smrj if (pfn2gartentry(type, pfnarray[items], &itemv)) 22953446Smrj break; 22963446Smrj *(entryp + items) = itemv; 22973446Smrj items++; 22983446Smrj } 22993446Smrj if (items < entries) 23003446Smrj return (-1); 23013446Smrj 23023446Smrj (void) ddi_dma_sync(dma_hdl, pg_offset * sizeof (uint32_t), 23033446Smrj entries * sizeof (uint32_t), DDI_DMA_SYNC_FORDEV); 23043446Smrj 23053446Smrj return (0); 23063446Smrj } 23073446Smrj 23083446Smrj /* 23093446Smrj * agp_bind_key() 23103446Smrj * 23113446Smrj * Description: 23123446Smrj * This function will call low level gart table access functions to 23133446Smrj * set up gart table translation. Also it will do some sanity 23143446Smrj * checking on key table entry. 23153446Smrj * 23163446Smrj * Arguments: 23173446Smrj * softstate driver soft state pointer 23183446Smrj * keyent key table entity pointer to be bound 23193446Smrj * pg_offset aperture start page to be bound 23203446Smrj * Returns: 23213446Smrj * EINVAL not a valid operation 23223446Smrj */ 23233446Smrj static int 23243446Smrj agp_bind_key(agpgart_softstate_t *softstate, 23253446Smrj keytable_ent_t *keyent, uint32_t pg_offset) 23263446Smrj { 23273446Smrj uint64_t pg_end; 23283446Smrj int ret = 0; 23293446Smrj 23303446Smrj ASSERT(keyent); 23313446Smrj ASSERT((keyent->kte_key >= 0) && (keyent->kte_key < AGP_MAXKEYS)); 23323446Smrj ASSERT(mutex_owned(&softstate->asoft_instmutex)); 23333446Smrj 23343446Smrj pg_end = pg_offset + keyent->kte_pages; 23353446Smrj 23363446Smrj if (pg_end > AGP_MB2PAGES(softstate->asoft_info.agpki_apersize)) { 23373446Smrj AGPDB_PRINT2((CE_WARN, 23383446Smrj "agp_bind_key: key=0x%x,exceed aper range", 23393446Smrj keyent->kte_key)); 23403446Smrj 23413446Smrj return (EINVAL); 23423446Smrj } 23433446Smrj 23443446Smrj if (agp_check_off(softstate->asoft_table, 23453446Smrj pg_offset, keyent->kte_pages)) { 23463446Smrj AGPDB_PRINT2((CE_WARN, 23473446Smrj "agp_bind_key: pg_offset=0x%x, pages=0x%lx overlaped", 23483446Smrj pg_offset, keyent->kte_pages)); 23493446Smrj return (EINVAL); 23503446Smrj } 23513446Smrj 23523446Smrj ASSERT(keyent->kte_pfnarray != NULL); 23533446Smrj 23543446Smrj switch (softstate->asoft_devreg.agprd_arctype) { 23553446Smrj case ARC_IGD810: 23563446Smrj case ARC_IGD830: 23573446Smrj ret = lyr_i8xx_add_to_gtt(pg_offset, keyent, 23583446Smrj &softstate->asoft_devreg); 23593446Smrj if (ret) 23603446Smrj return (EIO); 23613446Smrj break; 23623446Smrj case ARC_INTELAGP: 23633446Smrj case ARC_AMD64AGP: 23643446Smrj ret = agp_add_to_gart( 23653446Smrj softstate->asoft_devreg.agprd_arctype, 23663446Smrj keyent->kte_pfnarray, 23673446Smrj pg_offset, 23683446Smrj keyent->kte_pages, 23693446Smrj softstate->gart_dma_handle, 23703446Smrj (uint32_t *)softstate->gart_vbase); 23713446Smrj if (ret) 23723446Smrj return (EINVAL); 23733446Smrj /* Flush GTLB table */ 23743446Smrj lyr_flush_gart_cache(&softstate->asoft_devreg); 23753446Smrj break; 23763446Smrj default: 23773446Smrj AGPDB_PRINT2((CE_WARN, 23783446Smrj "agp_bind_key: arc type = 0x%x unsupported", 23793446Smrj softstate->asoft_devreg.agprd_arctype)); 23803446Smrj return (EINVAL); 23813446Smrj } 23823446Smrj return (0); 23833446Smrj } 23843446Smrj 23853446Smrj static int 23863446Smrj agpgart_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 23873446Smrj { 23883446Smrj int instance; 23893446Smrj agpgart_softstate_t *softstate; 23903446Smrj 23913446Smrj if (cmd != DDI_ATTACH) { 23923446Smrj AGPDB_PRINT2((CE_WARN, 23933446Smrj "agpgart_attach: only attach op supported")); 23943446Smrj return (DDI_FAILURE); 23953446Smrj } 23963446Smrj instance = ddi_get_instance(dip); 23973446Smrj 23983446Smrj if (ddi_soft_state_zalloc(agpgart_glob_soft_handle, instance) 23994478Skz151634 != DDI_SUCCESS) { 24003446Smrj AGPDB_PRINT2((CE_WARN, 24013446Smrj "agpgart_attach: soft state zalloc failed")); 24023446Smrj goto err1; 24033446Smrj 24043446Smrj } 24053446Smrj softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance); 24063446Smrj mutex_init(&softstate->asoft_instmutex, NULL, MUTEX_DRIVER, NULL); 24073446Smrj softstate->asoft_dip = dip; 24083446Smrj /* 24093446Smrj * Allocate LDI identifier for agpgart driver 24103446Smrj * Agpgart driver is the kernel consumer 24113446Smrj */ 24123446Smrj if (ldi_ident_from_dip(dip, &softstate->asoft_li)) { 24133446Smrj AGPDB_PRINT2((CE_WARN, 24143446Smrj "agpgart_attach: LDI indentifier allcation failed")); 24153446Smrj goto err2; 24163446Smrj } 24173446Smrj 24183446Smrj softstate->asoft_devreg.agprd_arctype = ARC_UNKNOWN; 24193446Smrj /* Install agp kstat */ 24203446Smrj if (agp_init_kstats(softstate)) { 24213446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_attach: init kstats error")); 24223446Smrj goto err3; 24233446Smrj } 24243446Smrj /* 24253446Smrj * devfs will create /dev/agpgart 24263446Smrj * and /devices/agpgart:agpgart 24273446Smrj */ 24283446Smrj 24293446Smrj if (ddi_create_minor_node(dip, AGPGART_DEVNODE, S_IFCHR, 24303446Smrj AGP_INST2MINOR(instance), 24313446Smrj DDI_NT_AGP_PSEUDO, 0)) { 24323446Smrj AGPDB_PRINT2((CE_WARN, 24333446Smrj "agpgart_attach: Can not create minor node")); 24343446Smrj goto err4; 24353446Smrj } 24363446Smrj 24373446Smrj softstate->asoft_table = kmem_zalloc( 24384478Skz151634 AGP_MAXKEYS * (sizeof (keytable_ent_t)), 24394478Skz151634 KM_SLEEP); 24403446Smrj 24413446Smrj return (DDI_SUCCESS); 24423446Smrj err4: 24433446Smrj agp_fini_kstats(softstate); 24443446Smrj err3: 24453446Smrj ldi_ident_release(softstate->asoft_li); 24463446Smrj err2: 24473446Smrj ddi_soft_state_free(agpgart_glob_soft_handle, instance); 24483446Smrj err1: 24493446Smrj return (DDI_FAILURE); 24503446Smrj } 24513446Smrj 24523446Smrj static int 24533446Smrj agpgart_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 24543446Smrj { 24553446Smrj int instance; 24563446Smrj agpgart_softstate_t *st; 24573446Smrj 24583446Smrj instance = ddi_get_instance(dip); 24593446Smrj 24603446Smrj st = ddi_get_soft_state(agpgart_glob_soft_handle, instance); 24613446Smrj 24623446Smrj if (cmd != DDI_DETACH) 24633446Smrj return (DDI_FAILURE); 24643446Smrj 24653446Smrj /* 24663446Smrj * Caller should free all the memory allocated explicitly. 24673446Smrj * We release the memory allocated by caller which is not 24683446Smrj * properly freed. mutex_enter here make sure assertion on 24693446Smrj * softstate mutex success in agp_dealloc_mem. 24703446Smrj */ 24713446Smrj mutex_enter(&st->asoft_instmutex); 24723446Smrj if (agp_del_allkeys(st)) { 24733446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_detach: agp_del_allkeys err")); 24743446Smrj AGPDB_PRINT2((CE_WARN, 24753446Smrj "you might free agp memory exported to your applications")); 24763446Smrj 24773446Smrj mutex_exit(&st->asoft_instmutex); 24783446Smrj return (DDI_FAILURE); 24793446Smrj } 24803446Smrj mutex_exit(&st->asoft_instmutex); 24813446Smrj if (st->asoft_table) { 24823446Smrj kmem_free(st->asoft_table, 24833446Smrj AGP_MAXKEYS * (sizeof (keytable_ent_t))); 24843446Smrj st->asoft_table = 0; 24853446Smrj } 24863446Smrj 24873446Smrj ddi_remove_minor_node(dip, AGPGART_DEVNODE); 24883446Smrj agp_fini_kstats(st); 24893446Smrj ldi_ident_release(st->asoft_li); 24903446Smrj mutex_destroy(&st->asoft_instmutex); 24913446Smrj ddi_soft_state_free(agpgart_glob_soft_handle, instance); 24923446Smrj 24933446Smrj return (DDI_SUCCESS); 24943446Smrj } 24953446Smrj 24963446Smrj /*ARGSUSED*/ 24973446Smrj static int 24983446Smrj agpgart_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 24993446Smrj void **resultp) 25003446Smrj { 25013446Smrj agpgart_softstate_t *st; 25023446Smrj int instance, rval = DDI_FAILURE; 25033446Smrj dev_t dev; 25043446Smrj 25053446Smrj switch (cmd) { 25063446Smrj case DDI_INFO_DEVT2DEVINFO: 25073446Smrj dev = (dev_t)arg; 25083446Smrj instance = AGP_DEV2INST(dev); 25093446Smrj st = ddi_get_soft_state(agpgart_glob_soft_handle, instance); 25103446Smrj if (st != NULL) { 25113446Smrj mutex_enter(&st->asoft_instmutex); 25123446Smrj *resultp = st->asoft_dip; 25133446Smrj mutex_exit(&st->asoft_instmutex); 25143446Smrj rval = DDI_SUCCESS; 25153446Smrj } else 25163446Smrj *resultp = NULL; 25173446Smrj 25183446Smrj break; 25193446Smrj case DDI_INFO_DEVT2INSTANCE: 25203446Smrj dev = (dev_t)arg; 25213446Smrj instance = AGP_DEV2INST(dev); 25223446Smrj *resultp = (void *)(uintptr_t)instance; 25233446Smrj rval = DDI_SUCCESS; 25243446Smrj 25253446Smrj break; 25263446Smrj default: 25273446Smrj break; 25283446Smrj } 25293446Smrj 25303446Smrj return (rval); 25313446Smrj } 25323446Smrj 25333446Smrj /* 25343446Smrj * agpgart_open() 25353446Smrj * 25363446Smrj * Description: 25373446Smrj * This function is the driver open entry point. If it is the 25383446Smrj * first time the agpgart driver is opened, the driver will 25393446Smrj * open other agp related layered drivers and set up the agpgart 25403446Smrj * table properly. 25413446Smrj * 25423446Smrj * Arguments: 25433446Smrj * dev device number pointer 25443446Smrj * openflags open flags 25453446Smrj * otyp OTYP_BLK, OTYP_CHR 25463446Smrj * credp user's credential's struct pointer 25473446Smrj * 25483446Smrj * Returns: 25493446Smrj * ENXIO operation error 25503446Smrj * EAGAIN resoure temporarily unvailable 25513446Smrj * 0 success 25523446Smrj */ 25533446Smrj /*ARGSUSED*/ 25543446Smrj static int 25553446Smrj agpgart_open(dev_t *dev, int openflags, int otyp, cred_t *credp) 25563446Smrj { 25573446Smrj int instance = AGP_DEV2INST(*dev); 25583446Smrj agpgart_softstate_t *softstate; 25593446Smrj int rc = 0; 25603446Smrj 25613446Smrj softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance); 25623446Smrj if (softstate == NULL) { 25633446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_open: get soft state err")); 25643446Smrj return (ENXIO); 25653446Smrj } 25663446Smrj mutex_enter(&softstate->asoft_instmutex); 25673446Smrj 25683446Smrj if (softstate->asoft_opened) { 25693446Smrj softstate->asoft_opened++; 25703446Smrj mutex_exit(&softstate->asoft_instmutex); 25713446Smrj return (0); 25723446Smrj } 25733446Smrj 25743446Smrj /* 25753446Smrj * The driver is opened first time, so we initialize layered 25763446Smrj * driver interface and softstate member here. 25773446Smrj */ 25783446Smrj softstate->asoft_pgused = 0; 25793446Smrj if (lyr_init(&softstate->asoft_devreg, softstate->asoft_li)) { 25803446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_open: lyr_init failed")); 25813446Smrj mutex_exit(&softstate->asoft_instmutex); 25823446Smrj return (EAGAIN); 25833446Smrj } 25843446Smrj 25853446Smrj /* Call into layered driver */ 25863446Smrj if (lyr_get_info(&softstate->asoft_info, &softstate->asoft_devreg)) { 25873446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_open: lyr_get_info error")); 25883446Smrj lyr_end(&softstate->asoft_devreg); 25893446Smrj mutex_exit(&softstate->asoft_instmutex); 25903446Smrj return (EIO); 25913446Smrj } 25923446Smrj 25933446Smrj /* 25943446Smrj * BIOS already set up gtt table for ARC_IGD830 25953446Smrj */ 25963446Smrj if (IS_INTEL_830(softstate->asoft_devreg.agprd_arctype)) { 25973446Smrj softstate->asoft_opened++; 25983446Smrj 25993446Smrj softstate->asoft_pgtotal = 26003446Smrj get_max_pages(softstate->asoft_info.agpki_apersize); 26013446Smrj 26023446Smrj if (lyr_config_devices(&softstate->asoft_devreg)) { 26033446Smrj AGPDB_PRINT2((CE_WARN, 26043446Smrj "agpgart_open: lyr_config_devices error")); 26053446Smrj lyr_end(&softstate->asoft_devreg); 26063446Smrj mutex_exit(&softstate->asoft_instmutex); 26073446Smrj 26083446Smrj return (EIO); 26093446Smrj } 26103446Smrj mutex_exit(&softstate->asoft_instmutex); 26113446Smrj return (0); 26123446Smrj } 26133446Smrj 26143446Smrj rc = alloc_gart_table(softstate); 26153446Smrj 26163446Smrj /* 26173446Smrj * Allocate physically contiguous pages for AGP arc or 26183446Smrj * i810 arc. If failed, divide aper_size by 2 to 26193446Smrj * reduce gart table size until 4 megabytes. This 26203446Smrj * is just a workaround for systems with very few 26213446Smrj * physically contiguous memory. 26223446Smrj */ 26233446Smrj if (rc) { 26243446Smrj while ((softstate->asoft_info.agpki_apersize >= 4) && 26253446Smrj (alloc_gart_table(softstate))) { 26263446Smrj softstate->asoft_info.agpki_apersize >>= 1; 26273446Smrj } 26283446Smrj if (softstate->asoft_info.agpki_apersize >= 4) 26293446Smrj rc = 0; 26303446Smrj } 26313446Smrj 26323446Smrj if (rc != 0) { 26333446Smrj AGPDB_PRINT2((CE_WARN, 26343446Smrj "agpgart_open: alloc gart table failed")); 26353446Smrj lyr_end(&softstate->asoft_devreg); 26363446Smrj mutex_exit(&softstate->asoft_instmutex); 26373446Smrj return (EAGAIN); 26383446Smrj } 26393446Smrj 26403446Smrj softstate->asoft_pgtotal = 26413446Smrj get_max_pages(softstate->asoft_info.agpki_apersize); 26423446Smrj /* 26433446Smrj * BIOS doesn't initialize GTT for i810, 26443446Smrj * So i810 GTT must be created by driver. 26453446Smrj * 26463446Smrj * Set up gart table and enable it. 26473446Smrj */ 26483446Smrj if (lyr_set_gart_addr(softstate->gart_pbase, 26493446Smrj &softstate->asoft_devreg)) { 26503446Smrj AGPDB_PRINT2((CE_WARN, 26513446Smrj "agpgart_open: set gart table addr failed")); 26523446Smrj free_gart_table(softstate); 26533446Smrj lyr_end(&softstate->asoft_devreg); 26543446Smrj mutex_exit(&softstate->asoft_instmutex); 26553446Smrj return (EIO); 26563446Smrj } 26573446Smrj if (lyr_config_devices(&softstate->asoft_devreg)) { 26583446Smrj AGPDB_PRINT2((CE_WARN, 26593446Smrj "agpgart_open: lyr_config_devices failed")); 26603446Smrj free_gart_table(softstate); 26613446Smrj lyr_end(&softstate->asoft_devreg); 26623446Smrj mutex_exit(&softstate->asoft_instmutex); 26633446Smrj return (EIO); 26643446Smrj } 26653446Smrj 26663446Smrj softstate->asoft_opened++; 26673446Smrj mutex_exit(&softstate->asoft_instmutex); 26683446Smrj 26693446Smrj return (0); 26703446Smrj } 26713446Smrj 26723446Smrj /* 26733446Smrj * agpgart_close() 26743446Smrj * 26753446Smrj * Description: 26763446Smrj * agpgart_close will release resources allocated in the first open 26773446Smrj * and close other open layered drivers. Also it frees the memory 26783446Smrj * allocated by ioctls. 26793446Smrj * 26803446Smrj * Arguments: 26813446Smrj * dev device number 26823446Smrj * flag file status flag 26833446Smrj * otyp OTYP_BLK, OTYP_CHR 26843446Smrj * credp user's credential's struct pointer 26853446Smrj * 26863446Smrj * Returns: 26873446Smrj * ENXIO not an error, to support "deferred attach" 26883446Smrj * 0 success 26893446Smrj */ 26903446Smrj /*ARGSUSED*/ 26913446Smrj static int 26923446Smrj agpgart_close(dev_t dev, int flag, int otyp, cred_t *credp) 26933446Smrj { 26943446Smrj int instance = AGP_DEV2INST(dev); 26953446Smrj agpgart_softstate_t *softstate; 26963446Smrj 26973446Smrj softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance); 26983446Smrj if (softstate == NULL) { 26993446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_close: get soft state err")); 27003446Smrj return (ENXIO); 27013446Smrj } 27023446Smrj 27033446Smrj mutex_enter(&softstate->asoft_instmutex); 27043446Smrj ASSERT(softstate->asoft_opened); 27053446Smrj 27063446Smrj 27073446Smrj /* 27083446Smrj * If the last process close this device is not the controlling 27093446Smrj * process, also release the control over agpgart driver here if the 27103446Smrj * the controlling process fails to release the control before it 27113446Smrj * close the driver. 27123446Smrj */ 27133446Smrj if (softstate->asoft_acquired == 1) { 27143446Smrj AGPDB_PRINT2((CE_WARN, 27153446Smrj "agpgart_close: auto release control over driver")); 27163446Smrj release_control(softstate); 27173446Smrj } 27183446Smrj 27193446Smrj if (lyr_unconfig_devices(&softstate->asoft_devreg)) { 27203446Smrj AGPDB_PRINT2((CE_WARN, 27213446Smrj "agpgart_close: lyr_unconfig_device error")); 27223446Smrj mutex_exit(&softstate->asoft_instmutex); 27233446Smrj return (EIO); 27243446Smrj } 27253446Smrj softstate->asoft_agpen = 0; 27263446Smrj 27273446Smrj if (!IS_INTEL_830(softstate->asoft_devreg.agprd_arctype)) { 27283446Smrj free_gart_table(softstate); 27293446Smrj } 27303446Smrj 27313446Smrj lyr_end(&softstate->asoft_devreg); 27323446Smrj 27333446Smrj /* 27343446Smrj * This statement must be positioned before agp_del_allkeys 27353446Smrj * agp_dealloc_mem indirectly called by agp_del_allkeys 27363446Smrj * will test this variable. 27373446Smrj */ 27383446Smrj softstate->asoft_opened = 0; 27393446Smrj 27403446Smrj /* 27413446Smrj * Free the memory allocated by user applications which 27423446Smrj * was never deallocated. 27433446Smrj */ 27443446Smrj (void) agp_del_allkeys(softstate); 27453446Smrj 27463446Smrj mutex_exit(&softstate->asoft_instmutex); 27473446Smrj 27483446Smrj return (0); 27493446Smrj } 27503446Smrj 27513446Smrj static int 27523446Smrj ioctl_agpgart_info(agpgart_softstate_t *softstate, void *arg, int flags) 27533446Smrj { 27543446Smrj agp_info_t infostruct; 27553446Smrj #ifdef _MULTI_DATAMODEL 27563446Smrj agp_info32_t infostruct32; 27573446Smrj #endif 27583446Smrj 27593446Smrj bzero(&infostruct, sizeof (agp_info_t)); 27603446Smrj 27613446Smrj #ifdef _MULTI_DATAMODEL 27623446Smrj bzero(&infostruct32, sizeof (agp_info32_t)); 27633446Smrj if (ddi_model_convert_from(flags & FMODELS) == DDI_MODEL_ILP32) { 27643446Smrj if (copyinfo(softstate, &infostruct)) 27653446Smrj return (EINVAL); 27663446Smrj 27673446Smrj agpinfo_default_to_32(infostruct, infostruct32); 27683446Smrj if (ddi_copyout(&infostruct32, arg, 27693446Smrj sizeof (agp_info32_t), flags) != 0) 27703446Smrj return (EFAULT); 27713446Smrj 27723446Smrj return (0); 27733446Smrj } 27743446Smrj #endif /* _MULTI_DATAMODEL */ 27753446Smrj if (copyinfo(softstate, &infostruct)) 27763446Smrj return (EINVAL); 27773446Smrj 27783446Smrj if (ddi_copyout(&infostruct, arg, sizeof (agp_info_t), flags) != 0) { 27793446Smrj return (EFAULT); 27803446Smrj } 27813446Smrj 27823446Smrj return (0); 27833446Smrj } 27843446Smrj 27853446Smrj static int 27863446Smrj ioctl_agpgart_acquire(agpgart_softstate_t *st) 27873446Smrj { 27883446Smrj if (st->asoft_acquired) { 27893446Smrj AGPDB_PRINT2((CE_WARN, "ioctl_acquire: already acquired")); 27903446Smrj return (EBUSY); 27913446Smrj } 27923446Smrj acquire_control(st); 27933446Smrj return (0); 27943446Smrj } 27953446Smrj 27963446Smrj static int 27973446Smrj ioctl_agpgart_release(agpgart_softstate_t *st) 27983446Smrj { 27993446Smrj if (is_controlling_proc(st) < 0) { 28003446Smrj AGPDB_PRINT2((CE_WARN, 28013446Smrj "ioctl_agpgart_release: not a controlling process")); 28023446Smrj return (EPERM); 28033446Smrj } 28043446Smrj release_control(st); 28053446Smrj return (0); 28063446Smrj } 28073446Smrj 28083446Smrj static int 28093446Smrj ioctl_agpgart_setup(agpgart_softstate_t *st, void *arg, int flags) 28103446Smrj { 28113446Smrj agp_setup_t data; 28123446Smrj int rc = 0; 28133446Smrj 28143446Smrj if (is_controlling_proc(st) < 0) { 28153446Smrj AGPDB_PRINT2((CE_WARN, 28163446Smrj "ioctl_agpgart_setup: not a controlling process")); 28173446Smrj return (EPERM); 28183446Smrj } 28193446Smrj 28203446Smrj if (!IS_TRUE_AGP(st->asoft_devreg.agprd_arctype)) { 28213446Smrj AGPDB_PRINT2((CE_WARN, 28223446Smrj "ioctl_agpgart_setup: no true agp bridge")); 28233446Smrj return (EINVAL); 28243446Smrj } 28253446Smrj 28263446Smrj if (ddi_copyin(arg, &data, sizeof (agp_setup_t), flags) != 0) 28273446Smrj return (EFAULT); 28283446Smrj 28293446Smrj if (rc = agp_setup(st, data.agps_mode)) 28303446Smrj return (rc); 28313446Smrj /* Store agp mode status for kstat */ 28323446Smrj st->asoft_agpen = 1; 28333446Smrj return (0); 28343446Smrj } 28353446Smrj 28363446Smrj static int 28373446Smrj ioctl_agpgart_alloc(agpgart_softstate_t *st, void *arg, int flags) 28383446Smrj { 28393446Smrj agp_allocate_t alloc_info; 28403446Smrj keytable_ent_t *entryp; 28413446Smrj size_t length; 28423446Smrj uint64_t pg_num; 28433446Smrj 28443446Smrj if (is_controlling_proc(st) < 0) { 28453446Smrj AGPDB_PRINT2((CE_WARN, 28463446Smrj "ioctl_agpgart_alloc: not a controlling process")); 28473446Smrj return (EPERM); 28483446Smrj } 28493446Smrj 28503446Smrj if (ddi_copyin(arg, &alloc_info, 28513446Smrj sizeof (agp_allocate_t), flags) != 0) { 28523446Smrj return (EFAULT); 28533446Smrj } 28543446Smrj pg_num = st->asoft_pgused + alloc_info.agpa_pgcount; 28553446Smrj if (pg_num > st->asoft_pgtotal) { 28563446Smrj AGPDB_PRINT2((CE_WARN, 28573446Smrj "ioctl_agpgart_alloc: exceeding the memory pages limit")); 28583446Smrj AGPDB_PRINT2((CE_WARN, 28593446Smrj "ioctl_agpgart_alloc: request %x pages failed", 28603446Smrj alloc_info.agpa_pgcount)); 28613446Smrj AGPDB_PRINT2((CE_WARN, 28623446Smrj "ioctl_agpgart_alloc: pages used %x total is %x", 28633446Smrj st->asoft_pgused, st->asoft_pgtotal)); 28643446Smrj 28653446Smrj return (EINVAL); 28663446Smrj } 28673446Smrj 28683446Smrj length = AGP_PAGES2BYTES(alloc_info.agpa_pgcount); 28693446Smrj entryp = agp_alloc_mem(st, length, alloc_info.agpa_type); 28703446Smrj if (!entryp) { 28713446Smrj AGPDB_PRINT2((CE_WARN, 28723446Smrj "ioctl_agpgart_alloc: allocate 0x%lx bytes failed", 28733446Smrj length)); 28743446Smrj return (ENOMEM); 28753446Smrj } 28763446Smrj ASSERT((entryp->kte_key >= 0) && (entryp->kte_key < AGP_MAXKEYS)); 28773446Smrj alloc_info.agpa_key = entryp->kte_key; 28783446Smrj if (alloc_info.agpa_type == AGP_PHYSICAL) { 28793446Smrj alloc_info.agpa_physical = 28803446Smrj (uint32_t)(entryp->kte_pfnarray[0] << AGP_PAGE_SHIFT); 28813446Smrj } 28823446Smrj /* Update the memory pagse used */ 28833446Smrj st->asoft_pgused += alloc_info.agpa_pgcount; 28843446Smrj 28853446Smrj if (ddi_copyout(&alloc_info, arg, 28863446Smrj sizeof (agp_allocate_t), flags) != 0) { 28873446Smrj 28883446Smrj return (EFAULT); 28893446Smrj } 28903446Smrj 28913446Smrj return (0); 28923446Smrj } 28933446Smrj 28943446Smrj static int 28953446Smrj ioctl_agpgart_dealloc(agpgart_softstate_t *st, intptr_t arg) 28963446Smrj { 28973446Smrj int key; 28983446Smrj keytable_ent_t *keyent; 28993446Smrj 29003446Smrj if (is_controlling_proc(st) < 0) { 29013446Smrj AGPDB_PRINT2((CE_WARN, 29023446Smrj "ioctl_agpgart_dealloc: not a controlling process")); 29033446Smrj return (EPERM); 29043446Smrj } 29053446Smrj key = (int)arg; 29063446Smrj if ((key >= AGP_MAXKEYS) || key < 0) { 29073446Smrj return (EINVAL); 29083446Smrj } 29093446Smrj keyent = &st->asoft_table[key]; 29103446Smrj if (!keyent->kte_memhdl) { 29113446Smrj return (EINVAL); 29123446Smrj } 29133446Smrj 29143446Smrj if (agp_dealloc_mem(st, keyent)) 29153446Smrj return (EINVAL); 29163446Smrj 29173446Smrj /* Update the memory pages used */ 29183446Smrj st->asoft_pgused -= keyent->kte_pages; 29193446Smrj bzero(keyent, sizeof (keytable_ent_t)); 29203446Smrj 29213446Smrj return (0); 29223446Smrj } 29233446Smrj 29243446Smrj static int 29253446Smrj ioctl_agpgart_bind(agpgart_softstate_t *st, void *arg, int flags) 29263446Smrj { 29273446Smrj agp_bind_t bind_info; 29283446Smrj keytable_ent_t *keyent; 29293446Smrj int key; 29303446Smrj uint32_t pg_offset; 29313446Smrj int retval = 0; 29323446Smrj 29333446Smrj if (is_controlling_proc(st) < 0) { 29343446Smrj AGPDB_PRINT2((CE_WARN, 29353446Smrj "ioctl_agpgart_bind: not a controlling process")); 29363446Smrj return (EPERM); 29373446Smrj } 29383446Smrj 29393446Smrj if (ddi_copyin(arg, &bind_info, sizeof (agp_bind_t), flags) != 0) { 29403446Smrj return (EFAULT); 29413446Smrj } 29423446Smrj 29433446Smrj key = bind_info.agpb_key; 29443446Smrj if ((key >= AGP_MAXKEYS) || key < 0) { 29453446Smrj AGPDB_PRINT2((CE_WARN, "ioctl_agpgart_bind: invalid key")); 29463446Smrj return (EINVAL); 29473446Smrj } 29483446Smrj 29493446Smrj if (IS_INTEL_830(st->asoft_devreg.agprd_arctype)) { 29503446Smrj if (AGP_PAGES2KB(bind_info.agpb_pgstart) < 29513446Smrj st->asoft_info.agpki_presize) { 29523446Smrj AGPDB_PRINT2((CE_WARN, 29534478Skz151634 "ioctl_agpgart_bind: bind to prealloc area " 29544478Skz151634 "pgstart = %dKB < presize = %ldKB", 29554478Skz151634 AGP_PAGES2KB(bind_info.agpb_pgstart), 29564478Skz151634 st->asoft_info.agpki_presize)); 29573446Smrj return (EINVAL); 29583446Smrj } 29593446Smrj } 29603446Smrj 29613446Smrj pg_offset = bind_info.agpb_pgstart; 29623446Smrj keyent = &st->asoft_table[key]; 29633446Smrj if (!keyent->kte_memhdl) { 29643446Smrj AGPDB_PRINT2((CE_WARN, 29653446Smrj "ioctl_agpgart_bind: Key = 0x%x can't get keyenty", 29663446Smrj key)); 29673446Smrj return (EINVAL); 29683446Smrj } 29693446Smrj 29703446Smrj if (keyent->kte_bound != 0) { 29713446Smrj AGPDB_PRINT2((CE_WARN, 29723446Smrj "ioctl_agpgart_bind: Key = 0x%x already bound", 29733446Smrj key)); 29743446Smrj return (EINVAL); 29753446Smrj } 29763446Smrj retval = agp_bind_key(st, keyent, pg_offset); 29773446Smrj 29783446Smrj if (retval == 0) { 29793446Smrj keyent->kte_pgoff = pg_offset; 29803446Smrj keyent->kte_bound = 1; 29813446Smrj } 29823446Smrj 29833446Smrj return (retval); 29843446Smrj } 29853446Smrj 29863446Smrj static int 29873446Smrj ioctl_agpgart_unbind(agpgart_softstate_t *st, void *arg, int flags) 29883446Smrj { 29893446Smrj int key, retval = 0; 29903446Smrj agp_unbind_t unbindinfo; 29913446Smrj keytable_ent_t *keyent; 29923446Smrj 29933446Smrj if (is_controlling_proc(st) < 0) { 29943446Smrj AGPDB_PRINT2((CE_WARN, 29953446Smrj "ioctl_agpgart_bind: not a controlling process")); 29963446Smrj return (EPERM); 29973446Smrj } 29983446Smrj 29993446Smrj if (ddi_copyin(arg, &unbindinfo, sizeof (unbindinfo), flags) != 0) { 30003446Smrj return (EFAULT); 30013446Smrj } 30023446Smrj key = unbindinfo.agpu_key; 30033446Smrj if ((key >= AGP_MAXKEYS) || key < 0) { 30043446Smrj AGPDB_PRINT2((CE_WARN, "ioctl_agpgart_unbind: invalid key")); 30053446Smrj return (EINVAL); 30063446Smrj } 30073446Smrj keyent = &st->asoft_table[key]; 30083446Smrj if (!keyent->kte_bound) { 30093446Smrj return (EINVAL); 30103446Smrj } 30113446Smrj 30123446Smrj if ((retval = agp_unbind_key(st, keyent)) != 0) 30133446Smrj return (retval); 30143446Smrj 30153446Smrj return (0); 30163446Smrj } 30173446Smrj 30183446Smrj /*ARGSUSED*/ 30193446Smrj static int 30203446Smrj agpgart_ioctl(dev_t dev, int cmd, intptr_t intarg, int flags, 30213446Smrj cred_t *credp, int *rvalp) 30223446Smrj { 30233446Smrj int instance; 30243446Smrj int retval = 0; 30253446Smrj void *arg = (void*)intarg; 30263446Smrj 30273446Smrj agpgart_softstate_t *softstate; 30283446Smrj 30293446Smrj instance = AGP_DEV2INST(dev); 30303446Smrj softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance); 30313446Smrj if (softstate == NULL) { 30323446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_ioctl: get soft state err")); 30333446Smrj return (ENXIO); 30343446Smrj } 30353446Smrj 30363446Smrj if ((cmd != AGPIOC_INFO) && secpolicy_gart_access(credp)) { 30373446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_ioctl: permission denied")); 30383446Smrj return (EPERM); 30393446Smrj } 30403446Smrj 30413446Smrj mutex_enter(&softstate->asoft_instmutex); 30423446Smrj 30433446Smrj switch (cmd) { 30443446Smrj case AGPIOC_INFO: 30453446Smrj retval = ioctl_agpgart_info(softstate, arg, flags); 30463446Smrj break; 30473446Smrj case AGPIOC_ACQUIRE: 30483446Smrj retval = ioctl_agpgart_acquire(softstate); 30493446Smrj break; 30503446Smrj case AGPIOC_RELEASE: 30513446Smrj retval = ioctl_agpgart_release(softstate); 30523446Smrj break; 30533446Smrj case AGPIOC_SETUP: 30543446Smrj retval = ioctl_agpgart_setup(softstate, arg, flags); 30553446Smrj break; 30563446Smrj case AGPIOC_ALLOCATE: 30573446Smrj retval = ioctl_agpgart_alloc(softstate, arg, flags); 30583446Smrj break; 30593446Smrj case AGPIOC_DEALLOCATE: 30603446Smrj retval = ioctl_agpgart_dealloc(softstate, intarg); 30613446Smrj break; 30623446Smrj case AGPIOC_BIND: 30633446Smrj retval = ioctl_agpgart_bind(softstate, arg, flags); 30643446Smrj break; 30653446Smrj case AGPIOC_UNBIND: 30663446Smrj retval = ioctl_agpgart_unbind(softstate, arg, flags); 30673446Smrj break; 30683446Smrj default: 30693446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_ioctl: wrong argument")); 30703446Smrj retval = ENXIO; 30713446Smrj break; 30723446Smrj } 30733446Smrj 30743446Smrj mutex_exit(&softstate->asoft_instmutex); 30753446Smrj return (retval); 30763446Smrj } 30773446Smrj 30783446Smrj static int 30793446Smrj agpgart_segmap(dev_t dev, off_t off, struct as *asp, 30803446Smrj caddr_t *addrp, off_t len, unsigned int prot, 30813446Smrj unsigned int maxprot, unsigned int flags, cred_t *credp) 30823446Smrj { 30833446Smrj 30843446Smrj struct agpgart_softstate *softstate; 30853446Smrj int instance; 30863446Smrj int rc = 0; 30873446Smrj 30883446Smrj instance = AGP_DEV2INST(dev); 30893446Smrj softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance); 30903446Smrj if (softstate == NULL) { 30913446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_segmap: get soft state err")); 30923446Smrj return (ENXIO); 30933446Smrj } 30943446Smrj if (!AGP_ALIGNED(len)) 30953446Smrj return (EINVAL); 30963446Smrj 30973446Smrj mutex_enter(&softstate->asoft_instmutex); 30983446Smrj 30993446Smrj /* 31003446Smrj * Process must have gart map privilege or gart access privilege 31013446Smrj * to map agp memory. 31023446Smrj */ 31033446Smrj if (secpolicy_gart_map(credp)) { 31043446Smrj mutex_exit(&softstate->asoft_instmutex); 31053446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_segmap: permission denied")); 31063446Smrj return (EPERM); 31073446Smrj } 31083446Smrj 31093446Smrj rc = devmap_setup(dev, (offset_t)off, asp, addrp, 31103446Smrj (size_t)len, prot, maxprot, flags, credp); 31113446Smrj 31123446Smrj mutex_exit(&softstate->asoft_instmutex); 31133446Smrj return (rc); 31143446Smrj } 31153446Smrj 31163446Smrj /*ARGSUSED*/ 31173446Smrj static int 31183446Smrj agpgart_devmap(dev_t dev, devmap_cookie_t cookie, offset_t offset, size_t len, 31193446Smrj size_t *mappedlen, uint_t model) 31203446Smrj { 31213446Smrj struct agpgart_softstate *softstate; 31223446Smrj int instance, status; 31233446Smrj struct keytable_ent *mementry; 31243446Smrj offset_t local_offset; 31253446Smrj 31263446Smrj instance = AGP_DEV2INST(dev); 31273446Smrj softstate = ddi_get_soft_state(agpgart_glob_soft_handle, instance); 31283446Smrj if (softstate == NULL) { 31293446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_devmap: get soft state err")); 31303446Smrj return (ENXIO); 31313446Smrj } 31323446Smrj 31333446Smrj 31343446Smrj if (offset > MB2BYTES(softstate->asoft_info.agpki_apersize)) { 31353446Smrj AGPDB_PRINT2((CE_WARN, "agpgart_devmap: offset is too large")); 31363446Smrj return (EINVAL); 31373446Smrj } 31383446Smrj 31393446Smrj /* 31403446Smrj * Can not find any memory now, so fail. 31413446Smrj */ 31423446Smrj 31433446Smrj mementry = agp_find_bound_keyent(softstate, AGP_BYTES2PAGES(offset)); 31443446Smrj 31453446Smrj if (mementry == NULL) { 31463446Smrj AGPDB_PRINT2((CE_WARN, 31473446Smrj "agpgart_devmap: can not find the proper keyent")); 31483446Smrj return (EINVAL); 31493446Smrj } 31503446Smrj 31513446Smrj local_offset = offset - AGP_PAGES2BYTES(mementry->kte_pgoff); 31523446Smrj 31533446Smrj if (len > (AGP_PAGES2BYTES(mementry->kte_pages) - local_offset)) { 31543446Smrj len = AGP_PAGES2BYTES(mementry->kte_pages) - local_offset; 31553446Smrj } 31563446Smrj 31573446Smrj switch (mementry->kte_type) { 31583446Smrj case AGP_NORMAL: 31596742Sms148562 if (PMEMP(mementry->kte_memhdl)->pmem_cookie) { 31606742Sms148562 status = devmap_pmem_setup(cookie, 31616742Sms148562 softstate->asoft_dip, 31626742Sms148562 &agp_devmap_cb, 31636742Sms148562 PMEMP(mementry->kte_memhdl)->pmem_cookie, 31646742Sms148562 local_offset, 31656742Sms148562 len, PROT_ALL, 31666742Sms148562 (DEVMAP_DEFAULTS|IOMEM_DATA_UC_WR_COMBINE), 31676742Sms148562 &mem_dev_acc_attr); 31686742Sms148562 } else { 31696742Sms148562 AGPDB_PRINT2((CE_WARN, 31706742Sms148562 "agpgart_devmap: not a valid memory type")); 31716742Sms148562 return (EINVAL); 31726742Sms148562 31736742Sms148562 } 31746742Sms148562 31753446Smrj break; 31763446Smrj default: 31773446Smrj AGPDB_PRINT2((CE_WARN, 31783446Smrj "agpgart_devmap: not a valid memory type")); 31793446Smrj return (EINVAL); 31803446Smrj } 31813446Smrj 31823446Smrj 31833446Smrj if (status == 0) { 31843446Smrj *mappedlen = len; 31853446Smrj } else { 31863446Smrj *mappedlen = 0; 31873446Smrj AGPDB_PRINT2((CE_WARN, 31883446Smrj "agpgart_devmap: devmap interface failed")); 31893446Smrj return (EINVAL); 31903446Smrj } 31913446Smrj 31923446Smrj return (0); 31933446Smrj } 31943446Smrj 31953446Smrj static struct cb_ops agpgart_cb_ops = { 31963446Smrj agpgart_open, /* open() */ 31973446Smrj agpgart_close, /* close() */ 31983446Smrj nodev, /* strategy() */ 31993446Smrj nodev, /* print routine */ 32003446Smrj nodev, /* no dump routine */ 32013446Smrj nodev, /* read() */ 32023446Smrj nodev, /* write() */ 32033446Smrj agpgart_ioctl, /* agpgart_ioctl */ 32043446Smrj agpgart_devmap, /* devmap routine */ 32053446Smrj nodev, /* no longer use mmap routine */ 32063446Smrj agpgart_segmap, /* system segmap routine */ 32073446Smrj nochpoll, /* no chpoll routine */ 32083446Smrj ddi_prop_op, /* system prop operations */ 32093446Smrj 0, /* not a STREAMS driver */ 32103446Smrj D_DEVMAP | D_MP, /* safe for multi-thread/multi-processor */ 32113446Smrj CB_REV, /* cb_ops version? */ 32123446Smrj nodev, /* cb_aread() */ 32133446Smrj nodev, /* cb_awrite() */ 32143446Smrj }; 32153446Smrj 32163446Smrj static struct dev_ops agpgart_ops = { 32173446Smrj DEVO_REV, /* devo_rev */ 32183446Smrj 0, /* devo_refcnt */ 32193446Smrj agpgart_getinfo, /* devo_getinfo */ 32203446Smrj nulldev, /* devo_identify */ 32213446Smrj nulldev, /* devo_probe */ 32223446Smrj agpgart_attach, /* devo_attach */ 32233446Smrj agpgart_detach, /* devo_detach */ 32243446Smrj nodev, /* devo_reset */ 32253446Smrj &agpgart_cb_ops, /* devo_cb_ops */ 32263446Smrj (struct bus_ops *)0, /* devo_bus_ops */ 32273446Smrj NULL, /* devo_power */ 3228*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* devo_quiesce */ 32293446Smrj }; 32303446Smrj 32313446Smrj static struct modldrv modldrv = { 32323446Smrj &mod_driverops, 3233*7656SSherry.Moore@Sun.COM "AGP driver", 32343446Smrj &agpgart_ops, 32353446Smrj }; 32363446Smrj 32373446Smrj static struct modlinkage modlinkage = { 32383446Smrj MODREV_1, /* MODREV_1 is indicated by manual */ 32393446Smrj {&modldrv, NULL, NULL, NULL} 32403446Smrj }; 32413446Smrj 32423446Smrj static void *agpgart_glob_soft_handle; 32433446Smrj 32443446Smrj int 32453446Smrj _init(void) 32463446Smrj { 32473446Smrj int ret = DDI_SUCCESS; 32483446Smrj 32493446Smrj ret = ddi_soft_state_init(&agpgart_glob_soft_handle, 32504478Skz151634 sizeof (agpgart_softstate_t), 32514478Skz151634 AGPGART_MAX_INSTANCES); 32523446Smrj 32533446Smrj if (ret != 0) { 32543446Smrj AGPDB_PRINT2((CE_WARN, 32553446Smrj "_init: soft state init error code=0x%x", ret)); 32563446Smrj return (ret); 32573446Smrj } 32583446Smrj 32593446Smrj if ((ret = mod_install(&modlinkage)) != 0) { 32603446Smrj AGPDB_PRINT2((CE_WARN, 32613446Smrj "_init: mod install error code=0x%x", ret)); 32623446Smrj ddi_soft_state_fini(&agpgart_glob_soft_handle); 32633446Smrj return (ret); 32643446Smrj } 32653446Smrj 32663446Smrj return (DDI_SUCCESS); 32673446Smrj } 32683446Smrj 32693446Smrj int 32703446Smrj _info(struct modinfo *modinfop) 32713446Smrj { 32723446Smrj return (mod_info(&modlinkage, modinfop)); 32733446Smrj } 32743446Smrj 32753446Smrj int 32763446Smrj _fini(void) 32773446Smrj { 32783446Smrj int ret; 32793446Smrj 32803446Smrj if ((ret = mod_remove(&modlinkage)) == 0) { 32813446Smrj ddi_soft_state_fini(&agpgart_glob_soft_handle); 32823446Smrj } 32833446Smrj 32843446Smrj return (ret); 32853446Smrj } 3286