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