13446Smrj /*
211260SMiao.Chen@Sun.COM * Copyright (c) 2009, Intel Corporation.
311260SMiao.Chen@Sun.COM * All Rights Reserved.
411260SMiao.Chen@Sun.COM */
511260SMiao.Chen@Sun.COM
611260SMiao.Chen@Sun.COM /*
711260SMiao.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
6711260SMiao.Chen@Sun.COM #define AGP_HASH_NODE 1024
6811260SMiao.Chen@Sun.COM
6911260SMiao.Chen@Sun.COM static void
list_head_init(struct list_head * head)7011260SMiao.Chen@Sun.COM list_head_init(struct list_head *head) {
7111260SMiao.Chen@Sun.COM struct list_head *entry, *tmp;
7211260SMiao.Chen@Sun.COM /* HASH for accelerate */
7311260SMiao.Chen@Sun.COM entry = kmem_zalloc(AGP_HASH_NODE *
74*11359SMiao.Chen@Sun.COM sizeof (struct list_head), KM_SLEEP);
7511260SMiao.Chen@Sun.COM head->next = entry;
7611260SMiao.Chen@Sun.COM for (int i = 0; i < AGP_HASH_NODE; i++) {
7711260SMiao.Chen@Sun.COM tmp = &entry[i];
7811260SMiao.Chen@Sun.COM tmp->next = tmp;
7911260SMiao.Chen@Sun.COM tmp->prev = tmp;
8011260SMiao.Chen@Sun.COM tmp->gttseg = NULL;
8111260SMiao.Chen@Sun.COM }
8211260SMiao.Chen@Sun.COM }
8311260SMiao.Chen@Sun.COM
8411260SMiao.Chen@Sun.COM static void
list_head_add_new(struct list_head * head,igd_gtt_seg_t * gttseg)8511260SMiao.Chen@Sun.COM list_head_add_new(struct list_head *head,
8611260SMiao.Chen@Sun.COM igd_gtt_seg_t *gttseg)
8711260SMiao.Chen@Sun.COM {
8811260SMiao.Chen@Sun.COM struct list_head *entry, *tmp;
8911260SMiao.Chen@Sun.COM int key;
90*11359SMiao.Chen@Sun.COM entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
9111260SMiao.Chen@Sun.COM key = gttseg->igs_pgstart % AGP_HASH_NODE;
9211260SMiao.Chen@Sun.COM tmp = &head->next[key];
9311260SMiao.Chen@Sun.COM tmp->next->prev = entry;
9411260SMiao.Chen@Sun.COM entry->next = tmp->next;
9511260SMiao.Chen@Sun.COM entry->prev = tmp;
9611260SMiao.Chen@Sun.COM tmp->next = entry;
9711260SMiao.Chen@Sun.COM entry->gttseg = gttseg;
9811260SMiao.Chen@Sun.COM }
9911260SMiao.Chen@Sun.COM
10011260SMiao.Chen@Sun.COM static void
list_head_del(struct list_head * entry)10111260SMiao.Chen@Sun.COM list_head_del(struct list_head *entry) {
10211260SMiao.Chen@Sun.COM (entry)->next->prev = (entry)->prev; \
10311260SMiao.Chen@Sun.COM (entry)->prev->next = (entry)->next; \
10411260SMiao.Chen@Sun.COM (entry)->gttseg = NULL; \
10511260SMiao.Chen@Sun.COM }
10611260SMiao.Chen@Sun.COM
10711260SMiao.Chen@Sun.COM #define list_head_for_each_safe(entry, temp, head) \
10811260SMiao.Chen@Sun.COM for (int key = 0; key < AGP_HASH_NODE; key++) \
10911260SMiao.Chen@Sun.COM for (entry = (&(head)->next[key])->next, temp = (entry)->next; \
11011260SMiao.Chen@Sun.COM entry != &(head)->next[key]; \
11111260SMiao.Chen@Sun.COM entry = temp, temp = temp->next)
11211260SMiao.Chen@Sun.COM
11311260SMiao.Chen@Sun.COM
1143446Smrj #define agpinfo_default_to_32(v, v32) \
11511260SMiao.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
agp_devmap_unmap(devmap_cookie_t handle,void * devprivate,offset_t off,size_t len,devmap_cookie_t new_handle1,void ** new_devprivate1,devmap_cookie_t new_handle2,void ** new_devprivate2)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
agp_devmap_map(devmap_cookie_t handle,dev_t dev,uint_t flags,offset_t offset,size_t len,void ** new_devprivate)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*/
agp_devmap_dup(devmap_cookie_t handle,void * devprivate,devmap_cookie_t new_handle,void ** new_devprivate)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
agp_master_regis_byname(ldi_handle_t * master_hdlp,ldi_ident_t agpgart_li)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
agp_target_regis_byname(ldi_handle_t * target_hdlp,ldi_ident_t agpgart_li)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
amd64_gart_regis_byname(amd64_garts_dev_t * cpu_garts,ldi_ident_t agpgart_li)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
agp_master_unregister(ldi_handle_t * master_hdlp)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
agp_target_unregister(ldi_handle_t * target_hdlp)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
amd64_gart_unregister(amd64_garts_dev_t * cpu_garts)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
lyr_detect_master_type(ldi_handle_t * master_hdlp)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
lyr_detect_target_type(ldi_handle_t * target_hdlp)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
lyr_init(agp_registered_dev_t * agp_regdev,ldi_ident_t agpgart_li)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
lyr_end(agp_registered_dev_t * agp_regdev)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
lyr_get_info(agp_kern_info_t * info,agp_registered_dev_t * agp_regdev)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
lyr_i8xx_add_to_gtt(uint32_t pg_offset,keytable_ent_t * keyent,agp_registered_dev_t * agp_regdev)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
lyr_i8xx_remove_from_gtt(uint32_t pg_offset,uint32_t npage,agp_registered_dev_t * agp_regdev)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
lyr_set_gart_addr(uint64_t phy_base,agp_registered_dev_t * agp_regdev)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
lyr_set_agp_cmd(uint32_t cmd,agp_registered_dev_t * agp_regdev)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
lyr_config_devices(agp_registered_dev_t * agp_regdev)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
lyr_unconfig_devices(agp_registered_dev_t * agp_regdev)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
lyr_flush_gart_cache(agp_registered_dev_t * agp_regdev)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
118911260SMiao.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
get_max_pages(uint32_t aper_size)11983446Smrj get_max_pages(uint32_t aper_size)
11993446Smrj {
120011260SMiao.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
120711260SMiao.Chen@Sun.COM size = ((i < j) ? i : j);
120811260SMiao.Chen@Sun.COM
120911260SMiao.Chen@Sun.COM if (size < AGP_MB2PAGES(MINAPERMEGAS))
121011260SMiao.Chen@Sun.COM size = AGP_MB2PAGES(MINAPERMEGAS);
121111260SMiao.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 *
agp_fill_empty_keyent(agpgart_softstate_t * softstate,keytable_ent_t * entryp)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 *
agp_find_bound_keyent(agpgart_softstate_t * softstate,uint32_t pg_offset)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
agp_check_off(keytable_ent_t * entryp,uint32_t pg_start,uint32_t pg_num)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
is_controlling_proc(agpgart_softstate_t * st)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
release_control(agpgart_softstate_t * st)13683446Smrj static void release_control(agpgart_softstate_t *st)
13693446Smrj {
13703446Smrj st->asoft_curpid = 0;
13713446Smrj st->asoft_acquired = 0;
13723446Smrj }
13733446Smrj
acquire_control(agpgart_softstate_t * st)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
agp_remove_from_gart(uint32_t pg_offset,uint32_t entries,ddi_dma_handle_t dma_hdl,uint32_t * tablep)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
agp_unbind_key(agpgart_softstate_t * softstate,keytable_ent_t * entryp)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
agp_dealloc_kmem(keytable_ent_t * entryp)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
agp_dealloc_mem(agpgart_softstate_t * st,keytable_ent_t * entryp)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
agp_del_allkeys(agpgart_softstate_t * softstate)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
pfn2gartentry(agp_arc_type_t arc_type,pfn_t pfn,uint32_t * itemv)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
agp_check_pfns(agp_arc_type_t arc_type,pfn_t * pfnarray,int items)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
kmem_getpfns(ddi_dma_handle_t dma_handle,ddi_dma_cookie_t * dma_cookiep,int cookies_num,pfn_t * pfnarray)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
copyinfo(agpgart_softstate_t * softstate,agp_info_t * info)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
agp_v2_setup(uint32_t tstatus,uint32_t mstatus,uint32_t mode)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
agp_v3_setup(uint32_t tstatus,uint32_t mstatus,uint32_t mode)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
agp_setup(agpgart_softstate_t * softstate,uint32_t mode)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 *
agp_alloc_kmem(agpgart_softstate_t * softstate,size_t length,int type)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 *
agp_alloc_mem(agpgart_softstate_t * st,size_t length,int type)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
free_gart_table(agpgart_softstate_t * st)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
alloc_gart_table(agpgart_softstate_t * st)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
agp_add_to_gart(agp_arc_type_t type,pfn_t * pfnarray,uint32_t pg_offset,uint32_t entries,ddi_dma_handle_t dma_hdl,uint32_t * tablep)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
agp_bind_key(agpgart_softstate_t * softstate,keytable_ent_t * keyent,uint32_t pg_offset)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
agpgart_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
249711260SMiao.Chen@Sun.COM list_head_init(&softstate->mapped_list);
249811260SMiao.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
agpgart_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
254511260SMiao.Chen@Sun.COM struct list_head *entry, *temp, *head;
254611260SMiao.Chen@Sun.COM igd_gtt_seg_t *gttseg;
254711260SMiao.Chen@Sun.COM list_head_for_each_safe(entry, temp, &st->mapped_list) {
254811260SMiao.Chen@Sun.COM gttseg = entry->gttseg;
254911260SMiao.Chen@Sun.COM list_head_del(entry);
255011260SMiao.Chen@Sun.COM kmem_free(entry, sizeof (*entry));
255111260SMiao.Chen@Sun.COM kmem_free(gttseg->igs_phyaddr,
255211260SMiao.Chen@Sun.COM sizeof (uint32_t) * gttseg->igs_npage);
255311260SMiao.Chen@Sun.COM kmem_free(gttseg, sizeof (igd_gtt_seg_t));
255411260SMiao.Chen@Sun.COM }
255511260SMiao.Chen@Sun.COM head = &st->mapped_list;
255611260SMiao.Chen@Sun.COM kmem_free(head->next,
255711260SMiao.Chen@Sun.COM AGP_HASH_NODE * sizeof (struct list_head));
255811260SMiao.Chen@Sun.COM head->next = NULL;
255911260SMiao.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
agpgart_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)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
agpgart_open(dev_t * dev,int openflags,int otyp,cred_t * credp)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;
263311260SMiao.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 }
268911260SMiao.Chen@Sun.COM devid = softstate->asoft_info.agpki_mdevid;
269011260SMiao.Chen@Sun.COM if (IS_INTEL_915(devid) ||
269111260SMiao.Chen@Sun.COM IS_INTEL_965(devid) ||
269211260SMiao.Chen@Sun.COM IS_INTEL_X33(devid) ||
269311260SMiao.Chen@Sun.COM IS_INTEL_G4X(devid)) {
269411260SMiao.Chen@Sun.COM rc = ldi_ioctl(softstate->asoft_devreg.agprd_targethdl,
269511260SMiao.Chen@Sun.COM INTEL_CHIPSET_FLUSH_SETUP, 0, FKIOCTL, kcred, 0);
269611260SMiao.Chen@Sun.COM }
269711260SMiao.Chen@Sun.COM if (rc) {
269811260SMiao.Chen@Sun.COM AGPDB_PRINT2((CE_WARN,
269911260SMiao.Chen@Sun.COM "agpgart_open: Intel chipset flush setup error"));
270011260SMiao.Chen@Sun.COM lyr_end(&softstate->asoft_devreg);
270111260SMiao.Chen@Sun.COM mutex_exit(&softstate->asoft_instmutex);
270211260SMiao.Chen@Sun.COM return (EIO);
270311260SMiao.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
agpgart_close(dev_t dev,int flag,int otyp,cred_t * credp)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;
279011260SMiao.Chen@Sun.COM int rc = 0;
279111260SMiao.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
281511260SMiao.Chen@Sun.COM devid = softstate->asoft_info.agpki_mdevid;
281611260SMiao.Chen@Sun.COM if (IS_INTEL_915(devid) ||
281711260SMiao.Chen@Sun.COM IS_INTEL_965(devid) ||
281811260SMiao.Chen@Sun.COM IS_INTEL_X33(devid) ||
281911260SMiao.Chen@Sun.COM IS_INTEL_G4X(devid)) {
282011260SMiao.Chen@Sun.COM rc = ldi_ioctl(softstate->asoft_devreg.agprd_targethdl,
282111260SMiao.Chen@Sun.COM INTEL_CHIPSET_FLUSH_FREE, 0, FKIOCTL, kcred, 0);
282211260SMiao.Chen@Sun.COM }
282311260SMiao.Chen@Sun.COM if (rc) {
282411260SMiao.Chen@Sun.COM AGPDB_PRINT2((CE_WARN,
282511260SMiao.Chen@Sun.COM "agpgart_open: Intel chipset flush free error"));
282611260SMiao.Chen@Sun.COM }
282711260SMiao.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
ioctl_agpgart_info(agpgart_softstate_t * softstate,void * arg,int flags)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
ioctl_agpgart_acquire(agpgart_softstate_t * st)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
ioctl_agpgart_release(agpgart_softstate_t * st)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
ioctl_agpgart_setup(agpgart_softstate_t * st,void * arg,int flags)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
ioctl_agpgart_alloc(agpgart_softstate_t * st,void * arg,int flags)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
ioctl_agpgart_dealloc(agpgart_softstate_t * st,intptr_t arg)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
ioctl_agpgart_bind(agpgart_softstate_t * st,void * arg,int flags)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
ioctl_agpgart_unbind(agpgart_softstate_t * st,void * arg,int flags)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
312711260SMiao.Chen@Sun.COM static int
ioctl_agpgart_flush_chipset(agpgart_softstate_t * st)312811260SMiao.Chen@Sun.COM ioctl_agpgart_flush_chipset(agpgart_softstate_t *st)
312911260SMiao.Chen@Sun.COM {
313011260SMiao.Chen@Sun.COM ldi_handle_t hdl;
313111260SMiao.Chen@Sun.COM uint32_t devid;
313211260SMiao.Chen@Sun.COM int rc = 0;
313311260SMiao.Chen@Sun.COM devid = st->asoft_info.agpki_mdevid;
313411260SMiao.Chen@Sun.COM hdl = st->asoft_devreg.agprd_targethdl;
313511260SMiao.Chen@Sun.COM if (IS_INTEL_915(devid) ||
313611260SMiao.Chen@Sun.COM IS_INTEL_965(devid) ||
313711260SMiao.Chen@Sun.COM IS_INTEL_X33(devid) ||
313811260SMiao.Chen@Sun.COM IS_INTEL_G4X(devid)) {
313911260SMiao.Chen@Sun.COM rc = ldi_ioctl(hdl, INTEL_CHIPSET_FLUSH, 0, FKIOCTL, kcred, 0);
314011260SMiao.Chen@Sun.COM }
314111260SMiao.Chen@Sun.COM return (rc);
314211260SMiao.Chen@Sun.COM }
314311260SMiao.Chen@Sun.COM
314411260SMiao.Chen@Sun.COM static int
ioctl_agpgart_pages_bind(agpgart_softstate_t * st,void * arg,int flags)314511260SMiao.Chen@Sun.COM ioctl_agpgart_pages_bind(agpgart_softstate_t *st, void *arg, int flags)
314611260SMiao.Chen@Sun.COM {
314711260SMiao.Chen@Sun.COM agp_bind_pages_t bind_info;
314811260SMiao.Chen@Sun.COM uint32_t pg_offset;
314911260SMiao.Chen@Sun.COM int err = 0;
315011260SMiao.Chen@Sun.COM ldi_handle_t hdl;
315111260SMiao.Chen@Sun.COM uint32_t npages;
315211260SMiao.Chen@Sun.COM igd_gtt_seg_t *gttseg;
315311260SMiao.Chen@Sun.COM uint32_t i;
315411260SMiao.Chen@Sun.COM int rval;
315511260SMiao.Chen@Sun.COM if (ddi_copyin(arg, &bind_info,
315611260SMiao.Chen@Sun.COM sizeof (agp_bind_pages_t), flags) != 0) {
315711260SMiao.Chen@Sun.COM return (EFAULT);
315811260SMiao.Chen@Sun.COM }
315911260SMiao.Chen@Sun.COM
316011260SMiao.Chen@Sun.COM gttseg = (igd_gtt_seg_t *)kmem_zalloc(sizeof (igd_gtt_seg_t),
316111260SMiao.Chen@Sun.COM KM_SLEEP);
316211260SMiao.Chen@Sun.COM
316311260SMiao.Chen@Sun.COM pg_offset = bind_info.agpb_pgstart;
316411260SMiao.Chen@Sun.COM
316511260SMiao.Chen@Sun.COM gttseg->igs_pgstart = pg_offset;
316611260SMiao.Chen@Sun.COM npages = (uint32_t)bind_info.agpb_pgcount;
316711260SMiao.Chen@Sun.COM gttseg->igs_npage = npages;
316811260SMiao.Chen@Sun.COM
316911260SMiao.Chen@Sun.COM gttseg->igs_type = AGP_NORMAL;
317011260SMiao.Chen@Sun.COM gttseg->igs_phyaddr = (uint32_t *)kmem_zalloc
317111260SMiao.Chen@Sun.COM (sizeof (uint32_t) * gttseg->igs_npage, KM_SLEEP);
317211260SMiao.Chen@Sun.COM
317311260SMiao.Chen@Sun.COM for (i = 0; i < npages; i++) {
317411260SMiao.Chen@Sun.COM gttseg->igs_phyaddr[i] = bind_info.agpb_pages[i] <<
317511260SMiao.Chen@Sun.COM GTT_PAGE_SHIFT;
317611260SMiao.Chen@Sun.COM }
317711260SMiao.Chen@Sun.COM
317811260SMiao.Chen@Sun.COM hdl = st->asoft_devreg.agprd_masterhdl;
317911260SMiao.Chen@Sun.COM if (ldi_ioctl(hdl, I8XX_ADD2GTT, (intptr_t)gttseg, FKIOCTL,
318011260SMiao.Chen@Sun.COM kcred, &rval)) {
318111260SMiao.Chen@Sun.COM AGPDB_PRINT2((CE_WARN, "ioctl_agpgart_pages_bind: start0x%x",
318211260SMiao.Chen@Sun.COM gttseg->igs_pgstart));
318311260SMiao.Chen@Sun.COM AGPDB_PRINT2((CE_WARN, "ioctl_agpgart_pages_bind: pages=0x%x",
318411260SMiao.Chen@Sun.COM gttseg->igs_npage));
318511260SMiao.Chen@Sun.COM AGPDB_PRINT2((CE_WARN, "ioctl_agpgart_pages_bind: type=0x%x",
318611260SMiao.Chen@Sun.COM gttseg->igs_type));
318711260SMiao.Chen@Sun.COM err = -1;
318811260SMiao.Chen@Sun.COM }
318911260SMiao.Chen@Sun.COM
319011260SMiao.Chen@Sun.COM list_head_add_new(&st->mapped_list, gttseg);
319111260SMiao.Chen@Sun.COM return (err);
319211260SMiao.Chen@Sun.COM }
319311260SMiao.Chen@Sun.COM
319411260SMiao.Chen@Sun.COM static int
ioctl_agpgart_pages_unbind(agpgart_softstate_t * st,void * arg,int flags)319511260SMiao.Chen@Sun.COM ioctl_agpgart_pages_unbind(agpgart_softstate_t *st, void *arg, int flags)
319611260SMiao.Chen@Sun.COM {
319711260SMiao.Chen@Sun.COM agp_unbind_pages_t unbind_info;
319811260SMiao.Chen@Sun.COM int rval;
319911260SMiao.Chen@Sun.COM ldi_handle_t hdl;
320011260SMiao.Chen@Sun.COM igd_gtt_seg_t *gttseg;
320111260SMiao.Chen@Sun.COM
320211260SMiao.Chen@Sun.COM if (ddi_copyin(arg, &unbind_info, sizeof (unbind_info), flags) != 0) {
320311260SMiao.Chen@Sun.COM return (EFAULT);
320411260SMiao.Chen@Sun.COM }
320511260SMiao.Chen@Sun.COM
320611260SMiao.Chen@Sun.COM struct list_head *entry, *temp;
320711260SMiao.Chen@Sun.COM list_head_for_each_safe(entry, temp, &st->mapped_list) {
320811260SMiao.Chen@Sun.COM if (entry->gttseg->igs_pgstart == unbind_info.agpb_pgstart) {
320911260SMiao.Chen@Sun.COM gttseg = entry->gttseg;
321011260SMiao.Chen@Sun.COM /* not unbind if VT switch */
321111260SMiao.Chen@Sun.COM if (unbind_info.agpb_type) {
321211260SMiao.Chen@Sun.COM list_head_del(entry);
321311260SMiao.Chen@Sun.COM kmem_free(entry, sizeof (*entry));
321411260SMiao.Chen@Sun.COM }
321511260SMiao.Chen@Sun.COM break;
321611260SMiao.Chen@Sun.COM }
321711260SMiao.Chen@Sun.COM }
321811260SMiao.Chen@Sun.COM ASSERT(gttseg != NULL);
321911260SMiao.Chen@Sun.COM gttseg->igs_pgstart = unbind_info.agpb_pgstart;
322011260SMiao.Chen@Sun.COM ASSERT(gttseg->igs_npage == unbind_info.agpb_pgcount);
322111260SMiao.Chen@Sun.COM
322211260SMiao.Chen@Sun.COM hdl = st->asoft_devreg.agprd_masterhdl;
322311260SMiao.Chen@Sun.COM if (ldi_ioctl(hdl, I8XX_REM_GTT, (intptr_t)gttseg, FKIOCTL,
322411260SMiao.Chen@Sun.COM kcred, &rval))
322511260SMiao.Chen@Sun.COM return (-1);
322611260SMiao.Chen@Sun.COM
322711260SMiao.Chen@Sun.COM if (unbind_info.agpb_type) {
322811260SMiao.Chen@Sun.COM kmem_free(gttseg->igs_phyaddr, sizeof (uint32_t) *
322911260SMiao.Chen@Sun.COM gttseg->igs_npage);
323011260SMiao.Chen@Sun.COM kmem_free(gttseg, sizeof (igd_gtt_seg_t));
323111260SMiao.Chen@Sun.COM }
323211260SMiao.Chen@Sun.COM
323311260SMiao.Chen@Sun.COM return (0);
323411260SMiao.Chen@Sun.COM }
323511260SMiao.Chen@Sun.COM
323611260SMiao.Chen@Sun.COM static int
ioctl_agpgart_pages_rebind(agpgart_softstate_t * st)323711260SMiao.Chen@Sun.COM ioctl_agpgart_pages_rebind(agpgart_softstate_t *st)
323811260SMiao.Chen@Sun.COM {
323911260SMiao.Chen@Sun.COM int rval;
324011260SMiao.Chen@Sun.COM ldi_handle_t hdl;
324111260SMiao.Chen@Sun.COM igd_gtt_seg_t *gttseg;
324211260SMiao.Chen@Sun.COM int err = 0;
324311260SMiao.Chen@Sun.COM
324411260SMiao.Chen@Sun.COM hdl = st->asoft_devreg.agprd_masterhdl;
324511260SMiao.Chen@Sun.COM struct list_head *entry, *temp;
324611260SMiao.Chen@Sun.COM list_head_for_each_safe(entry, temp, &st->mapped_list) {
324711260SMiao.Chen@Sun.COM gttseg = entry->gttseg;
324811260SMiao.Chen@Sun.COM list_head_del(entry);
324911260SMiao.Chen@Sun.COM kmem_free(entry, sizeof (*entry));
325011260SMiao.Chen@Sun.COM if (ldi_ioctl(hdl, I8XX_ADD2GTT, (intptr_t)gttseg, FKIOCTL,
325111260SMiao.Chen@Sun.COM kcred, &rval)) {
325211260SMiao.Chen@Sun.COM AGPDB_PRINT2((CE_WARN, "agpgart_pages_rebind errori"));
325311260SMiao.Chen@Sun.COM err = -1;
325411260SMiao.Chen@Sun.COM break;
325511260SMiao.Chen@Sun.COM }
325611260SMiao.Chen@Sun.COM kmem_free(gttseg->igs_phyaddr, sizeof (uint32_t) *
325711260SMiao.Chen@Sun.COM gttseg->igs_npage);
325811260SMiao.Chen@Sun.COM kmem_free(gttseg, sizeof (igd_gtt_seg_t));
325911260SMiao.Chen@Sun.COM
326011260SMiao.Chen@Sun.COM }
326111260SMiao.Chen@Sun.COM return (err);
326211260SMiao.Chen@Sun.COM
326311260SMiao.Chen@Sun.COM }
326411260SMiao.Chen@Sun.COM
32653446Smrj /*ARGSUSED*/
32663446Smrj static int
agpgart_ioctl(dev_t dev,int cmd,intptr_t intarg,int flags,cred_t * credp,int * rvalp)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;
331011260SMiao.Chen@Sun.COM case AGPIOC_FLUSHCHIPSET:
331111260SMiao.Chen@Sun.COM retval = ioctl_agpgart_flush_chipset(softstate);
331211260SMiao.Chen@Sun.COM break;
331311260SMiao.Chen@Sun.COM case AGPIOC_PAGES_BIND:
331411260SMiao.Chen@Sun.COM retval = ioctl_agpgart_pages_bind(softstate, arg, flags);
331511260SMiao.Chen@Sun.COM break;
331611260SMiao.Chen@Sun.COM case AGPIOC_PAGES_UNBIND:
331711260SMiao.Chen@Sun.COM retval = ioctl_agpgart_pages_unbind(softstate, arg, flags);
331811260SMiao.Chen@Sun.COM break;
331911260SMiao.Chen@Sun.COM case AGPIOC_PAGES_REBIND:
332011260SMiao.Chen@Sun.COM retval = ioctl_agpgart_pages_rebind(softstate);
332111260SMiao.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
agpgart_segmap(dev_t dev,off_t off,struct as * asp,caddr_t * addrp,off_t len,unsigned int prot,unsigned int maxprot,unsigned int flags,cred_t * credp)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
agpgart_devmap(dev_t dev,devmap_cookie_t cookie,offset_t offset,size_t len,size_t * mappedlen,uint_t model)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
_init(void)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
_info(struct modinfo * modinfop)35143446Smrj _info(struct modinfo *modinfop)
35153446Smrj {
35163446Smrj return (mod_info(&modlinkage, modinfop));
35173446Smrj }
35183446Smrj
35193446Smrj int
_fini(void)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