diff --git a/sys/dev/drm/drmP.h b/sys/dev/drm/drmP.h index eb91214..84f6ad5 100644 --- a/sys/dev/drm/drmP.h +++ b/sys/dev/drm/drmP.h @@ -472,13 +472,16 @@ typedef struct drm_agp_head { unsigned long page_mask; } drm_agp_head_t; -typedef struct drm_sg_mem { - unsigned long handle; - void *virtual; - int pages; - dma_addr_t *busaddr; - drm_dma_handle_t *dmah; /* Handle to PCI memory for ATI PCIGART table */ -} drm_sg_mem_t; +struct drm_sg_mem { + unsigned long handle; + void *virtual; + int pages; + dma_addr_t *busaddr; + /* Handle to allocated sg pages */ + struct drm_dma_handle *sg_dmah; + /* Handle to PCI memory for ATI PCIGART table */ + struct drm_dma_handle *dmah; +}; typedef TAILQ_HEAD(drm_map_list, drm_local_map) drm_map_list_t; @@ -617,93 +620,116 @@ struct drm_device { struct drm_driver_info *driver; drm_pci_id_list_t *id_entry; /* PCI ID, name, and chipset private */ - u_int16_t pci_device; /* PCI device id */ - u_int16_t pci_vendor; /* PCI vendor id */ - - char *unique; /* Unique identifier: e.g., busid */ - int unique_len; /* Length of unique field */ - device_t device; /* Device instance from newbus */ - struct cdev *devnode; /* Device number for mknod */ - int if_version; /* Highest interface version set */ + u_int16_t pci_device; /* PCI device id */ + u_int16_t pci_vendor; /* PCI vendor id */ - int flags; /* Flags to open(2) */ + char *unique; /* Unique identifier: e.g., busid */ + int unique_len; /* Length of unique field */ + device_t device; /* Device instance from newbus */ + struct cdev *devnode; /* Device number for mknod */ + int if_version; /* Highest interface version set */ - /* Locks */ - struct mtx vbl_lock; /* protects vblank operations */ - struct mtx dma_lock; /* protects dev->dma */ - struct mtx irq_lock; /* protects irq condition checks */ - struct mtx dev_lock; /* protects everything else */ - DRM_SPINTYPE drw_lock; - DRM_SPINTYPE tsk_lock; + int flags; /* Flags to open(2) */ - /* Usage Counters */ - int open_count; /* Outstanding files open */ - int buf_use; /* Buffers in use -- cannot alloc */ + /* + * Locks + */ + struct mtx vbl_lock;/* protects vblank operations */ + struct mtx dma_lock;/* protects dev->dma */ + struct mtx irq_lock;/* protects irq condition checks */ + struct mtx dev_lock;/* protects everything else */ + DRM_SPINTYPE drw_lock; + DRM_SPINTYPE tsk_lock; + + /* + * Usage Counters + */ + /* Outstanding files open */ + int open_count; + /* Buffers in use -- cannot alloc */ + int buf_use; - /* Performance counters */ - unsigned long counters; - enum drm_stat_type types[15]; - atomic_t counts[15]; + /* + * Performance counters + */ + unsigned long counters; + enum drm_stat_type types[15]; + atomic_t counts[15]; - /* Authentication */ - drm_file_list_t files; - drm_magic_head_t magiclist[DRM_HASH_SIZE]; + /* + * Authentication + */ + drm_file_list_t files; + drm_magic_head_t magiclist[DRM_HASH_SIZE]; /* Linked list of mappable regions. Protected by dev_lock */ - drm_map_list_t maplist; - - drm_local_map_t **context_sareas; - int max_context; - - drm_lock_data_t lock; /* Information on hardware lock */ - - /* DMA queues (contexts) */ - drm_device_dma_t *dma; /* Optional pointer for DMA support */ + drm_map_list_t maplist; - /* Context support */ - int irq; /* Interrupt used by board */ - int irq_enabled; /* True if the irq handler is enabled */ - int irqrid; /* Interrupt used by board */ - struct resource *irqr; /* Resource for interrupt used by board */ - void *irqh; /* Handle from bus_setup_intr */ + /* + * Context support + */ + drm_local_map_t **context_sareas; + int max_context; + /* Context swapping flag */ + atomic_t context_flag; + /* Last current context */ + int last_context; + + /* Information on hardware lock */ + drm_lock_data_t lock; + + /* Optional pointer for DMA support */ + drm_device_dma_t *dma; + + /* Interrupt used by board */ + int irq; + /* True if the irq handler is enabled */ + int irq_enabled; + /* Interrupt resource id used by board */ + int irqrid; + /* Resource for interrupt used by board */ + struct resource *irqr; + /* Handle from bus_setup_intr */ + void *irqh; /* Storage of resource pointers for drm_get_resource_* */ - struct resource *pcir[DRM_MAX_PCI_RESOURCE]; - int pcirid[DRM_MAX_PCI_RESOURCE]; - - int pci_domain; - int pci_bus; - int pci_slot; - int pci_func; - - atomic_t context_flag; /* Context swapping flag */ - int last_context; /* Last current context */ - - int vblank_disable_allowed; - atomic_t vbl_signal_pending; /* number of signals pending on all crtcs */ - struct callout vblank_disable_timer; - u32 max_vblank_count; /* size of vblank counter register */ - struct drm_vblank_info *vblank; /* per crtc vblank info */ - int num_crtcs; - - struct sigio *buf_sigio; /* Processes waiting for SIGIO */ - - /* Sysctl support */ - struct drm_sysctl_info *sysctl; - - drm_agp_head_t *agp; - drm_sg_mem_t *sg; /* Scatter gather memory */ - atomic_t *ctx_bitmap; - void *dev_private; - unsigned int agp_buffer_token; - drm_local_map_t *agp_buffer_map; - - struct unrhdr *drw_unrhdr; + struct resource *pcir[DRM_MAX_PCI_RESOURCE]; + int pcirid[DRM_MAX_PCI_RESOURCE]; + + int pci_domain; + int pci_bus; + int pci_slot; + int pci_func; + + int vblank_disable_allowed; + /* number of signals pending on all crtcs */ + atomic_t vbl_signal_pending; + struct callout vblank_disable_timer; + /* size of vblank counter register */ + u32 max_vblank_count; + /* per crtc vblank info */ + struct drm_vblank_info *vblank; + int num_crtcs; + /* Processes waiting for SIGIO */ + struct sigio *buf_sigio; + + /* Sysctl support */ + struct drm_sysctl_info *sysctl; + + drm_agp_head_t *agp; + /* Scatter gather memory */ + struct drm_sg_mem *sg; + atomic_t *ctx_bitmap; + void *dev_private; + unsigned int agp_buffer_token; + drm_local_map_t *agp_buffer_map; + + struct unrhdr *drw_unrhdr; /* RB tree of drawable infos */ RB_HEAD(drawable_tree, bsd_drm_drawable_info) drw_head; - struct task locked_task; - void (*locked_task_call)(struct drm_device *dev); + struct task locked_task; + void (*locked_task_call)(struct drm_device *dev); }; static __inline__ int drm_core_check_feature(struct drm_device *dev, @@ -822,7 +848,7 @@ int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request); int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request); /* Scatter Gather Support (drm_scatter.c) */ -void drm_sg_cleanup(drm_sg_mem_t *entry); +void drm_sg_cleanup(struct drm_sg_mem *entry); int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request); /* sysctl support (drm_sysctl.h) */ diff --git a/sys/dev/drm/drm_scatter.c b/sys/dev/drm/drm_scatter.c index c94976a..bf0cbeb 100644 --- a/sys/dev/drm/drm_scatter.c +++ b/sys/dev/drm/drm_scatter.c @@ -39,20 +39,16 @@ __FBSDID("$FreeBSD$"); #include "dev/drm/drmP.h" -#define DEBUG_SCATTER 0 +static void drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, + int nsegs, int error); -void drm_sg_cleanup(drm_sg_mem_t *entry) +int +drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request) { - free((void *)entry->handle, DRM_MEM_PAGES); - free(entry->busaddr, DRM_MEM_PAGES); - free(entry, DRM_MEM_SGLISTS); -} - -int drm_sg_alloc(struct drm_device * dev, struct drm_scatter_gather * request) -{ - drm_sg_mem_t *entry; + struct drm_sg_mem *entry; + struct drm_dma_handle *dmah; unsigned long pages; - int i; + int ret; if (dev->sg) return EINVAL; @@ -69,21 +65,56 @@ int drm_sg_alloc(struct drm_device * dev, struct drm_scatter_gather * request) entry->busaddr = malloc(pages * sizeof(*entry->busaddr), DRM_MEM_PAGES, M_WAITOK | M_ZERO); if (!entry->busaddr) { - drm_sg_cleanup(entry); + free(entry, DRM_MEM_SGLISTS); return ENOMEM; } - entry->handle = (long)malloc(pages << PAGE_SHIFT, DRM_MEM_PAGES, - M_WAITOK | M_ZERO); - if (entry->handle == 0) { - drm_sg_cleanup(entry); + dmah = malloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA, + M_ZERO | M_NOWAIT); + if (dmah == NULL) { + free(entry->busaddr, DRM_MEM_PAGES); + free(entry, DRM_MEM_SGLISTS); + return ENOMEM; + } + + ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */ + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ + NULL, NULL, /* filtfunc, filtfuncargs */ + request->size, pages, /* maxsize, nsegs */ + PAGE_SIZE, 0, /* maxsegsize, flags */ + NULL, NULL, /* lockfunc, lockfuncargs */ + &dmah->tag); + if (ret != 0) { + free(dmah, DRM_MEM_DMA); + free(entry->busaddr, DRM_MEM_PAGES); + free(entry, DRM_MEM_SGLISTS); return ENOMEM; } - for (i = 0; i < pages; i++) { - entry->busaddr[i] = vtophys(entry->handle + i * PAGE_SIZE); + ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &dmah->map); + if (ret != 0) { + bus_dma_tag_destroy(dmah->tag); + free(dmah, DRM_MEM_DMA); + free(entry->busaddr, DRM_MEM_PAGES); + free(entry, DRM_MEM_SGLISTS); + return ENOMEM; } + ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, + request->size, drm_sg_alloc_cb, entry, 0); + if (ret != 0) { + bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); + bus_dma_tag_destroy(dmah->tag); + free(dmah, DRM_MEM_DMA); + free(entry->busaddr, DRM_MEM_PAGES); + free(entry, DRM_MEM_SGLISTS); + return ENOMEM; + } + + entry->sg_dmah = dmah; + entry->handle = (unsigned long)dmah->vaddr; + DRM_DEBUG("sg alloc handle = %08lx\n", entry->handle); entry->virtual = (void *)entry->handle; @@ -101,22 +132,49 @@ int drm_sg_alloc(struct drm_device * dev, struct drm_scatter_gather * request) return 0; } -int drm_sg_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +static void +drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct drm_sg_mem *entry = arg; + int i; + + if (error != 0) + return; + + for(i = 0 ; i < nsegs ; i++) { + entry->busaddr[i] = segs[i].ds_addr; + } +} + +int +drm_sg_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_scatter_gather *request = data; - int ret; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("\n"); + + return drm_sg_alloc(dev, request); +} - ret = drm_sg_alloc(dev, request); - return ret; +void +drm_sg_cleanup(struct drm_sg_mem *entry) +{ + struct drm_dma_handle *dmah = entry->sg_dmah; + + bus_dmamap_unload(dmah->tag, dmah->map); + bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); + bus_dma_tag_destroy(dmah->tag); + free(dmah, DRM_MEM_DMA); + free(entry->busaddr, DRM_MEM_PAGES); + free(entry, DRM_MEM_SGLISTS); } -int drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_scatter_gather *request = data; - drm_sg_mem_t *entry; + struct drm_sg_mem *entry; DRM_LOCK(); entry = dev->sg;