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