Commit d3aadf21 authored by Vojtech Pavlik's avatar Vojtech Pavlik

Merge suse.cz:/home/vojtech/bk/linus into suse.cz:/home/vojtech/bk/input

parents 6ac8d4e2 0cd9efe3
......@@ -41,17 +41,13 @@ SPECIFIC DEVICES SUPPORTED
ConnectTech WhiteHEAT 4 port converter
ConnectTech has been very forthcoming with information about their
device, including providing a unit to test with. This driver will end up
being fully supported.
device, including providing a unit to test with.
Current status:
The device's firmware is downloaded on connection, the new firmware
runs properly and all four ports are successfully recognized and connected.
Data can be sent and received through the device on all ports.
Hardware flow control needs to be implemented.
The driver is officially supported by Connect Tech Inc.
http://www.connecttech.com
For any questions or problems with this driver, please contact Greg
Kroah-Hartman at greg@kroah.com
For any questions or problems with this driver, please contact
Stuart MacDonald at stuartm@connecttech.com
HandSpring Visor, Palm USB, and Clié USB driver
......
......@@ -1830,6 +1830,14 @@ L: linux-usb-devel@lists.sourceforge.net
W: http://www.kroah.com/linux/
S: Maintained
USB SERIAL WHITEHEAT DRIVER
P: Stuart MacDonald
M: stuartm@connecttech.com
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
W: http://www.connecttech.com
S: Supported
USB SUBSYSTEM
P: Greg Kroah-Hartman
M: greg@kroah.com
......
......@@ -91,9 +91,9 @@ CFLAGS := $(CFLAGS) -Wa,-mev6
HEAD := arch/alpha/kernel/head.o
core-y := arch/alpha/kernel/ arch/alpha/mm/
core-$(CONFIG_MATHEMU) += arch/alpha/math-emu/built-in.o
libs-y := arch/alpha/lib
core-y += arch/alpha/kernel/ arch/alpha/mm/
core-$(CONFIG_MATHEMU) += arch/alpha/math-emu/
libs-y += arch/alpha/lib/
MAKEBOOT = $(MAKE) -C arch/alpha/boot
......
......@@ -1119,3 +1119,27 @@ sys_call_table:
.quad sys_readahead
.quad sys_ni_syscall /* 380, sys_security */
.quad sys_tkill
.quad sys_setxattr
.quad sys_lsetxattr
.quad sys_fsetxattr
.quad sys_getxattr
.quad sys_lgetxattr
.quad sys_fgetxattr
.quad sys_listxattr
.quad sys_llistxattr
.quad sys_flistxattr /* 390 */
.quad sys_removexattr
.quad sys_lremovexattr
.quad sys_fremovexattr
.quad sys_futex
.quad sys_sched_setaffinity
.quad sys_sched_getaffinity
.quad sys_ni_syscall /* 397, tux */
.quad sys_io_setup
.quad sys_io_destroy
.quad sys_io_getevents /* 400 */
.quad sys_io_submit
.quad sys_io_cancel
.quad sys_ni_syscall /* 403, sys_alloc_hugepages */
.quad sys_ni_syscall /* 404, sys_free_hugepages */
.quad sys_exit_group
......@@ -2,7 +2,7 @@
# Makefile for alpha-specific library files..
#
EXTRA_AFLAGS := $(CFLAGS)
L_TARGET := lib.a
# Many of these routines have implementations tuned for ev6.
# Choose them iff we're targeting ev6 specifically.
......@@ -17,7 +17,7 @@ ifeq ($(CONFIG_ALPHA_EV67),y)
ev67 := ev67-
endif
OBJS = __divqu.o __remqu.o __divlu.o __remlu.o \
obj-y = __divqu.o __remqu.o __divlu.o __remlu.o \
udelay.o \
$(ev6)memset.o \
$(ev6)memcpy.o \
......@@ -46,12 +46,9 @@ OBJS = __divqu.o __remqu.o __divlu.o __remlu.o \
fpreg.o \
callback_srm.o srm_puts.o srm_printk.o
ifeq ($(CONFIG_SMP),y)
OBJS += dec_and_lock.o
endif
obj-$(CONFIG_SMP) += dec_and_lock.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
include $(TOPDIR)/Rules.make
__divqu.o: $(ev6)divide.S
$(CC) $(AFLAGS) -DDIV -c -o __divqu.o $(ev6)divide.S
......@@ -64,5 +61,3 @@ __divlu.o: $(ev6)divide.S
__remlu.o: $(ev6)divide.S
$(CC) $(AFLAGS) -DREM -DINTSIZE -c -o __remlu.o $(ev6)divide.S
include $(TOPDIR)/Rules.make
......@@ -2,10 +2,8 @@
# Makefile for the FPU instruction emulation.
#
obj-$(CONFIG_MATHEMU) += math-emu.o
math-emu-objs := math.o qrnnd.o
CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w
obj-$(CONFIG_MATHEMU) += math.o qrnnd.o
include $(TOPDIR)/Rules.make
......@@ -157,13 +157,20 @@ inline int elv_try_last_merge(request_queue_t *q, struct request **req,
return ret;
}
static int bio_rq_before(struct bio *bio, struct request *rq)
{
if (!kdev_same(to_kdev_t(bio->bi_bdev->bd_dev), rq->rq_dev))
return 0;
return bio->bi_sector < rq->sector;
}
/*
* elevator_linux starts here
*/
int elevator_linus_merge(request_queue_t *q, struct request **req,
struct bio *bio)
{
struct list_head *entry;
struct list_head *entry, *good;
struct request *__rq;
int ret;
......@@ -171,6 +178,7 @@ int elevator_linus_merge(request_queue_t *q, struct request **req,
return ret;
entry = &q->queue_head;
good = &q->queue_head;
ret = ELEVATOR_NO_MERGE;
while ((entry = entry->prev) != &q->queue_head) {
__rq = list_entry_rq(entry);
......@@ -178,37 +186,31 @@ int elevator_linus_merge(request_queue_t *q, struct request **req,
if (__rq->flags & (REQ_BARRIER | REQ_STARTED))
break;
if (!(__rq->flags & REQ_CMD))
continue;
if (elv_linus_sequence(__rq) < bio_sectors(bio))
break;
if (!*req && bio_rq_in_between(bio, __rq, &q->queue_head))
*req = __rq;
if (bio_data_dir(bio) != rq_data_dir(__rq)) {
if (bio_data_dir(bio) == WRITE)
break;
good = entry->prev;
continue;
}
if ((ret = elv_try_merge(__rq, bio))) {
if (ret == ELEVATOR_FRONT_MERGE)
elv_linus_sequence(__rq) -= bio_sectors(bio);
ret = elv_try_merge(__rq, bio);
if (ret) {
*req = __rq;
q->last_merge = &__rq->queuelist;
break;
return ret;
}
}
/*
* if *req, it's either a seek or merge in the middle of the queue
*/
if (*req) {
struct list_head *entry = &(*req)->queuelist;
int cost = ret ? 1 : ELV_LINUS_SEEK_COST;
if (bio_rq_before(bio, __rq))
good = entry->prev;
while ((entry = entry->next) != &q->queue_head) {
__rq = list_entry_rq(entry);
elv_linus_sequence(__rq) -= cost;
}
}
return ret;
if (good != &q->queue_head)
*req = list_entry_rq(good);
return ELEVATOR_NO_MERGE;
}
void elevator_linus_merge_req(request_queue_t *q, struct request *req,
......
......@@ -8,7 +8,7 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o
mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o
i810-objs := i810_drv.o i810_dma.o
i830-objs := i830_drv.o i830_dma.o
radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o
radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
ffb-objs := ffb_drv.o ffb_context.o
obj-$(CONFIG_DRM_GAMMA) += gamma.o
......
......@@ -165,7 +165,7 @@
#define pte_unmap(pte)
#endif
#if LINUX_VERSION_CODE < 0x020413 /* KERNEL_VERSION(2,4,19) */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
static inline struct page * vmalloc_to_page(void * vmalloc_addr)
{
unsigned long addr = (unsigned long) vmalloc_addr;
......@@ -190,7 +190,7 @@ static inline struct page * vmalloc_to_page(void * vmalloc_addr)
}
#endif
#if LINUX_VERSION_CODE < 0x020500
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
#define DRM_RPR_ARG(vma)
#else
#define DRM_RPR_ARG(vma) vma,
......@@ -597,7 +597,7 @@ typedef struct drm_device {
#endif
struct pci_dev *pdev;
#ifdef __alpha__
#if LINUX_VERSION_CODE < 0x020403
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3)
struct pci_controler *hose;
#else
struct pci_controller *hose;
......
......@@ -137,6 +137,7 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
}
map->offset = (unsigned long)map->handle;
if ( map->flags & _DRM_CONTAINS_LOCK ) {
dev->sigdata.lock =
dev->lock.hw_lock = map->handle; /* Pointer to lock */
}
break;
......
......@@ -306,7 +306,7 @@ static int DRM(setup)( drm_device_t *dev )
dev->map_count = 0;
dev->vmalist = NULL;
dev->lock.hw_lock = NULL;
dev->sigdata.lock = dev->lock.hw_lock = NULL;
init_waitqueue_head( &dev->lock.lock_queue );
dev->queue_count = 0;
dev->queue_reserved = 0;
......@@ -491,7 +491,7 @@ static int DRM(takedown)( drm_device_t *dev )
DRM(dma_takedown)( dev );
#endif
if ( dev->lock.hw_lock ) {
dev->lock.hw_lock = NULL; /* SHM removed */
dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */
dev->lock.pid = 0;
wake_up_interruptible( &dev->lock.lock_queue );
}
......
......@@ -237,7 +237,7 @@ int DRM(notifier)(void *priv)
/* Allow signal delivery if lock isn't held */
if (!_DRM_LOCK_IS_HELD(s->lock->lock)
if (!s->lock || !_DRM_LOCK_IS_HELD(s->lock->lock)
|| _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1;
/* Otherwise, set flag to force call to
......
......@@ -16,6 +16,9 @@
#define DRM_DEVICE drm_file_t *priv = filp->private_data; \
drm_device_t *dev = priv->dev
#define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs
#define DRM_TASKQUEUE_ARGS void *arg
/* For data going from/to the kernel through the ioctl argument */
#define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \
if ( copy_from_user(&arg1, arg2, arg3) ) \
......
......@@ -45,11 +45,11 @@
#define DRIVER_NAME "i830"
#define DRIVER_DESC "Intel 830M"
#define DRIVER_DATE "20011004"
#define DRIVER_DATE "20020828"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 2
#define DRIVER_PATCHLEVEL 0
#define DRIVER_PATCHLEVEL 1
#define DRIVER_IOCTLS \
[DRM_IOCTL_NR(DRM_IOCTL_I830_INIT)] = { i830_dma_init, 1, 1 }, \
......@@ -87,50 +87,10 @@
i830_dma_quiescent( dev ); \
} while (0)
#define __HAVE_DMA_IRQ 1
#define __HAVE_DMA_IRQ_BH 1
#define __HAVE_SHARED_IRQ 1
#define DRIVER_PREINSTALL() do { \
drm_i830_private_t *dev_priv = \
(drm_i830_private_t *)dev->dev_private; \
u16 tmp; \
tmp = I830_READ16( I830REG_HWSTAM ); \
tmp = tmp & 0x6000; \
I830_WRITE16( I830REG_HWSTAM, tmp ); \
\
tmp = I830_READ16( I830REG_INT_MASK_R ); \
tmp = tmp & 0x6000; /* Unmask interrupts */ \
I830_WRITE16( I830REG_INT_MASK_R, tmp ); \
tmp = I830_READ16( I830REG_INT_ENABLE_R ); \
tmp = tmp & 0x6000; /* Disable all interrupts */ \
I830_WRITE16( I830REG_INT_ENABLE_R, tmp ); \
} while (0)
#define DRIVER_POSTINSTALL() do { \
drm_i830_private_t *dev_priv = \
(drm_i830_private_t *)dev->dev_private; \
u16 tmp; \
tmp = I830_READ16( I830REG_INT_ENABLE_R ); \
tmp = tmp & 0x6000; \
tmp = tmp | 0x0003; /* Enable bp & user interrupts */ \
I830_WRITE16( I830REG_INT_ENABLE_R, tmp ); \
} while (0)
#define DRIVER_UNINSTALL() do { \
drm_i830_private_t *dev_priv = \
(drm_i830_private_t *)dev->dev_private; \
u16 tmp; \
if ( dev_priv ) { \
tmp = I830_READ16( I830REG_INT_IDENTITY_R ); \
tmp = tmp & ~(0x6000); /* Clear all interrupts */ \
if ( tmp != 0 ) \
I830_WRITE16( I830REG_INT_IDENTITY_R, tmp ); \
\
tmp = I830_READ16( I830REG_INT_ENABLE_R ); \
tmp = tmp & 0x6000; /* Disable all interrupts */ \
I830_WRITE16( I830REG_INT_ENABLE_R, tmp ); \
} \
} while (0)
/* Don't need an irq any more. The template code will make sure that
* a noop stub is generated for compatibility.
*/
#define __HAVE_DMA_IRQ 0
/* Buffer customization:
*/
......
This diff is collapsed.
......@@ -29,6 +29,7 @@
* Jeff Hartmann <jhartmann@valinux.com>
* Gareth Hughes <gareth@valinux.com>
* Abraham vd Merwe <abraham@2d3d.co.za>
* Keith Whitwell <keith@tungstengraphics.com>
*/
#include <linux/config.h>
......
......@@ -64,14 +64,13 @@ typedef struct drm_i830_private {
unsigned long hw_status_page;
unsigned long counter;
atomic_t flush_done;
wait_queue_head_t flush_queue; /* Processes waiting until flush */
drm_buf_t *mmap_buffer;
u32 front_di1, back_di1, zi1;
int back_offset;
int depth_offset;
int front_offset;
int w, h;
int pitch;
int back_pitch;
......@@ -107,14 +106,13 @@ extern int i830_swap_bufs(struct inode *inode, struct file *filp,
extern int i830_clear_bufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
#define I830_VERBOSE 0
#define I830_BASE(reg) ((unsigned long) \
dev_priv->mmio_map->handle)
#define I830_ADDR(reg) (I830_BASE(reg) + reg)
#define I830_DEREF(reg) *(__volatile__ int *)I830_ADDR(reg)
#define I830_READ(reg) I830_DEREF(reg)
#define I830_WRITE(reg,val) do { I830_DEREF(reg) = val; } while (0)
#define I830_DEREF(reg) *(__volatile__ unsigned int *)I830_ADDR(reg)
#define I830_READ(reg) readl((volatile u32 *)I830_ADDR(reg))
#define I830_WRITE(reg,val) writel(val, (volatile u32 *)I830_ADDR(reg))
#define I830_DEREF16(reg) *(__volatile__ u16 *)I830_ADDR(reg)
#define I830_READ16(reg) I830_DEREF16(reg)
#define I830_WRITE16(reg,val) do { I830_DEREF16(reg) = val; } while (0)
......@@ -143,15 +141,15 @@ extern int i830_clear_bufs(struct inode *inode, struct file *filp,
#define LP_RING 0x2030
#define HP_RING 0x2040
#define RING_TAIL 0x00
#define TAIL_ADDR 0x000FFFF8
#define TAIL_ADDR 0x001FFFF8
#define RING_HEAD 0x04
#define HEAD_WRAP_COUNT 0xFFE00000
#define HEAD_WRAP_ONE 0x00200000
#define HEAD_ADDR 0x001FFFFC
#define RING_START 0x08
#define START_ADDR 0x00FFFFF8
#define START_ADDR 0x0xFFFFF000
#define RING_LEN 0x0C
#define RING_NR_PAGES 0x000FF000
#define RING_NR_PAGES 0x001FF000
#define RING_REPORT_MASK 0x00000006
#define RING_REPORT_64K 0x00000002
#define RING_REPORT_128K 0x00000004
......@@ -182,6 +180,9 @@ extern int i830_clear_bufs(struct inode *inode, struct file *filp,
#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
#define CMD_3D (0x3<<29)
#define STATE3D_CONST_BLEND_COLOR_CMD (CMD_3D|(0x1d<<24)|(0x88<<16))
#define STATE3D_MAP_COORD_SETBIND_CMD (CMD_3D|(0x1d<<24)|(0x02<<16))
#define BR00_BITBLT_CLIENT 0x40000000
#define BR00_OP_COLOR_BLT 0x10000000
......@@ -206,6 +207,8 @@ extern int i830_clear_bufs(struct inode *inode, struct file *filp,
#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
#define MI_BATCH_BUFFER ((0x30<<23)|1)
#define MI_BATCH_BUFFER_START (0x31<<23)
#define MI_BATCH_BUFFER_END (0xA<<23)
#define MI_BATCH_NON_SECURE (1)
......
......@@ -48,10 +48,10 @@
#define DRIVER_NAME "radeon"
#define DRIVER_DESC "ATI Radeon"
#define DRIVER_DATE "20020611"
#define DRIVER_DATE "20020828"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 5
#define DRIVER_MINOR 6
#define DRIVER_PATCHLEVEL 0
/* Interface history:
......@@ -68,6 +68,11 @@
* 1.5 - Add r200 packets to cmdbuf ioctl
* - Add r200 function to init ioctl
* - Add 'scalar2' instruction to cmdbuf
* 1.6 - Add static agp memory manager
* Add irq handler (won't be turned on unless X server knows to)
* Add irq ioctls and irq_active getparam.
* Add wait command for cmdbuf ioctl
* Add agp offset query for getparam
*/
#define DRIVER_IOCTLS \
[DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \
......@@ -88,9 +93,18 @@
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_VERTEX2)] = { radeon_cp_vertex2, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_CMDBUF)] = { radeon_cp_cmdbuf, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_GETPARAM)] = { radeon_cp_getparam, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_FLIP)] = { radeon_cp_flip, 1, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_FLIP)] = { radeon_cp_flip, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_ALLOC)] = { radeon_mem_alloc, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_FREE)] = { radeon_mem_free, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_INIT_HEAP)] = { radeon_mem_init_heap, 1, 1 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 },
/* Driver customization:
/* When a client dies:
* - Check for and clean up flipped page state
* - Free any alloced agp memory.
*
* DRM infrastructure takes care of reclaiming dma buffers.
*/
#define DRIVER_PRERELEASE() do { \
if ( dev->dev_private ) { \
......@@ -98,22 +112,78 @@
if ( dev_priv->page_flipping ) { \
radeon_do_cleanup_pageflip( dev ); \
} \
radeon_mem_release( dev_priv->agp_heap ); \
} \
} while (0)
/* On unloading the module:
* - Free memory heap structure
* - Remove mappings made at startup and free dev_private.
*/
#define DRIVER_PRETAKEDOWN() do { \
if ( dev->dev_private ) radeon_do_cleanup_cp( dev ); \
if ( dev->dev_private ) { \
drm_radeon_private_t *dev_priv = dev->dev_private; \
radeon_mem_takedown( &(dev_priv->agp_heap) ); \
radeon_do_cleanup_cp( dev ); \
} \
} while (0)
/* DMA customization:
*/
#define __HAVE_DMA 1
#define __HAVE_DMA_IRQ 1
#define __HAVE_DMA_IRQ_BH 1
#define __HAVE_SHARED_IRQ 1
#define DRIVER_PREINSTALL() do { \
drm_radeon_private_t *dev_priv = \
(drm_radeon_private_t *)dev->dev_private; \
u32 tmp; \
\
/* Clear bit if it's already high: */ \
tmp = RADEON_READ( RADEON_GEN_INT_STATUS ); \
tmp = tmp & RADEON_SW_INT_TEST_ACK; \
RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp ); \
\
/* Disable *all* interrupts */ \
RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); \
} while (0)
#ifdef __linux__
#define IWH(x) init_waitqueue_head(x)
#else
#define IWH(x)
#endif
#define DRIVER_POSTINSTALL() do { \
drm_radeon_private_t *dev_priv = \
(drm_radeon_private_t *)dev->dev_private; \
\
atomic_set(&dev_priv->irq_received, 0); \
atomic_set(&dev_priv->irq_emitted, 0); \
IWH(&dev_priv->irq_queue); \
\
/* Turn on SW_INT only */ \
RADEON_WRITE( RADEON_GEN_INT_CNTL, \
RADEON_SW_INT_ENABLE ); \
} while (0)
#define DRIVER_UNINSTALL() do { \
drm_radeon_private_t *dev_priv = \
(drm_radeon_private_t *)dev->dev_private; \
if ( dev_priv ) { \
/* Disable *all* interrupts */ \
RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); \
} \
} while (0)
/* Buffer customization:
*/
#define DRIVER_BUF_PRIV_T drm_radeon_buf_priv_t
#define DRIVER_AGP_BUFFERS_MAP( dev ) \
#define DRIVER_AGP_BUFFERS_MAP( dev ) \
((drm_radeon_private_t *)((dev)->dev_private))->buffers
#endif
......@@ -1412,6 +1412,9 @@ int radeon_cp_idle( DRM_IOCTL_ARGS )
LOCK_TEST_WITH_RETURN( dev );
/* if (dev->irq) */
/* radeon_emit_and_wait_irq( dev ); */
return radeon_do_cp_idle( dev_priv );
}
......
......@@ -142,6 +142,9 @@
#define RADEON_CMD_PACKET3 5 /* emit hw packet */
#define RADEON_CMD_PACKET3_CLIP 6 /* emit hw packet wrapped in cliprects */
#define RADEON_CMD_SCALARS2 7 /* r200 stopgap */
#define RADEON_CMD_WAIT 8 /* emit hw wait commands -- note:
* doesn't make the cpu wait, just
* the graphics hardware */
typedef union {
......@@ -161,8 +164,14 @@ typedef union {
struct {
unsigned char cmd_type, buf_idx, pad0, pad1;
} dma;
struct {
unsigned char cmd_type, flags, pad0, pad1;
} wait;
} drm_radeon_cmd_header_t;
#define RADEON_WAIT_2D 0x1
#define RADEON_WAIT_3D 0x2
#define RADEON_FRONT 0x1
#define RADEON_BACK 0x2
......@@ -364,6 +373,11 @@ typedef struct {
#define DRM_IOCTL_RADEON_CMDBUF DRM_IOW( 0x50, drm_radeon_cmd_buffer_t)
#define DRM_IOCTL_RADEON_GETPARAM DRM_IOWR(0x51, drm_radeon_getparam_t)
#define DRM_IOCTL_RADEON_FLIP DRM_IO( 0x52)
#define DRM_IOCTL_RADEON_ALLOC DRM_IOWR( 0x53, drm_radeon_mem_alloc_t)
#define DRM_IOCTL_RADEON_FREE DRM_IOW( 0x54, drm_radeon_mem_free_t)
#define DRM_IOCTL_RADEON_INIT_HEAP DRM_IOW( 0x55, drm_radeon_mem_init_heap_t)
#define DRM_IOCTL_RADEON_IRQ_EMIT DRM_IOWR( 0x56, drm_radeon_irq_emit_t)
#define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( 0x57, drm_radeon_irq_wait_t)
typedef struct drm_radeon_init {
enum {
......@@ -499,14 +513,51 @@ typedef struct drm_radeon_indirect {
/* 1.3: An ioctl to get parameters that aren't available to the 3d
* client any other way.
*/
#define RADEON_PARAM_AGP_BUFFER_OFFSET 0x1
#define RADEON_PARAM_LAST_FRAME 0x2
#define RADEON_PARAM_LAST_DISPATCH 0x3
#define RADEON_PARAM_LAST_CLEAR 0x4
#define RADEON_PARAM_AGP_BUFFER_OFFSET 1 /* card offset of 1st agp buffer */
#define RADEON_PARAM_LAST_FRAME 2
#define RADEON_PARAM_LAST_DISPATCH 3
#define RADEON_PARAM_LAST_CLEAR 4
#define RADEON_PARAM_IRQ_ACTIVE 5
#define RADEON_PARAM_AGP_BASE 6 /* card offset of agp base */
typedef struct drm_radeon_getparam {
int param;
int *value;
} drm_radeon_getparam_t;
/* 1.6: Set up a memory manager for regions of shared memory:
*/
#define RADEON_MEM_REGION_AGP 1
#define RADEON_MEM_REGION_FB 2
typedef struct drm_radeon_mem_alloc {
int region;
int alignment;
int size;
int *region_offset; /* offset from start of fb or agp */
} drm_radeon_mem_alloc_t;
typedef struct drm_radeon_mem_free {
int region;
int region_offset;
} drm_radeon_mem_free_t;
typedef struct drm_radeon_mem_init_heap {
int region;
int size;
int start;
} drm_radeon_mem_init_heap_t;
/* 1.6: Userspace can request & wait on irq's:
*/
typedef struct drm_radeon_irq_emit {
int *irq_seq;
} drm_radeon_irq_emit_t;
typedef struct drm_radeon_irq_wait {
int irq_seq;
} drm_radeon_irq_wait_t;
#endif
......@@ -61,6 +61,15 @@ typedef struct drm_radeon_depth_clear_t {
u32 se_cntl;
} drm_radeon_depth_clear_t;
struct mem_block {
struct mem_block *next;
struct mem_block *prev;
int start;
int size;
int pid; /* 0: free, -1: heap, other: real pids */
};
typedef struct drm_radeon_private {
drm_radeon_ring_buffer_t ring;
drm_radeon_sarea_t *sarea_priv;
......@@ -126,6 +135,14 @@ typedef struct drm_radeon_private {
drm_map_t *ring_rptr;
drm_map_t *buffers;
drm_map_t *agp_textures;
struct mem_block *agp_heap;
struct mem_block *fb_heap;
wait_queue_head_t irq_queue;
atomic_t irq_received;
atomic_t irq_emitted;
} drm_radeon_private_t;
typedef struct drm_radeon_buf_priv {
......@@ -164,6 +181,20 @@ extern int radeon_cp_cmdbuf( DRM_IOCTL_ARGS );
extern int radeon_cp_getparam( DRM_IOCTL_ARGS );
extern int radeon_cp_flip( DRM_IOCTL_ARGS );
extern int radeon_mem_alloc( DRM_IOCTL_ARGS );
extern int radeon_mem_free( DRM_IOCTL_ARGS );
extern int radeon_mem_init_heap( DRM_IOCTL_ARGS );
extern void radeon_mem_takedown( struct mem_block **heap );
extern void radeon_mem_release( struct mem_block *heap );
extern int radeon_irq_emit( DRM_IOCTL_ARGS );
extern int radeon_irq_wait( DRM_IOCTL_ARGS );
extern int radeon_emit_and_wait_irq(drm_device_t *dev);
extern int radeon_wait_irq(drm_device_t *dev, int irq_nr);
extern int radeon_emit_irq(drm_device_t *dev);
/* Flags for stats.boxes
*/
#define RADEON_BOX_DMA_IDLE 0x1
......@@ -238,6 +269,16 @@ extern int radeon_cp_flip( DRM_IOCTL_ARGS );
? DRM_READ32( &dev_priv->scratch[(x)] ) \
: RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) )
#define RADEON_GEN_INT_CNTL 0x0040
# define RADEON_GUI_IDLE_INT_ENABLE (1 << 19)
# define RADEON_SW_INT_ENABLE (1 << 25)
#define RADEON_GEN_INT_STATUS 0x0044
# define RADEON_GUI_IDLE_INT_TEST_ACK (1 << 19)
# define RADEON_SW_INT_TEST_ACK (1 << 25)
# define RADEON_SW_INT_FIRE (1 << 26)
#define RADEON_HOST_PATH_CNTL 0x0130
# define RADEON_HDP_SOFT_RESET (1 << 26)
# define RADEON_HDP_WC_TIMEOUT_MASK (7 << 28)
......@@ -526,6 +567,8 @@ extern int radeon_cp_flip( DRM_IOCTL_ARGS );
#define RADEON_TXFORMAT_ARGB4444 5
#define RADEON_TXFORMAT_ARGB8888 6
#define RADEON_TXFORMAT_RGBA8888 7
#define RADEON_TXFORMAT_VYUY422 10
#define RADEON_TXFORMAT_YVYU422 11
#define R200_PP_TXCBLEND_0 0x2f00
#define R200_PP_TXCBLEND_1 0x2f10
......
/* radeon_mem.c -- Simple agp/fb memory manager for radeon -*- linux-c -*-
*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
* initial release of the Radeon 8500 driver under the XFree86 license.
* This notice must be preserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
#include "radeon.h"
#include "drmP.h"
#include "drm.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
/* Interrupts - Used for device synchronization and flushing in the
* following circumstances:
*
* - Exclusive FB access with hw idle:
* - Wait for GUI Idle (?) interrupt, then do normal flush.
*
* - Frame throttling, NV_fence:
* - Drop marker irq's into command stream ahead of time.
* - Wait on irq's with lock *not held*
* - Check each for termination condition
*
* - Internally in cp_getbuffer, etc:
* - as above, but wait with lock held???
*
* NOTE: These functions are misleadingly named -- the irq's aren't
* tied to dma at all, this is just a hangover from dri prehistory.
*/
void DRM(dma_service)( DRM_IRQ_ARGS )
{
drm_device_t *dev = (drm_device_t *) arg;
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *)dev->dev_private;
u32 temp;
/* Need to wait for fifo to drain?
*/
temp = RADEON_READ(RADEON_GEN_INT_STATUS);
temp = temp & RADEON_SW_INT_TEST_ACK;
if (temp == 0) return;
RADEON_WRITE(RADEON_GEN_INT_STATUS, temp);
atomic_inc(&dev_priv->irq_received);
#ifdef __linux__
queue_task(&dev->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
#endif /* __linux__ */
#ifdef __FreeBSD__
taskqueue_enqueue(taskqueue_swi, &dev->task);
#endif /* __FreeBSD__ */
}
void DRM(dma_immediate_bh)( DRM_TASKQUEUE_ARGS )
{
drm_device_t *dev = (drm_device_t *) arg;
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *)dev->dev_private;
#ifdef __linux__
wake_up_interruptible(&dev_priv->irq_queue);
#endif /* __linux__ */
#ifdef __FreeBSD__
wakeup( &dev_priv->irq_queue );
#endif
}
int radeon_emit_irq(drm_device_t *dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
atomic_inc(&dev_priv->irq_emitted);
BEGIN_RING(2);
OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) );
OUT_RING( RADEON_SW_INT_FIRE );
ADVANCE_RING();
COMMIT_RING();
return atomic_read(&dev_priv->irq_emitted);
}
int radeon_wait_irq(drm_device_t *dev, int irq_nr)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *)dev->dev_private;
#ifdef __linux__
DECLARE_WAITQUEUE(entry, current);
unsigned long end = jiffies + HZ*3;
#endif /* __linux__ */
int ret = 0;
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
return 0;
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
#ifdef __linux__
add_wait_queue(&dev_priv->irq_queue, &entry);
for (;;) {
current->state = TASK_INTERRUPTIBLE;
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
break;
if((signed)(end - jiffies) <= 0) {
ret = -EBUSY; /* Lockup? Missed irq? */
break;
}
schedule_timeout(HZ*3);
if (signal_pending(current)) {
ret = -EINTR;
break;
}
}
current->state = TASK_RUNNING;
remove_wait_queue(&dev_priv->irq_queue, &entry);
return ret;
#endif /* __linux__ */
#ifdef __FreeBSD__
ret = tsleep( &dev_priv->irq_queue, PZERO | PCATCH, \
"rdnirq", 3*hz );
if ( (ret == EWOULDBLOCK) || (ret == EINTR) )
return DRM_ERR(EBUSY);
return ret;
#endif /* __FreeBSD__ */
}
int radeon_emit_and_wait_irq(drm_device_t *dev)
{
return radeon_wait_irq( dev, radeon_emit_irq(dev) );
}
/* Needs the lock as it touches the ring.
*/
int radeon_irq_emit( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_irq_emit_t emit;
int result;
LOCK_TEST_WITH_RETURN( dev );
if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL( emit, (drm_radeon_irq_emit_t *)data,
sizeof(emit) );
result = radeon_emit_irq( dev );
if ( DRM_COPY_TO_USER( emit.irq_seq, &result, sizeof(int) ) ) {
DRM_ERROR( "copy_to_user\n" );
return DRM_ERR(EFAULT);
}
return 0;
}
/* Doesn't need the hardware lock.
*/
int radeon_irq_wait( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_irq_wait_t irqwait;
if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL( irqwait, (drm_radeon_irq_wait_t *)data,
sizeof(irqwait) );
return radeon_wait_irq( dev, irqwait.irq_seq );
}
/* radeon_mem.c -- Simple agp/fb memory manager for radeon -*- linux-c -*-
*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
* initial release of the Radeon 8500 driver under the XFree86 license.
* This notice must be preserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
#include "radeon.h"
#include "drmP.h"
#include "drm.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
/* Very simple allocator for agp memory, working on a static range
* already mapped into each client's address space.
*/
static struct mem_block *split_block(struct mem_block *p, int start, int size,
int pid )
{
/* Maybe cut off the start of an existing block */
if (start > p->start) {
struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock));
if (!newblock)
goto out;
newblock->start = start;
newblock->size = p->size - (start - p->start);
newblock->pid = 0;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
p->next = newblock;
p->size -= newblock->size;
p = newblock;
}
/* Maybe cut off the end of an existing block */
if (size < p->size) {
struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock));
if (!newblock)
goto out;
newblock->start = start + size;
newblock->size = p->size - size;
newblock->pid = 0;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
p->next = newblock;
p->size = size;
}
out:
/* Our block is in the middle */
p->pid = pid;
return p;
}
static struct mem_block *alloc_block( struct mem_block *heap, int size,
int align2, int pid )
{
struct mem_block *p;
int mask = (1 << align2)-1;
for (p = heap->next ; p != heap ; p = p->next) {
int start = (p->start + mask) & ~mask;
if (p->pid == 0 && start + size <= p->start + p->size)
return split_block( p, start, size, pid );
}
return NULL;
}
static struct mem_block *find_block( struct mem_block *heap, int start )
{
struct mem_block *p;
for (p = heap->next ; p != heap ; p = p->next)
if (p->start == start)
return p;
return NULL;
}
static void free_block( struct mem_block *p )
{
p->pid = 0;
/* Assumes a single contiguous range. Needs a special pid in
* 'heap' to stop it being subsumed.
*/
if (p->next->pid == 0) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
p->next->prev = p;
DRM_FREE(p);
}
if (p->prev->pid == 0) {
struct mem_block *q = p->prev;
q->size += p->size;
q->next = p->next;
q->next->prev = q;
DRM_FREE(p);
}
}
static void print_heap( struct mem_block *heap )
{
struct mem_block *p;
for (p = heap->next ; p != heap ; p = p->next)
DRM_DEBUG("0x%x..0x%x (0x%x) -- owner %d\n",
p->start, p->start + p->size,
p->size, p->pid);
}
/* Initialize. How to check for an uninitialized heap?
*/
static int init_heap(struct mem_block **heap, int start, int size)
{
struct mem_block *blocks = DRM_MALLOC(sizeof(*blocks));
if (!blocks)
return -ENOMEM;
*heap = DRM_MALLOC(sizeof(**heap));
if (!*heap) {
DRM_FREE( blocks );
return -ENOMEM;
}
blocks->start = start;
blocks->size = size;
blocks->pid = 0;
blocks->next = blocks->prev = *heap;
memset( *heap, 0, sizeof(**heap) );
(*heap)->pid = -1;
(*heap)->next = (*heap)->prev = blocks;
return 0;
}
/* Free all blocks associated with the releasing pid.
*/
void radeon_mem_release( struct mem_block *heap )
{
int pid = DRM_CURRENTPID;
struct mem_block *p;
if (!heap || !heap->next)
return;
for (p = heap->next ; p != heap ; p = p->next) {
if (p->pid == pid)
p->pid = 0;
}
/* Assumes a single contiguous range. Needs a special pid in
* 'heap' to stop it being subsumed.
*/
for (p = heap->next ; p != heap ; p = p->next) {
while (p->pid == 0 && p->next->pid == 0) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
p->next->prev = p;
DRM_FREE(q);
}
}
}
/* Shutdown.
*/
void radeon_mem_takedown( struct mem_block **heap )
{
struct mem_block *p;
if (!*heap)
return;
for (p = (*heap)->next ; p != *heap ; ) {
struct mem_block *q = p;
p = p->next;
DRM_FREE(q);
}
DRM_FREE( *heap );
*heap = 0;
}
/* IOCTL HANDLERS */
static struct mem_block **get_heap( drm_radeon_private_t *dev_priv,
int region )
{
switch( region ) {
case RADEON_MEM_REGION_AGP:
return &dev_priv->agp_heap;
case RADEON_MEM_REGION_FB:
return &dev_priv->fb_heap;
default:
return 0;
}
}
int radeon_mem_alloc( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_mem_alloc_t alloc;
struct mem_block *block, **heap;
if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL( alloc, (drm_radeon_mem_alloc_t *)data,
sizeof(alloc) );
heap = get_heap( dev_priv, alloc.region );
if (!heap || !*heap)
return DRM_ERR(EFAULT);
/* Make things easier on ourselves: all allocations at least
* 4k aligned.
*/
if (alloc.alignment < 12)
alloc.alignment = 12;
block = alloc_block( *heap, alloc.size, alloc.alignment,
DRM_CURRENTPID );
if (!block)
return DRM_ERR(ENOMEM);
if ( DRM_COPY_TO_USER( alloc.region_offset, &block->start,
sizeof(int) ) ) {
DRM_ERROR( "copy_to_user\n" );
return DRM_ERR(EFAULT);
}
return 0;
}
int radeon_mem_free( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_mem_free_t memfree;
struct mem_block *block, **heap;
if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL( memfree, (drm_radeon_mem_free_t *)data,
sizeof(memfree) );
heap = get_heap( dev_priv, memfree.region );
if (!heap || !*heap)
return DRM_ERR(EFAULT);
block = find_block( *heap, memfree.region_offset );
if (!block)
return DRM_ERR(EFAULT);
if (block->pid != DRM_CURRENTPID)
return DRM_ERR(EPERM);
free_block( block );
return 0;
}
int radeon_mem_init_heap( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_mem_init_heap_t initheap;
struct mem_block **heap;
if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL( initheap, (drm_radeon_mem_init_heap_t *)data,
sizeof(initheap) );
heap = get_heap( dev_priv, initheap.region );
if (!heap)
return DRM_ERR(EFAULT);
if (*heap) {
DRM_ERROR("heap already initialized?");
return DRM_ERR(EFAULT);
}
return init_heap( heap, initheap.start, initheap.size );
}
......@@ -719,7 +719,6 @@ static void radeon_cp_dispatch_swap( drm_device_t *dev )
RING_LOCALS;
DRM_DEBUG( "\n" );
/* Do some trivial performance monitoring...
*/
if (dev_priv->do_boxes)
......@@ -1088,6 +1087,8 @@ static int radeon_cp_dispatch_texture( drm_device_t *dev,
case RADEON_TXFORMAT_ARGB1555:
case RADEON_TXFORMAT_RGB565:
case RADEON_TXFORMAT_ARGB4444:
case RADEON_TXFORMAT_VYUY422:
case RADEON_TXFORMAT_YVYU422:
format = RADEON_COLOR_FORMAT_RGB565;
tex_width = tex->width * 2;
blit_width = image->width * 2;
......@@ -1226,6 +1227,7 @@ static int radeon_cp_dispatch_texture( drm_device_t *dev,
return ret;
}
static void radeon_cp_dispatch_stipple( drm_device_t *dev, u32 *stipple )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
......@@ -1306,6 +1308,9 @@ static int radeon_do_init_pageflip( drm_device_t *dev )
return 0;
}
/* Called whenever a client dies, from DRM(release).
* NOTE: Lock isn't necessarily held when this is called!
*/
int radeon_do_cleanup_pageflip( drm_device_t *dev )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
......@@ -1936,14 +1941,18 @@ static int radeon_emit_packet3_cliprect( drm_device_t *dev,
if ( i < cmdbuf->nbox ) {
if (DRM_COPY_FROM_USER_UNCHECKED( &box, &boxes[i], sizeof(box) ))
return DRM_ERR(EFAULT);
/* FIXME The second and subsequent times round this loop, send a
* WAIT_UNTIL_3D_IDLE before calling emit_clip_rect(). This
* fixes a lockup on fast machines when sending several
* cliprects with a cmdbuf, as when waving a 2D window over
* a 3D window. Something in the commands from user space
* seems to hang the card when they're sent several times
* in a row. That would be the correct place to fix it but
* this works around it until I can figure that out - Tim Smith */
/* FIXME The second and subsequent times round
* this loop, send a WAIT_UNTIL_3D_IDLE before
* calling emit_clip_rect(). This fixes a
* lockup on fast machines when sending
* several cliprects with a cmdbuf, as when
* waving a 2D window over a 3D
* window. Something in the commands from user
* space seems to hang the card when they're
* sent several times in a row. That would be
* the correct place to fix it but this works
* around it until I can figure that out - Tim
* Smith */
if ( i ) {
BEGIN_RING( 2 );
RADEON_WAIT_UNTIL_3D_IDLE();
......@@ -1967,6 +1976,34 @@ static int radeon_emit_packet3_cliprect( drm_device_t *dev,
}
static int radeon_emit_wait( drm_device_t *dev, int flags )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
DRM_DEBUG("%s: %x\n", __FUNCTION__, flags);
switch (flags) {
case RADEON_WAIT_2D:
BEGIN_RING( 2 );
RADEON_WAIT_UNTIL_2D_IDLE();
ADVANCE_RING();
break;
case RADEON_WAIT_3D:
BEGIN_RING( 2 );
RADEON_WAIT_UNTIL_3D_IDLE();
ADVANCE_RING();
break;
case RADEON_WAIT_2D|RADEON_WAIT_3D:
BEGIN_RING( 2 );
RADEON_WAIT_UNTIL_IDLE();
ADVANCE_RING();
break;
default:
return DRM_ERR(EINVAL);
}
return 0;
}
int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
{
......@@ -1989,7 +2026,6 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_radeon_cmd_buffer_t *)data,
sizeof(cmdbuf) );
DRM_DEBUG( "pid=%d\n", DRM_CURRENTPID );
RING_SPACE_TEST_WITH_RETURN( dev_priv );
VB_AGE_TEST_WITH_RETURN( dev_priv );
......@@ -2080,6 +2116,14 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
return DRM_ERR(EINVAL);
}
break;
case RADEON_CMD_WAIT:
DRM_DEBUG("RADEON_CMD_WAIT\n");
if (radeon_emit_wait( dev, header.wait.flags )) {
DRM_ERROR("radeon_emit_wait failed\n");
return DRM_ERR(EINVAL);
}
break;
default:
DRM_ERROR("bad cmd_type %d at %p\n",
header.header.cmd_type,
......@@ -2128,6 +2172,12 @@ int radeon_cp_getparam( DRM_IOCTL_ARGS )
dev_priv->stats.last_clear_reads++;
value = GET_SCRATCH( 2 );
break;
case RADEON_PARAM_IRQ_ACTIVE:
value = dev->irq ? 1 : 0;
break;
case RADEON_PARAM_AGP_BASE:
value = dev_priv->agp_vm_start;
break;
default:
return DRM_ERR(EINVAL);
}
......
......@@ -980,7 +980,7 @@ static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
best = NULL;
drive = hwgroup->drive;
do {
if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) {
if (!blk_queue_empty(&drive->queue) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) {
if (!best
|| (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
|| (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
......
......@@ -380,18 +380,21 @@ static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, lo
if (!list->ready && !list->buffer) {
add_wait_queue(&list->mousedev->wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
while (!list->ready) {
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
retval = 0;
if (list->ready || list->buffer)
break;
}
if (signal_pending(current)) {
retval = -ERESTARTSYS;
retval = -EAGAIN;
if (file->f_flags & O_NONBLOCK)
break;
retval = -ERESTARTSYS;
if (signal_pending(current))
break;
}
schedule();
}
......
......@@ -1142,6 +1142,7 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
struct usb_interface_descriptor *desc = interface->altsetting;
interface->dev.parent = &dev->dev;
interface->dev.driver = NULL;
interface->dev.bus = &usb_bus_type;
sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
dev->bus->busnum, dev->devpath,
......
......@@ -79,7 +79,7 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
if (HCC_EXT_CAPS (params)) {
// EHCI 0.96 ... could interpret these (legacy?)
dbg ("%s extended capabilities at pci %d",
dbg ("%s extended capabilities at pci %2x",
label, HCC_EXT_CAPS (params));
}
if (HCC_ISOC_CACHE (params)) {
......@@ -546,6 +546,18 @@ show_registers (struct device *dev, char *buf, size_t count, loff_t off)
next += temp;
}
#ifdef EHCI_STATS
temp = snprintf (next, size, "irq normal %ld err %ld reclaim %ld\n",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
size -= temp;
next += temp;
temp = snprintf (next, size, "complete %ld unlink %ld qpatch %ld\n",
ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch);
size -= temp;
next += temp;
#endif
spin_unlock_irqrestore (&ehci->lock, flags);
return count - size;
......
......@@ -63,8 +63,7 @@
* First was PCMCIA, like ISA; then CardBus, which is PCI.
* Next comes "CardBay", using USB 2.0 signals.
*
* Contains additional contributions by: Brad Hards, Rory Bolt, ...
*
* Contains additional contributions by Brad Hards, Rory Bolt, and others.
* Special thanks to Intel and VIA for providing host controllers to
* test this driver on, and Cypress (including In-System Design) for
* providing early devices for those host controllers to talk to!
......@@ -93,14 +92,20 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
#define DRIVER_VERSION "2002-Aug-28"
#define DRIVER_VERSION "2002-Sep-23"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
static const char hcd_name [] = "ehci-hcd";
// #define EHCI_VERBOSE_DEBUG
// #define have_split_iso
#ifdef DEBUG
#define EHCI_STATS
#endif
#define INTR_AUTOMAGIC /* to be removed later in 2.5 */
/* magic numbers that can affect system performance */
......@@ -118,6 +123,12 @@ static int log2_irq_thresh = 0; // 0 to 6
MODULE_PARM (log2_irq_thresh, "i");
MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
/* allow irqs at least every N URB completions */
static int max_completions = 16;
MODULE_PARM (max_completions, "i");
MODULE_PARM_DESC (max_completions,
"limit for urb completions called with irqs disenabled");
#define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
/*-------------------------------------------------------------------------*/
......@@ -426,11 +437,10 @@ static int ehci_start (struct usb_hcd *hcd)
/* PCI Serial Bus Release Number is at 0x60 offset */
pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
temp = readw (&ehci->caps->hci_version);
info ("USB %x.%x support enabled, EHCI rev %x.%02x",
((tempbyte & 0xf0)>>4),
(tempbyte & 0x0f),
temp >> 8,
temp & 0xff);
info ("USB %x.%x support enabled, EHCI rev %x.%02x, %s %s",
((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
temp >> 8, temp & 0xff,
hcd_name, DRIVER_VERSION);
/*
* From here on, khubd concurrently accesses the root
......@@ -441,11 +451,7 @@ static int ehci_start (struct usb_hcd *hcd)
*/
usb_connect (udev);
udev->speed = USB_SPEED_HIGH;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
if (usb_new_device (udev) != 0) {
#else
if (usb_register_root_hub (udev, &ehci->hcd.pdev->dev) != 0) {
#endif
if (hcd_register_root (hcd) != 0) {
if (hcd->state == USB_STATE_RUNNING)
ehci_ready (ehci);
ehci_reset (ehci);
......@@ -487,6 +493,13 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_tasklet ((unsigned long) ehci);
ehci_mem_cleanup (ehci);
#ifdef EHCI_STATS
dbg ("irq normal %ld err %ld reclaim %ld",
ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
dbg ("complete %ld unlink %ld qpatch %ld",
ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch);
#endif
dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
}
......@@ -591,21 +604,16 @@ dbg ("%s: resume port %d", hcd_to_bus (hcd)->bus_name, i);
static void ehci_tasklet (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags;
// FIXME don't pass flags; on sparc they aren't really flags.
// qh_completions can just leave irqs blocked,
// then have scan_async() allow IRQs if it's very busy
spin_lock_irqsave (&ehci->lock, flags);
spin_lock_irq (&ehci->lock);
if (ehci->reclaim_ready)
flags = end_unlink_async (ehci, flags);
flags = scan_async (ehci, flags);
end_unlink_async (ehci);
scan_async (ehci);
if (ehci->next_uframe != -1)
flags = scan_periodic (ehci, flags);
scan_periodic (ehci);
spin_unlock_irqrestore (&ehci->lock, flags);
spin_unlock_irq (&ehci->lock);
}
/*-------------------------------------------------------------------------*/
......@@ -639,11 +647,17 @@ static void ehci_irq (struct usb_hcd *hcd)
/* INT, ERR, and IAA interrupt rates can be throttled */
/* normal [4.15.1.2] or error [4.15.1.1] completion */
if (likely ((status & (STS_INT|STS_ERR)) != 0))
if (likely ((status & (STS_INT|STS_ERR)) != 0)) {
if (likely ((status & STS_ERR) == 0))
COUNT (ehci->stats.normal);
else
COUNT (ehci->stats.error);
bh = 1;
}
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
COUNT (ehci->stats.reclaim);
ehci->reclaim_ready = 1;
bh = 1;
}
......@@ -765,10 +779,10 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
spin_lock_irqsave (&ehci->lock, flags);
if (qh->qh_state == QH_STATE_LINKED) {
/* messy, can spin or block a microframe ... */
flags = intr_deschedule (ehci, qh, 1, flags);
intr_deschedule (ehci, qh, 1);
/* qh_state == IDLE */
}
flags = qh_completions (ehci, qh, flags);
qh_completions (ehci, qh);
/* reschedule QH iff another request is queued */
if (!list_empty (&qh->qtd_list)
......@@ -881,8 +895,6 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
/*-------------------------------------------------------------------------*/
static const char hcd_name [] = "ehci-hcd";
static const struct hc_driver ehci_driver = {
.description = hcd_name,
......
......@@ -239,7 +239,8 @@ static int ehci_hub_control (
/* whoever resets must GetPortStatus to complete it!! */
if ((temp & PORT_RESET)
&& jiffies > ehci->reset_done [wIndex]) {
&& time_after (jiffies,
ehci->reset_done [wIndex])) {
status |= 1 << USB_PORT_FEAT_C_RESET;
/* force reset to complete */
......
......@@ -158,16 +158,13 @@ static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token)
}
}
/* urb->lock ignored from here on (hcd is done with urb) */
static unsigned long ehci_urb_done (
struct ehci_hcd *ehci,
struct urb *urb,
unsigned long flags
) {
static void ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
{
#ifdef INTR_AUTOMAGIC
struct urb *resubmit = 0;
struct usb_device *dev = 0;
static int ehci_urb_enqueue (struct usb_hcd *, struct urb *, int);
#endif
if (likely (urb->hcpriv != 0)) {
......@@ -199,8 +196,15 @@ static unsigned long ehci_urb_done (
urb->status = 0;
}
if (likely (urb->status == 0))
COUNT (ehci->stats.complete);
else if (urb->status == -ECONNRESET || urb->status == -ENOENT)
COUNT (ehci->stats.unlink);
else
COUNT (ehci->stats.error);
/* complete() can reenter this HCD */
spin_unlock_irqrestore (&ehci->lock, flags);
spin_unlock (&ehci->lock);
usb_hcd_giveback_urb (&ehci->hcd, urb);
#ifdef INTR_AUTOMAGIC
......@@ -222,24 +226,25 @@ static unsigned long ehci_urb_done (
}
#endif
spin_lock_irqsave (&ehci->lock, flags);
return flags;
spin_lock (&ehci->lock);
}
/*
* Process and free completed qtds for a qh, returning URBs to drivers.
* Chases up to qh->hw_current, returns irqsave flags (maybe modified).
* Chases up to qh->hw_current. Returns number of completions called,
* indicating how much "real" work we did.
*/
static unsigned long
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qtd *qtd, *last;
struct list_head *next, *qtd_list = &qh->qtd_list;
int unlink = 0, halted = 0;
unsigned count = 0;
if (unlikely (list_empty (qtd_list)))
return flags;
return count;
/* scan QTDs till end of list, or we reach an active one */
for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list),
......@@ -252,8 +257,10 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
/* clean up any state from previous QTD ...*/
if (last) {
if (likely (last->urb != urb))
flags = ehci_urb_done (ehci, last->urb, flags);
if (likely (last->urb != urb)) {
ehci_urb_done (ehci, last->urb);
count++;
}
/* qh overlays can have HC's old cached copies of
* next qtd ptrs, if an URB was queued afterwards.
......@@ -262,6 +269,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
&& last->hw_next != qh->hw_qtd_next) {
qh->hw_alt_next = last->hw_alt_next;
qh->hw_qtd_next = last->hw_next;
COUNT (ehci->stats.qpatch);
}
ehci_qtd_free (ehci, last);
......@@ -347,7 +355,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
/* last urb's completion might still need calling */
if (likely (last != 0)) {
flags = ehci_urb_done (ehci, last->urb, flags);
ehci_urb_done (ehci, last->urb);
count++;
ehci_qtd_free (ehci, last);
}
......@@ -357,7 +366,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
struct ehci_qtd, qtd_list));
}
return flags;
return count;
}
/*-------------------------------------------------------------------------*/
......@@ -890,8 +899,7 @@ submit_async (
/* the async qh for the qtds being reclaimed are now unlinked from the HC */
/* caller must not own ehci->lock */
static unsigned long
end_unlink_async (struct ehci_hcd *ehci, unsigned long flags)
static void end_unlink_async (struct ehci_hcd *ehci)
{
struct ehci_qh *qh = ehci->reclaim;
......@@ -903,18 +911,15 @@ end_unlink_async (struct ehci_hcd *ehci, unsigned long flags)
ehci->reclaim = 0;
ehci->reclaim_ready = 0;
flags = qh_completions (ehci, qh, flags);
qh_completions (ehci, qh);
if (!list_empty (&qh->qtd_list)
&& HCD_IS_RUNNING (ehci->hcd.state))
qh_link_async (ehci, qh);
else
qh_put (ehci, qh); // refcount from async list
return flags;
}
/* makes sure the async qh will become idle */
/* caller must own ehci->lock */
......@@ -944,12 +949,14 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) {
/* can't get here without STS_ASS set */
if (ehci->hcd.state != USB_STATE_HALT) {
if (cmd & CMD_PSE) {
writel (cmd & ~CMD_ASE, &ehci->regs->command);
(void) handshake (&ehci->regs->status,
STS_ASS, 0, 150);
} else
ehci_ready (ehci);
writel (cmd & ~CMD_ASE, &ehci->regs->command);
(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
#if 0
// one VT8235 system wants to die with STS_FATAL
// unless this qh is leaked here. others seem ok...
qh = qh_get (qh);
dbg_qh ("async/off", ehci, qh);
#endif
}
qh->qh_next.qh = ehci->async = 0;
......@@ -986,13 +993,15 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
static unsigned long
scan_async (struct ehci_hcd *ehci, unsigned long flags)
static void
scan_async (struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
unsigned count;
rescan:
qh = ehci->async;
count = 0;
if (likely (qh != 0)) {
do {
/* clean any finished work for this qh */
......@@ -1001,13 +1010,16 @@ scan_async (struct ehci_hcd *ehci, unsigned long flags)
qh = qh_get (qh);
/* concurrent unlink could happen here */
flags = qh_completions (ehci, qh, flags);
count += qh_completions (ehci, qh);
qh_put (ehci, qh);
}
/* unlink idle entries, reducing HC PCI usage as
* well as HCD schedule-scanning costs. removing
* the last qh is deferred, since it's costly.
*
* FIXME don't unlink idle entries so quickly; it
* can penalize (common) half duplex protocols.
*/
if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
if (qh->qh_next.qh != qh) {
......@@ -1020,10 +1032,18 @@ scan_async (struct ehci_hcd *ehci, unsigned long flags)
jiffies + EHCI_ASYNC_JIFFIES);
}
}
/* keep latencies down: let any irqs in */
if (count > max_completions) {
spin_unlock_irq (&ehci->lock);
cpu_relax ();
spin_lock_irq (&ehci->lock);
goto rescan;
}
qh = qh->qh_next.qh;
if (!qh) /* unlinked? */
goto rescan;
} while (qh != ehci->async);
}
return flags;
}
......@@ -222,11 +222,10 @@ static int disable_periodic (struct ehci_hcd *ehci)
// FIXME microframe periods not yet handled
static unsigned long intr_deschedule (
static void intr_deschedule (
struct ehci_hcd *ehci,
struct ehci_qh *qh,
int wait,
unsigned long flags
int wait
) {
int status;
unsigned frame = qh->start;
......@@ -256,10 +255,8 @@ static unsigned long intr_deschedule (
*/
if (((ehci_get_frame (&ehci->hcd) - frame) % qh->period) == 0) {
if (wait) {
spin_unlock_irqrestore (&ehci->lock, flags);
udelay (125);
qh->hw_next = EHCI_LIST_END;
spin_lock_irqsave (&ehci->lock, flags);
} else {
/* we may not be IDLE yet, but if the qh is empty
* the race is very short. then if qh also isn't
......@@ -276,10 +273,9 @@ static unsigned long intr_deschedule (
hcd_to_bus (&ehci->hcd)->bandwidth_allocated -=
(qh->usecs + qh->c_usecs) / qh->period;
vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d",
qh, qh->period, frame,
atomic_read (&qh->refcount), ehci->periodic_sched);
return flags;
}
static int check_period (
......@@ -414,7 +410,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* stuff into the periodic schedule */
qh->qh_state = QH_STATE_LINKED;
dbg ("qh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)",
dbg ("scheduled qh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)",
qh, qh->usecs, qh->c_usecs,
qh->period, frame, uframe, qh->gap_uf);
do {
......@@ -495,29 +491,30 @@ static int intr_submit (
return status;
}
static unsigned long
static unsigned
intr_complete (
struct ehci_hcd *ehci,
unsigned frame,
struct ehci_qh *qh,
unsigned long flags /* caller owns ehci->lock ... */
struct ehci_qh *qh
) {
unsigned count;
/* nothing to report? */
if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
!= 0))
return flags;
return 0;
if (unlikely (list_empty (&qh->qtd_list))) {
dbg ("intr qh %p no TDs?", qh);
return flags;
return 0;
}
/* handle any completions */
flags = qh_completions (ehci, qh, flags);
count = qh_completions (ehci, qh);
if (unlikely (list_empty (&qh->qtd_list)))
flags = intr_deschedule (ehci, qh, 0, flags);
intr_deschedule (ehci, qh, 0);
return flags;
return count;
}
/*-------------------------------------------------------------------------*/
......@@ -866,12 +863,11 @@ itd_schedule (struct ehci_hcd *ehci, struct urb *urb)
#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
static unsigned long
static unsigned
itd_complete (
struct ehci_hcd *ehci,
struct ehci_itd *itd,
unsigned uframe,
unsigned long flags
unsigned uframe
) {
struct urb *urb = itd->urb;
struct usb_iso_packet_descriptor *desc;
......@@ -909,7 +905,7 @@ itd_complete (
/* handle completion now? */
if ((itd->index + 1) != urb->number_of_packets)
return flags;
return 0;
/*
* Always give the urb back to the driver ... expect it to submit
......@@ -924,16 +920,17 @@ itd_complete (
if (urb->status == -EINPROGRESS)
urb->status = 0;
spin_unlock_irqrestore (&ehci->lock, flags);
/* complete() can reenter this HCD */
spin_unlock (&ehci->lock);
usb_hcd_giveback_urb (&ehci->hcd, urb);
spin_lock_irqsave (&ehci->lock, flags);
spin_lock (&ehci->lock);
/* defer stopping schedule; completion can submit */
ehci->periodic_sched--;
if (!ehci->periodic_sched)
(void) disable_periodic (ehci);
return flags;
return 1;
}
/*-------------------------------------------------------------------------*/
......@@ -945,10 +942,6 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
dbg ("itd_submit urb %p", urb);
/* NOTE DMA mapping assumes this ... */
if (urb->iso_frame_desc [0].offset != 0)
return -EINVAL;
/* allocate ITDs w/o locking anything */
status = itd_urb_transaction (ehci, urb, mem_flags);
if (status < 0)
......@@ -979,10 +972,11 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
/*-------------------------------------------------------------------------*/
static unsigned long
scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
static void
scan_periodic (struct ehci_hcd *ehci)
{
unsigned frame, clock, now_uframe, mod;
unsigned count = 0;
mod = ehci->periodic_size << 3;
......@@ -1005,6 +999,14 @@ scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
u32 type, *hw_p;
unsigned uframes;
/* keep latencies down: let any irqs in */
if (count > max_completions) {
spin_unlock_irq (&ehci->lock);
cpu_relax ();
count = 0;
spin_lock_irq (&ehci->lock);
}
restart:
/* scan schedule to _before_ current frame index */
if (frame == clock)
......@@ -1028,8 +1030,8 @@ scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
last = (q.qh->hw_next == EHCI_LIST_END);
temp = q.qh->qh_next;
type = Q_NEXT_TYPE (q.qh->hw_next);
flags = intr_complete (ehci, frame,
qh_get (q.qh), flags);
count += intr_complete (ehci, frame,
qh_get (q.qh));
qh_put (ehci, q.qh);
q = temp;
break;
......@@ -1061,8 +1063,8 @@ scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
type = Q_NEXT_TYPE (*hw_p);
/* might free q.itd ... */
flags = itd_complete (ehci,
temp.itd, uf, flags);
count += itd_complete (ehci,
temp.itd, uf);
break;
}
}
......@@ -1078,7 +1080,7 @@ scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
#ifdef have_split_iso
case Q_TYPE_SITD:
last = (q.sitd->hw_next == EHCI_LIST_END);
flags = sitd_complete (ehci, q.sitd, flags);
sitd_complete (ehci, q.sitd);
type = Q_NEXT_TYPE (q.sitd->hw_next);
// FIXME unlink SITD after split completes
......@@ -1124,5 +1126,4 @@ scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
} else
frame = (frame + 1) % ehci->periodic_size;
}
return flags;
}
......@@ -21,6 +21,23 @@
/* definitions used for the EHCI driver */
/* statistics can be kept for for tuning/monitoring */
struct ehci_stats {
/* irq usage */
unsigned long normal;
unsigned long error;
unsigned long reclaim;
/* termination of urbs from core */
unsigned long complete;
unsigned long unlink;
/* qhs patched to recover from td queueing race
* (can avoid by using 'dummy td', allowing fewer irqs)
*/
unsigned long qpatch;
};
/* ehci_hcd->lock guards shared data against other CPUs:
* ehci_hcd: async, reclaim, periodic (and shadow), ...
* hcd_dev: ep[]
......@@ -72,6 +89,13 @@ struct ehci_hcd { /* one per controller */
struct pci_pool *sitd_pool; /* sitd per split iso urb */
struct timer_list watchdog;
#ifdef EHCI_STATS
struct ehci_stats stats;
# define COUNT(x) do { (x)++; } while (0)
#else
# define COUNT(x) do {} while (0)
#endif
};
/* unwrap an HCD pointer to get an EHCI_HCD pointer */
......@@ -400,10 +424,22 @@ struct ehci_fstn {
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb)
#define STUB_DEBUG_FILES
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_new_device (hcd_to_bus (hcd)->root_hub);
}
#else /* LINUX_VERSION_CODE */
// hcd_to_bus() eventually moves to hcd.h on 2.5 too
static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
{ return &hcd->self; }
// ... as does hcd_register_root()
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, &hcd->pdev->dev);
}
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
......
......@@ -92,6 +92,7 @@
#endif
#include <linux/usb.h>
#include <linux/version.h>
#include "../core/hcd.h"
#include <asm/io.h>
......@@ -108,7 +109,7 @@
* - lots more testing!!
*/
#define DRIVER_VERSION "2002-Sep-03"
#define DRIVER_VERSION "2002-Sep-17"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
......@@ -318,9 +319,6 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv;
int i;
unsigned long flags;
#ifdef DEBUG
int rescans = 0;
#endif
rescan:
/* free any eds, and dummy tds, still hanging around */
......@@ -340,16 +338,18 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
td_free (ohci, ed->dummy);
break;
default:
#ifdef DEBUG
err ("illegal ED %d state in free_config, %d",
err ("%s-%s ed %p (#%d) not unlinked; disconnect() bug? %d",
ohci->hcd.self.bus_name, udev->devpath, ed,
i, ed->state);
#endif
/* ED_OPER: some driver disconnect() is broken,
* it didn't even start its unlinks much less wait
* for their completions.
* OTHERWISE: hcd bug, ed is garbage
*
* ... we can't recycle this memory in either case,
* so just leak it to avoid oopsing.
*/
BUG ();
continue;
}
ed_free (ohci, ed);
}
......@@ -360,13 +360,9 @@ ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
#ifdef DEBUG
/* a driver->disconnect() returned before its unlinks completed? */
if (in_interrupt ()) {
dbg ("WARNING: spin in interrupt; driver->disconnect() bug");
dbg ("dev usb-%s-%s ep 0x%x",
warn ("disconnect() bug for dev usb-%s-%s ep 0x%x",
ohci->hcd.self.bus_name, udev->devpath, i);
}
BUG_ON (!(readl (&ohci->regs->intrenable) & OHCI_INTR_SF));
BUG_ON (rescans >= 2); /* HWBUG */
rescans++;
#endif
spin_unlock_irqrestore (&ohci->lock, flags);
......
This diff is collapsed.
......@@ -112,3 +112,13 @@ CONFIG_USB_SPEEDTCH
For more information, see Johan Verrept's webpages at
<http://linux-usb.sourceforge.net/SpeedTouch/>.
CONFIG_USB_LCD
Say Y here if you want to connect an USBLCD to your computer's
USB port. The USBLCD is a small USB interface board for
alphanumeric LCD modules. See <http://www.usblcd.de> for more
information.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called usblcd.o. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
/*****************************************************************************
* USBLCD Kernel Driver *
* See http://www.usblcd.de for Hardware and Documentation. *
* Version 1.01 *
* Version 1.03 *
* (C) 2002 Adams IT Services <info@usblcd.de> *
* *
* This file is licensed under the GPL. See COPYING in the package. *
......@@ -18,7 +18,7 @@
#include <asm/uaccess.h>
#include <linux/usb.h>
#define DRIVER_VERSION "USBLCD Driver Version 1.01"
#define DRIVER_VERSION "USBLCD Driver Version 1.03"
#define USBLCD_MINOR 144
......@@ -26,7 +26,7 @@
#define IOCTL_GET_DRV_VERSION 2
/* stall/wait timeout for USBLCD */
#define NAK_TIMEOUT (HZ)
#define NAK_TIMEOUT (10*HZ)
#define IBUF_SIZE 0x1000
#define OBUF_SIZE 0x10000
......@@ -318,7 +318,7 @@ static void disconnect_lcd(struct usb_interface *intf)
}
static struct usb_device_id id_table [] = {
{ .idVendor = 0x1212, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
{},
};
......
......@@ -232,6 +232,7 @@ struct usb_serial_device_type {
extern int usb_serial_register(struct usb_serial_device_type *new_device);
extern void usb_serial_deregister(struct usb_serial_device_type *device);
extern void usb_serial_port_softint(void *private);
extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
extern void usb_serial_disconnect(struct usb_interface *iface);
......
......@@ -498,7 +498,7 @@ int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *da
return -ENOMEM;
}
memcpy (transfer_buffer, data, length);
result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 3*HZ);
kfree (transfer_buffer);
return result;
}
......@@ -557,12 +557,11 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
retval = serial->type->open(port, filp);
else
retval = generic_open(port, filp);
}
if (retval) {
port->open_count = 0;
if (serial->type->owner)
__MOD_DEC_USE_COUNT(serial->type->owner);
if (retval) {
port->open_count = 0;
if (serial->type->owner)
__MOD_DEC_USE_COUNT(serial->type->owner);
}
}
up (&port->sem);
......@@ -1091,6 +1090,8 @@ static void generic_write_bulk_callback (struct urb *urb)
return;
}
usb_serial_port_softint((void *)port);
queue_task(&port->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
......@@ -1109,14 +1110,18 @@ static void generic_shutdown (struct usb_serial *serial)
}
}
static void port_softint(void *private)
void usb_serial_port_softint(void *private)
{
struct usb_serial_port *port = (struct usb_serial_port *)private;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct usb_serial *serial;
struct tty_struct *tty;
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port)
return;
serial = get_usb_serial (port, __FUNCTION__);
if (!serial)
return;
......@@ -1400,7 +1405,7 @@ int usb_serial_probe(struct usb_interface *interface,
port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
port->tqueue.routine = port_softint;
port->tqueue.routine = usb_serial_port_softint;
port->tqueue.data = port;
init_MUTEX (&port->sem);
}
......@@ -1690,6 +1695,7 @@ EXPORT_SYMBOL(usb_serial_register);
EXPORT_SYMBOL(usb_serial_deregister);
EXPORT_SYMBOL(usb_serial_probe);
EXPORT_SYMBOL(usb_serial_disconnect);
EXPORT_SYMBOL(usb_serial_port_softint);
#ifdef USES_EZUSB_FUNCTIONS
EXPORT_SYMBOL(ezusb_writememory);
EXPORT_SYMBOL(ezusb_set_reset);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment