diff options
-rw-r--r-- | harddoomdev.c | 199 | ||||
-rw-r--r-- | harddoomdev.h | 4 | ||||
-rw-r--r-- | pci.c | 19 | ||||
-rw-r--r-- | private_data.h | 10 | ||||
-rw-r--r-- | surface.c | 20 |
5 files changed, 174 insertions, 78 deletions
diff --git a/harddoomdev.c b/harddoomdev.c index 823e868..26eb34e 100644 --- a/harddoomdev.c +++ b/harddoomdev.c @@ -6,6 +6,8 @@ #include "private_data.h" #include "util.h" +#define PING_FREQUENCY 0x80 + void doomdev_write(void __iomem *iomem, size_t addr, uint32_t data) { iowrite32(data, iomem + addr); @@ -21,11 +23,44 @@ void write_command(void __iomem *iomem, uint32_t command) doomdev_write(iomem, HARDDOOM_FIFO_SEND, command); } -void send_command(void __iomem *iomem, uint32_t command) +void enable_intr(void __iomem *iomem, uint32_t intr) +{ + uint32_t interrupts; + + interrupts = doomdev_read(iomem, HARDDOOM_INTR_ENABLE); + doomdev_write(iomem, HARDDOOM_INTR_ENABLE, interrupts | intr); +} + +void disable_intr(void __iomem *iomem, uint32_t intr) { - while (doomdev_read(iomem, HARDDOOM_FIFO_FREE) == 0) {} + uint32_t interrupts; - write_command(iomem, command); + interrupts = doomdev_read(iomem, HARDDOOM_INTR_ENABLE); + doomdev_write(iomem, HARDDOOM_INTR_ENABLE, interrupts & (~intr)); +} + +void send_command(struct doom_data *doom_data, uint32_t command) +{ + uint32_t free; + + free = doomdev_read(doom_data->iomem, HARDDOOM_FIFO_FREE); + if (free == 0) { + deactivate_intr(doom_data->iomem, HARDDOOM_INTR_PONG_ASYNC); + } + + if (free == 0) { + enable_intr(doom_data->iomem, HARDDOOM_INTR_PONG_ASYNC); + down(&doom_data->pong_async_sem); + } + + if (doom_data->cmd_counter > PING_FREQUENCY) { + doom_data->cmd_counter = 0; + write_command(doom_data->iomem, HARDDOOM_CMD_PING_ASYNC); + } else { + doom_data->cmd_counter++; + } + + write_command(doom_data->iomem, command); } uint32_t get_interrupts(void __iomem *iomem) @@ -33,134 +68,157 @@ uint32_t get_interrupts(void __iomem *iomem) return doomdev_read(iomem, HARDDOOM_INTR); } +uint32_t get_enabled_interrupts(void __iomem *iomem) +{ + return doomdev_read(iomem, HARDDOOM_INTR_ENABLE); +} + void deactivate_intr(void __iomem *iomem, uint32_t intr) { doomdev_write(iomem, HARDDOOM_INTR, intr); } -void ping_sync(void __iomem *iomem) +void ping_sync(struct doom_data *doom_data) { - send_command(iomem, HARDDOOM_CMD_PING_SYNC); + send_command(doom_data, HARDDOOM_CMD_PING_SYNC); } -void set_surf_src_pt(void __iomem *iomem, dma_addr_t page_table) +void set_surf_src_pt(struct doom_data *doom_data, dma_addr_t page_table) { - send_command(iomem, HARDDOOM_CMD_SURF_SRC_PT(page_table)); + send_command(doom_data, HARDDOOM_CMD_SURF_SRC_PT(page_table)); } -void set_surf_dst_pt(void __iomem *iomem, dma_addr_t page_table) +void set_surf_dst_pt(struct doom_data *doom_data, dma_addr_t page_table) { - send_command(iomem, HARDDOOM_CMD_SURF_DST_PT(page_table)); + send_command(doom_data, HARDDOOM_CMD_SURF_DST_PT(page_table)); } -void set_surf_dims(void __iomem *iomem, uint32_t width, uint32_t height) +void set_surf_dims(struct doom_data *doom_data, uint32_t width, uint32_t height) { - send_command(iomem, HARDDOOM_CMD_SURF_DIMS(width, height)); + send_command(doom_data, HARDDOOM_CMD_SURF_DIMS(width, height)); } -void set_xy_a(void __iomem *iomem, uint16_t x, uint16_t y) +void set_xy_a(struct doom_data *doom_data, uint16_t x, uint16_t y) { - send_command(iomem, HARDDOOM_CMD_XY_A(x, y)); + send_command(doom_data, HARDDOOM_CMD_XY_A(x, y)); } -void set_xy_b(void __iomem *iomem, uint16_t x, uint16_t y) +void set_xy_b(struct doom_data *doom_data, uint16_t x, uint16_t y) { - send_command(iomem, HARDDOOM_CMD_XY_B(x, y)); + send_command(doom_data, HARDDOOM_CMD_XY_B(x, y)); } -void set_fill_color(void __iomem *iomem, uint8_t color) +void set_fill_color(struct doom_data *doom_data, uint8_t color) { - send_command(iomem, HARDDOOM_CMD_FILL_COLOR(color)); + send_command(doom_data, HARDDOOM_CMD_FILL_COLOR(color)); } -void set_texture_pt(void __iomem *iomem, dma_addr_t page_table_dev) +void set_texture_pt(struct doom_data *doom_data, dma_addr_t page_table_dev) { - send_command(iomem, HARDDOOM_CMD_TEXTURE_PT(page_table_dev)); + send_command(doom_data, HARDDOOM_CMD_TEXTURE_PT(page_table_dev)); } -void set_texture_dims(void __iomem *iomem, uint32_t size, uint16_t height) +void set_texture_dims(struct doom_data *doom_data, uint32_t size, uint16_t height) { - send_command(iomem, HARDDOOM_CMD_TEXTURE_DIMS(size,height)); + send_command(doom_data, HARDDOOM_CMD_TEXTURE_DIMS(size,height)); } -void set_ustart(void __iomem *iomem, uint32_t ustart) +void set_flat(struct doom_data *doom_data, dma_addr_t flat_dev) { - send_command(iomem, HARDDOOM_CMD_USTART(ustart)); + send_command(doom_data, HARDDOOM_CMD_FLAT_ADDR(flat_dev)); } -void set_ustep(void __iomem *iomem, uint32_t ustep) +void set_ustart(struct doom_data *doom_data, uint32_t ustart) { - send_command(iomem, HARDDOOM_CMD_USTEP(ustep)); + send_command(doom_data, HARDDOOM_CMD_USTART(ustart)); } -void set_draw_params(void __iomem *iomem, uint8_t flags) +void set_ustep(struct doom_data *doom_data, uint32_t ustep) { - send_command(iomem, HARDDOOM_CMD_DRAW_PARAMS(flags)); + send_command(doom_data, HARDDOOM_CMD_USTEP(ustep)); } -void fill_rect(struct surface_data *surface_data, struct doomdev_fill_rect rect) +void set_vstart(struct doom_data *doom_data, uint32_t vstart) { - void __iomem *iomem; - - iomem = surface_data->doom_data->iomem; + send_command(doom_data, HARDDOOM_CMD_VSTART(vstart)); +} - set_surf_dst_pt(iomem, surface_data->page_table_dev); - set_surf_dims(iomem, surface_data->width, surface_data->height); - set_xy_a(iomem, rect.pos_dst_x, rect.pos_dst_y); - set_fill_color(iomem, rect.color); +void set_vstep(struct doom_data *doom_data, uint32_t vstep) +{ + send_command(doom_data, HARDDOOM_CMD_VSTEP(vstep)); +} - send_command(iomem, HARDDOOM_CMD_FILL_RECT(rect.width, rect.height)); +void set_draw_params(struct doom_data *doom_data, uint8_t flags) +{ + send_command(doom_data, HARDDOOM_CMD_DRAW_PARAMS(flags)); } -void draw_line(struct surface_data *surface_data, struct doomdev_line line) +void fill_rect(struct surface_data *surface_data, struct doomdev_fill_rect rect) { - void __iomem *iomem; + set_surf_dst_pt(surface_data->doom_data, surface_data->page_table_dev); + set_surf_dims(surface_data->doom_data, surface_data->width, surface_data->height); + set_xy_a(surface_data->doom_data, rect.pos_dst_x, rect.pos_dst_y); + set_fill_color(surface_data->doom_data, rect.color); - iomem = surface_data->doom_data->iomem; + send_command(surface_data->doom_data, HARDDOOM_CMD_FILL_RECT(rect.width, rect.height)); +} - set_surf_dst_pt(iomem, surface_data->page_table_dev); - set_surf_dims(iomem, surface_data->width, surface_data->height); - set_xy_a(iomem, line.pos_a_x, line.pos_a_y); - set_xy_b(iomem, line.pos_b_x, line.pos_b_y); - set_fill_color(iomem, line.color); +void draw_line(struct surface_data *surface_data, struct doomdev_line line) +{ + set_surf_dst_pt(surface_data->doom_data, surface_data->page_table_dev); + set_surf_dims(surface_data->doom_data, surface_data->width, surface_data->height); + set_xy_a(surface_data->doom_data, line.pos_a_x, line.pos_a_y); + set_xy_b(surface_data->doom_data, line.pos_b_x, line.pos_b_y); + set_fill_color(surface_data->doom_data, line.color); - send_command(iomem, HARDDOOM_CMD_DRAW_LINE); + send_command(surface_data->doom_data, HARDDOOM_CMD_DRAW_LINE); } void copy_rect(struct surface_data *dst_data, struct surface_data *src_data, struct doomdev_copy_rect rect) { - void __iomem *iomem; - - iomem = dst_data->doom_data->iomem; + set_surf_dst_pt(dst_data->doom_data, dst_data->page_table_dev); + set_surf_src_pt(dst_data->doom_data, src_data->page_table_dev); + set_surf_dims(dst_data->doom_data, dst_data->width, dst_data->height); + set_xy_a(dst_data->doom_data, rect.pos_dst_x, rect.pos_dst_y); + set_xy_b(dst_data->doom_data, rect.pos_src_x, rect.pos_src_y); - set_surf_dst_pt(iomem, dst_data->page_table_dev); - set_surf_src_pt(iomem, src_data->page_table_dev); - set_surf_dims(iomem, dst_data->width, dst_data->height); - set_xy_a(iomem, rect.pos_dst_x, rect.pos_dst_y); - set_xy_b(iomem, rect.pos_src_x, rect.pos_src_y); - - send_command(iomem, HARDDOOM_CMD_COPY_RECT(rect.width, rect.height)); + send_command(dst_data->doom_data, HARDDOOM_CMD_COPY_RECT(rect.width, rect.height)); } void draw_column(struct surface_data *surface_data, struct texture_data *texture_data, struct doomdev_column column) { - void __iomem *iomem; - - iomem = surface_data->doom_data->iomem; - - set_surf_dst_pt(iomem, surface_data->page_table_dev); - set_surf_dims(iomem, surface_data->width, surface_data->height); - set_texture_pt(iomem, texture_data->page_table_dev); - set_texture_dims(iomem, texture_data->size, texture_data->height); - set_xy_a(iomem, column.x, column.y1); - set_xy_b(iomem, column.x, column.y2); - set_ustart(iomem, column.ustart); - set_ustep(iomem, column.ustep); - set_draw_params(iomem, 0); + set_surf_dst_pt(surface_data->doom_data, surface_data->page_table_dev); + set_surf_dims(surface_data->doom_data, surface_data->width, surface_data->height); + set_texture_pt(surface_data->doom_data, texture_data->page_table_dev); + set_texture_dims(surface_data->doom_data, texture_data->size, texture_data->height); + set_xy_a(surface_data->doom_data, column.x, column.y1); + set_xy_b(surface_data->doom_data, column.x, column.y2); + set_ustart(surface_data->doom_data, column.ustart); + set_ustep(surface_data->doom_data, column.ustep); + set_draw_params(surface_data->doom_data, 0); + + send_command(surface_data->doom_data, + HARDDOOM_CMD_DRAW_COLUMN(column.texture_offset)); +} - send_command(iomem, HARDDOOM_CMD_DRAW_COLUMN(column.texture_offset)); +void draw_span(struct surface_data *surface_data, struct flat_data *flat_data, + struct doomdev_span span) +{ + set_surf_dst_pt(surface_data->doom_data, surface_data->page_table_dev); + set_surf_dims(surface_data->doom_data, surface_data->width, + surface_data->height); + set_flat(surface_data->doom_data, flat_data->flat_dev); + set_xy_a(surface_data->doom_data, span.x1, span.y); + set_xy_b(surface_data->doom_data, span.x2, span.y); + set_ustart(surface_data->doom_data, span.ustart); + set_ustep(surface_data->doom_data, span.ustep); + set_vstart(surface_data->doom_data, span.vstart); + set_vstep(surface_data->doom_data, span.vstep); + set_draw_params(surface_data->doom_data, 0); + + send_command(surface_data->doom_data, HARDDOOM_CMD_DRAW_SPAN); } uint32_t doomdev_read_stat(void __iomem *iomem, size_t stat) @@ -188,7 +246,8 @@ void start_dev(struct pci_dev *dev) load_microcode(iomem); doomdev_write(iomem, HARDDOOM_RESET, 0xffffffe); - doomdev_write(iomem, HARDDOOM_INTR, HARDDOOM_INTR_MASK); + doomdev_write(iomem, HARDDOOM_INTR, + HARDDOOM_INTR_MASK ^ HARDDOOM_INTR_PONG_ASYNC); doomdev_write(iomem, HARDDOOM_INTR_ENABLE, HARDDOOM_INTR_MASK); doomdev_write(iomem, HARDDOOM_ENABLE, HARDDOOM_ENABLE_ALL ^ HARDDOOM_ENABLE_FETCH_CMD); diff --git a/harddoomdev.h b/harddoomdev.h index 929d5f2..ab7a398 100644 --- a/harddoomdev.h +++ b/harddoomdev.h @@ -10,8 +10,10 @@ void start_dev(struct pci_dev *dev); void shutdown_dev(struct pci_dev *dev); uint32_t get_interrupts(void __iomem *iomem); +uint32_t get_enabled_interrupts(void __iomem *iomem); void deactivate_intr(void __iomem *iomem, uint32_t intr); -void ping_sync(void __iomem *iomem); +void disable_intr(void __iomem *iomem, uint32_t intr); +void ping_sync(struct doom_data *doom_data); void draw_line(struct surface_data *surface_data, struct doomdev_line line); void fill_rect(struct surface_data *surface_data, struct doomdev_fill_rect rect); @@ -15,14 +15,25 @@ void handle_pong_sync(struct doom_data *doom_data) up(&doom_data->pong_sem); } +void handle_pong_async(struct doom_data *doom_data) +{ + up(&doom_data->pong_async_sem); + disable_intr(doom_data->iomem, HARDDOOM_INTR_PONG_ASYNC); +} + irqreturn_t doom_irq(int irq, void *dev) { uint32_t interrupts; struct doom_data *doom_data; + void __iomem *iomem; + doom_data = dev; + iomem = doom_data->iomem; - interrupts = get_interrupts(doom_data->iomem); + interrupts = ioread32(iomem + HARDDOOM_INTR) & ioread32(iomem + HARDDOOM_INTR_ENABLE); + iowrite32(interrupts, iomem + HARDDOOM_INTR); + if (!interrupts) { return IRQ_NONE; } @@ -32,7 +43,9 @@ irqreturn_t doom_irq(int irq, void *dev) interrupts &= ~HARDDOOM_INTR_PONG_SYNC; } - deactivate_intr(doom_data->iomem, HARDDOOM_INTR_MASK); + if (interrupts & HARDDOOM_INTR_PONG_ASYNC) { + handle_pong_async(doom_data); + } return IRQ_HANDLED; } @@ -61,6 +74,8 @@ int init_pci(struct pci_dev *dev) mutex_init(&doom_data->cmd_mutex); mutex_init(&doom_data->ping_mutex); sema_init(&doom_data->pong_sem, 0); + sema_init(&doom_data->pong_async_sem, 0); + doom_data->cmd_counter = 0; ORFAIL(request_irq(dev->irq, doom_irq, IRQF_SHARED, "doom", doom_data), error_irq); diff --git a/private_data.h b/private_data.h index ae1bf3e..fed5b60 100644 --- a/private_data.h +++ b/private_data.h @@ -12,6 +12,9 @@ struct doom_data { struct mutex cmd_mutex; struct mutex ping_mutex; struct semaphore pong_sem; + struct semaphore pong_async_sem; + + uint16_t cmd_counter; }; struct surface_data { @@ -42,4 +45,11 @@ struct texture_data { dma_addr_t page_table_dev; }; +struct flat_data { + struct doom_data *doom_data; + + uint8_t *flat_cpu; + dma_addr_t flat_dev; +}; + #endif @@ -17,7 +17,7 @@ long draw_lines(struct file *filp, unsigned long arg) struct doomdev_surf_ioctl_draw_lines *param; struct doomdev_line *lines; int i; - + surface_data = filp->private_data; param = (struct doomdev_surf_ioctl_draw_lines *) arg; lines = (struct doomdev_line *) param->lines_ptr; @@ -86,6 +86,8 @@ long copy_rects(struct file *filp, unsigned long arg) mutex_unlock(&dst_data->doom_data->cmd_mutex); + fdput(src_fds); + return param->rects_num; } @@ -125,6 +127,8 @@ long draw_columns(struct file *filp, unsigned long arg) mutex_unlock(&surface_data->doom_data->cmd_mutex); + fdput(texture_fds); + return param->columns_num; } @@ -159,9 +163,8 @@ ssize_t surface_read(struct file *filp, char __user *buf, size_t count, count = surface_data->surface_size - *offset; } - mutex_lock(&surface_data->doom_data->ping_mutex); - ping_sync(surface_data->doom_data->iomem); - + mutex_lock(&surface_data->doom_data->cmd_mutex); + ping_sync(surface_data->doom_data); down(&surface_data->doom_data->pong_sem); not_written = copy_to_user(buf, surface_data->surface_cpu + (*offset), @@ -169,7 +172,7 @@ ssize_t surface_read(struct file *filp, char __user *buf, size_t count, *offset += count - not_written; - mutex_unlock(&surface_data->doom_data->ping_mutex); + mutex_unlock(&surface_data->doom_data->cmd_mutex); return count - not_written; } @@ -212,6 +215,11 @@ int surface_release(struct inode *inode, struct file *filp) surface_data = filp->private_data; + mutex_lock(&surface_data->doom_data->ping_mutex); + ping_sync(surface_data->doom_data); + down(&surface_data->doom_data->pong_sem); + mutex_unlock(&surface_data->doom_data->ping_mutex); + free_surface_buffer(surface_data); kfree(surface_data); @@ -346,6 +354,8 @@ int new_surface(struct file *filp, struct doomdev_ioctl_create_surface *params) fd_s.file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; + fdput(fd_s); + return fd; error_fdget: |